Home | History | Annotate | Download | only in src
      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 (at) 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 
     48 static void zap(void)
     49 {
     50 	memset(freqs, 0, sizeof(freqs));
     51 }
     52 
     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 
     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 
     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 
     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