| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  Licensed under the terms of the GNU GPL License version 2. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <unistd.h>
 | 
					
						
							|  |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  | #include <errno.h>
 | 
					
						
							|  |  |  | #include <stdlib.h>
 | 
					
						
							|  |  |  | #include <string.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <getopt.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "cpufreq.h"
 | 
					
						
							|  |  |  | #include "helpers/helpers.h"
 | 
					
						
							|  |  |  | #include "helpers/bitmask.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define LINE_LEN 10
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static unsigned int count_cpus(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	FILE *fp; | 
					
						
							|  |  |  | 	char value[LINE_LEN]; | 
					
						
							|  |  |  | 	unsigned int ret = 0; | 
					
						
							|  |  |  | 	unsigned int cpunr = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	fp = fopen("/proc/stat", "r"); | 
					
						
							| 
									
										
										
										
											2011-04-19 20:33:50 +02:00
										 |  |  | 	if (!fp) { | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 		printf(_("Couldn't count the number of CPUs (%s: %s), assuming 1\n"), "/proc/stat", strerror(errno)); | 
					
						
							|  |  |  | 		return 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (!feof(fp)) { | 
					
						
							|  |  |  | 		if (!fgets(value, LINE_LEN, fp)) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		value[LINE_LEN - 1] = '\0'; | 
					
						
							|  |  |  | 		if (strlen(value) < (LINE_LEN - 2)) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		if (strstr(value, "cpu ")) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		if (sscanf(value, "cpu%d ", &cpunr) != 1) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		if (cpunr > ret) | 
					
						
							|  |  |  | 			ret = cpunr; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	fclose(fp); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* cpu count starts from 0, on error return 1 (UP) */ | 
					
						
							| 
									
										
										
										
											2011-04-19 20:33:50 +02:00
										 |  |  | 	return ret + 1; | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void proc_cpufreq_output(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned int cpu, nr_cpus; | 
					
						
							|  |  |  | 	struct cpufreq_policy *policy; | 
					
						
							|  |  |  | 	unsigned int min_pctg = 0; | 
					
						
							|  |  |  | 	unsigned int max_pctg = 0; | 
					
						
							|  |  |  | 	unsigned long min, max; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	printf(_("          minimum CPU frequency  -  maximum CPU frequency  -  governor\n")); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	nr_cpus = count_cpus(); | 
					
						
							| 
									
										
										
										
											2011-04-19 20:33:50 +02:00
										 |  |  | 	for (cpu = 0; cpu < nr_cpus; cpu++) { | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 		policy = cpufreq_get_policy(cpu); | 
					
						
							|  |  |  | 		if (!policy) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (cpufreq_get_hardware_limits(cpu, &min, &max)) { | 
					
						
							|  |  |  | 			max = 0; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			min_pctg = (policy->min * 100) / max; | 
					
						
							|  |  |  | 			max_pctg = (policy->max * 100) / max; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		printf("CPU%3d    %9lu kHz (%3d %%)  -  %9lu kHz (%3d %%)  -  %s\n", | 
					
						
							| 
									
										
										
										
											2011-04-19 20:33:50 +02:00
										 |  |  | 			cpu , policy->min, max ? min_pctg : 0, policy->max, | 
					
						
							|  |  |  | 			max ? max_pctg : 0, policy->governor); | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		cpufreq_put_policy(policy); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void print_speed(unsigned long speed) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned long tmp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (speed > 1000000) { | 
					
						
							|  |  |  | 		tmp = speed % 10000; | 
					
						
							|  |  |  | 		if (tmp >= 5000) | 
					
						
							|  |  |  | 			speed += 10000; | 
					
						
							| 
									
										
										
										
											2011-04-19 20:33:50 +02:00
										 |  |  | 		printf("%u.%02u GHz", ((unsigned int) speed/1000000), | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 			((unsigned int) (speed%1000000)/10000)); | 
					
						
							|  |  |  | 	} else if (speed > 100000) { | 
					
						
							|  |  |  | 		tmp = speed % 1000; | 
					
						
							|  |  |  | 		if (tmp >= 500) | 
					
						
							|  |  |  | 			speed += 1000; | 
					
						
							| 
									
										
										
										
											2011-04-19 20:33:50 +02:00
										 |  |  | 		printf("%u MHz", ((unsigned int) speed / 1000)); | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 	} else if (speed > 1000) { | 
					
						
							|  |  |  | 		tmp = speed % 100; | 
					
						
							|  |  |  | 		if (tmp >= 50) | 
					
						
							|  |  |  | 			speed += 100; | 
					
						
							| 
									
										
										
										
											2011-04-19 20:33:50 +02:00
										 |  |  | 		printf("%u.%01u MHz", ((unsigned int) speed/1000), | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 			((unsigned int) (speed%1000)/100)); | 
					
						
							|  |  |  | 	} else | 
					
						
							| 
									
										
										
										
											2011-04-19 20:33:50 +02:00
										 |  |  | 		printf("%lu kHz", speed); | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void print_duration(unsigned long duration) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned long tmp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (duration > 1000000) { | 
					
						
							|  |  |  | 		tmp = duration % 10000; | 
					
						
							|  |  |  | 		if (tmp >= 5000) | 
					
						
							|  |  |  | 			duration += 10000; | 
					
						
							| 
									
										
										
										
											2011-04-19 20:33:50 +02:00
										 |  |  | 		printf("%u.%02u ms", ((unsigned int) duration/1000000), | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 			((unsigned int) (duration%1000000)/10000)); | 
					
						
							|  |  |  | 	} else if (duration > 100000) { | 
					
						
							|  |  |  | 		tmp = duration % 1000; | 
					
						
							|  |  |  | 		if (tmp >= 500) | 
					
						
							|  |  |  | 			duration += 1000; | 
					
						
							| 
									
										
										
										
											2011-04-19 20:33:50 +02:00
										 |  |  | 		printf("%u us", ((unsigned int) duration / 1000)); | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 	} else if (duration > 1000) { | 
					
						
							|  |  |  | 		tmp = duration % 100; | 
					
						
							|  |  |  | 		if (tmp >= 50) | 
					
						
							|  |  |  | 			duration += 100; | 
					
						
							| 
									
										
										
										
											2011-04-19 20:33:50 +02:00
										 |  |  | 		printf("%u.%01u us", ((unsigned int) duration/1000), | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 			((unsigned int) (duration%1000)/100)); | 
					
						
							|  |  |  | 	} else | 
					
						
							| 
									
										
										
										
											2011-04-19 20:33:50 +02:00
										 |  |  | 		printf("%lu ns", duration); | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* --boost / -b */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 20:33:50 +02:00
										 |  |  | static int get_boost_mode(unsigned int cpu) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 	int support, active, b_states = 0, ret, pstate_no, i; | 
					
						
							|  |  |  | 	/* ToDo: Make this more global */ | 
					
						
							|  |  |  | 	unsigned long pstates[MAX_HW_PSTATES] = {0,}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (cpupower_cpu_info.vendor != X86_VENDOR_AMD && | 
					
						
							|  |  |  | 	    cpupower_cpu_info.vendor != X86_VENDOR_INTEL) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = cpufreq_has_boost_support(cpu, &support, &active, &b_states); | 
					
						
							|  |  |  | 	if (ret) { | 
					
						
							|  |  |  | 		printf(_("Error while evaluating Boost Capabilities" | 
					
						
							|  |  |  | 				" on CPU %d -- are you root?\n"), cpu); | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	/* P state changes via MSR are identified via cpuid 80000007
 | 
					
						
							|  |  |  | 	   on Intel and AMD, but we assume boost capable machines can do that | 
					
						
							|  |  |  | 	   if (cpuid_eax(0x80000000) >= 0x80000007 | 
					
						
							|  |  |  | 	   && (cpuid_edx(0x80000007) & (1 << 7))) | 
					
						
							|  |  |  | 	*/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 20:33:50 +02:00
										 |  |  | 	printf(_("  boost state support:\n")); | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	printf(_("    Supported: %s\n"), support ? _("yes") : _("no")); | 
					
						
							|  |  |  | 	printf(_("    Active: %s\n"), active ? _("yes") : _("no")); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (cpupower_cpu_info.vendor == X86_VENDOR_AMD && | 
					
						
							|  |  |  | 	    cpupower_cpu_info.family >= 0x10) { | 
					
						
							|  |  |  | 		ret = decode_pstates(cpu, cpupower_cpu_info.family, b_states, | 
					
						
							|  |  |  | 				     pstates, &pstate_no); | 
					
						
							|  |  |  | 		if (ret) | 
					
						
							|  |  |  | 			return ret; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-21 11:54:53 +02:00
										 |  |  | 		printf(_("    Boost States: %d\n"), b_states); | 
					
						
							|  |  |  | 		printf(_("    Total States: %d\n"), pstate_no); | 
					
						
							|  |  |  | 		for (i = 0; i < pstate_no; i++) { | 
					
						
							|  |  |  | 			if (i < b_states) | 
					
						
							|  |  |  | 				printf(_("    Pstate-Pb%d: %luMHz (boost state)" | 
					
						
							|  |  |  | 					 "\n"), i, pstates[i]); | 
					
						
							|  |  |  | 			else | 
					
						
							|  |  |  | 				printf(_("    Pstate-P%d:  %luMHz\n"), | 
					
						
							|  |  |  | 				       i - b_states, pstates[i]); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else if (cpupower_cpu_info.caps & CPUPOWER_CAP_HAS_TURBO_RATIO) { | 
					
						
							|  |  |  | 		double bclk; | 
					
						
							|  |  |  | 		unsigned long long intel_turbo_ratio = 0; | 
					
						
							|  |  |  | 		unsigned int ratio; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* Any way to autodetect this ? */ | 
					
						
							|  |  |  | 		if (cpupower_cpu_info.caps & CPUPOWER_CAP_IS_SNB) | 
					
						
							|  |  |  | 			bclk = 100.00; | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 		else | 
					
						
							| 
									
										
										
										
											2011-07-21 11:54:53 +02:00
										 |  |  | 			bclk = 133.33; | 
					
						
							|  |  |  | 		intel_turbo_ratio = msr_intel_get_turbo_ratio(cpu); | 
					
						
							|  |  |  | 		dprint ("    Ratio: 0x%llx - bclk: %f\n", | 
					
						
							|  |  |  | 			intel_turbo_ratio, bclk); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ratio = (intel_turbo_ratio >> 24) & 0xFF; | 
					
						
							|  |  |  | 		if (ratio) | 
					
						
							|  |  |  | 			printf(_("    %.0f MHz max turbo 4 active cores\n"), | 
					
						
							|  |  |  | 			       ratio * bclk); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ratio = (intel_turbo_ratio >> 16) & 0xFF; | 
					
						
							|  |  |  | 		if (ratio) | 
					
						
							|  |  |  | 			printf(_("    %.0f MHz max turbo 3 active cores\n"), | 
					
						
							|  |  |  | 			       ratio * bclk); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ratio = (intel_turbo_ratio >> 8) & 0xFF; | 
					
						
							|  |  |  | 		if (ratio) | 
					
						
							|  |  |  | 			printf(_("    %.0f MHz max turbo 2 active cores\n"), | 
					
						
							|  |  |  | 			       ratio * bclk); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ratio = (intel_turbo_ratio >> 0) & 0xFF; | 
					
						
							|  |  |  | 		if (ratio) | 
					
						
							|  |  |  | 			printf(_("    %.0f MHz max turbo 1 active cores\n"), | 
					
						
							|  |  |  | 			       ratio * bclk); | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void debug_output_one(unsigned int cpu) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	char *driver; | 
					
						
							|  |  |  | 	struct cpufreq_affected_cpus *cpus; | 
					
						
							|  |  |  | 	struct cpufreq_available_frequencies *freqs; | 
					
						
							|  |  |  | 	unsigned long min, max, freq_kernel, freq_hardware; | 
					
						
							|  |  |  | 	unsigned long total_trans, latency; | 
					
						
							|  |  |  | 	unsigned long long total_time; | 
					
						
							|  |  |  | 	struct cpufreq_policy *policy; | 
					
						
							| 
									
										
										
										
											2011-04-19 20:33:50 +02:00
										 |  |  | 	struct cpufreq_available_governors *governors; | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 	struct cpufreq_stats *stats; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 20:33:50 +02:00
										 |  |  | 	if (cpufreq_cpu_exists(cpu)) | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	freq_kernel = cpufreq_get_freq_kernel(cpu); | 
					
						
							|  |  |  | 	freq_hardware = cpufreq_get_freq_hardware(cpu); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	driver = cpufreq_get_driver(cpu); | 
					
						
							|  |  |  | 	if (!driver) { | 
					
						
							|  |  |  | 		printf(_("  no or unknown cpufreq driver is active on this CPU\n")); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		printf(_("  driver: %s\n"), driver); | 
					
						
							|  |  |  | 		cpufreq_put_driver(driver); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cpus = cpufreq_get_related_cpus(cpu); | 
					
						
							|  |  |  | 	if (cpus) { | 
					
						
							|  |  |  | 		printf(_("  CPUs which run at the same hardware frequency: ")); | 
					
						
							|  |  |  | 		while (cpus->next) { | 
					
						
							|  |  |  | 			printf("%d ", cpus->cpu); | 
					
						
							|  |  |  | 			cpus = cpus->next; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		printf("%d\n", cpus->cpu); | 
					
						
							|  |  |  | 		cpufreq_put_related_cpus(cpus); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cpus = cpufreq_get_affected_cpus(cpu); | 
					
						
							|  |  |  | 	if (cpus) { | 
					
						
							|  |  |  | 		printf(_("  CPUs which need to have their frequency coordinated by software: ")); | 
					
						
							|  |  |  | 		while (cpus->next) { | 
					
						
							|  |  |  | 			printf("%d ", cpus->cpu); | 
					
						
							|  |  |  | 			cpus = cpus->next; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		printf("%d\n", cpus->cpu); | 
					
						
							|  |  |  | 		cpufreq_put_affected_cpus(cpus); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	latency = cpufreq_get_transition_latency(cpu); | 
					
						
							|  |  |  | 	if (latency) { | 
					
						
							|  |  |  | 		printf(_("  maximum transition latency: ")); | 
					
						
							|  |  |  | 		print_duration(latency); | 
					
						
							|  |  |  | 		printf(".\n"); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!(cpufreq_get_hardware_limits(cpu, &min, &max))) { | 
					
						
							|  |  |  | 		printf(_("  hardware limits: ")); | 
					
						
							|  |  |  | 		print_speed(min); | 
					
						
							|  |  |  | 		printf(" - "); | 
					
						
							|  |  |  | 		print_speed(max); | 
					
						
							|  |  |  | 		printf("\n"); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	freqs = cpufreq_get_available_frequencies(cpu); | 
					
						
							|  |  |  | 	if (freqs) { | 
					
						
							|  |  |  | 		printf(_("  available frequency steps: ")); | 
					
						
							|  |  |  | 		while (freqs->next) { | 
					
						
							|  |  |  | 			print_speed(freqs->frequency); | 
					
						
							|  |  |  | 			printf(", "); | 
					
						
							|  |  |  | 			freqs = freqs->next; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		print_speed(freqs->frequency); | 
					
						
							|  |  |  | 		printf("\n"); | 
					
						
							|  |  |  | 		cpufreq_put_available_frequencies(freqs); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	governors = cpufreq_get_available_governors(cpu); | 
					
						
							|  |  |  | 	if (governors) { | 
					
						
							|  |  |  | 		printf(_("  available cpufreq governors: ")); | 
					
						
							|  |  |  | 		while (governors->next) { | 
					
						
							|  |  |  | 			printf("%s, ", governors->governor); | 
					
						
							|  |  |  | 			governors = governors->next; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		printf("%s\n", governors->governor); | 
					
						
							|  |  |  | 		cpufreq_put_available_governors(governors); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	policy = cpufreq_get_policy(cpu); | 
					
						
							|  |  |  | 	if (policy) { | 
					
						
							|  |  |  | 		printf(_("  current policy: frequency should be within ")); | 
					
						
							|  |  |  | 		print_speed(policy->min); | 
					
						
							|  |  |  | 		printf(_(" and ")); | 
					
						
							|  |  |  | 		print_speed(policy->max); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		printf(".\n                  "); | 
					
						
							|  |  |  | 		printf(_("The governor \"%s\" may" | 
					
						
							|  |  |  | 		       " decide which speed to use\n                  within this range.\n"), | 
					
						
							|  |  |  | 		       policy->governor); | 
					
						
							|  |  |  | 		cpufreq_put_policy(policy); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (freq_kernel || freq_hardware) { | 
					
						
							|  |  |  | 		printf(_("  current CPU frequency is ")); | 
					
						
							|  |  |  | 		if (freq_hardware) { | 
					
						
							|  |  |  | 			print_speed(freq_hardware); | 
					
						
							|  |  |  | 			printf(_(" (asserted by call to hardware)")); | 
					
						
							| 
									
										
										
										
											2011-04-19 20:33:50 +02:00
										 |  |  | 		} else | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 			print_speed(freq_kernel); | 
					
						
							|  |  |  | 		printf(".\n"); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	stats = cpufreq_get_stats(cpu, &total_time); | 
					
						
							|  |  |  | 	if (stats) { | 
					
						
							|  |  |  | 		printf(_("  cpufreq stats: ")); | 
					
						
							|  |  |  | 		while (stats) { | 
					
						
							|  |  |  | 			print_speed(stats->frequency); | 
					
						
							|  |  |  | 			printf(":%.2f%%", (100.0 * stats->time_in_state) / total_time); | 
					
						
							|  |  |  | 			stats = stats->next; | 
					
						
							|  |  |  | 			if (stats) | 
					
						
							|  |  |  | 				printf(", "); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		cpufreq_put_stats(stats); | 
					
						
							|  |  |  | 		total_trans = cpufreq_get_transitions(cpu); | 
					
						
							|  |  |  | 		if (total_trans) | 
					
						
							|  |  |  | 			printf("  (%lu)\n", total_trans); | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			printf("\n"); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	get_boost_mode(cpu); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* --freq / -f */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 20:33:50 +02:00
										 |  |  | static int get_freq_kernel(unsigned int cpu, unsigned int human) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 	unsigned long freq = cpufreq_get_freq_kernel(cpu); | 
					
						
							|  |  |  | 	if (!freq) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	if (human) { | 
					
						
							|  |  |  | 		print_speed(freq); | 
					
						
							|  |  |  | 		printf("\n"); | 
					
						
							|  |  |  | 	} else | 
					
						
							|  |  |  | 		printf("%lu\n", freq); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* --hwfreq / -w */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 20:33:50 +02:00
										 |  |  | static int get_freq_hardware(unsigned int cpu, unsigned int human) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 	unsigned long freq = cpufreq_get_freq_hardware(cpu); | 
					
						
							|  |  |  | 	if (!freq) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	if (human) { | 
					
						
							|  |  |  | 		print_speed(freq); | 
					
						
							|  |  |  | 		printf("\n"); | 
					
						
							|  |  |  | 	} else | 
					
						
							|  |  |  | 		printf("%lu\n", freq); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* --hwlimits / -l */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 20:33:50 +02:00
										 |  |  | static int get_hardware_limits(unsigned int cpu) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 	unsigned long min, max; | 
					
						
							|  |  |  | 	if (cpufreq_get_hardware_limits(cpu, &min, &max)) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	printf("%lu %lu\n", min, max); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* --driver / -d */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 20:33:50 +02:00
										 |  |  | static int get_driver(unsigned int cpu) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 	char *driver = cpufreq_get_driver(cpu); | 
					
						
							|  |  |  | 	if (!driver) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	printf("%s\n", driver); | 
					
						
							|  |  |  | 	cpufreq_put_driver(driver); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* --policy / -p */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 20:33:50 +02:00
										 |  |  | static int get_policy(unsigned int cpu) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 	struct cpufreq_policy *policy = cpufreq_get_policy(cpu); | 
					
						
							|  |  |  | 	if (!policy) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	printf("%lu %lu %s\n", policy->min, policy->max, policy->governor); | 
					
						
							|  |  |  | 	cpufreq_put_policy(policy); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* --governors / -g */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 20:33:50 +02:00
										 |  |  | static int get_available_governors(unsigned int cpu) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct cpufreq_available_governors *governors = | 
					
						
							|  |  |  | 		cpufreq_get_available_governors(cpu); | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 	if (!governors) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (governors->next) { | 
					
						
							|  |  |  | 		printf("%s ", governors->governor); | 
					
						
							|  |  |  | 		governors = governors->next; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	printf("%s\n", governors->governor); | 
					
						
							|  |  |  | 	cpufreq_put_available_governors(governors); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* --affected-cpus  / -a */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 20:33:50 +02:00
										 |  |  | static int get_affected_cpus(unsigned int cpu) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 	struct cpufreq_affected_cpus *cpus = cpufreq_get_affected_cpus(cpu); | 
					
						
							|  |  |  | 	if (!cpus) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (cpus->next) { | 
					
						
							|  |  |  | 		printf("%d ", cpus->cpu); | 
					
						
							|  |  |  | 		cpus = cpus->next; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	printf("%d\n", cpus->cpu); | 
					
						
							|  |  |  | 	cpufreq_put_affected_cpus(cpus); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* --related-cpus  / -r */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 20:33:50 +02:00
										 |  |  | static int get_related_cpus(unsigned int cpu) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 	struct cpufreq_affected_cpus *cpus = cpufreq_get_related_cpus(cpu); | 
					
						
							|  |  |  | 	if (!cpus) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (cpus->next) { | 
					
						
							|  |  |  | 		printf("%d ", cpus->cpu); | 
					
						
							|  |  |  | 		cpus = cpus->next; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	printf("%d\n", cpus->cpu); | 
					
						
							|  |  |  | 	cpufreq_put_related_cpus(cpus); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* --stats / -s */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 20:33:50 +02:00
										 |  |  | static int get_freq_stats(unsigned int cpu, unsigned int human) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 	unsigned long total_trans = cpufreq_get_transitions(cpu); | 
					
						
							|  |  |  | 	unsigned long long total_time; | 
					
						
							|  |  |  | 	struct cpufreq_stats *stats = cpufreq_get_stats(cpu, &total_time); | 
					
						
							|  |  |  | 	while (stats) { | 
					
						
							|  |  |  | 		if (human) { | 
					
						
							|  |  |  | 			print_speed(stats->frequency); | 
					
						
							| 
									
										
										
										
											2011-04-19 20:33:50 +02:00
										 |  |  | 			printf(":%.2f%%", | 
					
						
							|  |  |  | 				(100.0 * stats->time_in_state) / total_time); | 
					
						
							|  |  |  | 		} else | 
					
						
							|  |  |  | 			printf("%lu:%llu", | 
					
						
							|  |  |  | 				stats->frequency, stats->time_in_state); | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 		stats = stats->next; | 
					
						
							|  |  |  | 		if (stats) | 
					
						
							|  |  |  | 			printf(", "); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	cpufreq_put_stats(stats); | 
					
						
							|  |  |  | 	if (total_trans) | 
					
						
							|  |  |  | 		printf("  (%lu)\n", total_trans); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* --latency / -y */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 20:33:50 +02:00
										 |  |  | static int get_latency(unsigned int cpu, unsigned int human) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 	unsigned long latency = cpufreq_get_transition_latency(cpu); | 
					
						
							|  |  |  | 	if (!latency) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (human) { | 
					
						
							|  |  |  | 		print_duration(latency); | 
					
						
							|  |  |  | 		printf("\n"); | 
					
						
							|  |  |  | 	} else | 
					
						
							|  |  |  | 		printf("%lu\n", latency); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct option info_opts[] = { | 
					
						
							| 
									
										
										
										
											2011-04-19 20:33:50 +02:00
										 |  |  | 	{ .name = "debug",	.has_arg = no_argument,		.flag = NULL,	.val = 'e'}, | 
					
						
							|  |  |  | 	{ .name = "boost",	.has_arg = no_argument,		.flag = NULL,	.val = 'b'}, | 
					
						
							|  |  |  | 	{ .name = "freq",	.has_arg = no_argument,		.flag = NULL,	.val = 'f'}, | 
					
						
							|  |  |  | 	{ .name = "hwfreq",	.has_arg = no_argument,		.flag = NULL,	.val = 'w'}, | 
					
						
							|  |  |  | 	{ .name = "hwlimits",	.has_arg = no_argument,		.flag = NULL,	.val = 'l'}, | 
					
						
							|  |  |  | 	{ .name = "driver",	.has_arg = no_argument,		.flag = NULL,	.val = 'd'}, | 
					
						
							|  |  |  | 	{ .name = "policy",	.has_arg = no_argument,		.flag = NULL,	.val = 'p'}, | 
					
						
							|  |  |  | 	{ .name = "governors",	.has_arg = no_argument,		.flag = NULL,	.val = 'g'}, | 
					
						
							|  |  |  | 	{ .name = "related-cpus", .has_arg = no_argument,	.flag = NULL,	.val = 'r'}, | 
					
						
							|  |  |  | 	{ .name = "affected-cpus",.has_arg = no_argument,	.flag = NULL,	.val = 'a'}, | 
					
						
							|  |  |  | 	{ .name = "stats",	.has_arg = no_argument,		.flag = NULL,	.val = 's'}, | 
					
						
							|  |  |  | 	{ .name = "latency",	.has_arg = no_argument,		.flag = NULL,	.val = 'y'}, | 
					
						
							|  |  |  | 	{ .name = "proc",	.has_arg = no_argument,		.flag = NULL,	.val = 'o'}, | 
					
						
							|  |  |  | 	{ .name = "human",	.has_arg = no_argument,		.flag = NULL,	.val = 'm'}, | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 	{ }, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int cmd_freq_info(int argc, char **argv) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	extern char *optarg; | 
					
						
							|  |  |  | 	extern int optind, opterr, optopt; | 
					
						
							|  |  |  | 	int ret = 0, cont = 1; | 
					
						
							|  |  |  | 	unsigned int cpu = 0; | 
					
						
							|  |  |  | 	unsigned int human = 0; | 
					
						
							|  |  |  | 	int output_param = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	do { | 
					
						
							| 
									
										
										
										
											2011-08-06 18:11:43 +02:00
										 |  |  | 		ret = getopt_long(argc, argv, "oefwldpgrasmyb", info_opts, NULL); | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 		switch (ret) { | 
					
						
							|  |  |  | 		case '?': | 
					
						
							|  |  |  | 			output_param = '?'; | 
					
						
							|  |  |  | 			cont = 0; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case -1: | 
					
						
							|  |  |  | 			cont = 0; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case 'b': | 
					
						
							|  |  |  | 		case 'o': | 
					
						
							|  |  |  | 		case 'a': | 
					
						
							|  |  |  | 		case 'r': | 
					
						
							|  |  |  | 		case 'g': | 
					
						
							|  |  |  | 		case 'p': | 
					
						
							|  |  |  | 		case 'd': | 
					
						
							|  |  |  | 		case 'l': | 
					
						
							|  |  |  | 		case 'w': | 
					
						
							|  |  |  | 		case 'f': | 
					
						
							|  |  |  | 		case 'e': | 
					
						
							|  |  |  | 		case 's': | 
					
						
							|  |  |  | 		case 'y': | 
					
						
							|  |  |  | 			if (output_param) { | 
					
						
							|  |  |  | 				output_param = -1; | 
					
						
							|  |  |  | 				cont = 0; | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			output_param = ret; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case 'm': | 
					
						
							|  |  |  | 			if (human) { | 
					
						
							|  |  |  | 				output_param = -1; | 
					
						
							|  |  |  | 				cont = 0; | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			human = 1; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			fprintf(stderr, "invalid or unknown argument\n"); | 
					
						
							|  |  |  | 			return EXIT_FAILURE; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2011-04-19 20:33:50 +02:00
										 |  |  | 	} while (cont); | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	switch (output_param) { | 
					
						
							|  |  |  | 	case 'o': | 
					
						
							|  |  |  | 		if (!bitmask_isallclear(cpus_chosen)) { | 
					
						
							|  |  |  | 			printf(_("The argument passed to this tool can't be " | 
					
						
							|  |  |  | 				 "combined with passing a --cpu argument\n")); | 
					
						
							|  |  |  | 			return -EINVAL; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case 0: | 
					
						
							|  |  |  | 		output_param = 'e'; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Default is: show output of CPU 0 only */ | 
					
						
							|  |  |  | 	if (bitmask_isallclear(cpus_chosen)) | 
					
						
							|  |  |  | 		bitmask_setbit(cpus_chosen, 0); | 
					
						
							| 
									
										
										
										
											2011-04-19 20:33:50 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 	switch (output_param) { | 
					
						
							|  |  |  | 	case -1: | 
					
						
							|  |  |  | 		printf(_("You can't specify more than one --cpu parameter and/or\n" | 
					
						
							|  |  |  | 		       "more than one output-specific argument\n")); | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	case '?': | 
					
						
							|  |  |  | 		printf(_("invalid or unknown argument\n")); | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	case 'o': | 
					
						
							|  |  |  | 		proc_cpufreq_output(); | 
					
						
							|  |  |  | 		return EXIT_SUCCESS; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (cpu = bitmask_first(cpus_chosen); | 
					
						
							|  |  |  | 	     cpu <= bitmask_last(cpus_chosen); cpu++) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (!bitmask_isbitset(cpus_chosen, cpu)) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		if (cpufreq_cpu_exists(cpu)) { | 
					
						
							|  |  |  | 			printf(_("couldn't analyze CPU %d as it doesn't seem to be present\n"), cpu); | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		printf(_("analyzing CPU %d:\n"), cpu); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		switch (output_param) { | 
					
						
							|  |  |  | 		case 'b': | 
					
						
							|  |  |  | 			get_boost_mode(cpu); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case 'e': | 
					
						
							|  |  |  | 			debug_output_one(cpu); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case 'a': | 
					
						
							|  |  |  | 			ret = get_affected_cpus(cpu); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case 'r': | 
					
						
							|  |  |  | 			ret = get_related_cpus(cpu); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case 'g': | 
					
						
							|  |  |  | 			ret = get_available_governors(cpu); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case 'p': | 
					
						
							|  |  |  | 			ret = get_policy(cpu); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case 'd': | 
					
						
							|  |  |  | 			ret = get_driver(cpu); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case 'l': | 
					
						
							|  |  |  | 			ret = get_hardware_limits(cpu); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case 'w': | 
					
						
							|  |  |  | 			ret = get_freq_hardware(cpu, human); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case 'f': | 
					
						
							|  |  |  | 			ret = get_freq_kernel(cpu, human); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case 's': | 
					
						
							|  |  |  | 			ret = get_freq_stats(cpu, human); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case 'y': | 
					
						
							|  |  |  | 			ret = get_latency(cpu, human); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (ret) | 
					
						
							| 
									
										
										
										
											2011-04-19 20:33:50 +02:00
										 |  |  | 			return ret; | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } |