1/* 2 * Copyright 2007, Intel Corporation 3 * 4 * This file is part of PowerTOP 5 * 6 * This program file is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License as published by the 8 * Free Software Foundation; version 2 of the License. 9 * 10 * This program is distributed in the hope that it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 13 * for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program in a file named COPYING; if not, write to the 17 * Free Software Foundation, Inc., 18 * 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301 USA 20 * 21 * Authors: 22 * Arjan van de Ven <arjan@linux.intel.com> 23 */ 24 25#include <unistd.h> 26#include <stdio.h> 27#include <stdlib.h> 28#include <string.h> 29#include <stdint.h> 30#include <sys/types.h> 31#include <dirent.h> 32 33#include "powertop.h" 34 35struct cpufreqdata { 36 uint64_t frequency; 37 uint64_t count; 38}; 39 40struct cpufreqdata freqs[16]; 41struct cpufreqdata oldfreqs[16]; 42 43struct cpufreqdata delta[16]; 44 45char cpufreqstrings[6][80]; 46int topfreq = -1; 47 48static void zap(void) 49{ 50 memset(freqs, 0, sizeof(freqs)); 51} 52 53int sort_by_count (const void *av, const void *bv) 54{ 55 const struct cpufreqdata *a = av, *b = bv; 56 return b->count - a->count; 57} 58 59int sort_by_freq (const void *av, const void *bv) 60{ 61 const struct cpufreqdata *a = av, *b = bv; 62 return b->frequency - a->frequency; 63} 64 65static char *HzToHuman(unsigned long hz) 66{ 67 static char buffer[1024]; 68 memset(buffer, 0, 1024); 69 unsigned long long Hz; 70 71 Hz = hz; 72 73 /* default: just put the Number in */ 74 sprintf(buffer,_("%9lli"), Hz); 75 76 if (Hz>1000) 77 sprintf(buffer, _("%6lli Mhz"), (Hz+500)/1000); 78 79 if (Hz>1500000) 80 sprintf(buffer, _("%6.2f Ghz"), (Hz+5000.0)/1000000); 81 82 83 return buffer; 84} 85 86 87void do_cpufreq_stats(void) 88{ 89 DIR *dir; 90 struct dirent *dirent; 91 FILE *file; 92 char filename[PATH_MAX]; 93 char line[1024]; 94 95 int ret = 0; 96 int maxfreq = 0; 97 uint64_t total_time = 0; 98 99 memcpy(&oldfreqs, &freqs, sizeof(freqs)); 100 memset(&cpufreqstrings, 0, sizeof(cpufreqstrings)); 101 sprintf(cpufreqstrings[0], _("P-states (frequencies)\n")); 102 103 for (ret = 0; ret<16; ret++) 104 freqs[ret].count = 0; 105 106 dir = opendir("/sys/devices/system/cpu"); 107 if (!dir) 108 return; 109 110 while ((dirent = readdir(dir))) { 111 int i; 112 if (dirent->d_name[0]=='.') 113 continue; 114 sprintf(filename, "/sys/devices/system/cpu/%s/cpufreq/stats/time_in_state", dirent->d_name); 115 file = fopen(filename, "r"); 116 if (!file) 117 continue; 118 memset(line, 0, 1024); 119 120 i = 0; 121 while (!feof(file)) { 122 uint64_t f,count; 123 char *c; 124 if (fgets(line, 1023,file)==NULL) 125 break; 126 f = strtoull(line, &c, 10); 127 if (!c) 128 break; 129 count = strtoull(c, NULL, 10); 130 131 if (freqs[i].frequency && freqs[i].frequency != f) { 132 zap(); 133 break; 134 } 135 136 freqs[i].frequency = f; 137 freqs[i].count += count; 138 139 if (f && maxfreq < i) 140 maxfreq = i; 141 i++; 142 if (i>15) 143 break; 144 } 145 fclose(file); 146 } 147 148 closedir(dir); 149 150 for (ret = 0; ret < 16; ret++) { 151 delta[ret].count = freqs[ret].count - oldfreqs[ret].count; 152 total_time += delta[ret].count; 153 delta[ret].frequency = freqs[ret].frequency; 154 if (freqs[ret].frequency != oldfreqs[ret].frequency) 155 return; /* duff data */ 156 } 157 158 159 if (!total_time) 160 return; 161 162 qsort(&delta, maxfreq+1, sizeof(struct cpufreqdata), sort_by_count); 163 if (maxfreq>4) 164 maxfreq=4; 165 qsort(&delta, maxfreq+1, sizeof(struct cpufreqdata), sort_by_freq); 166 167 topfreq = -1; 168 for (ret = 0 ; ret<=maxfreq; ret++) { 169 sprintf(cpufreqstrings[ret+1], "%6s %5.1f%%\n", HzToHuman(delta[ret].frequency), delta[ret].count * 100.0 / total_time); 170 if (delta[ret].count > total_time/2) 171 topfreq = ret; 172 } 173 174} 175