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