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