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