xref: /onnv-gate/usr/src/cmd/powertop/common/turbo.c (revision 11122:393b5ac48d9b)
19338Srafael.vanoni@sun.com /*
29338Srafael.vanoni@sun.com  * Copyright 2009, Intel Corporation
39338Srafael.vanoni@sun.com  * Copyright 2009, Sun Microsystems, Inc
49338Srafael.vanoni@sun.com  *
59338Srafael.vanoni@sun.com  * This file is part of PowerTOP
69338Srafael.vanoni@sun.com  *
79338Srafael.vanoni@sun.com  * This program file is free software; you can redistribute it and/or modify it
89338Srafael.vanoni@sun.com  * under the terms of the GNU General Public License as published by the
99338Srafael.vanoni@sun.com  * Free Software Foundation; version 2 of the License.
109338Srafael.vanoni@sun.com  *
119338Srafael.vanoni@sun.com  * This program is distributed in the hope that it will be useful, but WITHOUT
129338Srafael.vanoni@sun.com  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
139338Srafael.vanoni@sun.com  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
149338Srafael.vanoni@sun.com  * for more details.
159338Srafael.vanoni@sun.com  *
169338Srafael.vanoni@sun.com  * You should have received a copy of the GNU General Public License
179338Srafael.vanoni@sun.com  * along with this program in a file named COPYING; if not, write to the
189338Srafael.vanoni@sun.com  * Free Software Foundation, Inc.,
199338Srafael.vanoni@sun.com  * 51 Franklin Street, Fifth Floor,
209338Srafael.vanoni@sun.com  * Boston, MA 02110-1301 USA
219338Srafael.vanoni@sun.com  *
229338Srafael.vanoni@sun.com  * Authors:
239338Srafael.vanoni@sun.com  *	Arjan van de Ven <arjan@linux.intel.com>
249338Srafael.vanoni@sun.com  *	Eric C Saxe <eric.saxe@sun.com>
259338Srafael.vanoni@sun.com  *	Aubrey Li <aubrey.li@intel.com>
269338Srafael.vanoni@sun.com  */
279338Srafael.vanoni@sun.com 
289338Srafael.vanoni@sun.com /*
299338Srafael.vanoni@sun.com  * GPL Disclaimer
309338Srafael.vanoni@sun.com  *
319338Srafael.vanoni@sun.com  * For the avoidance of doubt, except that if any license choice other
329338Srafael.vanoni@sun.com  * than GPL or LGPL is available it will apply instead, Sun elects to
339338Srafael.vanoni@sun.com  * use only the General Public License version 2 (GPLv2) at this time
349338Srafael.vanoni@sun.com  * for any software where a choice of GPL license versions is made
359338Srafael.vanoni@sun.com  * available with the language indicating that GPLv2 or any later
369338Srafael.vanoni@sun.com  * version may be used, or where a choice of which version of the GPL
379338Srafael.vanoni@sun.com  * is applied is otherwise unspecified.
389338Srafael.vanoni@sun.com  */
399338Srafael.vanoni@sun.com 
409338Srafael.vanoni@sun.com #include <stdlib.h>
419338Srafael.vanoni@sun.com #include <string.h>
429338Srafael.vanoni@sun.com #include <dtrace.h>
439338Srafael.vanoni@sun.com #include <kstat.h>
449338Srafael.vanoni@sun.com #include <errno.h>
459338Srafael.vanoni@sun.com #include "powertop.h"
469338Srafael.vanoni@sun.com 
479338Srafael.vanoni@sun.com /*
489338Srafael.vanoni@sun.com  * Global turbo related variables definitions
499338Srafael.vanoni@sun.com  */
509338Srafael.vanoni@sun.com boolean_t		g_turbo_supported;
519338Srafael.vanoni@sun.com double			g_turbo_ratio;
529338Srafael.vanoni@sun.com 
539338Srafael.vanoni@sun.com /*
549338Srafael.vanoni@sun.com  * The variables to store kstat snapshot
559338Srafael.vanoni@sun.com  */
569338Srafael.vanoni@sun.com static turbo_info_t	*cpu_turbo_info = NULL;
579338Srafael.vanoni@sun.com static turbo_info_t	*t_new = NULL;
589338Srafael.vanoni@sun.com 
599338Srafael.vanoni@sun.com /*
609338Srafael.vanoni@sun.com  * Perform setup necessary to enumerate and track CPU turbo information
619338Srafael.vanoni@sun.com  */
629338Srafael.vanoni@sun.com static int
pt_turbo_init(void)639338Srafael.vanoni@sun.com pt_turbo_init(void)
649338Srafael.vanoni@sun.com {
659338Srafael.vanoni@sun.com 	kstat_ctl_t 		*kc;
669338Srafael.vanoni@sun.com 	kstat_t 		*ksp;
679338Srafael.vanoni@sun.com 	kstat_named_t 		*knp;
689338Srafael.vanoni@sun.com 
699338Srafael.vanoni@sun.com 	/*
709338Srafael.vanoni@sun.com 	 * check if the CPU turbo is supported
719338Srafael.vanoni@sun.com 	 */
729338Srafael.vanoni@sun.com 	if ((kc = kstat_open()) == NULL) {
739338Srafael.vanoni@sun.com 		g_turbo_supported = B_FALSE;
749338Srafael.vanoni@sun.com 		return (errno);
759338Srafael.vanoni@sun.com 	}
769338Srafael.vanoni@sun.com 
779338Srafael.vanoni@sun.com 	ksp = kstat_lookup(kc, "turbo", 0, NULL);
789338Srafael.vanoni@sun.com 	if (ksp == NULL) {
799338Srafael.vanoni@sun.com 		g_turbo_supported = B_FALSE;
809338Srafael.vanoni@sun.com 		(void) kstat_close(kc);
819338Srafael.vanoni@sun.com 		return (-1);
829338Srafael.vanoni@sun.com 	}
839338Srafael.vanoni@sun.com 
849338Srafael.vanoni@sun.com 	(void) kstat_read(kc, ksp, NULL);
859338Srafael.vanoni@sun.com 
869338Srafael.vanoni@sun.com 	knp = kstat_data_lookup(ksp, "turbo_supported");
879338Srafael.vanoni@sun.com 	if (knp == NULL) {
88*11122Srafael.vanoni@sun.com 		pt_error("couldn't find 'turbo_supported' kstat\n");
899338Srafael.vanoni@sun.com 		g_turbo_supported = B_FALSE;
909338Srafael.vanoni@sun.com 		(void) kstat_close(kc);
919338Srafael.vanoni@sun.com 		return (-2);
929338Srafael.vanoni@sun.com 	}
939338Srafael.vanoni@sun.com 
949338Srafael.vanoni@sun.com 	/*
959338Srafael.vanoni@sun.com 	 * Initialize turbo information structure if turbo mode is supported
969338Srafael.vanoni@sun.com 	 */
979338Srafael.vanoni@sun.com 	if (knp->value.ui32) {
989338Srafael.vanoni@sun.com 		g_turbo_supported = B_TRUE;
999338Srafael.vanoni@sun.com 		cpu_turbo_info = calloc((size_t)g_ncpus, sizeof (turbo_info_t));
1009338Srafael.vanoni@sun.com 		t_new = calloc((size_t)g_ncpus, sizeof (turbo_info_t));
1019338Srafael.vanoni@sun.com 	}
1029338Srafael.vanoni@sun.com 
1039338Srafael.vanoni@sun.com 	(void) kstat_close(kc);
1049338Srafael.vanoni@sun.com 	return (0);
1059338Srafael.vanoni@sun.com }
1069338Srafael.vanoni@sun.com 
1079338Srafael.vanoni@sun.com /*
1089338Srafael.vanoni@sun.com  * Take a snapshot of each CPU's turbo information
1099338Srafael.vanoni@sun.com  * by looking through the turbo kstats.
1109338Srafael.vanoni@sun.com  */
1119338Srafael.vanoni@sun.com static int
pt_turbo_snapshot(turbo_info_t * turbo_snapshot)1129338Srafael.vanoni@sun.com pt_turbo_snapshot(turbo_info_t *turbo_snapshot)
1139338Srafael.vanoni@sun.com {
1149338Srafael.vanoni@sun.com 	kstat_ctl_t 		*kc;
1159338Srafael.vanoni@sun.com 	kstat_t 		*ksp;
1169338Srafael.vanoni@sun.com 	kstat_named_t 		*knp;
1179338Srafael.vanoni@sun.com 	int 			cpu;
1189338Srafael.vanoni@sun.com 	turbo_info_t		*turbo_info;
1199338Srafael.vanoni@sun.com 
1209338Srafael.vanoni@sun.com 	if ((kc = kstat_open()) == NULL)
1219338Srafael.vanoni@sun.com 		return (errno);
1229338Srafael.vanoni@sun.com 
1239338Srafael.vanoni@sun.com 	for (cpu = 0; cpu < g_ncpus; cpu++) {
1249338Srafael.vanoni@sun.com 		turbo_info = &turbo_snapshot[cpu];
1259338Srafael.vanoni@sun.com 		ksp = kstat_lookup(kc, "turbo", g_cpu_table[cpu], NULL);
1269338Srafael.vanoni@sun.com 		if (ksp == NULL) {
127*11122Srafael.vanoni@sun.com 			pt_error("couldn't find 'turbo' kstat for CPU %d\n",
128*11122Srafael.vanoni@sun.com 			    cpu);
1299338Srafael.vanoni@sun.com 			(void) kstat_close(kc);
1309338Srafael.vanoni@sun.com 			return (-1);
1319338Srafael.vanoni@sun.com 		}
1329338Srafael.vanoni@sun.com 
1339338Srafael.vanoni@sun.com 		if (kstat_read(kc, ksp, NULL) == -1) {
134*11122Srafael.vanoni@sun.com 			pt_error("couldn't read 'turbo' kstat for CPU %d\n",
135*11122Srafael.vanoni@sun.com 			    cpu);
1369338Srafael.vanoni@sun.com 			(void) kstat_close(kc);
1379338Srafael.vanoni@sun.com 			return (-2);
1389338Srafael.vanoni@sun.com 		}
1399338Srafael.vanoni@sun.com 
1409338Srafael.vanoni@sun.com 		knp = kstat_data_lookup(ksp, "turbo_mcnt");
1419338Srafael.vanoni@sun.com 		if (knp == NULL) {
142*11122Srafael.vanoni@sun.com 			pt_error("couldn't find 'turbo_mcnt' kstat for CPU "
143*11122Srafael.vanoni@sun.com 			    "%d\n", cpu);
1449338Srafael.vanoni@sun.com 			(void) kstat_close(kc);
1459338Srafael.vanoni@sun.com 			return (-3);
1469338Srafael.vanoni@sun.com 		}
1479338Srafael.vanoni@sun.com 
1489338Srafael.vanoni@sun.com 		/*
1499338Srafael.vanoni@sun.com 		 * snapshot IA32_MPERF_MSR
1509338Srafael.vanoni@sun.com 		 */
1519338Srafael.vanoni@sun.com 		turbo_info->t_mcnt = knp->value.ui64;
1529338Srafael.vanoni@sun.com 
1539338Srafael.vanoni@sun.com 		knp = kstat_data_lookup(ksp, "turbo_acnt");
1549338Srafael.vanoni@sun.com 		if (knp == NULL) {
155*11122Srafael.vanoni@sun.com 			pt_error("couldn't find 'turbo_acnt' kstat for CPU "
156*11122Srafael.vanoni@sun.com 			    "%d\n", cpu);
1579338Srafael.vanoni@sun.com 			(void) kstat_close(kc);
1589338Srafael.vanoni@sun.com 			return (-4);
1599338Srafael.vanoni@sun.com 		}
1609338Srafael.vanoni@sun.com 
1619338Srafael.vanoni@sun.com 		/*
1629338Srafael.vanoni@sun.com 		 * snapshot IA32_APERF_MSR
1639338Srafael.vanoni@sun.com 		 */
1649338Srafael.vanoni@sun.com 		turbo_info->t_acnt = knp->value.ui64;
1659338Srafael.vanoni@sun.com 	}
1669338Srafael.vanoni@sun.com 
1679338Srafael.vanoni@sun.com 	if (kstat_close(kc) != 0)
168*11122Srafael.vanoni@sun.com 		pt_error("couldn't close 'turbo' kstat\n");
1699338Srafael.vanoni@sun.com 
1709338Srafael.vanoni@sun.com 	return (0);
1719338Srafael.vanoni@sun.com }
1729338Srafael.vanoni@sun.com 
1739338Srafael.vanoni@sun.com /*
1749338Srafael.vanoni@sun.com  * Turbo support checking and information initialization
1759338Srafael.vanoni@sun.com  */
1769338Srafael.vanoni@sun.com int
pt_turbo_stat_prepare(void)1779338Srafael.vanoni@sun.com pt_turbo_stat_prepare(void)
1789338Srafael.vanoni@sun.com {
179*11122Srafael.vanoni@sun.com 	int ret = 0;
1809338Srafael.vanoni@sun.com 
181*11122Srafael.vanoni@sun.com 	if ((ret = pt_turbo_init()) != 0)
1829338Srafael.vanoni@sun.com 		return (ret);
1839338Srafael.vanoni@sun.com 
184*11122Srafael.vanoni@sun.com 	if ((ret = pt_turbo_snapshot(cpu_turbo_info)) != 0)
185*11122Srafael.vanoni@sun.com 		pt_error("failed to snapshot 'turbo' kstat\n");
1869338Srafael.vanoni@sun.com 
1879338Srafael.vanoni@sun.com 	return (ret);
1889338Srafael.vanoni@sun.com }
1899338Srafael.vanoni@sun.com 
1909338Srafael.vanoni@sun.com /*
1919338Srafael.vanoni@sun.com  * When doing the statistics collection, we compare two kstat snapshot
1929338Srafael.vanoni@sun.com  * and get a delta. the final ratio of performance boost will be worked
1939338Srafael.vanoni@sun.com  * out according to the kstat delta
1949338Srafael.vanoni@sun.com  */
1959338Srafael.vanoni@sun.com int
pt_turbo_stat_collect(void)1969338Srafael.vanoni@sun.com pt_turbo_stat_collect(void)
1979338Srafael.vanoni@sun.com {
1989338Srafael.vanoni@sun.com 	int		cpu;
1999338Srafael.vanoni@sun.com 	uint64_t	delta_mcnt, delta_acnt;
2009338Srafael.vanoni@sun.com 	double		ratio;
2019338Srafael.vanoni@sun.com 	int		ret;
2029338Srafael.vanoni@sun.com 
2039338Srafael.vanoni@sun.com 	/*
2049338Srafael.vanoni@sun.com 	 * Take a snapshot of turbo information to setup turbo_info_t
2059338Srafael.vanoni@sun.com 	 * structure
2069338Srafael.vanoni@sun.com 	 */
207*11122Srafael.vanoni@sun.com 	if ((ret = pt_turbo_snapshot(t_new)) != 0) {
208*11122Srafael.vanoni@sun.com 		pt_error("failed to snapshot 'turbo' kstat\n");
2099338Srafael.vanoni@sun.com 		return (ret);
2109338Srafael.vanoni@sun.com 	}
2119338Srafael.vanoni@sun.com 
2129338Srafael.vanoni@sun.com 	/*
2139338Srafael.vanoni@sun.com 	 * Calculate the kstat delta and work out the performance boost ratio
2149338Srafael.vanoni@sun.com 	 */
2159338Srafael.vanoni@sun.com 	for (cpu = 0; cpu < g_ncpus; cpu++) {
2169338Srafael.vanoni@sun.com 		delta_mcnt = t_new[cpu].t_mcnt - cpu_turbo_info[cpu].t_mcnt;
2179338Srafael.vanoni@sun.com 		delta_acnt = t_new[cpu].t_acnt - cpu_turbo_info[cpu].t_acnt;
2189338Srafael.vanoni@sun.com 
2199338Srafael.vanoni@sun.com 		if ((delta_mcnt > delta_acnt) || (delta_mcnt == 0))
2209338Srafael.vanoni@sun.com 			ratio = 1.0;
2219338Srafael.vanoni@sun.com 		else
2229338Srafael.vanoni@sun.com 			ratio = (double)delta_acnt / (double)delta_mcnt;
2239338Srafael.vanoni@sun.com 		g_turbo_ratio += ratio;
2249338Srafael.vanoni@sun.com 	}
2259338Srafael.vanoni@sun.com 
2269338Srafael.vanoni@sun.com 	g_turbo_ratio = g_turbo_ratio / (double)g_ncpus;
2279338Srafael.vanoni@sun.com 
2289338Srafael.vanoni@sun.com 	/*
2299338Srafael.vanoni@sun.com 	 * Update the structure of the kstat for the next time calculation
2309338Srafael.vanoni@sun.com 	 */
2319338Srafael.vanoni@sun.com 	(void) memcpy(cpu_turbo_info, t_new, g_ncpus * (sizeof (turbo_info_t)));
2329338Srafael.vanoni@sun.com 
2339338Srafael.vanoni@sun.com 	return (0);
2349338Srafael.vanoni@sun.com }
235