blob: 8edadd992ed7ed6991be95181c069da7a9eb9d92 [file] [log] [blame]
Arjan van der Ven329bb7a2007-06-17 06:27:18 +00001/*
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
Anurag Singhf051ada2011-11-07 09:33:35 -080035#define MAX_PSTATES 32
Patrick Caind2a9a4c2014-08-20 12:35:29 -070036#define MAX_CPUS 8
Arjan van der Ven329bb7a2007-06-17 06:27:18 +000037struct cpufreqdata {
38 uint64_t frequency;
39 uint64_t count;
40};
41
Patrick Caind2a9a4c2014-08-20 12:35:29 -070042struct cpufreqdata freqs[MAX_CPUS][MAX_PSTATES];
43struct cpufreqdata oldfreqs[MAX_CPUS][MAX_PSTATES];
Arjan van der Ven329bb7a2007-06-17 06:27:18 +000044
Patrick Caind2a9a4c2014-08-20 12:35:29 -070045struct cpufreqdata delta[MAX_CPUS][MAX_PSTATES];
Arjan van der Ven329bb7a2007-06-17 06:27:18 +000046
Patrick Caind2a9a4c2014-08-20 12:35:29 -070047char cpufreqstrings[25][256];
Arjan van der Ven329bb7a2007-06-17 06:27:18 +000048int topfreq = -1;
49
50static void zap(void)
51{
52 memset(freqs, 0, sizeof(freqs));
53}
54
55int sort_by_count (const void *av, const void *bv)
56{
57 const struct cpufreqdata *a = av, *b = bv;
58 return b->count - a->count;
59}
60
61int sort_by_freq (const void *av, const void *bv)
62{
63 const struct cpufreqdata *a = av, *b = bv;
64 return b->frequency - a->frequency;
65}
66
67static char *HzToHuman(unsigned long hz)
68{
69 static char buffer[1024];
70 memset(buffer, 0, 1024);
71 unsigned long long Hz;
72
73 Hz = hz;
74
75 /* default: just put the Number in */
76 sprintf(buffer,_("%9lli"), Hz);
77
78 if (Hz>1000)
79 sprintf(buffer, _("%6lli Mhz"), (Hz+500)/1000);
80
81 if (Hz>1500000)
Arjan van der Vena62cf922007-06-17 16:07:49 +000082 sprintf(buffer, _("%6.2f Ghz"), (Hz+5000.0)/1000000);
Arjan van der Ven329bb7a2007-06-17 06:27:18 +000083
84
85 return buffer;
86}
87
88
89void do_cpufreq_stats(void)
90{
91 DIR *dir;
92 struct dirent *dirent;
93 FILE *file;
94 char filename[PATH_MAX];
95 char line[1024];
96
Patrick Caind2a9a4c2014-08-20 12:35:29 -070097 int cpu = -1;
98 int ret, cpucount;
Arjan van der Ven329bb7a2007-06-17 06:27:18 +000099 int maxfreq = 0;
Patrick Caind2a9a4c2014-08-20 12:35:29 -0700100 uint64_t total_time[MAX_CPUS] = {0};
Arjan van der Ven329bb7a2007-06-17 06:27:18 +0000101
102 memcpy(&oldfreqs, &freqs, sizeof(freqs));
103 memset(&cpufreqstrings, 0, sizeof(cpufreqstrings));
Arjan van der Ven6fe1c572007-08-18 21:52:07 +0000104 sprintf(cpufreqstrings[0], _("P-states (frequencies)\n"));
Arjan van der Ven329bb7a2007-06-17 06:27:18 +0000105
Patrick Caind2a9a4c2014-08-20 12:35:29 -0700106 for (ret = 0; ret<MAX_PSTATES; ret++) {
107 for (cpucount = 0; cpucount < MAX_CPUS; cpucount++)
108 freqs[cpucount][ret].count = 0;
109 }
Arjan van der Ven329bb7a2007-06-17 06:27:18 +0000110
111 dir = opendir("/sys/devices/system/cpu");
112 if (!dir)
113 return;
114
115 while ((dirent = readdir(dir))) {
116 int i;
117 if (dirent->d_name[0]=='.')
118 continue;
119 sprintf(filename, "/sys/devices/system/cpu/%s/cpufreq/stats/time_in_state", dirent->d_name);
120 file = fopen(filename, "r");
121 if (!file)
122 continue;
123 memset(line, 0, 1024);
Patrick Caind2a9a4c2014-08-20 12:35:29 -0700124 cpu++;
125 if ( cpu >= MAX_CPUS)
126 cpu = MAX_CPUS -1;
Arjan van der Ven329bb7a2007-06-17 06:27:18 +0000127 i = 0;
128 while (!feof(file)) {
129 uint64_t f,count;
130 char *c;
131 if (fgets(line, 1023,file)==NULL)
132 break;
133 f = strtoull(line, &c, 10);
134 if (!c)
135 break;
136 count = strtoull(c, NULL, 10);
137
Patrick Caind2a9a4c2014-08-20 12:35:29 -0700138 if (freqs[cpu][i].frequency && freqs[cpu][i].frequency != f) {
Arjan van der Ven329bb7a2007-06-17 06:27:18 +0000139 zap();
140 break;
141 }
142
Patrick Caind2a9a4c2014-08-20 12:35:29 -0700143 freqs[cpu][i].frequency = f;
144 freqs[cpu][i].count += count;
Arjan van der Ven329bb7a2007-06-17 06:27:18 +0000145
146 if (f && maxfreq < i)
147 maxfreq = i;
148 i++;
Anurag Singhf051ada2011-11-07 09:33:35 -0800149 if (i>(MAX_PSTATES - 1))
Arjan van der Ven329bb7a2007-06-17 06:27:18 +0000150 break;
151 }
152 fclose(file);
153 }
154
155 closedir(dir);
156
Anurag Singhf051ada2011-11-07 09:33:35 -0800157 for (ret = 0; ret < MAX_PSTATES; ret++) {
Patrick Caind2a9a4c2014-08-20 12:35:29 -0700158 for (cpucount = 0; cpucount < MAX_CPUS; cpucount++) {
159 delta[cpucount][ret].count = freqs[cpucount][ret].count - oldfreqs[cpucount][ret].count;
160 total_time[cpucount] += delta[cpucount][ret].count;
161 delta[cpucount][ret].frequency = freqs[cpucount][ret].frequency;
162 if (freqs[cpucount][ret].frequency != oldfreqs[cpucount][ret].frequency)
163 return; /* duff data */
164 }
Arjan van der Ven329bb7a2007-06-17 06:27:18 +0000165 }
166
Patrick Caind2a9a4c2014-08-20 12:35:29 -0700167 for (cpucount = 0 ; cpucount < MAX_CPUS; cpucount++) {
168 if (total_time[cpucount])
169 break;
170 }
171 if (cpucount == MAX_CPUS)
Arjan van der Ven329bb7a2007-06-17 06:27:18 +0000172 return;
173
Arjan van der Ven329bb7a2007-06-17 06:27:18 +0000174 topfreq = -1;
Patrick Caind2a9a4c2014-08-20 12:35:29 -0700175
vanajau92c9a5f2016-09-13 12:27:08 +0530176 for (ret = 0 ; ret<=maxfreq && ret<=254; ret++) {
Patrick Caind2a9a4c2014-08-20 12:35:29 -0700177 uint64_t last_freq = -1;
178 strlcpy(cpufreqstrings[ret+1], " ",sizeof(cpufreqstrings[ret+1]));
179 for ( cpucount = 0; cpucount <= cpu; cpucount++) {
180 char temp_freq[32];
181 if (delta[cpucount][ret].frequency != last_freq && delta[cpucount][ret].frequency != 0) {
182 snprintf(temp_freq, sizeof(temp_freq), "%6s", HzToHuman(delta[cpucount][ret].frequency));
183 strncat(cpufreqstrings[ret+1], temp_freq, 32);
184 last_freq = delta[cpucount][ret].frequency;
185 }
186 snprintf(temp_freq, sizeof(temp_freq), "\t%5.1f%% ", delta[cpucount][ret].count * 100.0 / total_time[cpucount]);
187 strncat(cpufreqstrings[ret+1], temp_freq, 32);
188 if (delta[cpucount][ret].count > total_time[cpucount]/2)
189 topfreq = ret;
190 }
191 strncat(cpufreqstrings[ret+1], "\n", 1);
Arjan van der Ven329bb7a2007-06-17 06:27:18 +0000192 }
193
194}