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
35 struct cpufreqdata {
36 uint64_t frequency;
37 uint64_t count;
38 };
39
40 struct cpufreqdata freqs[16];
41 struct cpufreqdata oldfreqs[16];
42
43 struct cpufreqdata delta[16];
44
45 char cpufreqstrings[6][80];
46 int topfreq = -1;
47
zap(void)48 static void zap(void)
49 {
50 memset(freqs, 0, sizeof(freqs));
51 }
52
sort_by_count(const void * av,const void * bv)53 int 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
sort_by_freq(const void * av,const void * bv)59 int 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
HzToHuman(unsigned long hz)65 static 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
do_cpufreq_stats(void)87 void 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