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