brintos

brintos / linux-shallow public Read only

0
0
Text · 14.6 KiB · c96b773 Raw
652 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>4 */5 6 7#include <unistd.h>8#include <stdio.h>9#include <errno.h>10#include <stdlib.h>11#include <string.h>12#include <limits.h>13 14#include <getopt.h>15 16#include "cpufreq.h"17#include "helpers/sysfs.h"18#include "helpers/helpers.h"19#include "helpers/bitmask.h"20 21#define LINE_LEN 1022 23static unsigned int count_cpus(void)24{25	FILE *fp;26	char value[LINE_LEN];27	unsigned int ret = 0;28	unsigned int cpunr = 0;29 30	fp = fopen("/proc/stat", "r");31	if (!fp) {32		printf(_("Couldn't count the number of CPUs (%s: %s), assuming 1\n"), "/proc/stat", strerror(errno));33		return 1;34	}35 36	while (!feof(fp)) {37		if (!fgets(value, LINE_LEN, fp))38			continue;39		value[LINE_LEN - 1] = '\0';40		if (strlen(value) < (LINE_LEN - 2))41			continue;42		if (strstr(value, "cpu "))43			continue;44		if (sscanf(value, "cpu%d ", &cpunr) != 1)45			continue;46		if (cpunr > ret)47			ret = cpunr;48	}49	fclose(fp);50 51	/* cpu count starts from 0, on error return 1 (UP) */52	return ret + 1;53}54 55 56static void proc_cpufreq_output(void)57{58	unsigned int cpu, nr_cpus;59	struct cpufreq_policy *policy;60	unsigned int min_pctg = 0;61	unsigned int max_pctg = 0;62	unsigned long min, max;63 64	printf(_("          minimum CPU frequency  -  maximum CPU frequency  -  governor\n"));65 66	nr_cpus = count_cpus();67	for (cpu = 0; cpu < nr_cpus; cpu++) {68		policy = cpufreq_get_policy(cpu);69		if (!policy)70			continue;71 72		if (cpufreq_get_hardware_limits(cpu, &min, &max)) {73			max = 0;74		} else {75			min_pctg = (policy->min * 100) / max;76			max_pctg = (policy->max * 100) / max;77		}78		printf("CPU%3d    %9lu kHz (%3d %%)  -  %9lu kHz (%3d %%)  -  %s\n",79			cpu , policy->min, max ? min_pctg : 0, policy->max,80			max ? max_pctg : 0, policy->governor);81 82		cpufreq_put_policy(policy);83	}84}85 86static int no_rounding;87static void print_duration(unsigned long duration)88{89	unsigned long tmp;90 91	if (no_rounding) {92		if (duration > 1000000)93			printf("%u.%06u ms", ((unsigned int) duration/1000000),94				((unsigned int) duration%1000000));95		else if (duration > 100000)96			printf("%u us", ((unsigned int) duration/1000));97		else if (duration > 1000)98			printf("%u.%03u us", ((unsigned int) duration/1000),99				((unsigned int) duration%1000));100		else101			printf("%lu ns", duration);102	} else {103		if (duration > 1000000) {104			tmp = duration%10000;105			if (tmp >= 5000)106				duration += 10000;107			printf("%u.%02u ms", ((unsigned int) duration/1000000),108				((unsigned int) (duration%1000000)/10000));109		} else if (duration > 100000) {110			tmp = duration%1000;111			if (tmp >= 500)112				duration += 1000;113			printf("%u us", ((unsigned int) duration / 1000));114		} else if (duration > 1000) {115			tmp = duration%100;116			if (tmp >= 50)117				duration += 100;118			printf("%u.%01u us", ((unsigned int) duration/1000),119				((unsigned int) (duration%1000)/100));120		} else121			printf("%lu ns", duration);122	}123	return;124}125 126static int get_boost_mode_x86(unsigned int cpu)127{128	int support, active, b_states = 0, ret, pstate_no, i;129	/* ToDo: Make this more global */130	unsigned long pstates[MAX_HW_PSTATES] = {0,};131 132	ret = cpufreq_has_boost_support(cpu, &support, &active, &b_states);133	if (ret) {134		printf(_("Error while evaluating Boost Capabilities"135				" on CPU %d -- are you root?\n"), cpu);136		return ret;137	}138	/* P state changes via MSR are identified via cpuid 80000007139	   on Intel and AMD, but we assume boost capable machines can do that140	   if (cpuid_eax(0x80000000) >= 0x80000007141	   && (cpuid_edx(0x80000007) & (1 << 7)))142	*/143 144	printf(_("  boost state support:\n"));145 146	printf(_("    Supported: %s\n"), support ? _("yes") : _("no"));147	printf(_("    Active: %s\n"), active ? _("yes") : _("no"));148 149	if (cpupower_cpu_info.vendor == X86_VENDOR_AMD &&150	    cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_PSTATE) {151		return 0;152	} else if ((cpupower_cpu_info.vendor == X86_VENDOR_AMD &&153		    cpupower_cpu_info.family >= 0x10) ||154		   cpupower_cpu_info.vendor == X86_VENDOR_HYGON) {155		ret = decode_pstates(cpu, b_states, pstates, &pstate_no);156		if (ret)157			return ret;158 159		printf(_("    Boost States: %d\n"), b_states);160		printf(_("    Total States: %d\n"), pstate_no);161		for (i = 0; i < pstate_no; i++) {162			if (!pstates[i])163				continue;164			if (i < b_states)165				printf(_("    Pstate-Pb%d: %luMHz (boost state)"166					 "\n"), i, pstates[i]);167			else168				printf(_("    Pstate-P%d:  %luMHz\n"),169				       i - b_states, pstates[i]);170		}171	} else if (cpupower_cpu_info.caps & CPUPOWER_CAP_HAS_TURBO_RATIO) {172		double bclk;173		unsigned long long intel_turbo_ratio = 0;174		unsigned int ratio;175 176		/* Any way to autodetect this ? */177		if (cpupower_cpu_info.caps & CPUPOWER_CAP_IS_SNB)178			bclk = 100.00;179		else180			bclk = 133.33;181		intel_turbo_ratio = msr_intel_get_turbo_ratio(cpu);182		dprint ("    Ratio: 0x%llx - bclk: %f\n",183			intel_turbo_ratio, bclk);184 185		ratio = (intel_turbo_ratio >> 24) & 0xFF;186		if (ratio)187			printf(_("    %.0f MHz max turbo 4 active cores\n"),188			       ratio * bclk);189 190		ratio = (intel_turbo_ratio >> 16) & 0xFF;191		if (ratio)192			printf(_("    %.0f MHz max turbo 3 active cores\n"),193			       ratio * bclk);194 195		ratio = (intel_turbo_ratio >> 8) & 0xFF;196		if (ratio)197			printf(_("    %.0f MHz max turbo 2 active cores\n"),198			       ratio * bclk);199 200		ratio = (intel_turbo_ratio >> 0) & 0xFF;201		if (ratio)202			printf(_("    %.0f MHz max turbo 1 active cores\n"),203			       ratio * bclk);204	}205	return 0;206}207 208/* --boost / -b */209 210static int get_boost_mode(unsigned int cpu)211{212	struct cpufreq_available_frequencies *freqs;213 214	if (cpupower_cpu_info.vendor == X86_VENDOR_AMD ||215	    cpupower_cpu_info.vendor == X86_VENDOR_HYGON ||216	    cpupower_cpu_info.vendor == X86_VENDOR_INTEL)217		return get_boost_mode_x86(cpu);218 219	freqs = cpufreq_get_boost_frequencies(cpu);220	if (freqs) {221		printf(_("  boost frequency steps: "));222		while (freqs->next) {223			print_speed(freqs->frequency, no_rounding);224			printf(", ");225			freqs = freqs->next;226		}227		print_speed(freqs->frequency, no_rounding);228		printf("\n");229		cpufreq_put_available_frequencies(freqs);230	}231 232	return 0;233}234 235/* --freq / -f */236 237static int get_freq_kernel(unsigned int cpu, unsigned int human)238{239	unsigned long freq = cpufreq_get_freq_kernel(cpu);240	printf(_("  current CPU frequency: "));241	if (!freq) {242		printf(_(" Unable to call to kernel\n"));243		return -EINVAL;244	}245	if (human) {246		print_speed(freq, no_rounding);247	} else248		printf("%lu", freq);249	printf(_(" (asserted by call to kernel)\n"));250	return 0;251}252 253 254/* --hwfreq / -w */255 256static int get_freq_hardware(unsigned int cpu, unsigned int human)257{258	unsigned long freq = cpufreq_get_freq_hardware(cpu);259	printf(_("  current CPU frequency: "));260	if (!freq) {261		printf("Unable to call hardware\n");262		return -EINVAL;263	}264	if (human) {265		print_speed(freq, no_rounding);266	} else267		printf("%lu", freq);268	printf(_(" (asserted by call to hardware)\n"));269	return 0;270}271 272/* --hwlimits / -l */273 274static int get_hardware_limits(unsigned int cpu, unsigned int human)275{276	unsigned long min, max;277 278	if (cpufreq_get_hardware_limits(cpu, &min, &max)) {279		printf(_("Not Available\n"));280		return -EINVAL;281	}282 283	if (human) {284		printf(_("  hardware limits: "));285		print_speed(min, no_rounding);286		printf(" - ");287		print_speed(max, no_rounding);288		printf("\n");289	} else {290		printf("%lu %lu\n", min, max);291	}292	return 0;293}294 295/* --driver / -d */296 297static int get_driver(unsigned int cpu)298{299	char *driver = cpufreq_get_driver(cpu);300	if (!driver) {301		printf(_("  no or unknown cpufreq driver is active on this CPU\n"));302		return -EINVAL;303	}304	printf("  driver: %s\n", driver);305	cpufreq_put_driver(driver);306	return 0;307}308 309/* --policy / -p */310 311static int get_policy(unsigned int cpu)312{313	struct cpufreq_policy *policy = cpufreq_get_policy(cpu);314	if (!policy) {315		printf(_("  Unable to determine current policy\n"));316		return -EINVAL;317	}318	printf(_("  current policy: frequency should be within "));319	print_speed(policy->min, no_rounding);320	printf(_(" and "));321	print_speed(policy->max, no_rounding);322 323	printf(".\n                  ");324	printf(_("The governor \"%s\" may decide which speed to use\n"325	       "                  within this range.\n"),326	       policy->governor);327	cpufreq_put_policy(policy);328	return 0;329}330 331/* --governors / -g */332 333static int get_available_governors(unsigned int cpu)334{335	struct cpufreq_available_governors *governors =336		cpufreq_get_available_governors(cpu);337 338	printf(_("  available cpufreq governors: "));339	if (!governors) {340		printf(_("Not Available\n"));341		return -EINVAL;342	}343 344	while (governors->next) {345		printf("%s ", governors->governor);346		governors = governors->next;347	}348	printf("%s\n", governors->governor);349	cpufreq_put_available_governors(governors);350	return 0;351}352 353 354/* --affected-cpus  / -a */355 356static int get_affected_cpus(unsigned int cpu)357{358	struct cpufreq_affected_cpus *cpus = cpufreq_get_affected_cpus(cpu);359 360	printf(_("  CPUs which need to have their frequency coordinated by software: "));361	if (!cpus) {362		printf(_("Not Available\n"));363		return -EINVAL;364	}365 366	while (cpus->next) {367		printf("%d ", cpus->cpu);368		cpus = cpus->next;369	}370	printf("%d\n", cpus->cpu);371	cpufreq_put_affected_cpus(cpus);372	return 0;373}374 375/* --related-cpus  / -r */376 377static int get_related_cpus(unsigned int cpu)378{379	struct cpufreq_affected_cpus *cpus = cpufreq_get_related_cpus(cpu);380 381	printf(_("  CPUs which run at the same hardware frequency: "));382	if (!cpus) {383		printf(_("Not Available\n"));384		return -EINVAL;385	}386 387	while (cpus->next) {388		printf("%d ", cpus->cpu);389		cpus = cpus->next;390	}391	printf("%d\n", cpus->cpu);392	cpufreq_put_related_cpus(cpus);393	return 0;394}395 396/* --stats / -s */397 398static int get_freq_stats(unsigned int cpu, unsigned int human)399{400	unsigned long total_trans = cpufreq_get_transitions(cpu);401	unsigned long long total_time;402	struct cpufreq_stats *stats = cpufreq_get_stats(cpu, &total_time);403	while (stats) {404		if (human) {405			print_speed(stats->frequency, no_rounding);406			printf(":%.2f%%",407				(100.0 * stats->time_in_state) / total_time);408		} else409			printf("%lu:%llu",410				stats->frequency, stats->time_in_state);411		stats = stats->next;412		if (stats)413			printf(", ");414	}415	cpufreq_put_stats(stats);416	if (total_trans)417		printf("  (%lu)\n", total_trans);418	return 0;419}420 421/* --latency / -y */422 423static int get_latency(unsigned int cpu, unsigned int human)424{425	unsigned long latency = cpufreq_get_transition_latency(cpu);426 427	printf(_("  maximum transition latency: "));428	if (!latency || latency == UINT_MAX) {429		printf(_(" Cannot determine or is not supported.\n"));430		return -EINVAL;431	}432 433	if (human) {434		print_duration(latency);435		printf("\n");436	} else437		printf("%lu\n", latency);438	return 0;439}440 441/* --performance / -c */442 443static int get_perf_cap(unsigned int cpu)444{445	if (cpupower_cpu_info.vendor == X86_VENDOR_AMD &&446	    cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_PSTATE)447		amd_pstate_show_perf_and_freq(cpu, no_rounding);448 449	return 0;450}451 452static void debug_output_one(unsigned int cpu)453{454	struct cpufreq_available_frequencies *freqs;455 456	get_driver(cpu);457	get_related_cpus(cpu);458	get_affected_cpus(cpu);459	get_latency(cpu, 1);460	get_hardware_limits(cpu, 1);461 462	freqs = cpufreq_get_available_frequencies(cpu);463	if (freqs) {464		printf(_("  available frequency steps:  "));465		while (freqs->next) {466			print_speed(freqs->frequency, no_rounding);467			printf(", ");468			freqs = freqs->next;469		}470		print_speed(freqs->frequency, no_rounding);471		printf("\n");472		cpufreq_put_available_frequencies(freqs);473	}474 475	get_available_governors(cpu);476	get_policy(cpu);477	if (get_freq_hardware(cpu, 1) < 0)478		get_freq_kernel(cpu, 1);479	get_boost_mode(cpu);480	get_perf_cap(cpu);481}482 483static struct option info_opts[] = {484	{"debug",	 no_argument,		 NULL,	 'e'},485	{"boost",	 no_argument,		 NULL,	 'b'},486	{"freq",	 no_argument,		 NULL,	 'f'},487	{"hwfreq",	 no_argument,		 NULL,	 'w'},488	{"hwlimits",	 no_argument,		 NULL,	 'l'},489	{"driver",	 no_argument,		 NULL,	 'd'},490	{"policy",	 no_argument,		 NULL,	 'p'},491	{"governors",	 no_argument,		 NULL,	 'g'},492	{"related-cpus",  no_argument,	 NULL,	 'r'},493	{"affected-cpus", no_argument,	 NULL,	 'a'},494	{"stats",	 no_argument,		 NULL,	 's'},495	{"latency",	 no_argument,		 NULL,	 'y'},496	{"proc",	 no_argument,		 NULL,	 'o'},497	{"human",	 no_argument,		 NULL,	 'm'},498	{"no-rounding", no_argument,	 NULL,	 'n'},499	{"performance", no_argument,	 NULL,	 'c'},500	{ },501};502 503int cmd_freq_info(int argc, char **argv)504{505	extern char *optarg;506	extern int optind, opterr, optopt;507	int ret = 0, cont = 1;508	unsigned int cpu = 0;509	unsigned int human = 0;510	int output_param = 0;511 512	do {513		ret = getopt_long(argc, argv, "oefwldpgrasmybnc", info_opts,514				  NULL);515		switch (ret) {516		case '?':517			output_param = '?';518			cont = 0;519			break;520		case -1:521			cont = 0;522			break;523		case 'b':524		case 'o':525		case 'a':526		case 'r':527		case 'g':528		case 'p':529		case 'd':530		case 'l':531		case 'w':532		case 'f':533		case 'e':534		case 's':535		case 'y':536		case 'c':537			if (output_param) {538				output_param = -1;539				cont = 0;540				break;541			}542			output_param = ret;543			break;544		case 'm':545			if (human) {546				output_param = -1;547				cont = 0;548				break;549			}550			human = 1;551			break;552		case 'n':553			no_rounding = 1;554			break;555		default:556			fprintf(stderr, "invalid or unknown argument\n");557			return EXIT_FAILURE;558		}559	} while (cont);560 561	switch (output_param) {562	case 'o':563		if (!bitmask_isallclear(cpus_chosen)) {564			printf(_("The argument passed to this tool can't be "565				 "combined with passing a --cpu argument\n"));566			return -EINVAL;567		}568		break;569	case 0:570		output_param = 'e';571	}572 573	ret = 0;574 575	/* Default is: show output of base_cpu only */576	if (bitmask_isallclear(cpus_chosen))577		bitmask_setbit(cpus_chosen, base_cpu);578 579	switch (output_param) {580	case -1:581		printf(_("You can't specify more than one --cpu parameter and/or\n"582		       "more than one output-specific argument\n"));583		return -EINVAL;584	case '?':585		printf(_("invalid or unknown argument\n"));586		return -EINVAL;587	case 'o':588		proc_cpufreq_output();589		return EXIT_SUCCESS;590	}591 592	for (cpu = bitmask_first(cpus_chosen);593	     cpu <= bitmask_last(cpus_chosen); cpu++) {594 595		if (!bitmask_isbitset(cpus_chosen, cpu))596			continue;597 598		printf(_("analyzing CPU %d:\n"), cpu);599 600		if (sysfs_is_cpu_online(cpu) != 1) {601			printf(_(" *is offline\n"));602			printf("\n");603			continue;604		}605 606		switch (output_param) {607		case 'b':608			get_boost_mode(cpu);609			break;610		case 'e':611			debug_output_one(cpu);612			break;613		case 'a':614			ret = get_affected_cpus(cpu);615			break;616		case 'r':617			ret = get_related_cpus(cpu);618			break;619		case 'g':620			ret = get_available_governors(cpu);621			break;622		case 'p':623			ret = get_policy(cpu);624			break;625		case 'd':626			ret = get_driver(cpu);627			break;628		case 'l':629			ret = get_hardware_limits(cpu, human);630			break;631		case 'w':632			ret = get_freq_hardware(cpu, human);633			break;634		case 'f':635			ret = get_freq_kernel(cpu, human);636			break;637		case 's':638			ret = get_freq_stats(cpu, human);639			break;640		case 'y':641			ret = get_latency(cpu, human);642			break;643		case 'c':644			ret = get_perf_cap(cpu);645			break;646		}647		if (ret)648			return ret;649	}650	return ret;651}652