aboutsummaryrefslogtreecommitdiff
path: root/cpu
diff options
context:
space:
mode:
authorArjan van de Ven <arjan@linux.intel.com>2010-08-07 07:16:59 -0400
committerArjan van de Ven <arjan@linux.intel.com>2010-08-07 07:16:59 -0400
commitd8e3da347eab38ef7d9142896c06bb783a95ede0 (patch)
treedb967bafa51584adc5716b949b5e85388c8fe8ee /cpu
parent75daa32ada189d653656eb247a79c796b84f14b1 (diff)
downloadpowertop-d8e3da347eab38ef7d9142896c06bb783a95ede0.tar.gz
start doing cpu frequency work
Diffstat (limited to 'cpu')
-rw-r--r--cpu/abstract_cpu.cpp23
-rw-r--r--cpu/cpu.cpp81
-rw-r--r--cpu/cpu.h13
-rw-r--r--cpu/cpu_core.cpp31
-rw-r--r--cpu/cpu_linux.cpp103
-rw-r--r--cpu/cpu_package.cpp31
-rw-r--r--cpu/intel_cpus.cpp30
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++;
+ }
+
+
+ }
+
+}
+
+
diff --git a/cpu/cpu.h b/cpu/cpu.h
index ae0c18f..80c911b 100644
--- a/cpu/cpu.h
+++ b/cpu/cpu.h
@@ -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);
+ }
+ }
}