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