// SPDX-License-Identifier: GPL-2.0 /* * Intel dynamic_speed_select -- Enumerate and control features * Copyright (c) 2019 Intel Corporation. */ #include "isst.h" #define DISP_FREQ_MULTIPLIER 100000 static void printcpumask(int str_len, char *str, int mask_size, cpu_set_t *cpu_mask) { int i, max_cpus = get_topo_max_cpus(); unsigned int *mask; int size, index, curr_index; size = max_cpus / (sizeof(unsigned int) * 8); if (max_cpus % (sizeof(unsigned int) * 8)) size++; mask = calloc(size, sizeof(unsigned int)); if (!mask) return; for (i = 0; i < max_cpus; ++i) { int mask_index, bit_index; if (!CPU_ISSET_S(i, mask_size, cpu_mask)) continue; mask_index = i / (sizeof(unsigned int) * 8); bit_index = i % (sizeof(unsigned int) * 8); mask[mask_index] |= BIT(bit_index); } curr_index = 0; for (i = size - 1; i >= 0; --i) { index = snprintf(&str[curr_index], str_len - curr_index, "%08x", mask[i]); curr_index += index; if (i) { strncat(&str[curr_index], ",", str_len - curr_index); curr_index++; } } free(mask); } static void format_and_print_txt(FILE *outf, int level, char *header, char *value) { char *spaces = " "; static char delimiters[256]; int i, j = 0; if (!level) return; if (level == 1) { strcpy(delimiters, " "); } else { for (i = 0; i < level - 1; ++i) j += snprintf(&delimiters[j], sizeof(delimiters) - j, "%s", spaces); } if (header && value) { fprintf(outf, "%s", delimiters); fprintf(outf, "%s:%s\n", header, value); } else if (header) { fprintf(outf, "%s", delimiters); fprintf(outf, "%s\n", header); } } static int last_level; static void format_and_print(FILE *outf, int level, char *header, char *value) { char *spaces = " "; static char delimiters[256]; int i; if (!out_format_is_json()) { format_and_print_txt(outf, level, header, value); return; } if (level == 0) { if (header) fprintf(outf, "{"); else fprintf(outf, "\n}\n"); } else { int j = 0; for (i = 0; i < level; ++i) j += snprintf(&delimiters[j], sizeof(delimiters) - j, "%s", spaces); if (last_level == level) fprintf(outf, ",\n"); if (value) { if (last_level != level) fprintf(outf, "\n"); fprintf(outf, "%s\"%s\": ", delimiters, header); fprintf(outf, "\"%s\"", value); } else { for (i = last_level - 1; i >= level; --i) { int k = 0; for (j = i; j > 0; --j) k += snprintf(&delimiters[k], sizeof(delimiters) - k, "%s", spaces); if (i == level && header) fprintf(outf, "\n%s},", delimiters); else fprintf(outf, "\n%s}", delimiters); } if (abs(last_level - level) < 3) fprintf(outf, "\n"); if (header) fprintf(outf, "%s\"%s\": {", delimiters, header); } } last_level = level; } static void print_packag_info(int cpu, FILE *outf) { char header[256]; snprintf(header, sizeof(header), "package-%d", get_physical_package_id(cpu)); format_and_print(outf, 1, header, NULL); snprintf(header, sizeof(header), "die-%d", get_physical_die_id(cpu)); format_and_print(outf, 2, header, NULL); snprintf(header, sizeof(header), "cpu-%d", cpu); format_and_print(outf, 3, header, NULL); } static void _isst_pbf_display_information(int cpu, FILE *outf, int level, struct isst_pbf_info *pbf_info, int disp_level) { char header[256]; char value[256]; snprintf(header, sizeof(header), "speed-select-base-freq"); format_and_print(outf, disp_level, header, NULL); snprintf(header, sizeof(header), "high-priority-base-frequency(KHz)"); snprintf(value, sizeof(value), "%d", pbf_info->p1_high * DISP_FREQ_MULTIPLIER); format_and_print(outf, disp_level + 1, header, value); snprintf(header, sizeof(header), "high-priority-cpu-mask"); printcpumask(sizeof(value), value, pbf_info->core_cpumask_size, pbf_info->core_cpumask); format_and_print(outf, disp_level + 1, header, value); snprintf(header, sizeof(header), "low-priority-base-frequency(KHz)"); snprintf(value, sizeof(value), "%d", pbf_info->p1_low * DISP_FREQ_MULTIPLIER); format_and_print(outf, disp_level + 1, header, value); snprintf(header, sizeof(header), "tjunction-temperature(C)"); snprintf(value, sizeof(value), "%d", pbf_info->t_prochot); format_and_print(outf, disp_level + 1, header, value); snprintf(header, sizeof(header), "thermal-design-power(W)"); snprintf(value, sizeof(value), "%d", pbf_info->tdp); format_and_print(outf, disp_level + 1, header, value); } static void _isst_fact_display_information(int cpu, FILE *outf, int level, int fact_bucket, int fact_avx, struct isst_fact_info *fact_info, int base_level) { struct isst_fact_bucket_info *bucket_info = fact_info->bucket_info; char header[256]; char value[256]; int j; snprintf(header, sizeof(header), "speed-select-turbo-freq"); format_and_print(outf, base_level, header, NULL); for (j = 0; j < ISST_FACT_MAX_BUCKETS; ++j) { if (fact_bucket != 0xff && fact_bucket != j) continue; if (!bucket_info[j].high_priority_cores_count) break; snprintf(header, sizeof(header), "bucket-%d", j); format_and_print(outf, base_level + 1, header, NULL); snprintf(header, sizeof(header), "high-priority-cores-count"); snprintf(value, sizeof(value), "%d", bucket_info[j].high_priority_cores_count); format_and_print(outf, base_level + 2, header, value); if (fact_avx & 0x01) { snprintf(header, sizeof(header), "high-priority-max-frequency(KHz)"); snprintf(value, sizeof(value), "%d", bucket_info[j].sse_trl * DISP_FREQ_MULTIPLIER); format_and_print(outf, base_level + 2, header, value); } if (fact_avx & 0x02) { snprintf(header, sizeof(header), "high-priority-max-avx2-frequency(KHz)"); snprintf(value, sizeof(value), "%d", bucket_info[j].avx_trl * DISP_FREQ_MULTIPLIER); format_and_print(outf, base_level + 2, header, value); } if (fact_avx & 0x04) { snprintf(header, sizeof(header), "high-priority-max-avx512-frequency(KHz)"); snprintf(value, sizeof(value), "%d", bucket_info[j].avx512_trl * DISP_FREQ_MULTIPLIER); format_and_print(outf, base_level + 2, header, value); } } snprintf(header, sizeof(header), "speed-select-turbo-freq-clip-frequencies"); format_and_print(outf, base_level + 1, header, NULL); snprintf(header, sizeof(header), "low-priority-max-frequency(KHz)"); snprintf(value, sizeof(value), "%d", fact_info->lp_clipping_ratio_license_sse * DISP_FREQ_MULTIPLIER); format_and_print(outf, base_level + 2, header, value); snprintf(header, sizeof(header), "low-priority-max-avx2-frequency(KHz)"); snprintf(value, sizeof(value), "%d", fact_info->lp_clipping_ratio_license_avx2 * DISP_FREQ_MULTIPLIER); format_and_print(outf, base_level + 2, header, value); snprintf(header, sizeof(header), "low-priority-max-avx512-frequency(KHz)"); snprintf(value, sizeof(value), "%d", fact_info->lp_clipping_ratio_license_avx512 * DISP_FREQ_MULTIPLIER); format_and_print(outf, base_level + 2, header, value); } void isst_ctdp_display_information(int cpu, FILE *outf, int tdp_level, struct isst_pkg_ctdp *pkg_dev) { char header[256]; char value[256]; int i, base_level = 1; print_packag_info(cpu, outf); for (i = 0; i <= pkg_dev->levels; ++i) { struct isst_pkg_ctdp_level_info *ctdp_level; int j; ctdp_level = &pkg_dev->ctdp_level[i]; if (!ctdp_level->processed) continue; snprintf(header, sizeof(header), "perf-profile-level-%d", ctdp_level->level); format_and_print(outf, base_level + 3, header, NULL); snprintf(header, sizeof(header), "cpu-count"); j = get_cpu_count(get_physical_die_id(cpu), get_physical_die_id(cpu)); snprintf(value, sizeof(value), "%d", j); format_and_print(outf, base_level + 4, header, value); snprintf(header, sizeof(header), "enable-cpu-mask"); printcpumask(sizeof(value), value, ctdp_level->core_cpumask_size, ctdp_level->core_cpumask); format_and_print(outf, base_level + 4, header, value); snprintf(header, sizeof(header), "thermal-design-power-ratio"); snprintf(value, sizeof(value), "%d", ctdp_level->tdp_ratio); format_and_print(outf, base_level + 4, header, value); snprintf(header, sizeof(header), "base-frequency(KHz)"); snprintf(value, sizeof(value), "%d", ctdp_level->tdp_ratio * DISP_FREQ_MULTIPLIER); format_and_print(outf, base_level + 4, header, value); snprintf(header, sizeof(header), "speed-select-turbo-freq-support"); snprintf(value, sizeof(value), "%d", ctdp_level->fact_support); format_and_print(outf, base_level + 4, header, value); snprintf(header, sizeof(header), "speed-select-base-freq-support"); snprintf(value, sizeof(value), "%d", ctdp_level->pbf_support); format_and_print(outf, base_level + 4, header, value); snprintf(header, sizeof(header), "speed-select-base-freq-enabled"); snprintf(value, sizeof(value), "%d", ctdp_level->pbf_enabled); format_and_print(outf, base_level + 4, header, value); snprintf(header, sizeof(header), "speed-select-turbo-freq-enabled"); snprintf(value, sizeof(value), "%d", ctdp_level->fact_enabled); format_and_print(outf, base_level + 4, header, value); snprintf(header, sizeof(header), "thermal-design-power(W)"); snprintf(value, sizeof(value), "%d", ctdp_level->pkg_tdp); format_and_print(outf, base_level + 4, header, value); snprintf(header, sizeof(header), "tjunction-max(C)"); snprintf(value, sizeof(value), "%d", ctdp_level->t_proc_hot); format_and_print(outf, base_level + 4, header, value); snprintf(header, sizeof(header), "turbo-ratio-limits-sse"); format_and_print(outf, base_level + 4, header, NULL); for (j = 0; j < 8; ++j) { snprintf(header, sizeof(header), "bucket-%d", j); format_and_print(outf, base_level + 5, header, NULL); snprintf(header, sizeof(header), "core-count"); snprintf(value, sizeof(value), "%d", j); format_and_print(outf, base_level + 6, header, value); snprintf(header, sizeof(header), "turbo-ratio"); snprintf(value, sizeof(value), "%d", ctdp_level->trl_sse_active_cores[j]); format_and_print(outf, base_level + 6, header, value); } snprintf(header, sizeof(header), "turbo-ratio-limits-avx"); format_and_print(outf, base_level + 4, header, NULL); for (j = 0; j < 8; ++j) { snprintf(header, sizeof(header), "bucket-%d", j); format_and_print(outf, base_level + 5, header, NULL); snprintf(header, sizeof(header), "core-count"); snprintf(value, sizeof(value), "%d", j); format_and_print(outf, base_level + 6, header, value); snprintf(header, sizeof(header), "turbo-ratio"); snprintf(value, sizeof(value), "%d", ctdp_level->trl_avx_active_cores[j]); format_and_print(outf, base_level + 6, header, value); } snprintf(header, sizeof(header), "turbo-ratio-limits-avx512"); format_and_print(outf, base_level + 4, header, NULL); for (j = 0; j < 8; ++j) { snprintf(header, sizeof(header), "bucket-%d", j); format_and_print(outf, base_level + 5, header, NULL); snprintf(header, sizeof(header), "core-count"); snprintf(value, sizeof(value), "%d", j); format_and_print(outf, base_level + 6, header, value); snprintf(header, sizeof(header), "turbo-ratio"); snprintf(value, sizeof(value), "%d", ctdp_level->trl_avx_512_active_cores[j]); format_and_print(outf, base_level + 6, header, value); } if (ctdp_level->pbf_support) _isst_pbf_display_information(cpu, outf, i, &ctdp_level->pbf_info, base_level + 4); if (ctdp_level->fact_support) _isst_fact_display_information(cpu, outf, i, 0xff, 0xff, &ctdp_level->fact_info, base_level + 4); } format_and_print(outf, 1, NULL, NULL); } void isst_ctdp_display_information_start(FILE *outf) { last_level = 0; format_and_print(outf, 0, "start", NULL); } void isst_ctdp_display_information_end(FILE *outf) { format_and_print(outf, 0, NULL, NULL); } void isst_pbf_display_information(int cpu, FILE *outf, int level, struct isst_pbf_info *pbf_info) { print_packag_info(cpu, outf); _isst_pbf_display_information(cpu, outf, level, pbf_info, 4); format_and_print(outf, 1, NULL, NULL); } void isst_fact_display_information(int cpu, FILE *outf, int level, int fact_bucket, int fact_avx, struct isst_fact_info *fact_info) { print_packag_info(cpu, outf); _isst_fact_display_information(cpu, outf, level, fact_bucket, fact_avx, fact_info, 4); format_and_print(outf, 1, NULL, NULL); } void isst_clos_display_information(int cpu, FILE *outf, int clos, struct isst_clos_config *clos_config) { char header[256]; char value[256]; snprintf(header, sizeof(header), "package-%d", get_physical_package_id(cpu)); format_and_print(outf, 1, header, NULL); snprintf(header, sizeof(header), "die-%d", get_physical_die_id(cpu)); format_and_print(outf, 2, header, NULL); snprintf(header, sizeof(header), "cpu-%d", cpu); format_and_print(outf, 3, header, NULL); snprintf(header, sizeof(header), "core-power"); format_and_print(outf, 4, header, NULL); snprintf(header, sizeof(header), "clos"); snprintf(value, sizeof(value), "%d", clos); format_and_print(outf, 5, header, value); snprintf(header, sizeof(header), "epp"); snprintf(value, sizeof(value), "%d", clos_config->epp); format_and_print(outf, 5, header, value); snprintf(header, sizeof(header), "clos-proportional-priority"); snprintf(value, sizeof(value), "%d", clos_config->clos_prop_prio); format_and_print(outf, 5, header, value); snprintf(header, sizeof(header), "clos-min"); snprintf(value, sizeof(value), "%d", clos_config->clos_min); format_and_print(outf, 5, header, value); snprintf(header, sizeof(header), "clos-max"); snprintf(value, sizeof(value), "%d", clos_config->clos_max); format_and_print(outf, 5, header, value); snprintf(header, sizeof(header), "clos-desired"); snprintf(value, sizeof(value), "%d", clos_config->clos_desired); format_and_print(outf, 5, header, value); format_and_print(outf, 1, NULL, NULL); } void isst_display_result(int cpu, FILE *outf, char *feature, char *cmd, int result) { char header[256]; char value[256]; snprintf(header, sizeof(header), "package-%d", get_physical_package_id(cpu)); format_and_print(outf, 1, header, NULL); snprintf(header, sizeof(header), "die-%d", get_physical_die_id(cpu)); format_and_print(outf, 2, header, NULL); snprintf(header, sizeof(header), "cpu-%d", cpu); format_and_print(outf, 3, header, NULL); snprintf(header, sizeof(header), "%s", feature); format_and_print(outf, 4, header, NULL); snprintf(header, sizeof(header), "%s", cmd); snprintf(value, sizeof(value), "%d", result); format_and_print(outf, 5, header, value); format_and_print(outf, 1, NULL, NULL); }