Arjan van der Ven | 329bb7a | 2007-06-17 06:27:18 +0000 | [diff] [blame] | 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 | |
Anurag Singh | f051ada | 2011-11-07 09:33:35 -0800 | [diff] [blame] | 35 | #define MAX_PSTATES 32 |
Patrick Cain | d2a9a4c | 2014-08-20 12:35:29 -0700 | [diff] [blame] | 36 | #define MAX_CPUS 8 |
Arjan van der Ven | 329bb7a | 2007-06-17 06:27:18 +0000 | [diff] [blame] | 37 | struct cpufreqdata { |
| 38 | uint64_t frequency; |
| 39 | uint64_t count; |
| 40 | }; |
| 41 | |
Patrick Cain | d2a9a4c | 2014-08-20 12:35:29 -0700 | [diff] [blame] | 42 | struct cpufreqdata freqs[MAX_CPUS][MAX_PSTATES]; |
| 43 | struct cpufreqdata oldfreqs[MAX_CPUS][MAX_PSTATES]; |
Arjan van der Ven | 329bb7a | 2007-06-17 06:27:18 +0000 | [diff] [blame] | 44 | |
Patrick Cain | d2a9a4c | 2014-08-20 12:35:29 -0700 | [diff] [blame] | 45 | struct cpufreqdata delta[MAX_CPUS][MAX_PSTATES]; |
Arjan van der Ven | 329bb7a | 2007-06-17 06:27:18 +0000 | [diff] [blame] | 46 | |
Patrick Cain | d2a9a4c | 2014-08-20 12:35:29 -0700 | [diff] [blame] | 47 | char cpufreqstrings[25][256]; |
Arjan van der Ven | 329bb7a | 2007-06-17 06:27:18 +0000 | [diff] [blame] | 48 | int topfreq = -1; |
| 49 | |
| 50 | static void zap(void) |
| 51 | { |
| 52 | memset(freqs, 0, sizeof(freqs)); |
| 53 | } |
| 54 | |
| 55 | int 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 | |
| 61 | int 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 | |
| 67 | static 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 Ven | a62cf92 | 2007-06-17 16:07:49 +0000 | [diff] [blame] | 82 | sprintf(buffer, _("%6.2f Ghz"), (Hz+5000.0)/1000000); |
Arjan van der Ven | 329bb7a | 2007-06-17 06:27:18 +0000 | [diff] [blame] | 83 | |
| 84 | |
| 85 | return buffer; |
| 86 | } |
| 87 | |
| 88 | |
| 89 | void 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 Cain | d2a9a4c | 2014-08-20 12:35:29 -0700 | [diff] [blame] | 97 | int cpu = -1; |
| 98 | int ret, cpucount; |
Arjan van der Ven | 329bb7a | 2007-06-17 06:27:18 +0000 | [diff] [blame] | 99 | int maxfreq = 0; |
Patrick Cain | d2a9a4c | 2014-08-20 12:35:29 -0700 | [diff] [blame] | 100 | uint64_t total_time[MAX_CPUS] = {0}; |
Arjan van der Ven | 329bb7a | 2007-06-17 06:27:18 +0000 | [diff] [blame] | 101 | |
| 102 | memcpy(&oldfreqs, &freqs, sizeof(freqs)); |
| 103 | memset(&cpufreqstrings, 0, sizeof(cpufreqstrings)); |
Arjan van der Ven | 6fe1c57 | 2007-08-18 21:52:07 +0000 | [diff] [blame] | 104 | sprintf(cpufreqstrings[0], _("P-states (frequencies)\n")); |
Arjan van der Ven | 329bb7a | 2007-06-17 06:27:18 +0000 | [diff] [blame] | 105 | |
Patrick Cain | d2a9a4c | 2014-08-20 12:35:29 -0700 | [diff] [blame] | 106 | 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 Ven | 329bb7a | 2007-06-17 06:27:18 +0000 | [diff] [blame] | 110 | |
| 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 Cain | d2a9a4c | 2014-08-20 12:35:29 -0700 | [diff] [blame] | 124 | cpu++; |
| 125 | if ( cpu >= MAX_CPUS) |
| 126 | cpu = MAX_CPUS -1; |
Arjan van der Ven | 329bb7a | 2007-06-17 06:27:18 +0000 | [diff] [blame] | 127 | 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 Cain | d2a9a4c | 2014-08-20 12:35:29 -0700 | [diff] [blame] | 138 | if (freqs[cpu][i].frequency && freqs[cpu][i].frequency != f) { |
Arjan van der Ven | 329bb7a | 2007-06-17 06:27:18 +0000 | [diff] [blame] | 139 | zap(); |
| 140 | break; |
| 141 | } |
| 142 | |
Patrick Cain | d2a9a4c | 2014-08-20 12:35:29 -0700 | [diff] [blame] | 143 | freqs[cpu][i].frequency = f; |
| 144 | freqs[cpu][i].count += count; |
Arjan van der Ven | 329bb7a | 2007-06-17 06:27:18 +0000 | [diff] [blame] | 145 | |
| 146 | if (f && maxfreq < i) |
| 147 | maxfreq = i; |
| 148 | i++; |
Anurag Singh | f051ada | 2011-11-07 09:33:35 -0800 | [diff] [blame] | 149 | if (i>(MAX_PSTATES - 1)) |
Arjan van der Ven | 329bb7a | 2007-06-17 06:27:18 +0000 | [diff] [blame] | 150 | break; |
| 151 | } |
| 152 | fclose(file); |
| 153 | } |
| 154 | |
| 155 | closedir(dir); |
| 156 | |
Anurag Singh | f051ada | 2011-11-07 09:33:35 -0800 | [diff] [blame] | 157 | for (ret = 0; ret < MAX_PSTATES; ret++) { |
Patrick Cain | d2a9a4c | 2014-08-20 12:35:29 -0700 | [diff] [blame] | 158 | 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 Ven | 329bb7a | 2007-06-17 06:27:18 +0000 | [diff] [blame] | 165 | } |
| 166 | |
Patrick Cain | d2a9a4c | 2014-08-20 12:35:29 -0700 | [diff] [blame] | 167 | for (cpucount = 0 ; cpucount < MAX_CPUS; cpucount++) { |
| 168 | if (total_time[cpucount]) |
| 169 | break; |
| 170 | } |
| 171 | if (cpucount == MAX_CPUS) |
Arjan van der Ven | 329bb7a | 2007-06-17 06:27:18 +0000 | [diff] [blame] | 172 | return; |
| 173 | |
Arjan van der Ven | 329bb7a | 2007-06-17 06:27:18 +0000 | [diff] [blame] | 174 | topfreq = -1; |
Patrick Cain | d2a9a4c | 2014-08-20 12:35:29 -0700 | [diff] [blame] | 175 | |
vanajau | 92c9a5f | 2016-09-13 12:27:08 +0530 | [diff] [blame] | 176 | for (ret = 0 ; ret<=maxfreq && ret<=254; ret++) { |
Patrick Cain | d2a9a4c | 2014-08-20 12:35:29 -0700 | [diff] [blame] | 177 | 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 Ven | 329bb7a | 2007-06-17 06:27:18 +0000 | [diff] [blame] | 192 | } |
| 193 | |
| 194 | } |