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 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 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 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 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