diff options
author | Arjan van de Ven <arjan@linux.intel.com> | 2010-08-07 07:16:59 -0400 |
---|---|---|
committer | Arjan van de Ven <arjan@linux.intel.com> | 2010-08-07 07:16:59 -0400 |
commit | d8e3da347eab38ef7d9142896c06bb783a95ede0 (patch) | |
tree | db967bafa51584adc5716b949b5e85388c8fe8ee /cpu | |
parent | 75daa32ada189d653656eb247a79c796b84f14b1 (diff) | |
download | powertop-d8e3da347eab38ef7d9142896c06bb783a95ede0.tar.gz |
start doing cpu frequency work
Diffstat (limited to 'cpu')
-rw-r--r-- | cpu/abstract_cpu.cpp | 23 | ||||
-rw-r--r-- | cpu/cpu.cpp | 81 | ||||
-rw-r--r-- | cpu/cpu.h | 13 | ||||
-rw-r--r-- | cpu/cpu_core.cpp | 31 | ||||
-rw-r--r-- | cpu/cpu_linux.cpp | 103 | ||||
-rw-r--r-- | cpu/cpu_package.cpp | 31 | ||||
-rw-r--r-- | cpu/intel_cpus.cpp | 30 |
7 files changed, 302 insertions, 10 deletions
diff --git a/cpu/abstract_cpu.cpp b/cpu/abstract_cpu.cpp index 789b558..a6305d3 100644 --- a/cpu/abstract_cpu.cpp +++ b/cpu/abstract_cpu.cpp @@ -11,6 +11,10 @@ void abstract_cpu::measurement_start(void) delete cstates[i]; cstates.resize(0); + for (i = 0; i < pstates.size(); i++) + delete pstates[i]; + pstates.resize(0); + for (i = 0; i < children.size(); i++) if (children[i]) children[i]->measurement_start(); @@ -32,7 +36,7 @@ void abstract_cpu::measurement_end(void) children[i]->measurement_end(); for (i = 0; i < children.size(); i++) - if (children[i]) + if (children[i]) { for (j = 0; j < children[i]->cstates.size(); j++) { struct idle_state *state; state = children[i]->cstates[j]; @@ -42,6 +46,16 @@ void abstract_cpu::measurement_end(void) update_cstate( state->linux_name, state->human_name, state->usage_before, state->duration_before, state->before_count); finalize_cstate(state->linux_name, state->usage_after, state->duration_after, state->after_count); } + for (j = 0; j < children[i]->pstates.size(); j++) { + struct frequency *state; + state = children[i]->pstates[j]; + if (!state) + continue; + + update_pstate( state->freq, state->human_name, state->time_before, state->before_count); + finalize_pstate(state->freq, state->time_after, state->after_count); + } + } for (i = 0; i < cstates.size(); i++) { @@ -180,6 +194,7 @@ void abstract_cpu::insert_pstate(uint64_t freq, const char *human_name, uint64_t state->time_before = duration; + state->before_count = count; } void abstract_cpu::finalize_pstate(uint64_t freq, uint64_t duration, int count) @@ -198,7 +213,8 @@ void abstract_cpu::finalize_pstate(uint64_t freq, uint64_t duration, int count) cout << "Invalid P state finalize " << freq << " \n"; return; } - state->time_before = duration; + state->time_after += duration; + state->after_count += count; } @@ -219,5 +235,6 @@ void abstract_cpu::update_pstate(uint64_t freq, const char *human_name, uint64_t return; } - state->time_before = duration; + state->time_before += duration; + state->before_count += count; } diff --git a/cpu/cpu.cpp b/cpu/cpu.cpp index 42f6a18..d75abcc 100644 --- a/cpu/cpu.cpp +++ b/cpu/cpu.cpp @@ -265,3 +265,84 @@ void display_cpu_cstates(void) } +void display_cpu_pstates(void) +{ + char buffer[128]; + char linebuf[1024]; + unsigned int package, core, cpu; + int line; + class abstract_cpu *_package, * _core, * _cpu; + int ctr = 0; + + + for (package = 0; package < system_level.children.size(); package++) { + int first_pkg = 0; + _package = system_level.children[package]; + if (!_package) + continue; + + + for (core = 0; core < _package->children.size(); core++) { + _core = _package->children[core]; + if (!_core) + continue; + + for (line = LEVEL_HEADER; line < 10; line++) { + ctr = 22; + int first = 1; + linebuf[0] = 0; +// if (!_package->has_pstate_level(line)) +// continue; + + buffer[0] = 0; + if (first_pkg == 0) { + strcat(linebuf, _package->fill_pstate_name(line, buffer)); + expand_string(linebuf, 10); + strcat(linebuf, _package->fill_pstate_line(line, buffer)); + } + expand_string(linebuf, 20); + + strcat(linebuf, "| "); + + + buffer[0] = 0; + strcat(linebuf, _core->fill_pstate_name(line, buffer)); + expand_string(linebuf, ctr + 10); + strcat(linebuf, _core->fill_pstate_line(line, buffer)); + ctr += 20; + expand_string(linebuf, ctr); + + strcat(linebuf, "| "); + ctr += 2; + + for (cpu = 0; cpu < _core->children.size(); cpu++) { + _cpu = _core->children[cpu]; + if (!_cpu) + continue; + + if (first == 1) { + strcat(linebuf, _cpu->fill_pstate_name(line, buffer)); + expand_string(linebuf, ctr + 10); + first = 0; + ctr += 12; + } + buffer[0] = 0; + strcat(linebuf, _cpu->fill_pstate_line(line, buffer)); + ctr += 18; + expand_string(linebuf, ctr); + + } + strcat(linebuf, "| "); + printf("%s \n", linebuf); + } + + printf("\n"); + first_pkg++; + } + + + } + +} + + @@ -38,6 +38,9 @@ struct frequency { uint64_t time_before; uint64_t time_after; + int before_count; + int after_count; + double display_value; }; @@ -91,6 +94,9 @@ public: virtual char * fill_cstate_line(int line_nr, char *buffer); virtual char * fill_cstate_name(int line_nr, char *buffer); + virtual char * fill_pstate_line(int line_nr, char *buffer); + virtual char * fill_pstate_name(int line_nr, char *buffer); + }; class cpu_core: public abstract_cpu @@ -98,6 +104,9 @@ class cpu_core: public abstract_cpu public: virtual char * fill_cstate_line(int line_nr, char *buffer); virtual char * fill_cstate_name(int line_nr, char *buffer); + + virtual char * fill_pstate_line(int line_nr, char *buffer); + virtual char * fill_pstate_name(int line_nr, char *buffer); }; class cpu_package: public abstract_cpu @@ -105,6 +114,9 @@ class cpu_package: public abstract_cpu public: virtual char * fill_cstate_line(int line_nr, char *buffer); virtual char * fill_cstate_name(int line_nr, char *buffer); + + virtual char * fill_pstate_line(int line_nr, char *buffer); + virtual char * fill_pstate_name(int line_nr, char *buffer); }; #include "intel_cpus.h" @@ -112,6 +124,7 @@ public: extern void enumerate_cpus(void); extern void display_cpu_cstates(void); +extern void display_cpu_pstates(void); void start_cpu_measurement(void); void end_cpu_measurement(void); diff --git a/cpu/cpu_core.cpp b/cpu/cpu_core.cpp index ab6a777..d50ad73 100644 --- a/cpu/cpu_core.cpp +++ b/cpu/cpu_core.cpp @@ -37,3 +37,34 @@ char * cpu_core::fill_cstate_name(int line_nr, char *buffer) return buffer; } + + +char * cpu_core::fill_pstate_name(int line_nr, char *buffer) +{ + buffer[0] = 0; + + if (line_nr >= (int)pstates.size() || line_nr < 0) + return buffer; + + sprintf(buffer,"%s", pstates[line_nr]->human_name); + + return buffer; +} + +char * cpu_core::fill_pstate_line(int line_nr, char *buffer) +{ + buffer[0] = 0; + + if (line_nr == LEVEL_HEADER) { + sprintf(buffer," CORE"); + return buffer; + } + + if (line_nr >= (int)pstates.size() || line_nr < 0) + return buffer; + + + sprintf(buffer," %5.1f%% ", percentage(1.0* (pstates[line_nr]->time_after - pstates[line_nr]->time_before) / time_factor * 10000 / pstates[line_nr]->after_count)); + return buffer; +} + diff --git a/cpu/cpu_linux.cpp b/cpu/cpu_linux.cpp index e4b4c5d..9441953 100644 --- a/cpu/cpu_linux.cpp +++ b/cpu/cpu_linux.cpp @@ -4,6 +4,8 @@ #include "cpu.h" #include "../lib.h" +#include <stdlib.h> + #include <unistd.h> #include <stdio.h> #include <string.h> @@ -15,13 +17,15 @@ void cpu_linux::measurement_start(void) { - abstract_cpu::measurement_start(); + ifstream file; DIR *dir; struct dirent *entry; - char filename[128]; + char filename[256]; int len; + abstract_cpu::measurement_start(); + len = sprintf(filename, "/sys/devices/system/cpu/cpu%i/cpuidle", number); dir = opendir(filename); @@ -31,7 +35,6 @@ void cpu_linux::measurement_start(void) /* For each C-state, there is a stateX directory which * contains a 'usage' and a 'time' (duration) file */ while ((entry = readdir(dir))) { - ifstream file; char linux_name[64]; char human_name[64]; uint64_t usage = 0; @@ -76,6 +79,37 @@ void cpu_linux::measurement_start(void) } closedir(dir); + + sprintf(filename, "/sys/devices/system/cpu/cpu%i/cpufreq/stats/time_in_state", number); + + file.open(filename, ios::in); + + if (file) { + char line[1024]; + + while (file) { + uint64_t f,count; + char *c; + + memset(line, 0, 1024); + + file.getline(line, 1024); + + f = strtoull(line, &c, 10); + if (!c) + break; + + count = strtoull(c, NULL, 10); + + hz_to_human(f, line); + + if (f > 0) + update_pstate(f, line, count, 1); + + } + file.close(); + } + } @@ -83,7 +117,8 @@ void cpu_linux::measurement_end(void) { DIR *dir; struct dirent *entry; - char filename[128]; + char filename[256]; + ifstream file; int len; len = sprintf(filename, "/sys/devices/system/cpu/cpu%i/cpuidle", number); @@ -95,7 +130,6 @@ void cpu_linux::measurement_end(void) /* For each C-state, there is a stateX directory which * contains a 'usage' and a 'time' (duration) file */ while ((entry = readdir(dir))) { - ifstream file; char linux_name[64]; char human_name[64]; uint64_t usage = 0; @@ -130,6 +164,35 @@ void cpu_linux::measurement_end(void) } closedir(dir); + sprintf(filename, "/sys/devices/system/cpu/cpu%i/cpufreq/stats/time_in_state", number); + + file.open(filename, ios::in); + + if (file) { + char line[1024]; + + while (file) { + uint64_t f,count; + char *c; + + memset(line, 0, 1024); + + file.getline(line, 1024); + + f = strtoull(line, &c, 10); + if (!c) + break; + + count = strtoull(c, NULL, 10); + + if (f > 0) + finalize_pstate(f, count, 1); + + + } + file.close(); + } + abstract_cpu::measurement_end(); } @@ -170,3 +233,33 @@ char * cpu_linux::fill_cstate_name(int line_nr, char *buffer) return buffer; } + +char * cpu_linux::fill_pstate_name(int line_nr, char *buffer) +{ + buffer[0] = 0; + + if (line_nr >= (int)pstates.size() || line_nr < 0) + return buffer; + + sprintf(buffer,"%s", pstates[line_nr]->human_name); + + return buffer; +} + +char * cpu_linux::fill_pstate_line(int line_nr, char *buffer) +{ + buffer[0] = 0; + + if (line_nr == LEVEL_HEADER) { + sprintf(buffer," CPU %i", number); + return buffer; + } + + if (line_nr >= (int)pstates.size() || line_nr < 0) + return buffer; + + + sprintf(buffer," %5.1f%% ", percentage(1.0* (pstates[line_nr]->time_after - pstates[line_nr]->time_before) / time_factor * 10000)); + return buffer; +} + diff --git a/cpu/cpu_package.cpp b/cpu/cpu_package.cpp index 8e827f5..f9202df 100644 --- a/cpu/cpu_package.cpp +++ b/cpu/cpu_package.cpp @@ -38,3 +38,34 @@ char * cpu_package::fill_cstate_name(int line_nr, char *buffer) return buffer; } + + +char * cpu_package::fill_pstate_name(int line_nr, char *buffer) +{ + buffer[0] = 0; + + if (line_nr >= (int)pstates.size() || line_nr < 0) + return buffer; + + sprintf(buffer,"%s", pstates[line_nr]->human_name); + + return buffer; +} + +char * cpu_package::fill_pstate_line(int line_nr, char *buffer) +{ + buffer[0] = 0; + + if (line_nr == LEVEL_HEADER) { + sprintf(buffer,"Package"); + return buffer; + } + + if (line_nr >= (int)pstates.size() || line_nr < 0) + return buffer; + + + sprintf(buffer," %5.1f%% ", percentage(1.0* (pstates[line_nr]->time_after - pstates[line_nr]->time_before) / time_factor * 10000 / pstates[line_nr]->after_count)); + return buffer; +} + diff --git a/cpu/intel_cpus.cpp b/cpu/intel_cpus.cpp index 7b23d1a..fa8b3b4 100644 --- a/cpu/intel_cpus.cpp +++ b/cpu/intel_cpus.cpp @@ -41,7 +41,7 @@ void nhm_core::measurement_start(void) void nhm_core::measurement_end(void) { - unsigned int i; + unsigned int i, j; uint64_t time_delta; double ratio; @@ -84,6 +84,20 @@ void nhm_core::measurement_end(void) state->usage_delta = ratio * (state->usage_after - state->usage_before) / state->after_count; state->duration_delta = ratio * (state->duration_after - state->duration_before) / state->after_count; } + + for (i = 0; i < children.size(); i++) + if (children[i]) { + for (j = 0; j < children[i]->pstates.size(); j++) { + struct frequency *state; + state = children[i]->pstates[j]; + if (!state) + continue; + + update_pstate( state->freq, state->human_name, state->time_before, state->before_count); + finalize_pstate(state->freq, state->time_after, state->after_count); + } + } + } void nhm_package::measurement_start(void) @@ -102,7 +116,7 @@ void nhm_package::measurement_end(void) { uint64_t time_delta; double ratio; - unsigned int i; + unsigned int i, j; c3_after = get_msr(number, MSR_PKG_C3_RESIDENCY); @@ -142,6 +156,18 @@ void nhm_package::measurement_end(void) state->usage_delta = ratio * (state->usage_after - state->usage_before) / state->after_count; state->duration_delta = ratio * (state->duration_after - state->duration_before) / state->after_count; } + for (i = 0; i < children.size(); i++) + if (children[i]) { + for (j = 0; j < children[i]->pstates.size(); j++) { + struct frequency *state; + state = children[i]->pstates[j]; + if (!state) + continue; + + update_pstate( state->freq, state->human_name, state->time_before, state->before_count); + finalize_pstate(state->freq, state->time_after, state->after_count); + } + } } |