xref: /illumos-gate/usr/src/cmd/powertop/common/turbo.c (revision f6e9c6bd)
12c23960fSRafael Vanoni /*
22c23960fSRafael Vanoni  * Copyright 2009, Intel Corporation
32c23960fSRafael Vanoni  * Copyright 2009, Sun Microsystems, Inc
42c23960fSRafael Vanoni  *
52c23960fSRafael Vanoni  * This file is part of PowerTOP
62c23960fSRafael Vanoni  *
72c23960fSRafael Vanoni  * This program file is free software; you can redistribute it and/or modify it
82c23960fSRafael Vanoni  * under the terms of the GNU General Public License as published by the
92c23960fSRafael Vanoni  * Free Software Foundation; version 2 of the License.
102c23960fSRafael Vanoni  *
112c23960fSRafael Vanoni  * This program is distributed in the hope that it will be useful, but WITHOUT
122c23960fSRafael Vanoni  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
132c23960fSRafael Vanoni  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
142c23960fSRafael Vanoni  * for more details.
152c23960fSRafael Vanoni  *
162c23960fSRafael Vanoni  * You should have received a copy of the GNU General Public License
172c23960fSRafael Vanoni  * along with this program in a file named COPYING; if not, write to the
182c23960fSRafael Vanoni  * Free Software Foundation, Inc.,
192c23960fSRafael Vanoni  * 51 Franklin Street, Fifth Floor,
202c23960fSRafael Vanoni  * Boston, MA 02110-1301 USA
212c23960fSRafael Vanoni  *
222c23960fSRafael Vanoni  * Authors:
232c23960fSRafael Vanoni  *	Arjan van de Ven <arjan@linux.intel.com>
242c23960fSRafael Vanoni  *	Eric C Saxe <eric.saxe@sun.com>
252c23960fSRafael Vanoni  *	Aubrey Li <aubrey.li@intel.com>
262c23960fSRafael Vanoni  */
272c23960fSRafael Vanoni 
282c23960fSRafael Vanoni /*
292c23960fSRafael Vanoni  * GPL Disclaimer
302c23960fSRafael Vanoni  *
312c23960fSRafael Vanoni  * For the avoidance of doubt, except that if any license choice other
322c23960fSRafael Vanoni  * than GPL or LGPL is available it will apply instead, Sun elects to
332c23960fSRafael Vanoni  * use only the General Public License version 2 (GPLv2) at this time
342c23960fSRafael Vanoni  * for any software where a choice of GPL license versions is made
352c23960fSRafael Vanoni  * available with the language indicating that GPLv2 or any later
362c23960fSRafael Vanoni  * version may be used, or where a choice of which version of the GPL
372c23960fSRafael Vanoni  * is applied is otherwise unspecified.
382c23960fSRafael Vanoni  */
392c23960fSRafael Vanoni 
402c23960fSRafael Vanoni #include <stdlib.h>
412c23960fSRafael Vanoni #include <string.h>
422c23960fSRafael Vanoni #include <dtrace.h>
432c23960fSRafael Vanoni #include <kstat.h>
442c23960fSRafael Vanoni #include <errno.h>
452c23960fSRafael Vanoni #include "powertop.h"
462c23960fSRafael Vanoni 
472c23960fSRafael Vanoni /*
48b47b5b34SRafael Vanoni  * Global turbo related variables definitions
492c23960fSRafael Vanoni  */
502c23960fSRafael Vanoni boolean_t		g_turbo_supported;
512c23960fSRafael Vanoni double			g_turbo_ratio;
522c23960fSRafael Vanoni 
532c23960fSRafael Vanoni /*
54b47b5b34SRafael Vanoni  * The variables to store kstat snapshot
552c23960fSRafael Vanoni  */
562c23960fSRafael Vanoni static turbo_info_t	*cpu_turbo_info = NULL;
572c23960fSRafael Vanoni static turbo_info_t	*t_new = NULL;
582c23960fSRafael Vanoni 
592c23960fSRafael Vanoni /*
602c23960fSRafael Vanoni  * Perform setup necessary to enumerate and track CPU turbo information
612c23960fSRafael Vanoni  */
622c23960fSRafael Vanoni static int
pt_turbo_init(void)632c23960fSRafael Vanoni pt_turbo_init(void)
642c23960fSRafael Vanoni {
65*f6e9c6bdSToomas Soome 	kstat_ctl_t		*kc;
66*f6e9c6bdSToomas Soome 	kstat_t			*ksp;
67*f6e9c6bdSToomas Soome 	kstat_named_t		*knp;
682c23960fSRafael Vanoni 
692c23960fSRafael Vanoni 	/*
702c23960fSRafael Vanoni 	 * check if the CPU turbo is supported
712c23960fSRafael Vanoni 	 */
722c23960fSRafael Vanoni 	if ((kc = kstat_open()) == NULL) {
732c23960fSRafael Vanoni 		g_turbo_supported = B_FALSE;
742c23960fSRafael Vanoni 		return (errno);
752c23960fSRafael Vanoni 	}
762c23960fSRafael Vanoni 
772c23960fSRafael Vanoni 	ksp = kstat_lookup(kc, "turbo", 0, NULL);
782c23960fSRafael Vanoni 	if (ksp == NULL) {
792c23960fSRafael Vanoni 		g_turbo_supported = B_FALSE;
802c23960fSRafael Vanoni 		(void) kstat_close(kc);
812c23960fSRafael Vanoni 		return (-1);
822c23960fSRafael Vanoni 	}
832c23960fSRafael Vanoni 
842c23960fSRafael Vanoni 	(void) kstat_read(kc, ksp, NULL);
852c23960fSRafael Vanoni 
862c23960fSRafael Vanoni 	knp = kstat_data_lookup(ksp, "turbo_supported");
872c23960fSRafael Vanoni 	if (knp == NULL) {
882d83778aSRafael Vanoni 		pt_error("couldn't find 'turbo_supported' kstat\n");
892c23960fSRafael Vanoni 		g_turbo_supported = B_FALSE;
902c23960fSRafael Vanoni 		(void) kstat_close(kc);
912c23960fSRafael Vanoni 		return (-2);
922c23960fSRafael Vanoni 	}
932c23960fSRafael Vanoni 
942c23960fSRafael Vanoni 	/*
95b47b5b34SRafael Vanoni 	 * Initialize turbo information structure if turbo mode is supported
962c23960fSRafael Vanoni 	 */
972c23960fSRafael Vanoni 	if (knp->value.ui32) {
982c23960fSRafael Vanoni 		g_turbo_supported = B_TRUE;
992c23960fSRafael Vanoni 		cpu_turbo_info = calloc((size_t)g_ncpus, sizeof (turbo_info_t));
1002c23960fSRafael Vanoni 		t_new = calloc((size_t)g_ncpus, sizeof (turbo_info_t));
1012c23960fSRafael Vanoni 	}
1022c23960fSRafael Vanoni 
1032c23960fSRafael Vanoni 	(void) kstat_close(kc);
1042c23960fSRafael Vanoni 	return (0);
1052c23960fSRafael Vanoni }
1062c23960fSRafael Vanoni 
1072c23960fSRafael Vanoni /*
1082c23960fSRafael Vanoni  * Take a snapshot of each CPU's turbo information
1092c23960fSRafael Vanoni  * by looking through the turbo kstats.
1102c23960fSRafael Vanoni  */
1112c23960fSRafael Vanoni static int
pt_turbo_snapshot(turbo_info_t * turbo_snapshot)1122c23960fSRafael Vanoni pt_turbo_snapshot(turbo_info_t *turbo_snapshot)
1132c23960fSRafael Vanoni {
114*f6e9c6bdSToomas Soome 	kstat_ctl_t		*kc;
115*f6e9c6bdSToomas Soome 	kstat_t			*ksp;
116*f6e9c6bdSToomas Soome 	kstat_named_t		*knp;
117*f6e9c6bdSToomas Soome 	int			cpu;
1182c23960fSRafael Vanoni 	turbo_info_t		*turbo_info;
1192c23960fSRafael Vanoni 
1202c23960fSRafael Vanoni 	if ((kc = kstat_open()) == NULL)
1212c23960fSRafael Vanoni 		return (errno);
1222c23960fSRafael Vanoni 
1232c23960fSRafael Vanoni 	for (cpu = 0; cpu < g_ncpus; cpu++) {
1242c23960fSRafael Vanoni 		turbo_info = &turbo_snapshot[cpu];
125b47b5b34SRafael Vanoni 		ksp = kstat_lookup(kc, "turbo", g_cpu_table[cpu], NULL);
1262c23960fSRafael Vanoni 		if (ksp == NULL) {
1272d83778aSRafael Vanoni 			pt_error("couldn't find 'turbo' kstat for CPU %d\n",
1282d83778aSRafael Vanoni 			    cpu);
1292c23960fSRafael Vanoni 			(void) kstat_close(kc);
1302c23960fSRafael Vanoni 			return (-1);
1312c23960fSRafael Vanoni 		}
1322c23960fSRafael Vanoni 
1332c23960fSRafael Vanoni 		if (kstat_read(kc, ksp, NULL) == -1) {
1342d83778aSRafael Vanoni 			pt_error("couldn't read 'turbo' kstat for CPU %d\n",
1352d83778aSRafael Vanoni 			    cpu);
1362c23960fSRafael Vanoni 			(void) kstat_close(kc);
1372c23960fSRafael Vanoni 			return (-2);
1382c23960fSRafael Vanoni 		}
1392c23960fSRafael Vanoni 
1402c23960fSRafael Vanoni 		knp = kstat_data_lookup(ksp, "turbo_mcnt");
1412c23960fSRafael Vanoni 		if (knp == NULL) {
1422d83778aSRafael Vanoni 			pt_error("couldn't find 'turbo_mcnt' kstat for CPU "
1432d83778aSRafael Vanoni 			    "%d\n", cpu);
1442c23960fSRafael Vanoni 			(void) kstat_close(kc);
1452c23960fSRafael Vanoni 			return (-3);
1462c23960fSRafael Vanoni 		}
1472c23960fSRafael Vanoni 
1482c23960fSRafael Vanoni 		/*
1492c23960fSRafael Vanoni 		 * snapshot IA32_MPERF_MSR
1502c23960fSRafael Vanoni 		 */
1512c23960fSRafael Vanoni 		turbo_info->t_mcnt = knp->value.ui64;
1522c23960fSRafael Vanoni 
1532c23960fSRafael Vanoni 		knp = kstat_data_lookup(ksp, "turbo_acnt");
1542c23960fSRafael Vanoni 		if (knp == NULL) {
1552d83778aSRafael Vanoni 			pt_error("couldn't find 'turbo_acnt' kstat for CPU "
1562d83778aSRafael Vanoni 			    "%d\n", cpu);
1572c23960fSRafael Vanoni 			(void) kstat_close(kc);
1582c23960fSRafael Vanoni 			return (-4);
1592c23960fSRafael Vanoni 		}
1602c23960fSRafael Vanoni 
1612c23960fSRafael Vanoni 		/*
1622c23960fSRafael Vanoni 		 * snapshot IA32_APERF_MSR
1632c23960fSRafael Vanoni 		 */
1642c23960fSRafael Vanoni 		turbo_info->t_acnt = knp->value.ui64;
1652c23960fSRafael Vanoni 	}
1662c23960fSRafael Vanoni 
1672c23960fSRafael Vanoni 	if (kstat_close(kc) != 0)
1682d83778aSRafael Vanoni 		pt_error("couldn't close 'turbo' kstat\n");
1692c23960fSRafael Vanoni 
1702c23960fSRafael Vanoni 	return (0);
1712c23960fSRafael Vanoni }
1722c23960fSRafael Vanoni 
1732c23960fSRafael Vanoni /*
174b47b5b34SRafael Vanoni  * Turbo support checking and information initialization
1752c23960fSRafael Vanoni  */
1762c23960fSRafael Vanoni int
pt_turbo_stat_prepare(void)1772c23960fSRafael Vanoni pt_turbo_stat_prepare(void)
1782c23960fSRafael Vanoni {
1792d83778aSRafael Vanoni 	int ret = 0;
1802c23960fSRafael Vanoni 
1812d83778aSRafael Vanoni 	if ((ret = pt_turbo_init()) != 0)
1822c23960fSRafael Vanoni 		return (ret);
1832c23960fSRafael Vanoni 
1842d83778aSRafael Vanoni 	if ((ret = pt_turbo_snapshot(cpu_turbo_info)) != 0)
1852d83778aSRafael Vanoni 		pt_error("failed to snapshot 'turbo' kstat\n");
1862c23960fSRafael Vanoni 
1872c23960fSRafael Vanoni 	return (ret);
1882c23960fSRafael Vanoni }
1892c23960fSRafael Vanoni 
1902c23960fSRafael Vanoni /*
191b47b5b34SRafael Vanoni  * When doing the statistics collection, we compare two kstat snapshot
1922c23960fSRafael Vanoni  * and get a delta. the final ratio of performance boost will be worked
1932c23960fSRafael Vanoni  * out according to the kstat delta
1942c23960fSRafael Vanoni  */
1952c23960fSRafael Vanoni int
pt_turbo_stat_collect(void)1962c23960fSRafael Vanoni pt_turbo_stat_collect(void)
1972c23960fSRafael Vanoni {
1982c23960fSRafael Vanoni 	int		cpu;
1992c23960fSRafael Vanoni 	uint64_t	delta_mcnt, delta_acnt;
2002c23960fSRafael Vanoni 	double		ratio;
2012c23960fSRafael Vanoni 	int		ret;
2022c23960fSRafael Vanoni 
2032c23960fSRafael Vanoni 	/*
204b47b5b34SRafael Vanoni 	 * Take a snapshot of turbo information to setup turbo_info_t
2052c23960fSRafael Vanoni 	 * structure
2062c23960fSRafael Vanoni 	 */
2072d83778aSRafael Vanoni 	if ((ret = pt_turbo_snapshot(t_new)) != 0) {
2082d83778aSRafael Vanoni 		pt_error("failed to snapshot 'turbo' kstat\n");
2092c23960fSRafael Vanoni 		return (ret);
2102c23960fSRafael Vanoni 	}
2112c23960fSRafael Vanoni 
2122c23960fSRafael Vanoni 	/*
213b47b5b34SRafael Vanoni 	 * Calculate the kstat delta and work out the performance boost ratio
2142c23960fSRafael Vanoni 	 */
2152c23960fSRafael Vanoni 	for (cpu = 0; cpu < g_ncpus; cpu++) {
2162c23960fSRafael Vanoni 		delta_mcnt = t_new[cpu].t_mcnt - cpu_turbo_info[cpu].t_mcnt;
2172c23960fSRafael Vanoni 		delta_acnt = t_new[cpu].t_acnt - cpu_turbo_info[cpu].t_acnt;
2182c23960fSRafael Vanoni 
2192c23960fSRafael Vanoni 		if ((delta_mcnt > delta_acnt) || (delta_mcnt == 0))
2202c23960fSRafael Vanoni 			ratio = 1.0;
2212c23960fSRafael Vanoni 		else
2222c23960fSRafael Vanoni 			ratio = (double)delta_acnt / (double)delta_mcnt;
2232c23960fSRafael Vanoni 		g_turbo_ratio += ratio;
2242c23960fSRafael Vanoni 	}
2252c23960fSRafael Vanoni 
2262c23960fSRafael Vanoni 	g_turbo_ratio = g_turbo_ratio / (double)g_ncpus;
2272c23960fSRafael Vanoni 
2282c23960fSRafael Vanoni 	/*
229b47b5b34SRafael Vanoni 	 * Update the structure of the kstat for the next time calculation
2302c23960fSRafael Vanoni 	 */
2312c23960fSRafael Vanoni 	(void) memcpy(cpu_turbo_info, t_new, g_ncpus * (sizeof (turbo_info_t)));
2322c23960fSRafael Vanoni 
2332c23960fSRafael Vanoni 	return (0);
2342c23960fSRafael Vanoni }
235