162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de> 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <unistd.h> 862306a36Sopenharmony_ci#include <stdio.h> 962306a36Sopenharmony_ci#include <errno.h> 1062306a36Sopenharmony_ci#include <stdlib.h> 1162306a36Sopenharmony_ci#include <string.h> 1262306a36Sopenharmony_ci#include <limits.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <getopt.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include "cpufreq.h" 1762306a36Sopenharmony_ci#include "helpers/sysfs.h" 1862306a36Sopenharmony_ci#include "helpers/helpers.h" 1962306a36Sopenharmony_ci#include "helpers/bitmask.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define LINE_LEN 10 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic unsigned int count_cpus(void) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci FILE *fp; 2662306a36Sopenharmony_ci char value[LINE_LEN]; 2762306a36Sopenharmony_ci unsigned int ret = 0; 2862306a36Sopenharmony_ci unsigned int cpunr = 0; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci fp = fopen("/proc/stat", "r"); 3162306a36Sopenharmony_ci if (!fp) { 3262306a36Sopenharmony_ci printf(_("Couldn't count the number of CPUs (%s: %s), assuming 1\n"), "/proc/stat", strerror(errno)); 3362306a36Sopenharmony_ci return 1; 3462306a36Sopenharmony_ci } 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci while (!feof(fp)) { 3762306a36Sopenharmony_ci if (!fgets(value, LINE_LEN, fp)) 3862306a36Sopenharmony_ci continue; 3962306a36Sopenharmony_ci value[LINE_LEN - 1] = '\0'; 4062306a36Sopenharmony_ci if (strlen(value) < (LINE_LEN - 2)) 4162306a36Sopenharmony_ci continue; 4262306a36Sopenharmony_ci if (strstr(value, "cpu ")) 4362306a36Sopenharmony_ci continue; 4462306a36Sopenharmony_ci if (sscanf(value, "cpu%d ", &cpunr) != 1) 4562306a36Sopenharmony_ci continue; 4662306a36Sopenharmony_ci if (cpunr > ret) 4762306a36Sopenharmony_ci ret = cpunr; 4862306a36Sopenharmony_ci } 4962306a36Sopenharmony_ci fclose(fp); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci /* cpu count starts from 0, on error return 1 (UP) */ 5262306a36Sopenharmony_ci return ret + 1; 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic void proc_cpufreq_output(void) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci unsigned int cpu, nr_cpus; 5962306a36Sopenharmony_ci struct cpufreq_policy *policy; 6062306a36Sopenharmony_ci unsigned int min_pctg = 0; 6162306a36Sopenharmony_ci unsigned int max_pctg = 0; 6262306a36Sopenharmony_ci unsigned long min, max; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci printf(_(" minimum CPU frequency - maximum CPU frequency - governor\n")); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci nr_cpus = count_cpus(); 6762306a36Sopenharmony_ci for (cpu = 0; cpu < nr_cpus; cpu++) { 6862306a36Sopenharmony_ci policy = cpufreq_get_policy(cpu); 6962306a36Sopenharmony_ci if (!policy) 7062306a36Sopenharmony_ci continue; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci if (cpufreq_get_hardware_limits(cpu, &min, &max)) { 7362306a36Sopenharmony_ci max = 0; 7462306a36Sopenharmony_ci } else { 7562306a36Sopenharmony_ci min_pctg = (policy->min * 100) / max; 7662306a36Sopenharmony_ci max_pctg = (policy->max * 100) / max; 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci printf("CPU%3d %9lu kHz (%3d %%) - %9lu kHz (%3d %%) - %s\n", 7962306a36Sopenharmony_ci cpu , policy->min, max ? min_pctg : 0, policy->max, 8062306a36Sopenharmony_ci max ? max_pctg : 0, policy->governor); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci cpufreq_put_policy(policy); 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic int no_rounding; 8762306a36Sopenharmony_cistatic void print_duration(unsigned long duration) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci unsigned long tmp; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci if (no_rounding) { 9262306a36Sopenharmony_ci if (duration > 1000000) 9362306a36Sopenharmony_ci printf("%u.%06u ms", ((unsigned int) duration/1000000), 9462306a36Sopenharmony_ci ((unsigned int) duration%1000000)); 9562306a36Sopenharmony_ci else if (duration > 100000) 9662306a36Sopenharmony_ci printf("%u us", ((unsigned int) duration/1000)); 9762306a36Sopenharmony_ci else if (duration > 1000) 9862306a36Sopenharmony_ci printf("%u.%03u us", ((unsigned int) duration/1000), 9962306a36Sopenharmony_ci ((unsigned int) duration%1000)); 10062306a36Sopenharmony_ci else 10162306a36Sopenharmony_ci printf("%lu ns", duration); 10262306a36Sopenharmony_ci } else { 10362306a36Sopenharmony_ci if (duration > 1000000) { 10462306a36Sopenharmony_ci tmp = duration%10000; 10562306a36Sopenharmony_ci if (tmp >= 5000) 10662306a36Sopenharmony_ci duration += 10000; 10762306a36Sopenharmony_ci printf("%u.%02u ms", ((unsigned int) duration/1000000), 10862306a36Sopenharmony_ci ((unsigned int) (duration%1000000)/10000)); 10962306a36Sopenharmony_ci } else if (duration > 100000) { 11062306a36Sopenharmony_ci tmp = duration%1000; 11162306a36Sopenharmony_ci if (tmp >= 500) 11262306a36Sopenharmony_ci duration += 1000; 11362306a36Sopenharmony_ci printf("%u us", ((unsigned int) duration / 1000)); 11462306a36Sopenharmony_ci } else if (duration > 1000) { 11562306a36Sopenharmony_ci tmp = duration%100; 11662306a36Sopenharmony_ci if (tmp >= 50) 11762306a36Sopenharmony_ci duration += 100; 11862306a36Sopenharmony_ci printf("%u.%01u us", ((unsigned int) duration/1000), 11962306a36Sopenharmony_ci ((unsigned int) (duration%1000)/100)); 12062306a36Sopenharmony_ci } else 12162306a36Sopenharmony_ci printf("%lu ns", duration); 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci return; 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic int get_boost_mode_x86(unsigned int cpu) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci int support, active, b_states = 0, ret, pstate_no, i; 12962306a36Sopenharmony_ci /* ToDo: Make this more global */ 13062306a36Sopenharmony_ci unsigned long pstates[MAX_HW_PSTATES] = {0,}; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci ret = cpufreq_has_boost_support(cpu, &support, &active, &b_states); 13362306a36Sopenharmony_ci if (ret) { 13462306a36Sopenharmony_ci printf(_("Error while evaluating Boost Capabilities" 13562306a36Sopenharmony_ci " on CPU %d -- are you root?\n"), cpu); 13662306a36Sopenharmony_ci return ret; 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci /* P state changes via MSR are identified via cpuid 80000007 13962306a36Sopenharmony_ci on Intel and AMD, but we assume boost capable machines can do that 14062306a36Sopenharmony_ci if (cpuid_eax(0x80000000) >= 0x80000007 14162306a36Sopenharmony_ci && (cpuid_edx(0x80000007) & (1 << 7))) 14262306a36Sopenharmony_ci */ 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci printf(_(" boost state support:\n")); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci printf(_(" Supported: %s\n"), support ? _("yes") : _("no")); 14762306a36Sopenharmony_ci printf(_(" Active: %s\n"), active ? _("yes") : _("no")); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci if (cpupower_cpu_info.vendor == X86_VENDOR_AMD && 15062306a36Sopenharmony_ci cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_PSTATE) { 15162306a36Sopenharmony_ci return 0; 15262306a36Sopenharmony_ci } else if ((cpupower_cpu_info.vendor == X86_VENDOR_AMD && 15362306a36Sopenharmony_ci cpupower_cpu_info.family >= 0x10) || 15462306a36Sopenharmony_ci cpupower_cpu_info.vendor == X86_VENDOR_HYGON) { 15562306a36Sopenharmony_ci ret = decode_pstates(cpu, b_states, pstates, &pstate_no); 15662306a36Sopenharmony_ci if (ret) 15762306a36Sopenharmony_ci return ret; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci printf(_(" Boost States: %d\n"), b_states); 16062306a36Sopenharmony_ci printf(_(" Total States: %d\n"), pstate_no); 16162306a36Sopenharmony_ci for (i = 0; i < pstate_no; i++) { 16262306a36Sopenharmony_ci if (!pstates[i]) 16362306a36Sopenharmony_ci continue; 16462306a36Sopenharmony_ci if (i < b_states) 16562306a36Sopenharmony_ci printf(_(" Pstate-Pb%d: %luMHz (boost state)" 16662306a36Sopenharmony_ci "\n"), i, pstates[i]); 16762306a36Sopenharmony_ci else 16862306a36Sopenharmony_ci printf(_(" Pstate-P%d: %luMHz\n"), 16962306a36Sopenharmony_ci i - b_states, pstates[i]); 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci } else if (cpupower_cpu_info.caps & CPUPOWER_CAP_HAS_TURBO_RATIO) { 17262306a36Sopenharmony_ci double bclk; 17362306a36Sopenharmony_ci unsigned long long intel_turbo_ratio = 0; 17462306a36Sopenharmony_ci unsigned int ratio; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci /* Any way to autodetect this ? */ 17762306a36Sopenharmony_ci if (cpupower_cpu_info.caps & CPUPOWER_CAP_IS_SNB) 17862306a36Sopenharmony_ci bclk = 100.00; 17962306a36Sopenharmony_ci else 18062306a36Sopenharmony_ci bclk = 133.33; 18162306a36Sopenharmony_ci intel_turbo_ratio = msr_intel_get_turbo_ratio(cpu); 18262306a36Sopenharmony_ci dprint (" Ratio: 0x%llx - bclk: %f\n", 18362306a36Sopenharmony_ci intel_turbo_ratio, bclk); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci ratio = (intel_turbo_ratio >> 24) & 0xFF; 18662306a36Sopenharmony_ci if (ratio) 18762306a36Sopenharmony_ci printf(_(" %.0f MHz max turbo 4 active cores\n"), 18862306a36Sopenharmony_ci ratio * bclk); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci ratio = (intel_turbo_ratio >> 16) & 0xFF; 19162306a36Sopenharmony_ci if (ratio) 19262306a36Sopenharmony_ci printf(_(" %.0f MHz max turbo 3 active cores\n"), 19362306a36Sopenharmony_ci ratio * bclk); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci ratio = (intel_turbo_ratio >> 8) & 0xFF; 19662306a36Sopenharmony_ci if (ratio) 19762306a36Sopenharmony_ci printf(_(" %.0f MHz max turbo 2 active cores\n"), 19862306a36Sopenharmony_ci ratio * bclk); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci ratio = (intel_turbo_ratio >> 0) & 0xFF; 20162306a36Sopenharmony_ci if (ratio) 20262306a36Sopenharmony_ci printf(_(" %.0f MHz max turbo 1 active cores\n"), 20362306a36Sopenharmony_ci ratio * bclk); 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci return 0; 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci/* --boost / -b */ 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic int get_boost_mode(unsigned int cpu) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci struct cpufreq_available_frequencies *freqs; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci if (cpupower_cpu_info.vendor == X86_VENDOR_AMD || 21562306a36Sopenharmony_ci cpupower_cpu_info.vendor == X86_VENDOR_HYGON || 21662306a36Sopenharmony_ci cpupower_cpu_info.vendor == X86_VENDOR_INTEL) 21762306a36Sopenharmony_ci return get_boost_mode_x86(cpu); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci freqs = cpufreq_get_boost_frequencies(cpu); 22062306a36Sopenharmony_ci if (freqs) { 22162306a36Sopenharmony_ci printf(_(" boost frequency steps: ")); 22262306a36Sopenharmony_ci while (freqs->next) { 22362306a36Sopenharmony_ci print_speed(freqs->frequency, no_rounding); 22462306a36Sopenharmony_ci printf(", "); 22562306a36Sopenharmony_ci freqs = freqs->next; 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci print_speed(freqs->frequency, no_rounding); 22862306a36Sopenharmony_ci printf("\n"); 22962306a36Sopenharmony_ci cpufreq_put_available_frequencies(freqs); 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci return 0; 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci/* --freq / -f */ 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic int get_freq_kernel(unsigned int cpu, unsigned int human) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci unsigned long freq = cpufreq_get_freq_kernel(cpu); 24062306a36Sopenharmony_ci printf(_(" current CPU frequency: ")); 24162306a36Sopenharmony_ci if (!freq) { 24262306a36Sopenharmony_ci printf(_(" Unable to call to kernel\n")); 24362306a36Sopenharmony_ci return -EINVAL; 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci if (human) { 24662306a36Sopenharmony_ci print_speed(freq, no_rounding); 24762306a36Sopenharmony_ci } else 24862306a36Sopenharmony_ci printf("%lu", freq); 24962306a36Sopenharmony_ci printf(_(" (asserted by call to kernel)\n")); 25062306a36Sopenharmony_ci return 0; 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci/* --hwfreq / -w */ 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_cistatic int get_freq_hardware(unsigned int cpu, unsigned int human) 25762306a36Sopenharmony_ci{ 25862306a36Sopenharmony_ci unsigned long freq = cpufreq_get_freq_hardware(cpu); 25962306a36Sopenharmony_ci printf(_(" current CPU frequency: ")); 26062306a36Sopenharmony_ci if (!freq) { 26162306a36Sopenharmony_ci printf("Unable to call hardware\n"); 26262306a36Sopenharmony_ci return -EINVAL; 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci if (human) { 26562306a36Sopenharmony_ci print_speed(freq, no_rounding); 26662306a36Sopenharmony_ci } else 26762306a36Sopenharmony_ci printf("%lu", freq); 26862306a36Sopenharmony_ci printf(_(" (asserted by call to hardware)\n")); 26962306a36Sopenharmony_ci return 0; 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci/* --hwlimits / -l */ 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_cistatic int get_hardware_limits(unsigned int cpu, unsigned int human) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci unsigned long min, max; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci if (cpufreq_get_hardware_limits(cpu, &min, &max)) { 27962306a36Sopenharmony_ci printf(_("Not Available\n")); 28062306a36Sopenharmony_ci return -EINVAL; 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci if (human) { 28462306a36Sopenharmony_ci printf(_(" hardware limits: ")); 28562306a36Sopenharmony_ci print_speed(min, no_rounding); 28662306a36Sopenharmony_ci printf(" - "); 28762306a36Sopenharmony_ci print_speed(max, no_rounding); 28862306a36Sopenharmony_ci printf("\n"); 28962306a36Sopenharmony_ci } else { 29062306a36Sopenharmony_ci printf("%lu %lu\n", min, max); 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci return 0; 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci/* --driver / -d */ 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistatic int get_driver(unsigned int cpu) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci char *driver = cpufreq_get_driver(cpu); 30062306a36Sopenharmony_ci if (!driver) { 30162306a36Sopenharmony_ci printf(_(" no or unknown cpufreq driver is active on this CPU\n")); 30262306a36Sopenharmony_ci return -EINVAL; 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci printf(" driver: %s\n", driver); 30562306a36Sopenharmony_ci cpufreq_put_driver(driver); 30662306a36Sopenharmony_ci return 0; 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci/* --policy / -p */ 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cistatic int get_policy(unsigned int cpu) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci struct cpufreq_policy *policy = cpufreq_get_policy(cpu); 31462306a36Sopenharmony_ci if (!policy) { 31562306a36Sopenharmony_ci printf(_(" Unable to determine current policy\n")); 31662306a36Sopenharmony_ci return -EINVAL; 31762306a36Sopenharmony_ci } 31862306a36Sopenharmony_ci printf(_(" current policy: frequency should be within ")); 31962306a36Sopenharmony_ci print_speed(policy->min, no_rounding); 32062306a36Sopenharmony_ci printf(_(" and ")); 32162306a36Sopenharmony_ci print_speed(policy->max, no_rounding); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci printf(".\n "); 32462306a36Sopenharmony_ci printf(_("The governor \"%s\" may decide which speed to use\n" 32562306a36Sopenharmony_ci " within this range.\n"), 32662306a36Sopenharmony_ci policy->governor); 32762306a36Sopenharmony_ci cpufreq_put_policy(policy); 32862306a36Sopenharmony_ci return 0; 32962306a36Sopenharmony_ci} 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci/* --governors / -g */ 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic int get_available_governors(unsigned int cpu) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci struct cpufreq_available_governors *governors = 33662306a36Sopenharmony_ci cpufreq_get_available_governors(cpu); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci printf(_(" available cpufreq governors: ")); 33962306a36Sopenharmony_ci if (!governors) { 34062306a36Sopenharmony_ci printf(_("Not Available\n")); 34162306a36Sopenharmony_ci return -EINVAL; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci while (governors->next) { 34562306a36Sopenharmony_ci printf("%s ", governors->governor); 34662306a36Sopenharmony_ci governors = governors->next; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci printf("%s\n", governors->governor); 34962306a36Sopenharmony_ci cpufreq_put_available_governors(governors); 35062306a36Sopenharmony_ci return 0; 35162306a36Sopenharmony_ci} 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci/* --affected-cpus / -a */ 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_cistatic int get_affected_cpus(unsigned int cpu) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci struct cpufreq_affected_cpus *cpus = cpufreq_get_affected_cpus(cpu); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci printf(_(" CPUs which need to have their frequency coordinated by software: ")); 36162306a36Sopenharmony_ci if (!cpus) { 36262306a36Sopenharmony_ci printf(_("Not Available\n")); 36362306a36Sopenharmony_ci return -EINVAL; 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci while (cpus->next) { 36762306a36Sopenharmony_ci printf("%d ", cpus->cpu); 36862306a36Sopenharmony_ci cpus = cpus->next; 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci printf("%d\n", cpus->cpu); 37162306a36Sopenharmony_ci cpufreq_put_affected_cpus(cpus); 37262306a36Sopenharmony_ci return 0; 37362306a36Sopenharmony_ci} 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci/* --related-cpus / -r */ 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_cistatic int get_related_cpus(unsigned int cpu) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci struct cpufreq_affected_cpus *cpus = cpufreq_get_related_cpus(cpu); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci printf(_(" CPUs which run at the same hardware frequency: ")); 38262306a36Sopenharmony_ci if (!cpus) { 38362306a36Sopenharmony_ci printf(_("Not Available\n")); 38462306a36Sopenharmony_ci return -EINVAL; 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci while (cpus->next) { 38862306a36Sopenharmony_ci printf("%d ", cpus->cpu); 38962306a36Sopenharmony_ci cpus = cpus->next; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci printf("%d\n", cpus->cpu); 39262306a36Sopenharmony_ci cpufreq_put_related_cpus(cpus); 39362306a36Sopenharmony_ci return 0; 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci/* --stats / -s */ 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_cistatic int get_freq_stats(unsigned int cpu, unsigned int human) 39962306a36Sopenharmony_ci{ 40062306a36Sopenharmony_ci unsigned long total_trans = cpufreq_get_transitions(cpu); 40162306a36Sopenharmony_ci unsigned long long total_time; 40262306a36Sopenharmony_ci struct cpufreq_stats *stats = cpufreq_get_stats(cpu, &total_time); 40362306a36Sopenharmony_ci while (stats) { 40462306a36Sopenharmony_ci if (human) { 40562306a36Sopenharmony_ci print_speed(stats->frequency, no_rounding); 40662306a36Sopenharmony_ci printf(":%.2f%%", 40762306a36Sopenharmony_ci (100.0 * stats->time_in_state) / total_time); 40862306a36Sopenharmony_ci } else 40962306a36Sopenharmony_ci printf("%lu:%llu", 41062306a36Sopenharmony_ci stats->frequency, stats->time_in_state); 41162306a36Sopenharmony_ci stats = stats->next; 41262306a36Sopenharmony_ci if (stats) 41362306a36Sopenharmony_ci printf(", "); 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci cpufreq_put_stats(stats); 41662306a36Sopenharmony_ci if (total_trans) 41762306a36Sopenharmony_ci printf(" (%lu)\n", total_trans); 41862306a36Sopenharmony_ci return 0; 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci/* --latency / -y */ 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cistatic int get_latency(unsigned int cpu, unsigned int human) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci unsigned long latency = cpufreq_get_transition_latency(cpu); 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci printf(_(" maximum transition latency: ")); 42862306a36Sopenharmony_ci if (!latency || latency == UINT_MAX) { 42962306a36Sopenharmony_ci printf(_(" Cannot determine or is not supported.\n")); 43062306a36Sopenharmony_ci return -EINVAL; 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci if (human) { 43462306a36Sopenharmony_ci print_duration(latency); 43562306a36Sopenharmony_ci printf("\n"); 43662306a36Sopenharmony_ci } else 43762306a36Sopenharmony_ci printf("%lu\n", latency); 43862306a36Sopenharmony_ci return 0; 43962306a36Sopenharmony_ci} 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci/* --performance / -c */ 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_cistatic int get_perf_cap(unsigned int cpu) 44462306a36Sopenharmony_ci{ 44562306a36Sopenharmony_ci if (cpupower_cpu_info.vendor == X86_VENDOR_AMD && 44662306a36Sopenharmony_ci cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_PSTATE) 44762306a36Sopenharmony_ci amd_pstate_show_perf_and_freq(cpu, no_rounding); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci return 0; 45062306a36Sopenharmony_ci} 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_cistatic void debug_output_one(unsigned int cpu) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci struct cpufreq_available_frequencies *freqs; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci get_driver(cpu); 45762306a36Sopenharmony_ci get_related_cpus(cpu); 45862306a36Sopenharmony_ci get_affected_cpus(cpu); 45962306a36Sopenharmony_ci get_latency(cpu, 1); 46062306a36Sopenharmony_ci get_hardware_limits(cpu, 1); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci freqs = cpufreq_get_available_frequencies(cpu); 46362306a36Sopenharmony_ci if (freqs) { 46462306a36Sopenharmony_ci printf(_(" available frequency steps: ")); 46562306a36Sopenharmony_ci while (freqs->next) { 46662306a36Sopenharmony_ci print_speed(freqs->frequency, no_rounding); 46762306a36Sopenharmony_ci printf(", "); 46862306a36Sopenharmony_ci freqs = freqs->next; 46962306a36Sopenharmony_ci } 47062306a36Sopenharmony_ci print_speed(freqs->frequency, no_rounding); 47162306a36Sopenharmony_ci printf("\n"); 47262306a36Sopenharmony_ci cpufreq_put_available_frequencies(freqs); 47362306a36Sopenharmony_ci } 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci get_available_governors(cpu); 47662306a36Sopenharmony_ci get_policy(cpu); 47762306a36Sopenharmony_ci if (get_freq_hardware(cpu, 1) < 0) 47862306a36Sopenharmony_ci get_freq_kernel(cpu, 1); 47962306a36Sopenharmony_ci get_boost_mode(cpu); 48062306a36Sopenharmony_ci get_perf_cap(cpu); 48162306a36Sopenharmony_ci} 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_cistatic struct option info_opts[] = { 48462306a36Sopenharmony_ci {"debug", no_argument, NULL, 'e'}, 48562306a36Sopenharmony_ci {"boost", no_argument, NULL, 'b'}, 48662306a36Sopenharmony_ci {"freq", no_argument, NULL, 'f'}, 48762306a36Sopenharmony_ci {"hwfreq", no_argument, NULL, 'w'}, 48862306a36Sopenharmony_ci {"hwlimits", no_argument, NULL, 'l'}, 48962306a36Sopenharmony_ci {"driver", no_argument, NULL, 'd'}, 49062306a36Sopenharmony_ci {"policy", no_argument, NULL, 'p'}, 49162306a36Sopenharmony_ci {"governors", no_argument, NULL, 'g'}, 49262306a36Sopenharmony_ci {"related-cpus", no_argument, NULL, 'r'}, 49362306a36Sopenharmony_ci {"affected-cpus", no_argument, NULL, 'a'}, 49462306a36Sopenharmony_ci {"stats", no_argument, NULL, 's'}, 49562306a36Sopenharmony_ci {"latency", no_argument, NULL, 'y'}, 49662306a36Sopenharmony_ci {"proc", no_argument, NULL, 'o'}, 49762306a36Sopenharmony_ci {"human", no_argument, NULL, 'm'}, 49862306a36Sopenharmony_ci {"no-rounding", no_argument, NULL, 'n'}, 49962306a36Sopenharmony_ci {"performance", no_argument, NULL, 'c'}, 50062306a36Sopenharmony_ci { }, 50162306a36Sopenharmony_ci}; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ciint cmd_freq_info(int argc, char **argv) 50462306a36Sopenharmony_ci{ 50562306a36Sopenharmony_ci extern char *optarg; 50662306a36Sopenharmony_ci extern int optind, opterr, optopt; 50762306a36Sopenharmony_ci int ret = 0, cont = 1; 50862306a36Sopenharmony_ci unsigned int cpu = 0; 50962306a36Sopenharmony_ci unsigned int human = 0; 51062306a36Sopenharmony_ci int output_param = 0; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci do { 51362306a36Sopenharmony_ci ret = getopt_long(argc, argv, "oefwldpgrasmybnc", info_opts, 51462306a36Sopenharmony_ci NULL); 51562306a36Sopenharmony_ci switch (ret) { 51662306a36Sopenharmony_ci case '?': 51762306a36Sopenharmony_ci output_param = '?'; 51862306a36Sopenharmony_ci cont = 0; 51962306a36Sopenharmony_ci break; 52062306a36Sopenharmony_ci case -1: 52162306a36Sopenharmony_ci cont = 0; 52262306a36Sopenharmony_ci break; 52362306a36Sopenharmony_ci case 'b': 52462306a36Sopenharmony_ci case 'o': 52562306a36Sopenharmony_ci case 'a': 52662306a36Sopenharmony_ci case 'r': 52762306a36Sopenharmony_ci case 'g': 52862306a36Sopenharmony_ci case 'p': 52962306a36Sopenharmony_ci case 'd': 53062306a36Sopenharmony_ci case 'l': 53162306a36Sopenharmony_ci case 'w': 53262306a36Sopenharmony_ci case 'f': 53362306a36Sopenharmony_ci case 'e': 53462306a36Sopenharmony_ci case 's': 53562306a36Sopenharmony_ci case 'y': 53662306a36Sopenharmony_ci case 'c': 53762306a36Sopenharmony_ci if (output_param) { 53862306a36Sopenharmony_ci output_param = -1; 53962306a36Sopenharmony_ci cont = 0; 54062306a36Sopenharmony_ci break; 54162306a36Sopenharmony_ci } 54262306a36Sopenharmony_ci output_param = ret; 54362306a36Sopenharmony_ci break; 54462306a36Sopenharmony_ci case 'm': 54562306a36Sopenharmony_ci if (human) { 54662306a36Sopenharmony_ci output_param = -1; 54762306a36Sopenharmony_ci cont = 0; 54862306a36Sopenharmony_ci break; 54962306a36Sopenharmony_ci } 55062306a36Sopenharmony_ci human = 1; 55162306a36Sopenharmony_ci break; 55262306a36Sopenharmony_ci case 'n': 55362306a36Sopenharmony_ci no_rounding = 1; 55462306a36Sopenharmony_ci break; 55562306a36Sopenharmony_ci default: 55662306a36Sopenharmony_ci fprintf(stderr, "invalid or unknown argument\n"); 55762306a36Sopenharmony_ci return EXIT_FAILURE; 55862306a36Sopenharmony_ci } 55962306a36Sopenharmony_ci } while (cont); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci switch (output_param) { 56262306a36Sopenharmony_ci case 'o': 56362306a36Sopenharmony_ci if (!bitmask_isallclear(cpus_chosen)) { 56462306a36Sopenharmony_ci printf(_("The argument passed to this tool can't be " 56562306a36Sopenharmony_ci "combined with passing a --cpu argument\n")); 56662306a36Sopenharmony_ci return -EINVAL; 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci break; 56962306a36Sopenharmony_ci case 0: 57062306a36Sopenharmony_ci output_param = 'e'; 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci ret = 0; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci /* Default is: show output of base_cpu only */ 57662306a36Sopenharmony_ci if (bitmask_isallclear(cpus_chosen)) 57762306a36Sopenharmony_ci bitmask_setbit(cpus_chosen, base_cpu); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci switch (output_param) { 58062306a36Sopenharmony_ci case -1: 58162306a36Sopenharmony_ci printf(_("You can't specify more than one --cpu parameter and/or\n" 58262306a36Sopenharmony_ci "more than one output-specific argument\n")); 58362306a36Sopenharmony_ci return -EINVAL; 58462306a36Sopenharmony_ci case '?': 58562306a36Sopenharmony_ci printf(_("invalid or unknown argument\n")); 58662306a36Sopenharmony_ci return -EINVAL; 58762306a36Sopenharmony_ci case 'o': 58862306a36Sopenharmony_ci proc_cpufreq_output(); 58962306a36Sopenharmony_ci return EXIT_SUCCESS; 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci for (cpu = bitmask_first(cpus_chosen); 59362306a36Sopenharmony_ci cpu <= bitmask_last(cpus_chosen); cpu++) { 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci if (!bitmask_isbitset(cpus_chosen, cpu)) 59662306a36Sopenharmony_ci continue; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci printf(_("analyzing CPU %d:\n"), cpu); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci if (sysfs_is_cpu_online(cpu) != 1) { 60162306a36Sopenharmony_ci printf(_(" *is offline\n")); 60262306a36Sopenharmony_ci printf("\n"); 60362306a36Sopenharmony_ci continue; 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci switch (output_param) { 60762306a36Sopenharmony_ci case 'b': 60862306a36Sopenharmony_ci get_boost_mode(cpu); 60962306a36Sopenharmony_ci break; 61062306a36Sopenharmony_ci case 'e': 61162306a36Sopenharmony_ci debug_output_one(cpu); 61262306a36Sopenharmony_ci break; 61362306a36Sopenharmony_ci case 'a': 61462306a36Sopenharmony_ci ret = get_affected_cpus(cpu); 61562306a36Sopenharmony_ci break; 61662306a36Sopenharmony_ci case 'r': 61762306a36Sopenharmony_ci ret = get_related_cpus(cpu); 61862306a36Sopenharmony_ci break; 61962306a36Sopenharmony_ci case 'g': 62062306a36Sopenharmony_ci ret = get_available_governors(cpu); 62162306a36Sopenharmony_ci break; 62262306a36Sopenharmony_ci case 'p': 62362306a36Sopenharmony_ci ret = get_policy(cpu); 62462306a36Sopenharmony_ci break; 62562306a36Sopenharmony_ci case 'd': 62662306a36Sopenharmony_ci ret = get_driver(cpu); 62762306a36Sopenharmony_ci break; 62862306a36Sopenharmony_ci case 'l': 62962306a36Sopenharmony_ci ret = get_hardware_limits(cpu, human); 63062306a36Sopenharmony_ci break; 63162306a36Sopenharmony_ci case 'w': 63262306a36Sopenharmony_ci ret = get_freq_hardware(cpu, human); 63362306a36Sopenharmony_ci break; 63462306a36Sopenharmony_ci case 'f': 63562306a36Sopenharmony_ci ret = get_freq_kernel(cpu, human); 63662306a36Sopenharmony_ci break; 63762306a36Sopenharmony_ci case 's': 63862306a36Sopenharmony_ci ret = get_freq_stats(cpu, human); 63962306a36Sopenharmony_ci break; 64062306a36Sopenharmony_ci case 'y': 64162306a36Sopenharmony_ci ret = get_latency(cpu, human); 64262306a36Sopenharmony_ci break; 64362306a36Sopenharmony_ci case 'c': 64462306a36Sopenharmony_ci ret = get_perf_cap(cpu); 64562306a36Sopenharmony_ci break; 64662306a36Sopenharmony_ci } 64762306a36Sopenharmony_ci if (ret) 64862306a36Sopenharmony_ci return ret; 64962306a36Sopenharmony_ci } 65062306a36Sopenharmony_ci return ret; 65162306a36Sopenharmony_ci} 652