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