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("couldn't find 'turbo_supported' kstat\n"); 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("couldn't find 'turbo' kstat for CPU %d\n", 128 cpu); 129 (void) kstat_close(kc); 130 return (-1); 131 } 132 133 if (kstat_read(kc, ksp, NULL) == -1) { 134 pt_error("couldn't read 'turbo' kstat for CPU %d\n", 135 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("couldn't find 'turbo_mcnt' kstat for CPU " 143 "%d\n", 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("couldn't find 'turbo_acnt' kstat for CPU " 156 "%d\n", 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("couldn't close 'turbo' kstat\n"); 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 = 0; 180 181 if ((ret = pt_turbo_init()) != 0) 182 return (ret); 183 184 if ((ret = pt_turbo_snapshot(cpu_turbo_info)) != 0) 185 pt_error("failed to snapshot 'turbo' kstat\n"); 186 187 return (ret); 188 } 189 190 /* 191 * When doing the statistics collection, we compare two kstat snapshot 192 * and get a delta. the final ratio of performance boost will be worked 193 * out according to the kstat delta 194 */ 195 int 196 pt_turbo_stat_collect(void) 197 { 198 int cpu; 199 uint64_t delta_mcnt, delta_acnt; 200 double ratio; 201 int ret; 202 203 /* 204 * Take a snapshot of turbo information to setup turbo_info_t 205 * structure 206 */ 207 if ((ret = pt_turbo_snapshot(t_new)) != 0) { 208 pt_error("failed to snapshot 'turbo' kstat\n"); 209 return (ret); 210 } 211 212 /* 213 * Calculate the kstat delta and work out the performance boost ratio 214 */ 215 for (cpu = 0; cpu < g_ncpus; cpu++) { 216 delta_mcnt = t_new[cpu].t_mcnt - cpu_turbo_info[cpu].t_mcnt; 217 delta_acnt = t_new[cpu].t_acnt - cpu_turbo_info[cpu].t_acnt; 218 219 if ((delta_mcnt > delta_acnt) || (delta_mcnt == 0)) 220 ratio = 1.0; 221 else 222 ratio = (double)delta_acnt / (double)delta_mcnt; 223 g_turbo_ratio += ratio; 224 } 225 226 g_turbo_ratio = g_turbo_ratio / (double)g_ncpus; 227 228 /* 229 * Update the structure of the kstat for the next time calculation 230 */ 231 (void) memcpy(cpu_turbo_info, t_new, g_ncpus * (sizeof (turbo_info_t))); 232 233 return (0); 234 } 235