xref: /titanic_50/usr/src/cmd/powertop/common/turbo.c (revision b47b5b34b42fa8056577c43496cdb99a4c99f8d7)
1*b47b5b34SRafael Vanoni /*
2*b47b5b34SRafael Vanoni  * Copyright 2009, Intel Corporation
3*b47b5b34SRafael Vanoni  * Copyright 2009, Sun Microsystems, Inc
4*b47b5b34SRafael Vanoni  *
5*b47b5b34SRafael Vanoni  * This file is part of PowerTOP
6*b47b5b34SRafael Vanoni  *
7*b47b5b34SRafael Vanoni  * This program file is free software; you can redistribute it and/or modify it
8*b47b5b34SRafael Vanoni  * under the terms of the GNU General Public License as published by the
9*b47b5b34SRafael Vanoni  * Free Software Foundation; version 2 of the License.
10*b47b5b34SRafael Vanoni  *
11*b47b5b34SRafael Vanoni  * This program is distributed in the hope that it will be useful, but WITHOUT
12*b47b5b34SRafael Vanoni  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13*b47b5b34SRafael Vanoni  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14*b47b5b34SRafael Vanoni  * for more details.
15*b47b5b34SRafael Vanoni  *
16*b47b5b34SRafael Vanoni  * You should have received a copy of the GNU General Public License
17*b47b5b34SRafael Vanoni  * along with this program in a file named COPYING; if not, write to the
18*b47b5b34SRafael Vanoni  * Free Software Foundation, Inc.,
19*b47b5b34SRafael Vanoni  * 51 Franklin Street, Fifth Floor,
20*b47b5b34SRafael Vanoni  * Boston, MA 02110-1301 USA
21*b47b5b34SRafael Vanoni  *
22*b47b5b34SRafael Vanoni  * Authors:
23*b47b5b34SRafael Vanoni  *	Arjan van de Ven <arjan@linux.intel.com>
24*b47b5b34SRafael Vanoni  *	Eric C Saxe <eric.saxe@sun.com>
25*b47b5b34SRafael Vanoni  *	Aubrey Li <aubrey.li@intel.com>
26*b47b5b34SRafael Vanoni  */
27*b47b5b34SRafael Vanoni 
28*b47b5b34SRafael Vanoni /*
29*b47b5b34SRafael Vanoni  * GPL Disclaimer
30*b47b5b34SRafael Vanoni  *
31*b47b5b34SRafael Vanoni  * For the avoidance of doubt, except that if any license choice other
32*b47b5b34SRafael Vanoni  * than GPL or LGPL is available it will apply instead, Sun elects to
33*b47b5b34SRafael Vanoni  * use only the General Public License version 2 (GPLv2) at this time
34*b47b5b34SRafael Vanoni  * for any software where a choice of GPL license versions is made
35*b47b5b34SRafael Vanoni  * available with the language indicating that GPLv2 or any later
36*b47b5b34SRafael Vanoni  * version may be used, or where a choice of which version of the GPL
37*b47b5b34SRafael Vanoni  * is applied is otherwise unspecified.
38*b47b5b34SRafael Vanoni  */
39*b47b5b34SRafael Vanoni 
40*b47b5b34SRafael Vanoni #include <stdlib.h>
41*b47b5b34SRafael Vanoni #include <string.h>
42*b47b5b34SRafael Vanoni #include <dtrace.h>
43*b47b5b34SRafael Vanoni #include <kstat.h>
44*b47b5b34SRafael Vanoni #include <errno.h>
45*b47b5b34SRafael Vanoni #include "powertop.h"
46*b47b5b34SRafael Vanoni 
47*b47b5b34SRafael Vanoni /*
48*b47b5b34SRafael Vanoni  * Global turbo related variables definitions
49*b47b5b34SRafael Vanoni  */
50*b47b5b34SRafael Vanoni boolean_t		g_turbo_supported;
51*b47b5b34SRafael Vanoni double			g_turbo_ratio;
52*b47b5b34SRafael Vanoni 
53*b47b5b34SRafael Vanoni /*
54*b47b5b34SRafael Vanoni  * The variables to store kstat snapshot
55*b47b5b34SRafael Vanoni  */
56*b47b5b34SRafael Vanoni static turbo_info_t	*cpu_turbo_info = NULL;
57*b47b5b34SRafael Vanoni static turbo_info_t	*t_new = NULL;
58*b47b5b34SRafael Vanoni 
59*b47b5b34SRafael Vanoni /*
60*b47b5b34SRafael Vanoni  * Perform setup necessary to enumerate and track CPU turbo information
61*b47b5b34SRafael Vanoni  */
62*b47b5b34SRafael Vanoni static int
63*b47b5b34SRafael Vanoni pt_turbo_init(void)
64*b47b5b34SRafael Vanoni {
65*b47b5b34SRafael Vanoni 	kstat_ctl_t 		*kc;
66*b47b5b34SRafael Vanoni 	kstat_t 		*ksp;
67*b47b5b34SRafael Vanoni 	kstat_named_t 		*knp;
68*b47b5b34SRafael Vanoni 
69*b47b5b34SRafael Vanoni 	/*
70*b47b5b34SRafael Vanoni 	 * check if the CPU turbo is supported
71*b47b5b34SRafael Vanoni 	 */
72*b47b5b34SRafael Vanoni 	if ((kc = kstat_open()) == NULL) {
73*b47b5b34SRafael Vanoni 		g_turbo_supported = B_FALSE;
74*b47b5b34SRafael Vanoni 		return (errno);
75*b47b5b34SRafael Vanoni 	}
76*b47b5b34SRafael Vanoni 
77*b47b5b34SRafael Vanoni 	ksp = kstat_lookup(kc, "turbo", 0, NULL);
78*b47b5b34SRafael Vanoni 	if (ksp == NULL) {
79*b47b5b34SRafael Vanoni 		g_turbo_supported = B_FALSE;
80*b47b5b34SRafael Vanoni 		(void) kstat_close(kc);
81*b47b5b34SRafael Vanoni 		return (-1);
82*b47b5b34SRafael Vanoni 	}
83*b47b5b34SRafael Vanoni 
84*b47b5b34SRafael Vanoni 	(void) kstat_read(kc, ksp, NULL);
85*b47b5b34SRafael Vanoni 
86*b47b5b34SRafael Vanoni 	knp = kstat_data_lookup(ksp, "turbo_supported");
87*b47b5b34SRafael Vanoni 	if (knp == NULL) {
88*b47b5b34SRafael Vanoni 		pt_error("%s : couldn't find item turbo_supported\n", __FILE__);
89*b47b5b34SRafael Vanoni 		g_turbo_supported = B_FALSE;
90*b47b5b34SRafael Vanoni 		(void) kstat_close(kc);
91*b47b5b34SRafael Vanoni 		return (-2);
92*b47b5b34SRafael Vanoni 	}
93*b47b5b34SRafael Vanoni 
94*b47b5b34SRafael Vanoni 	/*
95*b47b5b34SRafael Vanoni 	 * Initialize turbo information structure if turbo mode is supported
96*b47b5b34SRafael Vanoni 	 */
97*b47b5b34SRafael Vanoni 	if (knp->value.ui32) {
98*b47b5b34SRafael Vanoni 		g_turbo_supported = B_TRUE;
99*b47b5b34SRafael Vanoni 		cpu_turbo_info = calloc((size_t)g_ncpus, sizeof (turbo_info_t));
100*b47b5b34SRafael Vanoni 		t_new = calloc((size_t)g_ncpus, sizeof (turbo_info_t));
101*b47b5b34SRafael Vanoni 	}
102*b47b5b34SRafael Vanoni 
103*b47b5b34SRafael Vanoni 	(void) kstat_close(kc);
104*b47b5b34SRafael Vanoni 	return (0);
105*b47b5b34SRafael Vanoni }
106*b47b5b34SRafael Vanoni 
107*b47b5b34SRafael Vanoni /*
108*b47b5b34SRafael Vanoni  * Take a snapshot of each CPU's turbo information
109*b47b5b34SRafael Vanoni  * by looking through the turbo kstats.
110*b47b5b34SRafael Vanoni  */
111*b47b5b34SRafael Vanoni static int
112*b47b5b34SRafael Vanoni pt_turbo_snapshot(turbo_info_t *turbo_snapshot)
113*b47b5b34SRafael Vanoni {
114*b47b5b34SRafael Vanoni 	kstat_ctl_t 		*kc;
115*b47b5b34SRafael Vanoni 	kstat_t 		*ksp;
116*b47b5b34SRafael Vanoni 	kstat_named_t 		*knp;
117*b47b5b34SRafael Vanoni 	int 			cpu;
118*b47b5b34SRafael Vanoni 	turbo_info_t		*turbo_info;
119*b47b5b34SRafael Vanoni 
120*b47b5b34SRafael Vanoni 	if ((kc = kstat_open()) == NULL)
121*b47b5b34SRafael Vanoni 		return (errno);
122*b47b5b34SRafael Vanoni 
123*b47b5b34SRafael Vanoni 	for (cpu = 0; cpu < g_ncpus; cpu++) {
124*b47b5b34SRafael Vanoni 		turbo_info = &turbo_snapshot[cpu];
125*b47b5b34SRafael Vanoni 		ksp = kstat_lookup(kc, "turbo", g_cpu_table[cpu], NULL);
126*b47b5b34SRafael Vanoni 		if (ksp == NULL) {
127*b47b5b34SRafael Vanoni 			pt_error("%s : couldn't find turbo kstat for CPU "
128*b47b5b34SRafael Vanoni 			"%d\n", __FILE__, cpu);
129*b47b5b34SRafael Vanoni 			(void) kstat_close(kc);
130*b47b5b34SRafael Vanoni 			return (-1);
131*b47b5b34SRafael Vanoni 		}
132*b47b5b34SRafael Vanoni 
133*b47b5b34SRafael Vanoni 		if (kstat_read(kc, ksp, NULL) == -1) {
134*b47b5b34SRafael Vanoni 			pt_error("%s : couldn't read turbo kstat for "
135*b47b5b34SRafael Vanoni 			    "CPU %d\n", __FILE__, cpu);
136*b47b5b34SRafael Vanoni 			(void) kstat_close(kc);
137*b47b5b34SRafael Vanoni 			return (-2);
138*b47b5b34SRafael Vanoni 		}
139*b47b5b34SRafael Vanoni 
140*b47b5b34SRafael Vanoni 		knp = kstat_data_lookup(ksp, "turbo_mcnt");
141*b47b5b34SRafael Vanoni 		if (knp == NULL) {
142*b47b5b34SRafael Vanoni 			pt_error("%s : couldn't find turbo mcnt "
143*b47b5b34SRafael Vanoni 			    "kstat for CPU %d\n", __FILE__, cpu);
144*b47b5b34SRafael Vanoni 			(void) kstat_close(kc);
145*b47b5b34SRafael Vanoni 			return (-3);
146*b47b5b34SRafael Vanoni 		}
147*b47b5b34SRafael Vanoni 
148*b47b5b34SRafael Vanoni 		/*
149*b47b5b34SRafael Vanoni 		 * snapshot IA32_MPERF_MSR
150*b47b5b34SRafael Vanoni 		 */
151*b47b5b34SRafael Vanoni 		turbo_info->t_mcnt = knp->value.ui64;
152*b47b5b34SRafael Vanoni 
153*b47b5b34SRafael Vanoni 		knp = kstat_data_lookup(ksp, "turbo_acnt");
154*b47b5b34SRafael Vanoni 		if (knp == NULL) {
155*b47b5b34SRafael Vanoni 			pt_error("%s : couldn't find turbo acnt "
156*b47b5b34SRafael Vanoni 			    "kstat for CPU %d\n", __FILE__, cpu);
157*b47b5b34SRafael Vanoni 			(void) kstat_close(kc);
158*b47b5b34SRafael Vanoni 			return (-4);
159*b47b5b34SRafael Vanoni 		}
160*b47b5b34SRafael Vanoni 
161*b47b5b34SRafael Vanoni 		/*
162*b47b5b34SRafael Vanoni 		 * snapshot IA32_APERF_MSR
163*b47b5b34SRafael Vanoni 		 */
164*b47b5b34SRafael Vanoni 		turbo_info->t_acnt = knp->value.ui64;
165*b47b5b34SRafael Vanoni 	}
166*b47b5b34SRafael Vanoni 
167*b47b5b34SRafael Vanoni 	if (kstat_close(kc) != 0)
168*b47b5b34SRafael Vanoni 		pt_error("%s : couldn't close kstat\n", __FILE__);
169*b47b5b34SRafael Vanoni 
170*b47b5b34SRafael Vanoni 	return (0);
171*b47b5b34SRafael Vanoni }
172*b47b5b34SRafael Vanoni 
173*b47b5b34SRafael Vanoni /*
174*b47b5b34SRafael Vanoni  * Turbo support checking and information initialization
175*b47b5b34SRafael Vanoni  */
176*b47b5b34SRafael Vanoni int
177*b47b5b34SRafael Vanoni pt_turbo_stat_prepare(void)
178*b47b5b34SRafael Vanoni {
179*b47b5b34SRafael Vanoni 	int	ret;
180*b47b5b34SRafael Vanoni 
181*b47b5b34SRafael Vanoni 	ret = pt_turbo_init();
182*b47b5b34SRafael Vanoni 
183*b47b5b34SRafael Vanoni 	if (ret != 0) {
184*b47b5b34SRafael Vanoni 		return (ret);
185*b47b5b34SRafael Vanoni 	}
186*b47b5b34SRafael Vanoni 
187*b47b5b34SRafael Vanoni 	ret = pt_turbo_snapshot(cpu_turbo_info);
188*b47b5b34SRafael Vanoni 
189*b47b5b34SRafael Vanoni 	if (ret != 0) {
190*b47b5b34SRafael Vanoni 		pt_error("%s : turbo snapshot failed\n", __FILE__);
191*b47b5b34SRafael Vanoni 	}
192*b47b5b34SRafael Vanoni 
193*b47b5b34SRafael Vanoni 	return (ret);
194*b47b5b34SRafael Vanoni }
195*b47b5b34SRafael Vanoni 
196*b47b5b34SRafael Vanoni /*
197*b47b5b34SRafael Vanoni  * When doing the statistics collection, we compare two kstat snapshot
198*b47b5b34SRafael Vanoni  * and get a delta. the final ratio of performance boost will be worked
199*b47b5b34SRafael Vanoni  * out according to the kstat delta
200*b47b5b34SRafael Vanoni  */
201*b47b5b34SRafael Vanoni int
202*b47b5b34SRafael Vanoni pt_turbo_stat_collect(void)
203*b47b5b34SRafael Vanoni {
204*b47b5b34SRafael Vanoni 	int		cpu;
205*b47b5b34SRafael Vanoni 	uint64_t	delta_mcnt, delta_acnt;
206*b47b5b34SRafael Vanoni 	double		ratio;
207*b47b5b34SRafael Vanoni 	int		ret;
208*b47b5b34SRafael Vanoni 
209*b47b5b34SRafael Vanoni 	/*
210*b47b5b34SRafael Vanoni 	 * Take a snapshot of turbo information to setup turbo_info_t
211*b47b5b34SRafael Vanoni 	 * structure
212*b47b5b34SRafael Vanoni 	 */
213*b47b5b34SRafael Vanoni 	ret = pt_turbo_snapshot(t_new);
214*b47b5b34SRafael Vanoni 	if (ret != 0) {
215*b47b5b34SRafael Vanoni 		pt_error("%s : turbo stat collection failed\n", __FILE__);
216*b47b5b34SRafael Vanoni 		return (ret);
217*b47b5b34SRafael Vanoni 	}
218*b47b5b34SRafael Vanoni 
219*b47b5b34SRafael Vanoni 	/*
220*b47b5b34SRafael Vanoni 	 * Calculate the kstat delta and work out the performance boost ratio
221*b47b5b34SRafael Vanoni 	 */
222*b47b5b34SRafael Vanoni 	for (cpu = 0; cpu < g_ncpus; cpu++) {
223*b47b5b34SRafael Vanoni 		delta_mcnt = t_new[cpu].t_mcnt - cpu_turbo_info[cpu].t_mcnt;
224*b47b5b34SRafael Vanoni 		delta_acnt = t_new[cpu].t_acnt - cpu_turbo_info[cpu].t_acnt;
225*b47b5b34SRafael Vanoni 
226*b47b5b34SRafael Vanoni 		if ((delta_mcnt > delta_acnt) || (delta_mcnt == 0))
227*b47b5b34SRafael Vanoni 			ratio = 1.0;
228*b47b5b34SRafael Vanoni 		else
229*b47b5b34SRafael Vanoni 			ratio = (double)delta_acnt / (double)delta_mcnt;
230*b47b5b34SRafael Vanoni 		g_turbo_ratio += ratio;
231*b47b5b34SRafael Vanoni 	}
232*b47b5b34SRafael Vanoni 
233*b47b5b34SRafael Vanoni 	g_turbo_ratio = g_turbo_ratio / (double)g_ncpus;
234*b47b5b34SRafael Vanoni 
235*b47b5b34SRafael Vanoni 	/*
236*b47b5b34SRafael Vanoni 	 * Update the structure of the kstat for the next time calculation
237*b47b5b34SRafael Vanoni 	 */
238*b47b5b34SRafael Vanoni 	(void) memcpy(cpu_turbo_info, t_new, g_ncpus * (sizeof (turbo_info_t)));
239*b47b5b34SRafael Vanoni 
240*b47b5b34SRafael Vanoni 	return (0);
241*b47b5b34SRafael Vanoni }
242