summaryrefslogtreecommitdiffstats
path: root/src/cpu
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 20:00:20 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 20:00:20 +0000
commitfcb4cb5c3d0fec0fede160d565134d553d783fb2 (patch)
tree7be42535554ca6badc1847d83ef123f4dc3c5506 /src/cpu
parentInitial commit. (diff)
downloadpowertop-upstream.tar.xz
powertop-upstream.zip
Adding upstream version 2.15.upstream/2.15upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/cpu')
-rw-r--r--src/cpu/abstract_cpu.cpp535
-rw-r--r--src/cpu/cpu.cpp1075
-rw-r--r--src/cpu/cpu.h234
-rw-r--r--src/cpu/cpu_core.cpp100
-rw-r--r--src/cpu/cpu_linux.cpp350
-rw-r--r--src/cpu/cpu_package.cpp113
-rw-r--r--src/cpu/cpu_rapl_device.cpp74
-rw-r--r--src/cpu/cpu_rapl_device.h57
-rw-r--r--src/cpu/cpudevice.cpp86
-rw-r--r--src/cpu/cpudevice.h63
-rw-r--r--src/cpu/dram_rapl_device.cpp75
-rw-r--r--src/cpu/dram_rapl_device.h57
-rw-r--r--src/cpu/intel_cpus.cpp757
-rw-r--r--src/cpu/intel_cpus.h180
-rw-r--r--src/cpu/intel_gpu.cpp122
-rw-r--r--src/cpu/rapl/rapl_interface.cpp699
-rw-r--r--src/cpu/rapl/rapl_interface.h91
17 files changed, 4668 insertions, 0 deletions
diff --git a/src/cpu/abstract_cpu.cpp b/src/cpu/abstract_cpu.cpp
new file mode 100644
index 0000000..066891d
--- /dev/null
+++ b/src/cpu/abstract_cpu.cpp
@@ -0,0 +1,535 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <iostream>
+#include <fstream>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include "cpu.h"
+#include "../lib.h"
+
+abstract_cpu::~abstract_cpu()
+{
+ unsigned int i=0;
+ for (i=0; i < cstates.size(); i++){
+ delete cstates[i];
+ }
+ cstates.clear();
+
+ for (i=0; i < pstates.size(); i++){
+ delete pstates[i];
+ }
+ pstates.clear();
+}
+
+void abstract_cpu::account_freq(uint64_t freq, uint64_t duration)
+{
+ struct frequency *state = NULL;
+ unsigned int i;
+
+ for (i = 0; i < pstates.size(); i++) {
+ if (freq == pstates[i]->freq) {
+ state = pstates[i];
+ break;
+ }
+ }
+
+
+ if (!state) {
+ state = new(std::nothrow) struct frequency;
+
+ if (!state)
+ return;
+
+ memset(state, 0, sizeof(*state));
+
+ pstates.push_back(state);
+
+ state->freq = freq;
+ hz_to_human(freq, state->human_name);
+ if (freq == 0)
+ pt_strcpy(state->human_name, _("Idle"));
+ if (is_turbo(freq, max_frequency, max_minus_one_frequency))
+ pt_strcpy(state->human_name, _("Turbo Mode"));
+
+ state->after_count = 1;
+ }
+
+
+ state->time_after += duration;
+
+
+}
+
+void abstract_cpu::freq_updated(uint64_t time)
+{
+ if(parent)
+ parent->calculate_freq(time);
+ old_idle = idle;
+}
+
+void abstract_cpu::measurement_start(void)
+{
+ unsigned int i;
+ ifstream file;
+ char filename[4096];
+
+ last_stamp = 0;
+
+ for (i = 0; i < cstates.size(); i++)
+ delete cstates[i];
+ cstates.resize(0);
+
+ for (i = 0; i < pstates.size(); i++)
+ delete pstates[i];
+ pstates.resize(0);
+
+ current_frequency = 0;
+ idle = false;
+ old_idle = true;
+
+
+ snprintf(filename, sizeof(filename), "/sys/devices/system/cpu/cpu%i/cpufreq/scaling_available_frequencies", number);
+ file.open(filename, ios::in);
+ if (file) {
+ file >> max_frequency;
+ file >> max_minus_one_frequency;
+ file.close();
+ }
+
+ for (i = 0; i < children.size(); i++)
+ if (children[i])
+ children[i]->measurement_start();
+
+ gettimeofday(&stamp_before, NULL);
+
+ last_stamp = 0;
+
+ for (i = 0; i < children.size(); i++)
+ if (children[i])
+ children[i]->wiggle();
+
+}
+
+void abstract_cpu::measurement_end(void)
+{
+ unsigned int i, j;
+
+ total_stamp = 0;
+ gettimeofday(&stamp_after, NULL);
+ for (i = 0; i < children.size(); i++)
+ if (children[i])
+ children[i]->wiggle();
+
+ time_factor = 1000000.0 * (stamp_after.tv_sec - stamp_before.tv_sec) + stamp_after.tv_usec - stamp_before.tv_usec;
+
+
+ for (i = 0; i < children.size(); i++)
+ if (children[i])
+ children[i]->measurement_end();
+
+ for (i = 0; i < children.size(); i++)
+ if (children[i]) {
+ for (j = 0; j < children[i]->cstates.size(); j++) {
+ struct idle_state *state;
+ state = children[i]->cstates[j];
+ if (!state)
+ continue;
+
+ 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++) {
+ struct idle_state *state = cstates[i];
+
+ if (state->after_count == 0)
+ continue;
+
+ if (state->after_count != state->before_count)
+ continue;
+
+ state->usage_delta = (state->usage_after - state->usage_before) / state->after_count;
+ state->duration_delta = (state->duration_after - state->duration_before) / state->after_count;
+ }
+}
+
+void abstract_cpu::insert_cstate(const char *linux_name, const char *human_name, uint64_t usage, uint64_t duration, int count, int level)
+{
+ struct idle_state *state;
+ const char *c;
+
+ state = new(std::nothrow) struct idle_state;
+
+ if (!state)
+ return;
+
+ memset(state, 0, sizeof(*state));
+
+ cstates.push_back(state);
+
+ pt_strcpy(state->linux_name, linux_name);
+ pt_strcpy(state->human_name, human_name);
+
+ state->line_level = -1;
+
+ c = human_name;
+ while (*c) {
+ if (strcmp(linux_name, "active")==0) {
+ state->line_level = LEVEL_C0;
+ break;
+ }
+ if (*c >= '0' && *c <='9') {
+ state->line_level = strtoull(c, NULL, 10);
+ if(*(c+1) != '-'){
+ int greater_line_level = strtoull(c, NULL, 10);
+ for(unsigned int pos = 0; pos < cstates.size(); pos++){
+ if(*c == cstates[pos]->human_name[1]){
+ if(*(c+1) != cstates[pos]->human_name[2]){
+ greater_line_level = max(greater_line_level, cstates[pos]->line_level);
+ state->line_level = greater_line_level + 1;
+ }
+ }
+ }
+ }
+ break;
+ }
+ c++;
+ }
+
+ /* some architectures (ARM) don't have good numbers in their human name.. fall back to the linux name for those */
+ c = linux_name;
+ while (*c && state->line_level < 0) {
+ if (*c >= '0' && *c <='9') {
+ state->line_level = strtoull(c, NULL, 10);
+ break;
+ }
+ c++;
+ }
+
+ if (level >= 0)
+ state->line_level = level;
+
+ state->usage_before = usage;
+ state->duration_before = duration;
+ state->before_count = count;
+}
+
+void abstract_cpu::finalize_cstate(const char *linux_name, uint64_t usage, uint64_t duration, int count)
+{
+ unsigned int i;
+ struct idle_state *state = NULL;
+
+ for (i = 0; i < cstates.size(); i++) {
+ if (strcmp(linux_name, cstates[i]->linux_name) == 0) {
+ state = cstates[i];
+ break;
+ }
+ }
+
+ if (!state) {
+ cout << "Invalid C state finalize " << linux_name << " \n";
+ return;
+ }
+
+ state->usage_after += usage;
+ state->duration_after += duration;
+ state->after_count += count;
+}
+
+void abstract_cpu::update_cstate(const char *linux_name, const char *human_name, uint64_t usage, uint64_t duration, int count, int level)
+{
+ unsigned int i;
+ struct idle_state *state = NULL;
+
+ for (i = 0; i < cstates.size(); i++) {
+ if (strcmp(linux_name, cstates[i]->linux_name) == 0) {
+ state = cstates[i];
+ break;
+ }
+ }
+
+ if (!state) {
+ insert_cstate(linux_name, human_name, usage, duration, count, level);
+ return;
+ }
+
+ state->usage_before += usage;
+ state->duration_before += duration;
+ state->before_count += count;
+
+}
+
+int abstract_cpu::has_cstate_level(int level)
+{
+ unsigned int i;
+
+ if (level == LEVEL_HEADER)
+ return 1;
+
+ for (i = 0; i < cstates.size(); i++)
+ if (cstates[i]->line_level == level)
+ return 1;
+
+ for (i = 0; i < children.size(); i++)
+ if (children[i])
+ if (children[i]->has_cstate_level(level))
+ return 1;
+ return 0;
+}
+
+int abstract_cpu::has_pstate_level(int level)
+{
+ unsigned int i;
+
+ if (level == LEVEL_HEADER)
+ return 1;
+
+ if (level >= 0 && level < (int)pstates.size())
+ return 1;
+
+ for (i = 0; i < children.size(); i++)
+ if (children[i])
+ if (children[i]->has_pstate_level(level))
+ return 1;
+ return 0;
+}
+
+
+
+void abstract_cpu::insert_pstate(uint64_t freq, const char *human_name, uint64_t duration, int count)
+{
+ struct frequency *state;
+
+ state = new(std::nothrow) struct frequency;
+
+ if (!state)
+ return;
+
+ memset(state, 0, sizeof(*state));
+
+ pstates.push_back(state);
+
+ state->freq = freq;
+ pt_strcpy(state->human_name, human_name);
+
+
+ state->time_before = duration;
+ state->before_count = count;
+}
+
+void abstract_cpu::finalize_pstate(uint64_t freq, uint64_t duration, int count)
+{
+ unsigned int i;
+ struct frequency *state = NULL;
+
+ for (i = 0; i < pstates.size(); i++) {
+ if (freq == pstates[i]->freq) {
+ state = pstates[i];
+ break;
+ }
+ }
+
+ if (!state) {
+ cout << "Invalid P state finalize " << freq << " \n";
+ return;
+ }
+ state->time_after += duration;
+ state->after_count += count;
+
+}
+
+void abstract_cpu::update_pstate(uint64_t freq, const char *human_name, uint64_t duration, int count)
+{
+ unsigned int i;
+ struct frequency *state = NULL;
+
+ for (i = 0; i < pstates.size(); i++) {
+ if (freq == pstates[i]->freq) {
+ state = pstates[i];
+ break;
+ }
+ }
+
+ if (!state) {
+ insert_pstate(freq, human_name, duration, count);
+ return;
+ }
+
+ state->time_before += duration;
+ state->before_count += count;
+}
+
+
+void abstract_cpu::calculate_freq(uint64_t time)
+{
+ uint64_t freq = 0;
+ bool is_idle = true;
+ unsigned int i;
+
+ /* calculate the maximum frequency of all children */
+ for (i = 0; i < children.size(); i++)
+ if (children[i] && children[i]->has_pstates()) {
+ uint64_t f = 0;
+ if (!children[i]->idle) {
+ f = children[i]->current_frequency;
+ is_idle = false;
+ }
+ if (f > freq)
+ freq = f;
+ }
+
+ current_frequency = freq;
+ idle = is_idle;
+ freq_updated(time);
+}
+
+void abstract_cpu::change_effective_frequency(uint64_t time, uint64_t frequency)
+{
+ unsigned int i;
+ uint64_t time_delta, fr;
+
+ if (last_stamp)
+ time_delta = time - last_stamp;
+ else
+ time_delta = 1;
+
+ fr = effective_frequency;
+ if (old_idle)
+ fr = 0;
+
+ account_freq(fr, time_delta);
+
+ effective_frequency = frequency;
+ last_stamp = time;
+
+ /* propagate to all children */
+ for (i = 0; i < children.size(); i++)
+ if (children[i]) {
+ children[i]->change_effective_frequency(time, frequency);
+ }
+}
+
+
+void abstract_cpu::wiggle(void)
+{
+ char filename[PATH_MAX];
+ ifstream ifile;
+ ofstream ofile;
+ uint64_t minf,maxf;
+ uint64_t setspeed = 0;
+
+ /* wiggle a CPU so that we have a record of it at the start and end of the perf trace */
+
+ snprintf(filename, sizeof(filename), "/sys/devices/system/cpu/cpu%i/cpufreq/scaling_max_freq", first_cpu);
+ ifile.open(filename, ios::in);
+ ifile >> maxf;
+ ifile.close();
+
+ snprintf(filename, sizeof(filename), "/sys/devices/system/cpu/cpu%i/cpufreq/scaling_min_freq", first_cpu);
+ ifile.open(filename, ios::in);
+ ifile >> minf;
+ ifile.close();
+
+ /* In case of the userspace governor, remember the old setspeed setting, it will be affected by wiggle */
+ snprintf(filename, sizeof(filename), "/sys/devices/system/cpu/cpu%i/cpufreq/scaling_setspeed", first_cpu);
+ ifile.open(filename, ios::in);
+ /* Note that non-userspace governors report "<unsupported>". In that case ifile will fail and setspeed remains 0 */
+ ifile >> setspeed;
+ ifile.close();
+
+ ofile.open(filename, ios::out);
+ ofile << maxf;
+ ofile.close();
+ ofile.open(filename, ios::out);
+ ofile << minf;
+ ofile.close();
+ snprintf(filename, sizeof(filename), "/sys/devices/system/cpu/cpu%i/cpufreq/scaling_max_freq", first_cpu);
+ ofile.open(filename, ios::out);
+ ofile << minf;
+ ofile.close();
+ ofile.open(filename, ios::out);
+ ofile << maxf;
+ ofile.close();
+
+ if (setspeed != 0) {
+ snprintf(filename, sizeof(filename), "/sys/devices/system/cpu/cpu%i/cpufreq/scaling_setspeed", first_cpu);
+ ofile.open(filename, ios::out);
+ ofile << setspeed;
+ ofile.close();
+ }
+}
+uint64_t abstract_cpu::total_pstate_time(void)
+{
+ unsigned int i;
+ uint64_t stamp = 0;
+
+ for (i = 0; i < pstates.size(); i++)
+ stamp += pstates[i]->time_after;
+
+ return stamp;
+}
+
+
+void abstract_cpu::validate(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < children.size(); i++) {
+ if (children[i])
+ children[i]->validate();
+ }
+}
+
+void abstract_cpu::reset_pstate_data(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < pstates.size(); i++) {
+ pstates[i]->time_before = 0;
+ pstates[i]->time_after = 0;
+ }
+ for (i = 0; i < cstates.size(); i++) {
+ cstates[i]->duration_before = 0;
+ cstates[i]->duration_after = 0;
+ cstates[i]->before_count = 0;
+ cstates[i]->after_count = 0;
+ }
+
+ for (i = 0; i < children.size(); i++)
+ if (children[i])
+ children[i]->reset_pstate_data();
+}
diff --git a/src/cpu/cpu.cpp b/src/cpu/cpu.cpp
new file mode 100644
index 0000000..1c12765
--- /dev/null
+++ b/src/cpu/cpu.cpp
@@ -0,0 +1,1075 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <iostream>
+#include <fstream>
+#include <vector>
+#include <string.h>
+#include <stdlib.h>
+#include <ncurses.h>
+#include <unistd.h>
+#include "cpu.h"
+#include "cpudevice.h"
+#include "cpu_rapl_device.h"
+#include "dram_rapl_device.h"
+#include "intel_cpus.h"
+#include "../parameters/parameters.h"
+
+#include "../perf/perf_bundle.h"
+#include "../lib.h"
+#include "../display.h"
+#include "../report/report.h"
+#include "../report/report-maker.h"
+#include "../report/report-data-html.h"
+
+static class abstract_cpu system_level;
+
+vector<class abstract_cpu *> all_cpus;
+
+static class perf_bundle * perf_events;
+
+
+
+class perf_power_bundle: public perf_bundle
+{
+ virtual void handle_trace_point(void *trace, int cpu, uint64_t time);
+
+};
+
+
+static class abstract_cpu * new_package(int package, int cpu, char * vendor, int family, int model)
+{
+ class abstract_cpu *ret = NULL;
+ class cpudevice *cpudev;
+ class cpu_rapl_device *cpu_rapl_dev;
+ class dram_rapl_device *dram_rapl_dev;
+
+ char packagename[128];
+ if (strcmp(vendor, "GenuineIntel") == 0)
+ if (family == 6)
+ if (is_supported_intel_cpu(model, cpu)) {
+ ret = new class nhm_package(model);
+ ret->set_intel_MSR(true);
+ }
+
+ if (!ret) {
+ ret = new class cpu_package;
+ ret->set_intel_MSR(false);
+ }
+
+ ret->set_number(package, cpu);
+ ret->set_type("Package");
+ ret->childcount = 0;
+
+ snprintf(packagename, sizeof(packagename), _("cpu package %i"), cpu);
+ cpudev = new class cpudevice(_("cpu package"), packagename, ret);
+ all_devices.push_back(cpudev);
+
+ snprintf(packagename, sizeof(packagename), _("package-%i"), cpu);
+ cpu_rapl_dev = new class cpu_rapl_device(cpudev, _("cpu rapl package"), packagename, ret);
+ if (cpu_rapl_dev->device_present())
+ all_devices.push_back(cpu_rapl_dev);
+ else
+ delete cpu_rapl_dev;
+
+ snprintf(packagename, sizeof(packagename), _("package-%i"), cpu);
+ dram_rapl_dev = new class dram_rapl_device(cpudev, _("dram rapl package"), packagename, ret);
+ if (dram_rapl_dev->device_present())
+ all_devices.push_back(dram_rapl_dev);
+ else
+ delete dram_rapl_dev;
+
+ return ret;
+}
+
+static class abstract_cpu * new_core(int core, int cpu, char * vendor, int family, int model)
+{
+ class abstract_cpu *ret = NULL;
+
+ if (strcmp(vendor, "GenuineIntel") == 0)
+ if (family == 6)
+ if (is_supported_intel_cpu(model, cpu)) {
+ ret = new class nhm_core(model);
+ ret->set_intel_MSR(true);
+ }
+
+ if (!ret) {
+ ret = new class cpu_core;
+ ret->set_intel_MSR(false);
+ }
+
+ ret->set_number(core, cpu);
+ ret->childcount = 0;
+ ret->set_type("Core");
+
+ return ret;
+}
+
+static class abstract_cpu * new_i965_gpu(void)
+{
+ class abstract_cpu *ret = NULL;
+
+ ret = new class i965_core;
+ ret->childcount = 0;
+ ret->set_type("GPU");
+
+ return ret;
+}
+
+static class abstract_cpu * new_cpu(int number, char * vendor, int family, int model)
+{
+ class abstract_cpu * ret = NULL;
+
+ if (strcmp(vendor, "GenuineIntel") == 0)
+ if (family == 6)
+ if (is_supported_intel_cpu(model, number)) {
+ ret = new class nhm_cpu;
+ ret->set_intel_MSR(true);
+ }
+
+ if (!ret) {
+ ret = new class cpu_linux;
+ ret->set_intel_MSR(false);
+ }
+ ret->set_number(number, number);
+ ret->set_type("CPU");
+ ret->childcount = 0;
+
+ return ret;
+}
+
+
+
+
+static void handle_one_cpu(unsigned int number, char *vendor, int family, int model)
+{
+ char filename[PATH_MAX];
+ ifstream file;
+ unsigned int package_number = 0;
+ unsigned int core_number = 0;
+ class abstract_cpu *package, *core, *cpu;
+
+ snprintf(filename, sizeof(filename), "/sys/devices/system/cpu/cpu%i/topology/core_id", number);
+ file.open(filename, ios::in);
+ if (file) {
+ file >> core_number;
+ file.close();
+ }
+
+ snprintf(filename, sizeof(filename), "/sys/devices/system/cpu/cpu%i/topology/physical_package_id", number);
+ file.open(filename, ios::in);
+ if (file) {
+ file >> package_number;
+ if (package_number == (unsigned int) -1)
+ package_number = 0;
+ file.close();
+ }
+
+
+ if (system_level.children.size() <= package_number)
+ system_level.children.resize(package_number + 1, NULL);
+
+ if (!system_level.children[package_number]) {
+ system_level.children[package_number] = new_package(package_number, number, vendor, family, model);
+ system_level.childcount++;
+ }
+
+ package = system_level.children[package_number];
+ package->parent = &system_level;
+
+ if (package->children.size() <= core_number)
+ package->children.resize(core_number + 1, NULL);
+
+ if (!package->children[core_number]) {
+ package->children[core_number] = new_core(core_number, number, vendor, family, model);
+ package->childcount++;
+ }
+
+ core = package->children[core_number];
+ core->parent = package;
+
+ if (core->children.size() <= number)
+ core->children.resize(number + 1, NULL);
+ if (!core->children[number]) {
+ core->children[number] = new_cpu(number, vendor, family, model);
+ core->childcount++;
+ }
+
+ cpu = core->children[number];
+ cpu->parent = core;
+
+ if (number >= all_cpus.size())
+ all_cpus.resize(number + 1, NULL);
+ all_cpus[number] = cpu;
+}
+
+static void handle_i965_gpu(void)
+{
+ unsigned int core_number = 0;
+ class abstract_cpu *package;
+
+
+ package = system_level.children[0];
+
+ core_number = package->children.size();
+
+ if (package->children.size() <= core_number)
+ package->children.resize(core_number + 1, NULL);
+
+ if (!package->children[core_number]) {
+ package->children[core_number] = new_i965_gpu();
+ package->childcount++;
+ }
+}
+
+
+void enumerate_cpus(void)
+{
+ ifstream file;
+ char line[4096];
+
+ int number = -1;
+ char vendor[128];
+ int family = 0;
+ int model = 0;
+
+ file.open("/proc/cpuinfo", ios::in);
+
+ if (!file)
+ return;
+ /* Not all /proc/cpuinfo include "vendor_id\t". */
+ vendor[0] = '\0';
+
+ while (file) {
+
+ file.getline(line, sizeof(line));
+ if (strncmp(line, "vendor_id\t",10) == 0) {
+ char *c;
+ c = strchr(line, ':');
+ if (c) {
+ c++;
+ if (*c == ' ')
+ c++;
+ pt_strcpy(vendor, c);
+ }
+ }
+ if (strncmp(line, "processor\t",10) == 0) {
+ char *c;
+ c = strchr(line, ':');
+ if (c) {
+ c++;
+ number = strtoull(c, NULL, 10);
+ }
+ }
+ if (strncmp(line, "cpu family\t",11) == 0) {
+ char *c;
+ c = strchr(line, ':');
+ if (c) {
+ c++;
+ family = strtoull(c, NULL, 10);
+ }
+ }
+ if (strncmp(line, "model\t",6) == 0) {
+ char *c;
+ c = strchr(line, ':');
+ if (c) {
+ c++;
+ model = strtoull(c, NULL, 10);
+ }
+ }
+ /* on x86 and others 'bogomips' is last
+ * on ARM it *can* be bogomips, or 'CPU revision'
+ * on POWER, it's revision
+ */
+ if (strncasecmp(line, "bogomips\t", 9) == 0
+ || strncasecmp(line, "CPU revision\t", 13) == 0
+ || strncmp(line, "revision", 8) == 0) {
+ if (number == -1) {
+ /* Not all /proc/cpuinfo include "processor\t". */
+ number = 0;
+ }
+ if (number >= 0) {
+ handle_one_cpu(number, vendor, family, model);
+ set_max_cpu(number);
+ number = -2;
+ }
+ }
+ }
+
+
+ file.close();
+
+ if (access("/sys/class/drm/card0/power/rc6_residency_ms", R_OK) == 0)
+ handle_i965_gpu();
+
+ perf_events = new perf_power_bundle();
+
+ if (!perf_events->add_event("power:cpu_idle")){
+ perf_events->add_event("power:power_start");
+ perf_events->add_event("power:power_end");
+ }
+ if (!perf_events->add_event("power:cpu_frequency"))
+ perf_events->add_event("power:power_frequency");
+
+}
+
+void start_cpu_measurement(void)
+{
+ perf_events->start();
+ system_level.measurement_start();
+}
+
+void end_cpu_measurement(void)
+{
+ system_level.measurement_end();
+ perf_events->stop();
+}
+
+static void expand_string(char *string, unsigned int newlen)
+{
+ while (strlen(string) < newlen)
+ strcat(string, " ");
+}
+
+static int has_state_level(class abstract_cpu *acpu, int state, int line)
+{
+ switch (state) {
+ case PSTATE:
+ return acpu->has_pstate_level(line);
+ break;
+ case CSTATE:
+ return acpu->has_cstate_level(line);
+ break;
+ }
+ return 0;
+}
+
+static const char * fill_state_name(class abstract_cpu *acpu, int state, int line, char *buf)
+{
+ switch (state) {
+ case PSTATE:
+ return acpu->fill_pstate_name(line, buf);
+ break;
+ case CSTATE:
+ return acpu->fill_cstate_name(line, buf);
+ break;
+ }
+ return "-EINVAL";
+}
+
+static const char * fill_state_line(class abstract_cpu *acpu, int state, int line,
+ char *buf, const char *sep = "")
+{
+ switch (state) {
+ case PSTATE:
+ return acpu->fill_pstate_line(line, buf);
+ break;
+ case CSTATE:
+ return acpu->fill_cstate_line(line, buf, sep);
+ break;
+ }
+ return "-EINVAL";
+}
+
+static int get_cstates_num(void)
+{
+ unsigned int package, core, cpu;
+ class abstract_cpu *_package, * _core, * _cpu;
+ unsigned int i;
+ int cstates_num;
+
+ for (package = 0, cstates_num = 0;
+ package < system_level.children.size(); package++) {
+ _package = system_level.children[package];
+ if (_package == NULL)
+ continue;
+
+ /* walk package cstates and get largest cstates number */
+ for (i = 0; i < _package->cstates.size(); i++)
+ cstates_num = std::max(cstates_num,
+ (_package->cstates[i])->line_level);
+
+ /*
+ * for each core in this package, walk core cstates and get
+ * largest cstates number
+ */
+ for (core = 0; core < _package->children.size(); core++) {
+ _core = _package->children[core];
+ if (_core == NULL)
+ continue;
+
+ for (i = 0; i < _core->cstates.size(); i++)
+ cstates_num = std::max(cstates_num,
+ (_core->cstates[i])->line_level);
+
+ /*
+ * for each core, walk the logical cpus in case
+ * there is are more linux cstates than hw cstates
+ */
+ for (cpu = 0; cpu < _core->children.size(); cpu++) {
+ _cpu = _core->children[cpu];
+ if (_cpu == NULL)
+ continue;
+
+ for (i = 0; i < _cpu->cstates.size(); i++)
+ cstates_num = std::max(cstates_num,
+ (_cpu->cstates[i])->line_level);
+ }
+ }
+ }
+
+ return cstates_num;
+}
+
+void report_display_cpu_cstates(void)
+{
+ char buffer[512], buffer2[512], tmp_num[50];
+ unsigned int package, core, cpu;
+ int line, cstates_num, title=0, core_num=0;
+ class abstract_cpu *_package, *_core = NULL, * _cpu;
+ const char* core_type = NULL;
+
+ cstates_num = get_cstates_num();
+ /* div attr css_class and css_id */
+ tag_attr div_attr;
+ init_div(&div_attr, "clear_block", "cpuidle");
+
+ /* Set Table attributes, rows, and cols */
+ table_attributes std_table_css;
+ table_size pkg_tbl_size;
+ table_size core_tbl_size;
+ table_size cpu_tbl_size;
+
+
+ /* Set Title attributes */
+ tag_attr title_attr;
+ init_title_attr(&title_attr);
+
+ /* Report add section */
+ report.add_div(&div_attr);
+ report.add_title(&title_attr, __("Processor Idle State Report"));
+
+ /* Set array of data in row Major order */
+ int idx1, idx2, idx3;
+ string tmp_str;
+
+ for (package = 0; package < system_level.children.size(); package++) {
+ bool first_core = true;
+ idx1=0;
+ idx2=0;
+ idx3=0;
+
+ _package = system_level.children[package];
+ if (!_package)
+ continue;
+ /* Tables for PKG, CORE, CPU */
+ pkg_tbl_size.cols=2;
+ pkg_tbl_size.rows= ((cstates_num+1)-LEVEL_HEADER)+1;
+ string *pkg_data = new string[pkg_tbl_size.cols * pkg_tbl_size.rows];
+
+ core_tbl_size.cols=2;
+ core_tbl_size.rows=(cstates_num *_package->children.size())
+ + _package->children.size();
+ string *core_data = new string[core_tbl_size.cols * core_tbl_size.rows];
+ int num_cpus=0, num_cores=0;
+
+ for (core = 0; core < _package->children.size(); core++) {
+ _core = _package->children[core];
+ if (!_core)
+ continue;
+ core_type = _core->get_type();
+ if (core_type != NULL)
+ if (strcmp(core_type, "Core") == 0 )
+ num_cores+=1;
+
+ for (cpu = 0; cpu < _core->children.size(); cpu++) {
+ _cpu = _core->children[cpu];
+ if (!_cpu)
+ continue;
+ num_cpus+=1;
+ }
+ }
+ cpu_tbl_size.cols=(2 * (num_cpus / num_cores)) + 1;
+ cpu_tbl_size.rows = ((cstates_num+1-LEVEL_HEADER) * _package->children.size())
+ + _package->children.size();
+ string *cpu_data = new string[cpu_tbl_size.cols * cpu_tbl_size.rows];
+
+ for (core = 0; core < _package->children.size(); core++) {
+ cpu_data[idx3]="&nbsp;";
+ idx3+=1;
+ _core = _package->children[core];
+
+ if (!_core)
+ continue;
+
+ /* *** PKG STARTS *** */
+ for (line = LEVEL_HEADER; line <= cstates_num; line++) {
+ bool first_cpu = true;
+ if (!_package->has_cstate_level(line))
+ continue;
+ buffer[0] = 0;
+ buffer2[0] = 0;
+ if (line == LEVEL_HEADER) {
+ if (first_core) {
+ pkg_data[idx1]=__("Package");
+ idx1+=1;
+ sprintf(tmp_num,"%d", _package->get_number());
+ pkg_data[idx1]= string(tmp_num);
+ idx1+=1;
+ }
+ } else if (first_core) {
+ tmp_str=string(_package->fill_cstate_name(line, buffer));
+ pkg_data[idx1]=(tmp_str=="" ? "&nbsp;" : tmp_str);
+ idx1+=1;
+ tmp_str=string(_package->fill_cstate_line(line, buffer2));
+ pkg_data[idx1]=(tmp_str=="" ? "&nbsp;" : tmp_str);
+ idx1+=1;
+ }
+
+ /* *** CORE STARTS *** */
+ if (!_core->can_collapse()) {
+ buffer[0] = 0;
+ buffer2[0] = 0;
+
+ /*
+ * Patch for compatibility with Ryzen processors
+ * See https://github.com/fenrus75/powertop/issues/64
+ */
+ if(idx2 >= core_tbl_size.cols * core_tbl_size.rows) break;
+
+ if (line == LEVEL_HEADER) {
+ /* Here we need to check for which core type we
+ * are using. Do not use the core type for the
+ * report.addf as it breaks an important macro use
+ * for translation decision making for the reports.
+ * */
+ core_type = _core->get_type();
+ if (core_type != NULL) {
+ if (strcmp(core_type, "Core") == 0 ) {
+ core_data[idx2]="";
+ idx2+=1;
+ snprintf(tmp_num, sizeof(tmp_num), __("Core %d"), _core->get_number());
+ core_data[idx2]=string(tmp_num);
+ idx2+=1;
+ core_num+=1;
+ } else {
+ core_data[idx2]="";
+ idx2+=1;
+ snprintf(tmp_num, sizeof(tmp_num), __("GPU %d"), _core->get_number());
+ core_data[idx2]=string(tmp_num);
+ idx2+=1;
+ }
+ }
+ } else {
+
+
+ tmp_str=string(_core->fill_cstate_name(line, buffer));
+ core_data[idx2]=(tmp_str=="" ? "&nbsp;" : tmp_str);
+ idx2+=1;
+ tmp_str=string(_core->fill_cstate_line(line, buffer2));
+ core_data[idx2]=(tmp_str=="" ? "&nbsp;" : tmp_str);
+ idx2+=1;
+ }
+ }
+ // *** CPU STARTS ***
+ for (cpu = 0; cpu < _core->children.size(); cpu++) {
+ _cpu = _core->children[cpu];
+
+ if (!_cpu)
+ continue;
+ if (line == LEVEL_HEADER) {
+ cpu_data[idx3] = __("CPU");
+ idx3+=1;
+ sprintf(tmp_num,"%d",_cpu->get_number());
+ cpu_data[idx3]=string(tmp_num);
+ idx3+=1;
+ continue;
+ }
+
+ if (first_cpu) {
+ title+=1;
+ cpu_data[idx3]=(string(_cpu->fill_cstate_name(line, buffer)));
+ idx3+=1;
+ first_cpu = false;
+ }
+
+ buffer[0] = 0;
+ tmp_str=string(_cpu->fill_cstate_percentage(line, buffer));
+ cpu_data[idx3]=(tmp_str=="" ? "&nbsp;" : tmp_str);
+ idx3+=1;
+
+ if (line != LEVEL_C0){
+ tmp_str=string(_cpu->fill_cstate_time(line, buffer));
+ cpu_data[idx3]=(tmp_str=="" ? "&nbsp;" : tmp_str);
+ idx3+=1;
+ } else {
+ cpu_data[idx3]="&nbsp;";
+ idx3+=1;
+ }
+ }
+ }
+ first_core = false;
+ }
+
+ /* Report Output */
+ if(core_num > 0)
+ title=title/core_num;
+ else if(_core && _core->children.size() > 0)
+ title=title/_core->children.size();
+
+ init_pkg_table_attr(&std_table_css, pkg_tbl_size.rows, pkg_tbl_size.cols);
+ report.add_table(pkg_data, &std_table_css);
+ if (!_core->can_collapse()){
+ init_core_table_attr(&std_table_css, title+1, core_tbl_size.rows,
+ core_tbl_size.cols);
+ report.add_table(core_data, &std_table_css);
+ }
+ init_cpu_table_attr(&std_table_css, title+1, cpu_tbl_size.rows,
+ cpu_tbl_size.cols);
+ report.add_table(cpu_data, &std_table_css);
+ delete [] pkg_data;
+ delete [] core_data;
+ delete [] cpu_data;
+ }
+ report.end_div();
+}
+
+void report_display_cpu_pstates(void)
+{
+ char buffer[512], buffer2[512], tmp_num[50];
+ unsigned int package, core, cpu;
+ int line, title=0;
+ class abstract_cpu *_package, *_core = NULL, * _cpu;
+ unsigned int i, pstates_num;
+ const char* core_type = NULL;
+
+ /* div attr css_class and css_id */
+ tag_attr div_attr;
+ init_div(&div_attr, "clear_block", "cpufreq");
+
+ /* Set Table attributes, rows, and cols */
+ table_attributes std_table_css;
+ table_size pkg_tbl_size;
+ table_size core_tbl_size;
+ table_size cpu_tbl_size;
+
+
+ /* Set Title attributes */
+ tag_attr title_attr;
+ init_title_attr(&title_attr);
+
+ /* Report add section */
+ report.add_div(&div_attr);
+ report.add_title(&title_attr, __("Processor Frequency Report"));
+
+ /* Set array of data in row Major order */
+ int idx1, idx2, idx3, num_cpus=0, num_cores=0;
+ string tmp_str;
+
+ for (i = 0, pstates_num = 0; i < all_cpus.size(); i++) {
+ if (all_cpus[i])
+ pstates_num = std::max<unsigned int>(pstates_num,
+ all_cpus[i]->pstates.size());
+ }
+
+ for (package = 0; package < system_level.children.size(); package++) {
+ bool first_core = true;
+ idx1=0;
+ idx2=0;
+ idx3=0;
+
+ _package = system_level.children[package];
+ if (!_package)
+ continue;
+
+ /* Tables for PKG, CORE, CPU */
+ pkg_tbl_size.cols=2;
+ pkg_tbl_size.rows=((pstates_num+1)-LEVEL_HEADER)+2;
+ string *pkg_data = new string[pkg_tbl_size.cols * pkg_tbl_size.rows];
+
+ core_tbl_size.cols=2;
+ core_tbl_size.rows=((pstates_num+2) *_package->children.size());
+ string *core_data = new string[core_tbl_size.cols * core_tbl_size.rows];
+
+ /* PKG */
+ num_cpus=0;
+ num_cores=0;
+ for (core = 0; core < _package->children.size(); core++) {
+ _core = _package->children[core];
+ if (!_core)
+ continue;
+
+ core_type = _core->get_type();
+ if (core_type != NULL)
+ if (strcmp(core_type, "Core") == 0 )
+ num_cores+=1;
+
+ for (cpu = 0; cpu < _core->children.size(); cpu++) {
+ _cpu = _core->children[cpu];
+ if (!_cpu)
+ continue;
+ num_cpus+=1;
+ }
+ }
+ cpu_tbl_size.cols= (num_cpus/ num_cores) + 1;
+ cpu_tbl_size.rows= (pstates_num+2) * _package->children.size()
+ + _package->children.size();
+ string *cpu_data = new string[cpu_tbl_size.cols * cpu_tbl_size.rows];
+
+ /* Core */
+ for (core = 0; core < _package->children.size(); core++) {
+ cpu_data[idx3]="&nbsp;";
+ idx3+=1;
+ _core = _package->children[core];
+ if (!_core)
+ continue;
+
+ if (!_core->has_pstates())
+ continue;
+
+ for (line = LEVEL_HEADER; line < (int)pstates_num; line++) {
+ bool first_cpu = true;
+
+ if (!_package->has_pstate_level(line))
+ continue;
+
+ buffer[0] = 0;
+ buffer2[0] = 0;
+ if (first_core) {
+ if (line == LEVEL_HEADER) {
+ pkg_data[idx1]=__("Package");
+ idx1+=1;
+ sprintf(tmp_num,"%d", _package->get_number());
+ pkg_data[idx1]= string(tmp_num);
+ idx1+=1;
+ } else {
+ tmp_str=string(_package->fill_pstate_name(line, buffer));
+ pkg_data[idx1]=(tmp_str=="" ? "&nbsp;" : tmp_str);
+ idx1+=1;
+ tmp_str=string(_package->fill_pstate_line(line, buffer2));
+ pkg_data[idx1]=(tmp_str=="" ? "&nbsp;" : tmp_str);
+ idx1+=1;
+ }
+ }
+
+
+ if (!_core->can_collapse()) {
+ buffer[0] = 0;
+ buffer2[0] = 0;
+ if (line == LEVEL_HEADER) {
+ core_data[idx2]="";
+ idx2+=1;
+ snprintf(tmp_num, sizeof(tmp_num), __("Core %d"), _core->get_number());
+ core_data[idx2]=string(tmp_num);
+ idx2+=1;
+ } else {
+ tmp_str=string(_core->fill_pstate_name(line, buffer));
+ core_data[idx2]= (tmp_str=="" ? "&nbsp;" : tmp_str);
+ idx2+=1;
+ tmp_str=string(_core->fill_pstate_line(line, buffer2));
+ core_data[idx2]= (tmp_str=="" ? "&nbsp;" : tmp_str);
+ idx2+=1;
+ }
+ }
+
+ /* CPU */
+ for (cpu = 0; cpu < _core->children.size(); cpu++) {
+ buffer[0] = 0;
+ _cpu = _core->children[cpu];
+ if (!_cpu)
+ continue;
+
+ if (line == LEVEL_HEADER) {
+ snprintf(tmp_num, sizeof(tmp_num), __("CPU %d"), _cpu->get_number());
+ cpu_data[idx3] = string(tmp_num);
+ idx3+=1;
+ continue;
+ }
+
+ if (first_cpu) {
+ tmp_str=string(_cpu->fill_pstate_name(line, buffer));
+ cpu_data[idx3]=(tmp_str=="" ? "&nbsp;" : tmp_str);
+ idx3+=1;
+ first_cpu = false;
+ }
+
+ buffer[0] = 0;
+ tmp_str=string(_cpu->fill_pstate_line(line, buffer));
+ cpu_data[idx3]=(tmp_str=="" ? "&nbsp;" : tmp_str);
+ idx3+=1;
+ }
+ }
+ first_core = false;
+ }
+ init_pkg_table_attr(&std_table_css, pkg_tbl_size.rows, pkg_tbl_size.cols);
+ report.add_table(pkg_data, &std_table_css);
+ if(_core && !_core->can_collapse()){
+ title=pstates_num+2;
+ init_core_table_attr(&std_table_css, title,
+ core_tbl_size.rows, core_tbl_size.cols);
+ report.add_table(core_data, &std_table_css);
+ } else {
+ title=pstates_num+1;
+ }
+
+ init_cpu_table_attr(&std_table_css, title,
+ cpu_tbl_size.rows, cpu_tbl_size.cols);
+ report.add_table(cpu_data, &std_table_css);
+ delete [] pkg_data;
+ delete [] core_data;
+ delete [] cpu_data;
+ }
+ report.end_div();
+}
+
+void impl_w_display_cpu_states(int state)
+{
+ WINDOW *win;
+ char buffer[128];
+ char linebuf[1024];
+ unsigned int package, core, cpu;
+ int line, loop, cstates_num, pstates_num;
+ class abstract_cpu *_package, * _core, * _cpu;
+ int ctr = 0;
+ unsigned int i;
+
+ cstates_num = get_cstates_num();
+
+ for (i = 0, pstates_num = 0; i < all_cpus.size(); i++) {
+ if (!all_cpus[i])
+ continue;
+
+ pstates_num = std::max<int>(pstates_num, all_cpus[i]->pstates.size());
+ }
+
+ if (state == PSTATE) {
+ win = get_ncurses_win("Frequency stats");
+ loop = pstates_num;
+ } else {
+ win = get_ncurses_win("Idle stats");
+ loop = cstates_num;
+ }
+
+ if (!win)
+ return;
+
+ wclear(win);
+ wmove(win, 2,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;
+ if (!_core->has_pstates() && state == PSTATE)
+ continue;
+
+ for (line = LEVEL_HEADER; line <= loop; line++) {
+ int first = 1;
+ ctr = 0;
+ linebuf[0] = 0;
+
+ if (!has_state_level(_package, state, line))
+ continue;
+
+ buffer[0] = 0;
+ if (first_pkg == 0) {
+ strcat(linebuf, fill_state_name(_package, state, line, buffer));
+ expand_string(linebuf, ctr + 10);
+ strcat(linebuf, fill_state_line(_package, state, line, buffer));
+ }
+ ctr += 20;
+ expand_string(linebuf, ctr);
+
+ strcat(linebuf, "| ");
+ ctr += strlen("| ");
+
+ if (!_core->can_collapse()) {
+ buffer[0] = 0;
+ strcat(linebuf, fill_state_name(_core, state, line, buffer));
+ expand_string(linebuf, ctr + 10);
+ strcat(linebuf, fill_state_line(_core, state, line, buffer));
+ ctr += 20;
+ expand_string(linebuf, ctr);
+
+ strcat(linebuf, "| ");
+ ctr += strlen("| ");
+ }
+
+ for (cpu = 0; cpu < _core->children.size(); cpu++) {
+ _cpu = _core->children[cpu];
+ if (!_cpu)
+ continue;
+
+ if (first == 1) {
+ strcat(linebuf, fill_state_name(_cpu, state, line, buffer));
+ expand_string(linebuf, ctr + 10);
+ first = 0;
+ ctr += 12;
+ }
+ buffer[0] = 0;
+ strcat(linebuf, fill_state_line(_cpu, state, line, buffer));
+ ctr += 10;
+ expand_string(linebuf, ctr);
+
+ }
+ strcat(linebuf, "\n");
+ wprintw(win, "%s", linebuf);
+ }
+ wprintw(win, "\n");
+ first_pkg++;
+ }
+ }
+}
+
+void w_display_cpu_pstates(void)
+{
+ impl_w_display_cpu_states(PSTATE);
+}
+
+void w_display_cpu_cstates(void)
+{
+ impl_w_display_cpu_states(CSTATE);
+}
+
+struct power_entry {
+#ifndef __i386__
+ int dummy;
+#endif
+ int64_t type;
+ int64_t value;
+} __attribute__((packed));
+
+
+void perf_power_bundle::handle_trace_point(void *trace, int cpunr, uint64_t time)
+{
+ struct event_format *event;
+ struct pevent_record rec; /* holder */
+ class abstract_cpu *cpu;
+ int type;
+
+ rec.data = trace;
+
+ type = pevent_data_type(perf_event::pevent, &rec);
+ event = pevent_find_event(perf_event::pevent, type);
+
+ if (!event)
+ return;
+
+ if (cpunr >= (int)all_cpus.size()) {
+ cout << "INVALID cpu nr in handle_trace_point\n";
+ return;
+ }
+
+ cpu = all_cpus[cpunr];
+
+#if 0
+ unsigned int i;
+ printf("Time is %llu \n", time);
+ for (i = 0; i < system_level.children.size(); i++)
+ if (system_level.children[i])
+ system_level.children[i]->validate();
+#endif
+ unsigned long long val;
+ int ret;
+ if (strcmp(event->name, "cpu_idle")==0) {
+
+ ret = pevent_get_field_val(NULL, event, "state", &rec, &val, 0);
+ if (ret < 0) {
+ fprintf(stderr, _("cpu_idle event returned no state?\n"));
+ exit(-1);
+ }
+
+ if (val == (unsigned int)-1)
+ cpu->go_unidle(time);
+ else
+ cpu->go_idle(time);
+ }
+
+ if (strcmp(event->name, "power_frequency") == 0
+ || strcmp(event->name, "cpu_frequency") == 0){
+
+ ret = pevent_get_field_val(NULL, event, "state", &rec, &val, 0);
+ if (ret < 0) {
+ fprintf(stderr, _("power or cpu_frequency event returned no state?\n"));
+ exit(-1);
+ }
+
+ cpu->change_freq(time, val);
+ }
+
+ if (strcmp(event->name, "power_start")==0)
+ cpu->go_idle(time);
+ if (strcmp(event->name, "power_end")==0)
+ cpu->go_unidle(time);
+
+#if 0
+ unsigned int i;
+ for (i = 0; i < system_level.children.size(); i++)
+ if (system_level.children[i])
+ system_level.children[i]->validate();
+#endif
+}
+
+void process_cpu_data(void)
+{
+ unsigned int i;
+ system_level.reset_pstate_data();
+
+ perf_events->process();
+
+ for (i = 0; i < system_level.children.size(); i++)
+ if (system_level.children[i])
+ system_level.children[i]->validate();
+
+}
+
+void end_cpu_data(void)
+{
+ system_level.reset_pstate_data();
+
+ perf_events->clear();
+}
+
+void clear_cpu_data(void)
+{
+ if (perf_events)
+ perf_events->release();
+ delete perf_events;
+}
+
+
+void clear_all_cpus(void)
+{
+ unsigned int i;
+ for (i = 0; i < all_cpus.size(); i++) {
+ delete all_cpus[i];
+ }
+ all_cpus.clear();
+}
diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h
new file mode 100644
index 0000000..9114764
--- /dev/null
+++ b/src/cpu/cpu.h
@@ -0,0 +1,234 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+
+#ifndef __INCLUDE_GUARD_CPUDEV_H
+#define __INCLUDE_GUARD_CPUDEV_H
+
+#include <iostream>
+#include <vector>
+#include <string>
+#include <stdint.h>
+#include <sys/time.h>
+
+using namespace std;
+
+class abstract_cpu;
+
+#define LEVEL_C0 -1
+#define LEVEL_HEADER -2
+
+#define PSTATE 1
+#define CSTATE 2
+
+struct idle_state {
+ char linux_name[16]; /* state0 etc.. cpuidle name */
+ char human_name[32];
+
+ uint64_t usage_before;
+ uint64_t usage_after;
+ uint64_t usage_delta;
+
+ uint64_t duration_before;
+ uint64_t duration_after;
+ uint64_t duration_delta;
+
+ int before_count;
+ int after_count;
+
+ int line_level;
+};
+
+struct frequency {
+ char human_name[32];
+ int line_level;
+
+ uint64_t freq;
+
+ uint64_t time_after;
+ uint64_t time_before;
+
+ int before_count;
+ int after_count;
+
+ double display_value;
+};
+
+class abstract_cpu
+{
+protected:
+ int first_cpu;
+ struct timeval stamp_before, stamp_after;
+ double time_factor;
+ uint64_t max_frequency = 0;
+ uint64_t max_minus_one_frequency = 0;
+
+ virtual void account_freq(uint64_t frequency, uint64_t duration);
+ virtual void freq_updated(uint64_t time);
+
+public:
+ uint64_t last_stamp;
+ uint64_t total_stamp;
+ int number;
+ int childcount;
+ const char* name;
+ bool idle, old_idle, has_intel_MSR;
+ uint64_t current_frequency;
+ uint64_t effective_frequency;
+
+ vector<class abstract_cpu *> children;
+ vector<struct idle_state *> cstates;
+ vector<struct frequency *> pstates;
+
+ virtual ~abstract_cpu();
+
+ class abstract_cpu *parent;
+
+
+ int get_first_cpu() { return first_cpu; }
+ void set_number(int _number, int cpu) {this->number = _number; this->first_cpu = cpu;};
+ void set_intel_MSR(bool _bool_value) {this->has_intel_MSR = _bool_value;};
+ void set_type(const char* _name) {this->name = _name;};
+ int get_number(void) { return number; };
+ const char* get_type(void) { return name; };
+
+ virtual void measurement_start(void);
+ virtual void measurement_end(void);
+
+ virtual int can_collapse(void) { return 0;};
+
+
+ /* C state related methods */
+
+ void insert_cstate(const char *linux_name, const char *human_name, uint64_t usage, uint64_t duration, int count, int level = -1);
+ void update_cstate(const char *linux_name, const char *human_name, uint64_t usage, uint64_t duration, int count, int level = -1);
+ void finalize_cstate(const char *linux_name, uint64_t usage, uint64_t duration, int count);
+
+ virtual int has_cstate_level(int level);
+
+ virtual char * fill_cstate_line(int line_nr, char *buffer, const char *separator="") { return buffer;};
+ virtual char * fill_cstate_percentage(int line_nr, char *buffer) { return buffer; };
+ virtual char * fill_cstate_time(int line_nr, char *buffer) { return buffer; };
+ virtual char * fill_cstate_name(int line_nr, char *buffer) { return buffer;};
+
+
+ /* P state related methods */
+ void insert_pstate(uint64_t freq, const char *human_name, uint64_t duration, int count);
+ void update_pstate(uint64_t freq, const char *human_name, uint64_t duration, int count);
+ void finalize_pstate(uint64_t freq, uint64_t duration, int count);
+
+
+ virtual char * fill_pstate_line(int line_nr, char *buffer) { return buffer;};
+ virtual char * fill_pstate_name(int line_nr, char *buffer) { return buffer;};
+ virtual int has_pstate_level(int level);
+ virtual int has_pstates(void) { return 1; };
+
+ /* Frequency micro accounting methods */
+ virtual void calculate_freq(uint64_t time);
+ virtual void go_idle(uint64_t time) { idle = true; freq_updated(time); }
+ virtual void go_unidle(uint64_t time) { idle = false; freq_updated(time); }
+ virtual void change_freq(uint64_t time, int freq) { current_frequency = freq; freq_updated(time); }
+
+ virtual void change_effective_frequency(uint64_t time, uint64_t freq);
+
+ virtual void wiggle(void);
+
+ virtual uint64_t total_pstate_time(void);
+
+ virtual void validate(void);
+ virtual void reset_pstate_data(void);
+};
+
+extern vector<class abstract_cpu *> all_cpus;
+
+class cpu_linux: public abstract_cpu
+{
+ void parse_pstates_start(void);
+ void parse_cstates_start(void);
+ void parse_pstates_end(void);
+ void parse_cstates_end(void);
+
+public:
+ virtual void measurement_start(void);
+ virtual void measurement_end(void);
+
+ virtual char * fill_cstate_line(int line_nr, char *buffer, const char *separator="");
+ virtual char * fill_cstate_name(int line_nr, char *buffer);
+ virtual char * fill_cstate_percentage(int line_nr, char *buffer);
+ virtual char * fill_cstate_time(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
+{
+public:
+ virtual char * fill_cstate_line(int line_nr, char *buffer, const char *separator="");
+ 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);
+
+ virtual int can_collapse(void) { return childcount == 1;};
+};
+
+class cpu_package: public abstract_cpu
+{
+protected:
+ virtual void freq_updated(uint64_t time);
+public:
+ virtual char * fill_cstate_line(int line_nr, char *buffer, const char *separator="");
+ 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);
+ virtual int can_collapse(void) { return childcount == 1;};
+};
+
+extern void enumerate_cpus(void);
+
+extern void report_display_cpu_pstates(void);
+extern void report_display_cpu_cstates(void);
+
+
+
+extern void display_cpu_cstates(const char *start= "",
+ const char *end = "",
+ const char *linestart = "",
+ const char *separator = "| ",
+ const char *lineend = "\n");
+
+extern void w_display_cpu_cstates(void);
+extern void w_display_cpu_pstates(void);
+
+
+extern void start_cpu_measurement(void);
+extern void end_cpu_measurement(void);
+extern void process_cpu_data(void);
+extern void end_cpu_data(void);
+extern void clear_cpu_data(void);
+extern void clear_all_cpus(void);
+
+#endif
diff --git a/src/cpu/cpu_core.cpp b/src/cpu/cpu_core.cpp
new file mode 100644
index 0000000..e1372f7
--- /dev/null
+++ b/src/cpu/cpu_core.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <stdio.h>
+#include "cpu.h"
+#include "../lib.h"
+
+#include "../parameters/parameters.h"
+
+char * cpu_core::fill_cstate_line(int line_nr, char *buffer, const char *separator)
+{
+ unsigned int i;
+ buffer[0] = 0;
+
+ if (line_nr == LEVEL_HEADER)
+ sprintf(buffer, this->has_intel_MSR ? _(" Core(HW)"): _(" Core(OS)"));
+
+ for (i = 0; i < cstates.size(); i++) {
+ if (cstates[i]->line_level != line_nr)
+ continue;
+ sprintf(buffer,"%5.1f%%", percentage(cstates[i]->duration_delta / time_factor));
+ }
+
+ return buffer;
+}
+
+
+char * cpu_core::fill_cstate_name(int line_nr, char *buffer)
+{
+ unsigned int i;
+ buffer[0] = 0;
+
+ for (i = 0; i < cstates.size(); i++) {
+ if (cstates[i]->line_level != line_nr)
+ continue;
+
+ sprintf(buffer,"%s", cstates[i]->human_name);
+ }
+
+ 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;
+ unsigned int i;
+
+ if (total_stamp ==0) {
+ for (i = 0; i < pstates.size(); i++)
+ total_stamp += pstates[i]->time_after;
+ if (total_stamp == 0)
+ total_stamp = 1;
+ }
+
+ 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) / total_stamp));
+ return buffer;
+}
diff --git a/src/cpu/cpu_linux.cpp b/src/cpu/cpu_linux.cpp
new file mode 100644
index 0000000..d7ce93d
--- /dev/null
+++ b/src/cpu/cpu_linux.cpp
@@ -0,0 +1,350 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <iostream>
+#include <fstream>
+
+#include "cpu.h"
+#include "../lib.h"
+
+#include <stdlib.h>
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+
+void cpu_linux::parse_cstates_start(void)
+{
+ ifstream file;
+ DIR *dir;
+ struct dirent *entry;
+ char filename[256];
+ int len;
+
+ len = snprintf(filename, sizeof(filename), "/sys/devices/system/cpu/cpu%i/cpuidle", number);
+
+ dir = opendir(filename);
+ if (!dir)
+ return;
+
+ /* For each C-state, there is a stateX directory which
+ * contains a 'usage' and a 'time' (duration) file */
+ while ((entry = readdir(dir))) {
+ char linux_name[64];
+ char human_name[64];
+ uint64_t usage = 0;
+ uint64_t duration = 0;
+
+
+ if (strlen(entry->d_name) < 3)
+ continue;
+
+ pt_strcpy(linux_name, entry->d_name);
+ pt_strcpy(human_name, linux_name);
+
+ snprintf(filename + len, sizeof(filename) - len, "/%s/name", entry->d_name);
+
+ file.open(filename, ios::in);
+ if (file) {
+ file.getline(human_name, sizeof(human_name));
+ file.close();
+ }
+
+ if (strcmp(human_name, "C0")==0)
+ pt_strcpy(human_name, _("C0 polling"));
+
+ snprintf(filename + len, sizeof(filename) - len, "/%s/usage", entry->d_name);
+ file.open(filename, ios::in);
+ if (file) {
+ file >> usage;
+ file.close();
+ } else
+ continue;
+
+ snprintf(filename + len, sizeof(filename) - len, "/%s/time", entry->d_name);
+
+ file.open(filename, ios::in);
+ if (file) {
+ file >> duration;
+ file.close();
+ }
+
+
+ update_cstate(linux_name, human_name, usage, duration, 1);
+
+ }
+ closedir(dir);
+}
+
+
+void cpu_linux::parse_pstates_start(void)
+{
+ ifstream file;
+ char filename[256];
+ unsigned int i;
+
+ last_stamp = 0;
+ for (i = 0; i < children.size(); i++)
+ if (children[i])
+ children[i]->wiggle();
+
+ snprintf(filename, sizeof(filename), "/sys/devices/system/cpu/cpu%i/cpufreq/stats/time_in_state", first_cpu);
+
+ file.open(filename, ios::in);
+
+ if (file) {
+ char line[1024];
+
+ while (file) {
+ uint64_t f;
+ file.getline(line, sizeof(line));
+ f = strtoull(line, NULL, 10);
+ account_freq(f, 0);
+ }
+ file.close();
+ }
+ account_freq(0, 0);
+}
+
+void cpu_linux::measurement_start(void)
+{
+ abstract_cpu::measurement_start();
+ parse_cstates_start();
+ parse_pstates_start();
+}
+
+void cpu_linux::parse_cstates_end(void)
+{
+ DIR *dir;
+ struct dirent *entry;
+ char filename[256];
+ ifstream file;
+ int len;
+
+ len = snprintf(filename, sizeof(filename), "/sys/devices/system/cpu/cpu%i/cpuidle", number);
+
+ dir = opendir(filename);
+ if (!dir)
+ return;
+
+ /* For each C-state, there is a stateX directory which
+ * contains a 'usage' and a 'time' (duration) file */
+ while ((entry = readdir(dir))) {
+ char linux_name[64];
+ char human_name[64];
+ uint64_t usage = 0;
+ uint64_t duration = 0;
+
+
+ if (strlen(entry->d_name) < 3)
+ continue;
+
+ pt_strcpy(linux_name, entry->d_name);
+ pt_strcpy(human_name, linux_name);
+
+
+ snprintf(filename + len, sizeof(filename) - len, "/%s/usage", entry->d_name);
+ file.open(filename, ios::in);
+ if (file) {
+ file >> usage;
+ file.close();
+ } else
+ continue;
+
+ snprintf(filename + len, sizeof(filename) - len, "/%s/time", entry->d_name);
+
+ file.open(filename, ios::in);
+ if (file) {
+ file >> duration;
+ file.close();
+ }
+
+
+ finalize_cstate(linux_name, usage, duration, 1);
+
+ }
+ closedir(dir);
+}
+
+void cpu_linux::parse_pstates_end(void)
+{
+ char filename[256];
+ ifstream file;
+
+ snprintf(filename, sizeof(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, sizeof(line));
+
+ file.getline(line, sizeof(line));
+
+ f = strtoull(line, &c, 10);
+ if (!c)
+ break;
+
+ count = strtoull(c, NULL, 10);
+
+ if (f > 0)
+ finalize_pstate(f, count, 1);
+
+
+ }
+ file.close();
+ }
+}
+
+void cpu_linux::measurement_end(void)
+{
+ parse_cstates_end();
+ parse_pstates_end();
+ abstract_cpu::measurement_end();
+}
+
+char * cpu_linux::fill_cstate_line(int line_nr, char *buffer, const char *separator)
+{
+ unsigned int i;
+ buffer[0] = 0;
+
+ if (line_nr == LEVEL_HEADER) {
+ sprintf(buffer,_(" CPU(OS) %i"), number);
+ return buffer;
+ }
+
+ for (i = 0; i < cstates.size(); i++) {
+ if (cstates[i]->line_level != line_nr)
+ continue;
+
+ if (line_nr == LEVEL_C0)
+ sprintf(buffer,"%5.1f%%", percentage(cstates[i]->duration_delta / time_factor));
+ else
+ sprintf(buffer,"%5.1f%%%s %6.1f ms",
+ percentage(cstates[i]->duration_delta / time_factor),
+ separator,
+ 1.0 * cstates[i]->duration_delta / (1 + cstates[i]->usage_delta) / 1000);
+ }
+
+ return buffer;
+}
+
+char * cpu_linux::fill_cstate_percentage(int line_nr, char *buffer)
+{
+ unsigned int i;
+ buffer[0] = 0;
+
+ for (i = 0; i < cstates.size(); i++) {
+ if (cstates[i]->line_level != line_nr)
+ continue;
+
+ sprintf(buffer,"%5.1f%%",
+ percentage(cstates[i]->duration_delta / time_factor));
+ break;
+ }
+
+ return buffer;
+}
+
+char * cpu_linux::fill_cstate_time(int line_nr, char *buffer)
+{
+ unsigned int i;
+ buffer[0] = 0;
+
+ if (line_nr == LEVEL_C0)
+ return buffer;
+
+ for (i = 0; i < cstates.size(); i++) {
+ if (cstates[i]->line_level != line_nr)
+ continue;
+
+ sprintf(buffer,"%6.1f ms",
+ 1.0 * cstates[i]->duration_delta /
+ (1 + cstates[i]->usage_delta) / 1000);
+ break;
+ }
+
+ return buffer;
+}
+
+char * cpu_linux::fill_cstate_name(int line_nr, char *buffer)
+{
+ unsigned int i;
+ buffer[0] = 0;
+
+ for (i = 0; i < cstates.size(); i++) {
+ if (cstates[i]->line_level != line_nr)
+ continue;
+
+ sprintf(buffer,"%s", cstates[i]->human_name);
+ }
+
+ 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 (total_stamp ==0) {
+ unsigned int i;
+ for (i = 0; i < pstates.size(); i++)
+ total_stamp += pstates[i]->time_after;
+ if (total_stamp == 0)
+ total_stamp = 1;
+ }
+
+ 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) / total_stamp));
+ return buffer;
+}
diff --git a/src/cpu/cpu_package.cpp b/src/cpu/cpu_package.cpp
new file mode 100644
index 0000000..926a484
--- /dev/null
+++ b/src/cpu/cpu_package.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <stdio.h>
+#include "cpu.h"
+#include "../lib.h"
+#include "../parameters/parameters.h"
+
+void cpu_package::freq_updated(uint64_t time)
+{
+ if (parent)
+ parent->calculate_freq(time);
+ /*
+ * Make the frequency changes to propagate to all cores in a package.
+ */
+ change_effective_frequency(time, current_frequency);
+ old_idle = idle;
+}
+
+char * cpu_package::fill_cstate_line(int line_nr, char *buffer, const char *separator)
+{
+ unsigned int i;
+ buffer[0] = 0;
+
+ if (line_nr == LEVEL_HEADER) {
+ sprintf(buffer, this->has_intel_MSR ? _(" Pkg(HW)"): _(" Pkg(OS)"));
+ }
+
+ for (i = 0; i < cstates.size(); i++) {
+ if (cstates[i]->line_level != line_nr)
+ continue;
+
+ sprintf(buffer,"%5.1f%%", percentage(cstates[i]->duration_delta / time_factor));
+ }
+
+ return buffer;
+}
+
+
+char * cpu_package::fill_cstate_name(int line_nr, char *buffer)
+{
+ unsigned int i;
+ buffer[0] = 0;
+
+ for (i = 0; i < cstates.size(); i++) {
+ if (cstates[i]->line_level != line_nr)
+ continue;
+
+ sprintf(buffer,"%s", cstates[i]->human_name);
+ }
+
+ 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;
+ unsigned int i;
+
+ if (total_stamp ==0) {
+ for (i = 0; i < pstates.size(); i++)
+ total_stamp += pstates[i]->time_after;
+ if (total_stamp == 0)
+ total_stamp = 1;
+ }
+
+
+ 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) / total_stamp));
+ return buffer;
+}
diff --git a/src/cpu/cpu_rapl_device.cpp b/src/cpu/cpu_rapl_device.cpp
new file mode 100644
index 0000000..357a1c8
--- /dev/null
+++ b/src/cpu/cpu_rapl_device.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ * Srinivas Pandruvada<Srinivas.Pandruvada@linux.intel.com>
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "../parameters/parameters.h"
+#include "cpu_rapl_device.h"
+
+cpu_rapl_device::cpu_rapl_device(cpudevice *parent, const char *classname, const char *dev_name, class abstract_cpu *_cpu)
+ : cpudevice(classname, dev_name, _cpu),
+ device_valid(false)
+{
+ if (_cpu)
+ rapl = new c_rapl_interface(dev_name, cpu->get_first_cpu());
+ else
+ rapl = new c_rapl_interface();
+ last_time = time(NULL);
+ if (rapl->pp0_domain_present()) {
+ device_valid = true;
+ parent->add_child(this);
+ rapl->get_pp0_energy_status(&last_energy);
+ }
+}
+
+void cpu_rapl_device::start_measurement(void)
+{
+ last_time = time(NULL);
+
+ rapl->get_pp0_energy_status(&last_energy);
+}
+
+void cpu_rapl_device::end_measurement(void)
+{
+ time_t curr_time = time(NULL);
+ double energy;
+
+ consumed_power = 0.0;
+ if ((curr_time - last_time) > 0) {
+ rapl->get_pp0_energy_status(&energy);
+ consumed_power = (energy-last_energy)/(curr_time-last_time);
+ last_energy = energy;
+ last_time = curr_time;
+ }
+}
+
+double cpu_rapl_device::power_usage(struct result_bundle *result, struct parameter_bundle *bundle)
+{
+ if (rapl->pp0_domain_present())
+ return consumed_power;
+ else
+ return 0.0;
+}
diff --git a/src/cpu/cpu_rapl_device.h b/src/cpu/cpu_rapl_device.h
new file mode 100644
index 0000000..407f2da
--- /dev/null
+++ b/src/cpu/cpu_rapl_device.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ * Srinivas Pandruvada <Srinivas.Pandruvada@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_CPU_RAPL_DEVICE_H
+#define _INCLUDE_GUARD_CPU_RAPL_DEVICE_H
+
+#include <vector>
+#include <string>
+
+using namespace std;
+
+#include <sys/time.h>
+#include "cpudevice.h"
+#include "rapl/rapl_interface.h"
+
+class cpu_rapl_device: public cpudevice {
+
+ c_rapl_interface *rapl;
+ time_t last_time;
+ double last_energy;
+ double consumed_power;
+ bool device_valid;
+
+public:
+ cpu_rapl_device(cpudevice *parent, const char *classname = "cpu_core", const char *device_name = "cpu_core", class abstract_cpu *_cpu = NULL);
+ ~cpu_rapl_device() { delete rapl; }
+ virtual const char * device_name(void) {return "CPU core";};
+ bool device_present() { return device_valid;}
+ virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle);
+ virtual void start_measurement(void);
+ virtual void end_measurement(void);
+
+};
+
+
+#endif
diff --git a/src/cpu/cpudevice.cpp b/src/cpu/cpudevice.cpp
new file mode 100644
index 0000000..4c7ca7b
--- /dev/null
+++ b/src/cpu/cpudevice.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include "cpudevice.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "../lib.h"
+#include "../parameters/parameters.h"
+
+
+cpudevice::cpudevice(const char *classname, const char *dev_name, class abstract_cpu *_cpu)
+{
+ pt_strcpy(_class, classname);
+ pt_strcpy(_cpuname, dev_name);
+ cpu = _cpu;
+ wake_index = get_param_index("cpu-wakeups");;
+ consumption_index = get_param_index("cpu-consumption");;
+ r_wake_index = get_result_index("cpu-wakeups");;
+ r_consumption_index = get_result_index("cpu-consumption");;
+}
+
+const char * cpudevice::device_name(void)
+{
+ if (child_devices.size())
+ return "CPU misc";
+ else
+ return "CPU use";
+}
+
+double cpudevice::power_usage(struct result_bundle *result, struct parameter_bundle *bundle)
+{
+ double power;
+ double factor;
+ double _utilization;
+ double child_power;
+
+ power = 0;
+ factor = get_parameter_value(wake_index, bundle);
+ _utilization = get_result_value(r_wake_index, result);
+
+ power += _utilization * factor / 10000.0;
+
+ factor = get_parameter_value(consumption_index, bundle);
+ _utilization = get_result_value(r_consumption_index, result);
+
+ power += _utilization * factor;
+
+ for (unsigned int i = 0; i < child_devices.size(); ++i) {
+ child_power = child_devices[i]->power_usage(result, bundle);
+ if ((power - child_power) > 0.0)
+ power -= child_power;
+ }
+
+ return power;
+}
+
+double cpudevice::utilization(void)
+{
+ double _utilization;
+ _utilization = get_result_value(r_consumption_index);
+
+ return _utilization * 100;
+
+}
diff --git a/src/cpu/cpudevice.h b/src/cpu/cpudevice.h
new file mode 100644
index 0000000..841a101
--- /dev/null
+++ b/src/cpu/cpudevice.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_CPUDEVICE_H
+#define _INCLUDE_GUARD_CPUDEVICE_H
+
+#include <vector>
+#include <string>
+
+using namespace std;
+
+#include "../devices/device.h"
+#include "cpu.h"
+
+class cpudevice: public device {
+protected:
+ char _class[128];
+ char _cpuname[128];
+
+ vector<string> params;
+ class abstract_cpu *cpu;
+ int wake_index;
+ int consumption_index;
+ int r_wake_index;
+ int r_consumption_index;
+
+ vector<device *>child_devices;
+
+public:
+ cpudevice(const char *classname = "cpu", const char *device_name = "cpu0", class abstract_cpu *_cpu = NULL);
+ virtual const char * class_name(void) { return _class;};
+
+ virtual const char * device_name(void);
+
+ virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle);
+ virtual bool show_in_list(void) {return false;};
+ virtual double utilization(void); /* percentage */
+ void add_child(device *dev_ptr) { child_devices.push_back(dev_ptr);}
+};
+
+
+#endif \ No newline at end of file
diff --git a/src/cpu/dram_rapl_device.cpp b/src/cpu/dram_rapl_device.cpp
new file mode 100644
index 0000000..36d47a2
--- /dev/null
+++ b/src/cpu/dram_rapl_device.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ * Srinivas Pandruvada <Srinivas.Pandruvada@linux.intel.com>
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "../parameters/parameters.h"
+#include "dram_rapl_device.h"
+
+
+dram_rapl_device::dram_rapl_device(cpudevice *parent, const char *classname, const char *dev_name, class abstract_cpu *_cpu)
+ : cpudevice(classname, dev_name, _cpu),
+ device_valid(false)
+{
+ if (_cpu)
+ rapl = new c_rapl_interface(dev_name, cpu->get_first_cpu());
+ else
+ rapl = new c_rapl_interface();
+ last_time = time(NULL);
+ if (rapl->dram_domain_present()) {
+ device_valid = true;
+ parent->add_child(this);
+ rapl->get_dram_energy_status(&last_energy);
+ }
+}
+
+void dram_rapl_device::start_measurement(void)
+{
+ last_time = time(NULL);
+
+ rapl->get_dram_energy_status(&last_energy);
+}
+
+void dram_rapl_device::end_measurement(void)
+{
+ time_t curr_time = time(NULL);
+ double energy;
+
+ consumed_power = 0.0;
+ if ((curr_time - last_time) > 0) {
+ rapl->get_dram_energy_status(&energy);
+ consumed_power = (energy-last_energy)/(curr_time-last_time);
+ last_energy = energy;
+ last_time = curr_time;
+ }
+}
+
+double dram_rapl_device::power_usage(struct result_bundle *result, struct parameter_bundle *bundle)
+{
+ if (rapl->dram_domain_present())
+ return consumed_power;
+ else
+ return 0.0;
+}
diff --git a/src/cpu/dram_rapl_device.h b/src/cpu/dram_rapl_device.h
new file mode 100644
index 0000000..dc53094
--- /dev/null
+++ b/src/cpu/dram_rapl_device.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ * Srinivas Pandruvada <Srinivas.Pandruvada@linux.intel.com>
+ */
+#ifndef _INCLUDE_GUARD_DRAM_RAPL_DEVICE_H
+#define _INCLUDE_GUARD_DRAM_RAPL_DEVICE_H
+
+#include <vector>
+#include <string>
+
+using namespace std;
+
+#include <sys/time.h>
+#include "cpudevice.h"
+#include "rapl/rapl_interface.h"
+
+class dram_rapl_device: public cpudevice {
+
+ c_rapl_interface *rapl;
+ time_t last_time;
+ double last_energy;
+ double consumed_power;
+ bool device_valid;
+
+public:
+ dram_rapl_device(cpudevice *parent, const char *classname = "dram_core", const char *device_name = "dram_core", class abstract_cpu *_cpu = NULL);
+ ~dram_rapl_device() { delete rapl; }
+ virtual const char * device_name(void) {return "DRAM";};
+ bool device_present() { return device_valid;}
+ virtual double power_usage(struct result_bundle *result, struct parameter_bundle *bundle);
+ void start_measurement(void);
+ void end_measurement(void);
+
+};
+
+
+#endif
diff --git a/src/cpu/intel_cpus.cpp b/src/cpu/intel_cpus.cpp
new file mode 100644
index 0000000..a7145d7
--- /dev/null
+++ b/src/cpu/intel_cpus.cpp
@@ -0,0 +1,757 @@
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include "intel_cpus.h"
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <limits.h>
+
+#include "../lib.h"
+#include "../parameters/parameters.h"
+#include "../display.h"
+
+static int intel_cpu_models[] = {
+ 0x1A, /* Core i7, Xeon 5500 series */
+ 0x1E, /* Core i7 and i5 Processor - Lynnfield Jasper Forest */
+ 0x1F, /* Core i7 and i5 Processor - Nehalem */
+ 0x25, /* Westmere */
+ 0x27, /* Medfield Atom */
+ 0x2A, /* SNB */
+ 0x2C, /* Westmere */
+ 0x2D, /* SNB Xeon */
+ 0x2E, /* Nehalem-EX Xeon */
+ 0x2F, /* Westmere-EX Xeon */
+ 0x37, /* BYT-M */
+ 0x3A, /* IVB */
+ 0x3C, /* HSW */
+ 0x3D, /* BDW */
+ 0x3E, /* IVB Xeon */
+ 0x3F, /* HSX */
+ 0x45, /* HSW-ULT */
+ 0x46, /* HSW-G */
+ 0x47, /* BDW-H */
+ 0x4C, /* BSW */
+ 0x4D, /* AVN */
+ 0x4F, /* BDX */
+ 0x4E, /* SKY */
+ 0x55, /* SKY-X */
+ 0x56, /* BDX-DE */
+ 0x5C, /* BXT-P */
+ 0x5E, /* SKY */
+ 0x5F, /* DNV */
+ 0x66, /* CNL-U/Y */
+ 0x6A, /* ICL_X*/
+ 0x7A, /* GLK */
+ 0x7D, /* ICL_DESKTOP */
+ 0x7E, /* ICL_MOBILE */
+ 0x8A, /* LKF */
+ 0x8C, /* TGL_MOBILE */
+ 0x8D, /* TGL_DESKTOP */
+ 0x8E, /* KBL_MOBILE */
+ 0X8F, /* SAPPHIRERAPIDS_X */
+ 0x96, /* EHL */
+ 0x97, /* ADL_DESKTOP */
+ 0x9A, /* ADL_MOBILE */
+ 0x9C, /* JSL */
+ 0x9D, /* ICL_NNPI */
+ 0x9E, /* KBL_DESKTOP */
+ 0xA5, /* CML_DESKTOP */
+ 0xA6, /* CML_MOBILE */
+ 0xA7, /* RKL_DESKTOP */
+ 0xAA, /* MTL_MOBILE */
+ 0xAC, /* MTL_DESKTOP */
+ 0xB7, /* RPL_DESKTOP */
+ 0xBA, /* RPL_P */
+ 0xBE, /* ADL_N */
+ 0xBF, /* RPL_S */
+ 0 /* last entry must be zero */
+};
+
+static int intel_pstate_driver_loaded = -1;
+
+int is_supported_intel_cpu(int model, int cpu)
+{
+ int i;
+ uint64_t msr;
+
+ for (i = 0; intel_cpu_models[i] != 0; i++)
+ if (model == intel_cpu_models[i])
+ if (cpu < 0 || read_msr(cpu, MSR_APERF, &msr) >= 0)
+ return 1;
+
+ return 0;
+}
+
+int is_intel_pstate_driver_loaded()
+{
+ const char *filename = "/sys/devices/system/cpu/cpu0/cpufreq/scaling_driver";
+ const string intel_pstate("intel_pstate");
+ char line[32] = { '\0' };
+ ifstream file;
+
+ if (intel_pstate_driver_loaded > -1)
+ return intel_pstate_driver_loaded;
+
+ file.open(filename, ios::in);
+
+ if (!file)
+ return -1;
+
+ file.getline(line, sizeof(line)-1);
+ file.close();
+
+ const string scaling_driver(line);
+ if (scaling_driver == intel_pstate) {
+ intel_pstate_driver_loaded = 1;
+ } else {
+ intel_pstate_driver_loaded = 0;
+ }
+
+ return intel_pstate_driver_loaded;
+}
+
+static uint64_t get_msr(int cpu, uint64_t offset)
+{
+ ssize_t retval;
+ uint64_t msr;
+
+ retval = read_msr(cpu, offset, &msr);
+ if (retval < 0) {
+ reset_display();
+ fprintf(stderr, _("read_msr cpu%d 0x%llx : "), cpu, (unsigned long long)offset);
+ fprintf(stderr, "%s\n", strerror(errno));
+ exit(-2);
+ }
+
+ return msr;
+}
+
+intel_util::intel_util()
+{
+ byt_ahci_support=0;
+}
+
+void intel_util::byt_has_ahci()
+{
+ dir = opendir("/sys/bus/pci/devices/0000:00:13.0");
+ if (!dir)
+ byt_ahci_support=0;
+ else {
+ byt_ahci_support=1;
+ closedir(dir);
+ }
+}
+
+int intel_util::get_byt_ahci_support()
+{
+ return byt_ahci_support;
+}
+
+nhm_core::nhm_core(int model)
+{
+ has_c7_res = 0;
+
+ switch(model) {
+ case 0x2A: /* SNB */
+ case 0x2D: /* SNB Xeon */
+ case 0x3A: /* IVB */
+ case 0x3C: /* HSW */
+ case 0x3D: /* BDW */
+ case 0x3E: /* IVB Xeon */
+ case 0x45: /* HSW-ULT */
+ case 0x4E: /* SKY */
+ case 0x55: /* SKY-X */
+ case 0x5E: /* SKY */
+ case 0x5F: /* DNV */
+ case 0x5C: /* BXT-P */
+ case 0x66: /* CNL-U/Y */
+ case 0x6A: /* ICL_X*/
+ case 0x7A: /* GLK */
+ case 0x7D: /* ICL_DESKTOP */
+ case 0x7E: /* ICL_MOBILE */
+ case 0x8A: /* LKF */
+ case 0x8C: /* TGL_MOBILE */
+ case 0x8D: /* TGL_DESKTOP */
+ case 0x8E: /* KBL_MOBILE */
+ case 0x8F: /* SAPPHIRERAPIDS_X */
+ case 0x96: /* EHL */
+ case 0x97: /* ADL_DESKTOP */
+ case 0x9A: /* ADL_MOBILE */
+ case 0x9C: /* JSL */
+ case 0x9D: /* ICL_NNPI */
+ case 0x9E: /* KBL_DESKTOP */
+ case 0xA5: /* CML_DESKTOP */
+ case 0xA6: /* CML_MOBILE */
+ case 0xA7: /* RKL_DESKTOP */
+ case 0xAA: /* MTL_MOBILE */
+ case 0xAC: /* MTL_DESKTOP */
+ case 0xB7: /* RPL_DESKTOP */
+ case 0xBA: /* RPL_P */
+ case 0xBE: /* ADL_N */
+ case 0xBF: /* RPL_S */
+ has_c7_res = 1;
+ }
+
+ has_c3_res = 1;
+ has_c1_res = 0;
+
+ switch (model) {
+ case 0x37: /* BYT-M does not support C3/C4 */
+ case 0x4C: /* BSW does not support C3 */
+ has_c3_res = 0;
+ has_c1_res = 1;
+ }
+
+}
+
+void nhm_core::measurement_start(void)
+{
+ ifstream file;
+ char filename[PATH_MAX];
+
+ /* the abstract function needs to be first since it clears all state */
+ abstract_cpu::measurement_start();
+
+ last_stamp = 0;
+
+ if (this->has_c1_res)
+ c1_before = get_msr(first_cpu, MSR_CORE_C1_RESIDENCY);
+ if (this->has_c3_res)
+ c3_before = get_msr(first_cpu, MSR_CORE_C3_RESIDENCY);
+ c6_before = get_msr(first_cpu, MSR_CORE_C6_RESIDENCY);
+ if (this->has_c7_res)
+ c7_before = get_msr(first_cpu, MSR_CORE_C7_RESIDENCY);
+ tsc_before = get_msr(first_cpu, MSR_TSC);
+
+ if (this->has_c1_res)
+ insert_cstate("core c1", "C1 (cc1)", 0, c1_before, 1);
+ if (this->has_c3_res)
+ insert_cstate("core c3", "C3 (cc3)", 0, c3_before, 1);
+ insert_cstate("core c6", "C6 (cc6)", 0, c6_before, 1);
+ if (this->has_c7_res) {
+ insert_cstate("core c7", "C7 (cc7)", 0, c7_before, 1);
+ }
+
+
+ snprintf(filename, sizeof(filename), "/sys/devices/system/cpu/cpu%i/cpufreq/stats/time_in_state", first_cpu);
+
+ file.open(filename, ios::in);
+
+ if (file) {
+ char line[1024];
+
+ while (file) {
+ uint64_t f;
+ file.getline(line, 1024);
+ f = strtoull(line, NULL, 10);
+ account_freq(f, 0);
+ }
+ file.close();
+ }
+ account_freq(0, 0);
+
+}
+
+void nhm_core::measurement_end(void)
+{
+ unsigned int i;
+ uint64_t time_delta;
+ double ratio;
+
+ if (this->has_c1_res)
+ c1_after = get_msr(first_cpu, MSR_CORE_C1_RESIDENCY);
+ if (this->has_c3_res)
+ c3_after = get_msr(first_cpu, MSR_CORE_C3_RESIDENCY);
+ c6_after = get_msr(first_cpu, MSR_CORE_C6_RESIDENCY);
+ if (this->has_c7_res)
+ c7_after = get_msr(first_cpu, MSR_CORE_C7_RESIDENCY);
+ tsc_after = get_msr(first_cpu, MSR_TSC);
+
+ if (this->has_c1_res)
+ finalize_cstate("core c1", 0, c1_after, 1);
+ if (this->has_c3_res)
+ finalize_cstate("core c3", 0, c3_after, 1);
+ finalize_cstate("core c6", 0, c6_after, 1);
+ if (this->has_c7_res)
+ finalize_cstate("core c7", 0, c7_after, 1);
+
+ gettimeofday(&stamp_after, NULL);
+
+ time_factor = 1000000.0 * (stamp_after.tv_sec - stamp_before.tv_sec) + stamp_after.tv_usec - stamp_before.tv_usec;
+
+ for (i = 0; i < children.size(); i++)
+ if (children[i]) {
+ children[i]->measurement_end();
+ children[i]->wiggle();
+ }
+
+ time_delta = 1000000 * (stamp_after.tv_sec - stamp_before.tv_sec) + stamp_after.tv_usec - stamp_before.tv_usec;
+
+ ratio = 1.0 * time_delta / (tsc_after - tsc_before);
+
+ for (i = 0; i < cstates.size(); i++) {
+ struct idle_state *state = cstates[i];
+
+ if (state->after_count == 0)
+ continue;
+
+ if (state->after_count != state->before_count)
+ continue;
+
+ 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;
+ }
+
+#if 0
+ 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);
+ }
+ }
+#endif
+ total_stamp = 0;
+}
+
+char * nhm_core::fill_pstate_line(int line_nr, char *buffer)
+{
+ const int intel_pstate = is_intel_pstate_driver_loaded();
+ buffer[0] = 0;
+ unsigned int i;
+
+ if (!intel_pstate && total_stamp ==0) {
+ for (i = 0; i < pstates.size(); i++)
+ total_stamp += pstates[i]->time_after;
+ if (total_stamp == 0)
+ total_stamp = 1;
+ }
+
+ if (line_nr == LEVEL_HEADER) {
+ sprintf(buffer,_(" Core"));
+ return buffer;
+ }
+
+ if (intel_pstate > 0 || line_nr >= (int)pstates.size() || line_nr < 0)
+ return buffer;
+
+ sprintf(buffer," %5.1f%% ", percentage(1.0* (pstates[line_nr]->time_after) / total_stamp));
+
+ return buffer;
+}
+
+nhm_package::nhm_package(int model)
+{
+ has_c8c9c10_res = 0;
+ has_c2c6_res = 0;
+ has_c7_res = 0;
+ has_c6c_res = 0;
+
+ switch(model) {
+ case 0x2A: /* SNB */
+ case 0x2D: /* SNB Xeon */
+ case 0x3A: /* IVB */
+ case 0x3C: /* HSW */
+ case 0x3D: /* BDW */
+ case 0x3E: /* IVB Xeon */
+ case 0x45: /* HSW-ULT */
+ case 0x4E: /* SKY */
+ case 0x55: /* SKY-X */
+ case 0x5C: /* BXT-P */
+ case 0x5E: /* SKY */
+ case 0x5F: /* DNV */
+ case 0x66: /* CNL-U/Y */
+ case 0x6A: /* ICL_X*/
+ case 0x7A: /* GLK */
+ case 0x7D: /* ICL_DESKTOP */
+ case 0x7E: /* ICL_MOBILE */
+ case 0x8A: /* LKF */
+ case 0x8C: /* TGL_MOBILE */
+ case 0x8D: /* TGL_DESKTOP */
+ case 0x8E: /* KBL_MOBILE */
+ case 0x8F: /* SAPPHIRERAPIDS_X */
+ case 0x96: /* EHL */
+ case 0x97: /* ADL_DESKTOP */
+ case 0X9A: /* ADL_MOBILE */
+ case 0x9C: /* JSL */
+ case 0x9D: /* ICL_NNPI */
+ case 0x9E: /* KBL_DESKTOP */
+ case 0xA5: /* CML_DESKTOP */
+ case 0xA6: /* CML_MOBILE */
+ case 0xA7: /* RKL_DESKTOP */
+ case 0xAA: /* MTL_MOBILE */
+ case 0xAC: /* MTL_DESKTOP */
+ case 0xB7: /* RPL_DESKTOP */
+ case 0xBA: /* RPL_P */
+ case 0xBE: /* ADL_N */
+ case 0xBF: /* RPL_S */
+ has_c2c6_res=1;
+ has_c7_res = 1;
+ }
+
+ has_c3_res = 1;
+
+ switch(model) {
+ /* BYT-M doesn't have C3 or C7 */
+ /* BYT-T doesn't have C3 but it has C7 */
+ case 0x37:
+ has_c2c6_res=1;
+ this->byt_has_ahci();
+ if ((this->get_byt_ahci_support()) == 0)
+ has_c7_res = 1;/*BYT-T PC7 <- S0iX*/
+ else
+ has_c7_res = 0;
+ break;
+ case 0x4C: /* BSW doesn't have C3 */
+ has_c3_res = 0;
+ has_c6c_res = 1; /* BSW only exposes package C6 */
+ break;
+ }
+
+ /*Has C8/9/10*/
+ switch(model) {
+ case 0x3D: /* BDW */
+ case 0x45: /* HSW */
+ case 0x4E: /* SKY */
+ case 0x5C: /* BXT-P */
+ case 0x5E: /* SKY */
+ case 0x5F: /* DNV */
+ case 0x66: /* CNL-U/Y */
+ case 0x7A: /* GLK */
+ case 0x7D: /* ICL_DESKTOP */
+ case 0x7E: /* ICL_MOBILE */
+ case 0x8A: /* LKF */
+ case 0x8C: /* TGL_MOBILE */
+ case 0x8D: /* TGL_DESKTOP */
+ case 0x8E: /* KBL_MOBILE */
+ case 0x96: /* EHL */
+ case 0x97: /* ADL_DESKTOP */
+ case 0x9A: /* ADL_MOBILE */
+ case 0x9C: /* JSL */
+ case 0x9D: /* ICL_NNPI */
+ case 0x9E: /* KBL_DESKTOP */
+ case 0xA5: /* CML_DESKTOP */
+ case 0xA6: /* CML_MOBILE */
+ case 0xA7: /* RKL_DESKTOP */
+ case 0xAA: /* MTL_MOBILE */
+ case 0xAC: /* MTL_DESKTOP */
+ case 0xB7: /* RPL_DESKTOP */
+ case 0xBA: /* RPL_P */
+ case 0xBE: /* ADL_N */
+ case 0xBF: /* RPL_S */
+ has_c8c9c10_res = 1;
+ break;
+ }
+}
+
+char * nhm_package::fill_pstate_line(int line_nr, char *buffer)
+{
+ const int intel_pstate = is_intel_pstate_driver_loaded();
+ buffer[0] = 0;
+ unsigned int i;
+
+ if (!intel_pstate && total_stamp ==0) {
+ for (i = 0; i < pstates.size(); i++)
+ total_stamp += pstates[i]->time_after;
+ if (total_stamp == 0)
+ total_stamp = 1;
+ }
+
+
+ if (line_nr == LEVEL_HEADER) {
+ sprintf(buffer,_(" Package"));
+ return buffer;
+ }
+
+ if (intel_pstate > 0 || line_nr >= (int)pstates.size() || line_nr < 0)
+ return buffer;
+
+ sprintf(buffer," %5.1f%% ", percentage(1.0* (pstates[line_nr]->time_after) / total_stamp));
+
+ return buffer;
+}
+
+
+
+void nhm_package::measurement_start(void)
+{
+ abstract_cpu::measurement_start();
+
+ last_stamp = 0;
+
+ if (this->has_c2c6_res)
+ c2_before = get_msr(number, MSR_PKG_C2_RESIDENCY);
+
+ if (this->has_c3_res)
+ c3_before = get_msr(number, MSR_PKG_C3_RESIDENCY);
+
+ /*
+ * Hack for Braswell where C7 MSR is actually BSW C6
+ */
+ if (this->has_c6c_res)
+ c6_before = get_msr(number, MSR_PKG_C7_RESIDENCY);
+ else
+ c6_before = get_msr(number, MSR_PKG_C6_RESIDENCY);
+
+ if (this->has_c7_res)
+ c7_before = get_msr(number, MSR_PKG_C7_RESIDENCY);
+ if (this->has_c8c9c10_res) {
+ c8_before = get_msr(number, MSR_PKG_C8_RESIDENCY);
+ c9_before = get_msr(number, MSR_PKG_C9_RESIDENCY);
+ c10_before = get_msr(number, MSR_PKG_C10_RESIDENCY);
+ }
+ tsc_before = get_msr(first_cpu, MSR_TSC);
+
+ if (this->has_c2c6_res)
+ insert_cstate("pkg c2", "C2 (pc2)", 0, c2_before, 1);
+
+ if (this->has_c3_res)
+ insert_cstate("pkg c3", "C3 (pc3)", 0, c3_before, 1);
+ insert_cstate("pkg c6", "C6 (pc6)", 0, c6_before, 1);
+ if (this->has_c7_res)
+ insert_cstate("pkg c7", "C7 (pc7)", 0, c7_before, 1);
+ if (this->has_c8c9c10_res) {
+ insert_cstate("pkg c8", "C8 (pc8)", 0, c8_before, 1);
+ insert_cstate("pkg c9", "C9 (pc9)", 0, c9_before, 1);
+ insert_cstate("pkg c10", "C10 (pc10)", 0, c10_before, 1);
+ }
+}
+
+void nhm_package::measurement_end(void)
+{
+ uint64_t time_delta;
+ double ratio;
+ unsigned int i, j;
+
+ for (i = 0; i < children.size(); i++)
+ if (children[i])
+ children[i]->wiggle();
+
+
+ if (this->has_c2c6_res)
+ c2_after = get_msr(number, MSR_PKG_C2_RESIDENCY);
+
+ if (this->has_c3_res)
+ c3_after = get_msr(number, MSR_PKG_C3_RESIDENCY);
+
+ if (this->has_c6c_res)
+ c6_after = get_msr(number, MSR_PKG_C7_RESIDENCY);
+ else
+ c6_after = get_msr(number, MSR_PKG_C6_RESIDENCY);
+
+ if (this->has_c7_res)
+ c7_after = get_msr(number, MSR_PKG_C7_RESIDENCY);
+ if (has_c8c9c10_res) {
+ c8_after = get_msr(number, MSR_PKG_C8_RESIDENCY);
+ c9_after = get_msr(number, MSR_PKG_C9_RESIDENCY);
+ c10_after = get_msr(number, MSR_PKG_C10_RESIDENCY);
+ }
+ tsc_after = get_msr(first_cpu, MSR_TSC);
+
+ gettimeofday(&stamp_after, NULL);
+
+ time_factor = 1000000.0 * (stamp_after.tv_sec - stamp_before.tv_sec) + stamp_after.tv_usec - stamp_before.tv_usec;
+
+
+ if (this->has_c2c6_res)
+ finalize_cstate("pkg c2", 0, c2_after, 1);
+
+ if (this->has_c3_res)
+ finalize_cstate("pkg c3", 0, c3_after, 1);
+ finalize_cstate("pkg c6", 0, c6_after, 1);
+ if (this->has_c7_res)
+ finalize_cstate("pkg c7", 0, c7_after, 1);
+ if (has_c8c9c10_res) {
+ finalize_cstate("pkg c8", 0, c8_after, 1);
+ finalize_cstate("pkg c9", 0, c9_after, 1);
+ finalize_cstate("pkg c10", 0, c10_after, 1);
+ }
+
+ for (i = 0; i < children.size(); i++)
+ if (children[i])
+ children[i]->measurement_end();
+
+ time_delta = 1000000 * (stamp_after.tv_sec - stamp_before.tv_sec) + stamp_after.tv_usec - stamp_before.tv_usec;
+
+ ratio = 1.0 * time_delta / (tsc_after - tsc_before);
+
+
+ for (i = 0; i < cstates.size(); i++) {
+ struct idle_state *state = cstates[i];
+
+ if (state->after_count == 0)
+ continue;
+
+ if (state->after_count != state->before_count)
+ continue;
+
+ 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);
+ }
+ }
+ total_stamp = 0;
+
+}
+
+void nhm_cpu::measurement_start(void)
+{
+ ifstream file;
+ char filename[PATH_MAX];
+
+ cpu_linux::measurement_start();
+
+ last_stamp = 0;
+
+ aperf_before = get_msr(number, MSR_APERF);
+ mperf_before = get_msr(number, MSR_MPERF);
+ tsc_before = get_msr(number, MSR_TSC);
+
+ insert_cstate("active", _("C0 active"), 0, aperf_before, 1);
+
+ snprintf(filename, sizeof(filename), "/sys/devices/system/cpu/cpu%i/cpufreq/stats/time_in_state", first_cpu);
+
+ file.open(filename, ios::in);
+
+ if (file) {
+ char line[1024];
+
+ while (file) {
+ uint64_t f;
+ file.getline(line, sizeof(line));
+ f = strtoull(line, NULL, 10);
+ account_freq(f, 0);
+ }
+ file.close();
+ }
+ account_freq(0, 0);
+}
+
+void nhm_cpu::measurement_end(void)
+{
+ uint64_t time_delta;
+ double ratio;
+ unsigned int i;
+
+ aperf_after = get_msr(number, MSR_APERF);
+ mperf_after = get_msr(number, MSR_MPERF);
+ tsc_after = get_msr(number, MSR_TSC);
+
+
+
+ finalize_cstate("active", 0, aperf_after, 1);
+
+
+ cpu_linux::measurement_end();
+
+ time_delta = 1000000 * (stamp_after.tv_sec - stamp_before.tv_sec) + stamp_after.tv_usec - stamp_before.tv_usec;
+
+ ratio = 1.0 * time_delta / (tsc_after - tsc_before);
+
+
+ for (i = 0; i < cstates.size(); i++) {
+ struct idle_state *state = cstates[i];
+ if (state->line_level != LEVEL_C0)
+ continue;
+
+ 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;
+ }
+
+ total_stamp = 0;
+
+}
+
+char * nhm_cpu::fill_pstate_name(int line_nr, char *buffer)
+{
+ if (line_nr == LEVEL_C0) {
+ sprintf(buffer, _("Average"));
+ return buffer;
+ }
+ return cpu_linux::fill_pstate_name(line_nr, buffer);
+}
+
+char * nhm_cpu::fill_pstate_line(int line_nr, char *buffer)
+{
+ const int intel_pstate = is_intel_pstate_driver_loaded();
+
+ if (!intel_pstate && total_stamp ==0) {
+ unsigned int i;
+ for (i = 0; i < pstates.size(); i++)
+ total_stamp += pstates[i]->time_after;
+ if (total_stamp == 0)
+ total_stamp = 1;
+ }
+
+ if (line_nr == LEVEL_HEADER) {
+ sprintf(buffer,_(" CPU %i"), number);
+ return buffer;
+ }
+
+ if (line_nr == LEVEL_C0) {
+ double F;
+ F = 1.0 * (tsc_after - tsc_before) * (aperf_after - aperf_before) / (mperf_after - mperf_before) / time_factor * 1000;
+ hz_to_human(F, buffer, 1);
+ return buffer;
+ }
+ if (intel_pstate > 0 || line_nr >= (int)pstates.size() || line_nr < 0)
+ return buffer;
+
+ sprintf(buffer," %5.1f%% ", percentage(1.0* (pstates[line_nr]->time_after) / total_stamp));
+
+ return buffer;
+}
+
+
+int nhm_cpu::has_pstate_level(int level)
+{
+ if (level == LEVEL_C0)
+ return 1;
+ return cpu_linux::has_pstate_level(level);
+}
diff --git a/src/cpu/intel_cpus.h b/src/cpu/intel_cpus.h
new file mode 100644
index 0000000..79afb98
--- /dev/null
+++ b/src/cpu/intel_cpus.h
@@ -0,0 +1,180 @@
+#ifndef PowerTop_INTEL_CPUS_H_84F09FB4F519470FA914AA9B02453221
+#define PowerTop_INTEL_CPUS_H_84F09FB4F519470FA914AA9B02453221
+/*
+ * Copyright 2010, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include <stdint.h>
+#include <sys/time.h>
+#include <dirent.h>
+
+#include "cpu.h"
+
+
+#define MSR_TSC 0x10
+#define MSR_NEHALEM_PLATFORM_INFO 0xCE
+#define MSR_NEHALEM_TURBO_RATIO_LIMIT 0x1AD
+#define MSR_APERF 0xE8
+#define MSR_MPERF 0xE7
+#define MSR_PKG_C2_RESIDENCY 0x60D
+#define MSR_PKG_C3_RESIDENCY 0x3F8
+#define MSR_PKG_C6_RESIDENCY 0x3F9
+#define MSR_PKG_C7_RESIDENCY 0x3FA
+#define MSR_PKG_C8_RESIDENCY 0x630
+#define MSR_PKG_C9_RESIDENCY 0x631
+#define MSR_PKG_C10_RESIDENCY 0x632
+#define MSR_CORE_C1_RESIDENCY 0x660
+#define MSR_CORE_C3_RESIDENCY 0x3FC
+#define MSR_CORE_C6_RESIDENCY 0x3FD
+#define MSR_CORE_C7_RESIDENCY 0x3FE
+
+class intel_util
+{
+protected:
+ int byt_ahci_support;
+ DIR *dir;
+public:
+ intel_util();
+ virtual void byt_has_ahci();
+ virtual int get_byt_ahci_support();
+};
+
+class nhm_package: public cpu_package, public intel_util
+{
+private:
+ uint64_t c2_before, c2_after;
+ uint64_t c3_before, c3_after;
+ uint64_t c6_before, c6_after;
+ uint64_t c7_before, c7_after;
+ uint64_t c8_before, c8_after;
+ uint64_t c9_before, c9_after;
+ uint64_t c10_before, c10_after;
+ uint64_t tsc_before, tsc_after;
+
+ uint64_t last_stamp;
+ uint64_t total_stamp;
+public:
+ int has_c7_res;
+ int has_c2c6_res;
+ int has_c3_res;
+ int has_c6c_res; /* BSW */
+ int has_c8c9c10_res;
+ nhm_package(int model);
+ virtual void measurement_start(void);
+ virtual void measurement_end(void);
+ virtual int can_collapse(void) { return 0;};
+
+ virtual char * fill_pstate_line(int line_nr, char *buffer);
+};
+
+class nhm_core: public cpu_core, public intel_util
+{
+private:
+ uint64_t c1_before, c1_after;
+ uint64_t c3_before, c3_after;
+ uint64_t c6_before, c6_after;
+ uint64_t c7_before, c7_after;
+ uint64_t tsc_before, tsc_after;
+
+ uint64_t last_stamp;
+ uint64_t total_stamp;
+public:
+ int has_c1_res;
+ int has_c7_res;
+ int has_c3_res;
+ nhm_core(int model);
+ virtual void measurement_start(void);
+ virtual void measurement_end(void);
+ virtual int can_collapse(void) { return 0;};
+
+ virtual char * fill_pstate_line(int line_nr, char *buffer);
+};
+
+class nhm_cpu: public cpu_linux, public intel_util
+{
+private:
+ uint64_t aperf_before;
+ uint64_t aperf_after;
+ uint64_t mperf_before;
+ uint64_t mperf_after;
+ uint64_t tsc_before, tsc_after;
+
+ uint64_t last_stamp;
+ uint64_t total_stamp;
+public:
+ virtual void measurement_start(void);
+ virtual void measurement_end(void);
+ virtual int can_collapse(void) { return 0;};
+
+ virtual char * fill_pstate_name(int line_nr, char *buffer);
+ virtual char * fill_pstate_line(int line_nr, char *buffer);
+ virtual int has_pstate_level(int level);
+};
+
+class atom_package: public cpu_package
+{
+public:
+ virtual void measurement_start(void);
+ virtual void measurement_end(void);
+
+};
+
+class atom_core: public cpu_core
+{
+public:
+ virtual void measurement_start(void);
+ virtual void measurement_end(void);
+
+};
+
+
+class i965_core: public cpu_core
+{
+private:
+ uint64_t rc6_before, rc6_after;
+ uint64_t rc6p_before, rc6p_after;
+ uint64_t rc6pp_before, rc6pp_after;
+
+ struct timeval before;
+ struct timeval after;
+
+public:
+ virtual void measurement_start(void);
+ virtual void measurement_end(void);
+ virtual int can_collapse(void) { return 0;};
+
+ virtual char * fill_pstate_line(int line_nr, char *buffer);
+ virtual char * fill_pstate_name(int line_nr, char *buffer);
+ virtual char * fill_cstate_line(int line_nr, char *buffer, const char *separator);
+ virtual int has_pstate_level(int level) { return 0; };
+ virtual int has_pstates(void) { return 0; };
+ virtual void wiggle(void) { };
+
+};
+
+int is_supported_intel_cpu(int model, int cpu);
+int byt_has_ahci();
+
+int is_intel_pstate_driver_loaded();
+
+#endif
diff --git a/src/cpu/intel_gpu.cpp b/src/cpu/intel_gpu.cpp
new file mode 100644
index 0000000..e0f4ac2
--- /dev/null
+++ b/src/cpu/intel_gpu.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2012, Intel Corporation
+ *
+ * This file is part of PowerTOP
+ *
+ * This program file is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program in a file named COPYING; if not, write to the
+ * Free Software Foundation, Inc,
+ * 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ * or just google for it.
+ *
+ * Authors:
+ * Arjan van de Ven <arjan@linux.intel.com>
+ */
+#include "intel_cpus.h"
+#include <iostream>
+#include <fstream>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "../lib.h"
+#include "../parameters/parameters.h"
+#include "../display.h"
+
+void i965_core::measurement_start(void)
+{
+ ifstream file;
+
+ gettimeofday(&before, NULL);
+ rc6_before = read_sysfs("/sys/class/drm/card0/power/rc6_residency_ms", NULL);
+ rc6p_before = read_sysfs("/sys/class/drm/card0/power/rc6p_residency_ms", NULL);
+ rc6pp_before = read_sysfs("/sys/class/drm/card0/power/rc6pp_residency_ms", NULL);
+
+ update_cstate("gpu c0", "Powered On", 0, 0, 1, 0);
+ update_cstate("gpu rc6", "RC6", 0, rc6_before, 1, 1);
+ update_cstate("gpu rc6p", "RC6p", 0, rc6p_before, 1, 2);
+ update_cstate("gpu rc6pp", "RC6pp", 0, rc6pp_before, 1, 3);
+}
+
+char * i965_core::fill_cstate_line(int line_nr, char *buffer, const char *separator)
+{
+ buffer[0] = 0;
+ double ratio, d = -1.0, time_delta;
+
+ if (line_nr == LEVEL_HEADER) {
+ sprintf(buffer,_(" GPU "));
+ return buffer;
+ }
+
+ buffer[0] = 0;
+
+ time_delta = 1000000 * (after.tv_sec - before.tv_sec) + after.tv_usec - before.tv_usec;
+ ratio = 100000.0/time_delta;
+
+ switch (line_nr) {
+ case 0:
+ d = 100.0 - ratio * (rc6_after + rc6p_after + rc6pp_after - rc6_before - rc6p_before - rc6pp_before);
+ break;
+ case 1:
+ d = ratio * (rc6_after - rc6_before);
+ break;
+ case 2:
+ d = ratio * (rc6p_after - rc6p_before);
+ break;
+ case 3:
+ d = ratio * (rc6pp_after - rc6pp_before);
+ break;
+ default:
+ return buffer;
+ }
+
+ /* cope with rounding errors due to the measurement interval */
+ if (d < 0.0)
+ d = 0.0;
+ if (d > 100.0)
+ d = 100.0;
+
+ sprintf(buffer,"%5.1f%%", d);
+
+ return buffer;
+}
+
+
+void i965_core::measurement_end(void)
+{
+ gettimeofday(&after, NULL);
+
+ rc6_after = read_sysfs("/sys/class/drm/card0/power/rc6_residency_ms", NULL);
+ rc6p_after = read_sysfs("/sys/class/drm/card0/power/rc6p_residency_ms", NULL);
+ rc6pp_after = read_sysfs("/sys/class/drm/card0/power/rc6pp_residency_ms", NULL);
+}
+
+char * i965_core::fill_pstate_line(int line_nr, char *buffer)
+{
+ buffer[0] = 0;
+ return buffer;
+}
+
+char * i965_core::fill_pstate_name(int line_nr, char *buffer)
+{
+ buffer[0] = 0;
+ return buffer;
+}
+
diff --git a/src/cpu/rapl/rapl_interface.cpp b/src/cpu/rapl/rapl_interface.cpp
new file mode 100644
index 0000000..d6bd4c8
--- /dev/null
+++ b/src/cpu/rapl/rapl_interface.cpp
@@ -0,0 +1,699 @@
+/* rapl_interface.cpp: rapl interface for power top implementation
+ *
+ * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ *
+ * Author Name <Srinivas.Pandruvada@linux.intel.com>
+ *
+ */
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <math.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include "lib.h"
+#include "rapl_interface.h"
+
+#ifdef DEBUG
+#define RAPL_DBG_PRINT printf
+#define RAPL_ERROR_PRINT printf
+#else
+#define RAPL_DBG_PRINT(...) ((void) 0)
+#define RAPL_ERROR_PRINT(...) ((void) 0)
+#endif
+#define RAPL_INFO_PRINT(format, m) fprintf(stderr, format, m)
+
+#define MAX_TEMP_STR_SIZE 20
+
+// RAPL interface
+#define MSR_RAPL_POWER_UNIT 0x606
+#define MSR_PKG_POWER_LIMIT 0x610
+
+#define MSR_PKG_ENERY_STATUS 0x611
+#define MSR_PKG_POWER_INFO 0x614
+#define MSR_PKG_PERF_STATUS 0x613
+
+#define MSR_DRAM_POWER_LIMIT 0x618
+#define MSR_DRAM_ENERY_STATUS 0x619
+#define MSR_DRAM_PERF_STATUS 0x61B
+#define MSR_DRAM_POWER_INFO 0x61c
+
+#define MSR_PP0_POWER_LIMIT 0x638
+#define MSR_PP0_ENERY_STATUS 0x639
+#define MSR_PP0_POLICY 0x63A
+#define MSR_PP0_PERF_STATUS 0x63B
+
+#define MSR_PP1_POWER_LIMIT 0x640
+#define MSR_PP1_ENERY_STATUS 0x641
+#define MSR_PP1_POLICY 0x642
+
+#define PKG_DOMAIN_PRESENT 0x01
+#define DRAM_DOMAIN_PRESENT 0x02
+#define PP0_DOMAIN_PRESENT 0x04
+#define PP1_DOMAIN_PRESENT 0x08
+
+c_rapl_interface::c_rapl_interface(const char *dev_name, int cpu) :
+ powercap_sysfs_present(false),
+ powercap_core_path(),
+ powercap_uncore_path(),
+ powercap_dram_path(),
+ first_cpu(cpu),
+ measurment_interval(def_sampling_interval),
+ last_pkg_energy_status(0.0),
+ last_dram_energy_status(0.0),
+ last_pp0_energy_status(0.0),
+ last_pp1_energy_status(0.0)
+{
+ uint64_t value;
+ int ret;
+ string package_path;
+ DIR *dir;
+ struct dirent *entry;
+
+ RAPL_INFO_PRINT("RAPL device for cpu %d\n", cpu);
+
+ rapl_domains = 0;
+
+ if (dev_name) {
+ string base_path = "/sys/class/powercap/intel-rapl/";
+ if ((dir = opendir(base_path.c_str())) != NULL) {
+ while ((entry = readdir(dir)) != NULL) {
+ string path = base_path + entry->d_name + "/name";
+ string str = read_sysfs_string(path);
+ if (str.length() > 0) {
+ if (str == dev_name) {
+ package_path = base_path + entry->d_name + "/";
+ powercap_sysfs_present = true;
+ rapl_domains |= PKG_DOMAIN_PRESENT;
+ break;
+ }
+ }
+ }
+ closedir(dir);
+ }
+ }
+
+ if (powercap_sysfs_present) {
+ if ((dir = opendir(package_path.c_str())) != NULL) {
+ while ((entry = readdir(dir)) != NULL) {
+ string path = package_path + entry->d_name;
+ string str = read_sysfs_string(path + "/name");
+ if (str.length() > 0) {
+ if (str == "core") {
+ rapl_domains |= PP0_DOMAIN_PRESENT;
+ powercap_core_path = path + "/";
+ }
+ else if (str == "dram") {
+ rapl_domains |= DRAM_DOMAIN_PRESENT;
+ powercap_dram_path = path + "/";
+ }
+ else if (str == "uncore") {
+ rapl_domains |= PP1_DOMAIN_PRESENT;
+ powercap_uncore_path = path + "/";
+ }
+ }
+ }
+ closedir(dir);
+ }
+
+ RAPL_INFO_PRINT("RAPL Using PowerCap Sysfs : Domain Mask %x\n", rapl_domains);
+ return;
+ }
+
+ // Fallback to using MSRs
+
+ // presence of each domain
+ // Check presence of PKG domain
+ ret = read_msr(first_cpu, MSR_PKG_ENERY_STATUS, &value);
+ if (ret > 0) {
+ rapl_domains |= PKG_DOMAIN_PRESENT;
+ RAPL_DBG_PRINT("Domain : PKG present\n");
+ } else {
+ RAPL_DBG_PRINT("Domain : PKG Not present\n");
+ }
+
+ // Check presence of DRAM domain
+ ret = read_msr(first_cpu, MSR_DRAM_ENERY_STATUS, &value);
+ if (ret > 0) {
+ rapl_domains |= DRAM_DOMAIN_PRESENT;
+ RAPL_DBG_PRINT("Domain : DRAM present\n");
+ } else {
+ RAPL_DBG_PRINT("Domain : DRAM Not present\n");
+ }
+
+ // Check presence of PP0 domain
+ ret = read_msr(first_cpu, MSR_PP0_ENERY_STATUS, &value);
+ if (ret > 0) {
+ rapl_domains |= PP0_DOMAIN_PRESENT;
+ RAPL_DBG_PRINT("Domain : PP0 present\n");
+ } else {
+ RAPL_DBG_PRINT("Domain : PP0 Not present\n");
+ }
+
+ // Check presence of PP1 domain
+ ret = read_msr(first_cpu, MSR_PP1_ENERY_STATUS, &value);
+ if (ret > 0) {
+ rapl_domains |= PP1_DOMAIN_PRESENT;
+ RAPL_DBG_PRINT("Domain : PP1 present\n");
+ } else {
+ RAPL_DBG_PRINT("Domain : PP1 Not present\n");
+ }
+
+ power_units = get_power_unit();
+ energy_status_units = get_energy_status_unit();
+ time_units = get_time_unit();
+
+ RAPL_DBG_PRINT("RAPL Domain mask: %x\n", rapl_domains);
+}
+
+bool c_rapl_interface::pkg_domain_present()
+{
+ if ((rapl_domains & PKG_DOMAIN_PRESENT)) {
+ return true;
+ }
+
+ return false;
+}
+
+bool c_rapl_interface::dram_domain_present()
+{
+ if ((rapl_domains & DRAM_DOMAIN_PRESENT)) {
+ return true;
+ }
+
+ return false;
+}
+
+bool c_rapl_interface::pp0_domain_present()
+{
+ if ((rapl_domains & PP0_DOMAIN_PRESENT)) {
+ return true;
+ }
+
+ return false;
+}
+
+bool c_rapl_interface::pp1_domain_present()
+{
+ if ((rapl_domains & PP1_DOMAIN_PRESENT)) {
+ return true;
+ }
+
+ return false;
+}
+
+int c_rapl_interface::read_msr(int cpu, unsigned int idx, uint64_t *val)
+{
+ return ::read_msr(cpu, idx, val);
+}
+
+int c_rapl_interface::write_msr(int cpu, unsigned int idx, uint64_t val)
+{
+ return ::write_msr(cpu, idx, val);
+}
+
+int c_rapl_interface::get_rapl_power_unit(uint64_t *value)
+{
+ int ret;
+
+ ret = read_msr(first_cpu, MSR_RAPL_POWER_UNIT, value);
+
+ return ret;
+}
+
+double c_rapl_interface::get_power_unit()
+{
+ int ret;
+ uint64_t value;
+
+ ret = get_rapl_power_unit(&value);
+ if(ret < 0)
+ {
+ return ret;
+ }
+
+ return (double) 1/pow((double)2, (double)(value & 0xf));
+}
+
+double c_rapl_interface::get_energy_status_unit()
+{
+ int ret;
+ uint64_t value;
+
+ ret = get_rapl_power_unit(&value);
+ if(ret < 0)
+ {
+ return ret;
+ }
+
+ return (double)1/ pow((double)2, (double)((value & 0x1f00) >> 8));
+}
+
+double c_rapl_interface::get_time_unit()
+{
+ int ret;
+ uint64_t value;
+
+ ret = get_rapl_power_unit(&value);
+ if(ret < 0)
+ {
+ return ret;
+ }
+
+ return (double)1 / pow((double)2, (double)((value & 0xf0000) >> 16));
+}
+
+int c_rapl_interface::get_pkg_energy_status(double *status)
+{
+ int ret;
+ uint64_t value;
+
+ if (!pkg_domain_present()) {
+ return -1;
+ }
+
+ ret = read_msr(first_cpu, MSR_PKG_ENERY_STATUS, &value);
+ if(ret < 0)
+ {
+ RAPL_ERROR_PRINT("get_pkg_energy_status failed\n");
+ return ret;
+ }
+
+ *status = (double) (value & 0xffffffff) * get_energy_status_unit();
+
+ return ret;
+}
+
+int c_rapl_interface::get_pkg_power_info(double *thermal_spec_power,
+ double *max_power, double *min_power, double *max_time_window)
+{
+ int ret;
+ uint64_t value;
+
+ if (!pkg_domain_present()) {
+ return -1;
+ }
+ ret = read_msr(first_cpu, MSR_PKG_POWER_INFO, &value);
+ if(ret < 0)
+ {
+ RAPL_ERROR_PRINT("get_pkg_power_info failed\n");
+ return ret;
+ }
+ *thermal_spec_power = (value & 0x7FFF) * power_units;
+ *min_power = ((value & 0x7FFF0000) >> 16) * power_units;
+ *max_power = ((value & 0x7FFF00000000) >> 32) * power_units;
+ *max_time_window = ((value & 0x3f000000000000)>>48) * time_units;
+
+ return ret;
+}
+
+int c_rapl_interface::get_pkg_power_limit(uint64_t *value)
+{
+ int ret;
+
+ if (!pkg_domain_present()) {
+ return -1;
+ }
+
+ ret = read_msr(first_cpu, MSR_PKG_POWER_LIMIT, value);
+ if(ret < 0)
+ {
+ RAPL_ERROR_PRINT("get_pkg_power_limit failed\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+int c_rapl_interface::set_pkg_power_limit(uint64_t value)
+{
+ int ret;
+
+ if (!pkg_domain_present()) {
+ return -1;
+ }
+
+ ret = write_msr(first_cpu, MSR_PKG_POWER_LIMIT, value);
+ if(ret < 0)
+ {
+ RAPL_ERROR_PRINT("set_pkg_power_limit failed\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+int c_rapl_interface::get_dram_energy_status(double *status)
+{
+ int ret;
+ uint64_t value;
+
+ if (!dram_domain_present()) {
+ return -1;
+ }
+
+ if (powercap_sysfs_present) {
+ string str = read_sysfs_string(powercap_dram_path + "energy_uj");
+ if (str.length() > 0) {
+ *status = atof(str.c_str()) / 1000000; // uj to Js
+ return 0;
+ }
+
+ return -EINVAL;
+ }
+
+ ret = read_msr(first_cpu, MSR_DRAM_ENERY_STATUS, &value);
+ if(ret < 0)
+ {
+ RAPL_ERROR_PRINT("get_dram_energy_status failed\n");
+ return ret;
+ }
+
+ *status = (double) (value & 0xffffffff) * get_energy_status_unit();
+
+ return ret;
+}
+
+int c_rapl_interface::get_dram_power_info(double *thermal_spec_power,
+ double *max_power, double *min_power, double *max_time_window)
+{
+ int ret;
+ uint64_t value;
+
+ if (!dram_domain_present()) {
+ return -1;
+ }
+ ret = read_msr(first_cpu, MSR_DRAM_POWER_INFO, &value);
+ if(ret < 0)
+ {
+ RAPL_ERROR_PRINT("get_dram_power_info failed\n");
+ return ret;
+ }
+
+ *thermal_spec_power = (value & 0x7FFF) * power_units;
+ *min_power = ((value & 0x7FFF0000) >> 16) * power_units;
+ *max_power = ((value & 0x7FFF00000000) >> 32) * power_units;
+ *max_time_window = ((value & 0x3f000000000000)>>48) * time_units;
+
+ return ret;
+}
+
+int c_rapl_interface::get_dram_power_limit(uint64_t *value)
+{
+ int ret;
+
+ if (!dram_domain_present()) {
+ return -1;
+ }
+
+ ret = read_msr(first_cpu, MSR_DRAM_POWER_LIMIT, value);
+ if(ret < 0)
+ {
+ RAPL_ERROR_PRINT("get_dram_power_limit failed\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+int c_rapl_interface::set_dram_power_limit(uint64_t value)
+{
+ int ret;
+
+ if (!dram_domain_present()) {
+ return -1;
+ }
+
+ ret = write_msr(first_cpu, MSR_DRAM_POWER_LIMIT, value);
+ if(ret < 0)
+ {
+ RAPL_ERROR_PRINT("set_dram_power_limit failed\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+int c_rapl_interface::get_pp0_energy_status(double *status)
+{
+ int ret;
+ uint64_t value;
+
+ if (!pp0_domain_present()) {
+ return -1;
+ }
+
+ if (powercap_sysfs_present) {
+ string str = read_sysfs_string(powercap_core_path + "energy_uj");
+ if (str.length() > 0) {
+ *status = atof(str.c_str()) / 1000000; // uj to Js
+ return 0;
+ }
+
+ return -EINVAL;
+ }
+
+ ret = read_msr(first_cpu, MSR_PP0_ENERY_STATUS, &value);
+ if(ret < 0)
+ {
+ RAPL_ERROR_PRINT("get_pp0_energy_status failed\n");
+ return ret;
+ }
+
+ *status = (double) (value & 0xffffffff) * get_energy_status_unit();
+
+ return ret;
+}
+
+int c_rapl_interface::get_pp0_power_limit(uint64_t *value)
+{
+ int ret;
+
+ if (!pp0_domain_present()) {
+ return -1;
+ }
+
+ ret = read_msr(first_cpu, MSR_PP0_POWER_LIMIT, value);
+ if(ret < 0)
+ {
+ RAPL_ERROR_PRINT("get_pp0_power_limit failed\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+int c_rapl_interface::set_pp0_power_limit(uint64_t value)
+{
+ int ret;
+
+ if (!pp0_domain_present()) {
+ return -1;
+ }
+
+ ret = write_msr(first_cpu, MSR_PP0_POWER_LIMIT, value);
+ if(ret < 0)
+ {
+ RAPL_ERROR_PRINT("set_pp0_power_limit failed\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+int c_rapl_interface::get_pp0_power_policy(unsigned int *pp0_power_policy)
+{
+ int ret;
+ uint64_t value;
+
+ if (!pp0_domain_present()) {
+ return -1;
+ }
+
+ ret = read_msr(first_cpu, MSR_PP0_POLICY, &value);
+ if(ret < 0)
+ {
+ RAPL_ERROR_PRINT("get_pp0_power_policy failed\n");
+ return ret;
+ }
+
+ *pp0_power_policy = value & 0x0f;
+
+ return ret;
+}
+
+int c_rapl_interface::get_pp1_energy_status(double *status)
+{
+ int ret;
+ uint64_t value;
+
+ if (!pp1_domain_present()) {
+ return -1;
+ }
+
+ if (powercap_sysfs_present) {
+ string str = read_sysfs_string(powercap_uncore_path + "energy_uj");
+ if (str.length() > 0) {
+ *status = atof(str.c_str()) / 1000000; // uj to Js
+ return 0;
+ }
+
+ return -EINVAL;
+ }
+
+ ret = read_msr(first_cpu, MSR_PP1_ENERY_STATUS, &value);
+ if(ret < 0)
+ {
+ RAPL_ERROR_PRINT("get_pp1_energy_status failed\n");
+ return ret;
+ }
+
+ *status = (double) (value & 0xffffffff) * get_energy_status_unit();
+
+ return ret;
+}
+
+int c_rapl_interface::get_pp1_power_limit(uint64_t *value)
+{
+ int ret;
+
+ if (!pp1_domain_present()) {
+ return -1;
+ }
+
+ ret = read_msr(first_cpu, MSR_PP1_POWER_LIMIT, value);
+ if(ret < 0)
+ {
+ RAPL_ERROR_PRINT("get_pp1_power_info failed\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+int c_rapl_interface::set_pp1_power_limit(uint64_t value)
+{
+ int ret;
+
+ if (!pp1_domain_present()) {
+ return -1;
+ }
+
+ ret = write_msr(first_cpu, MSR_PP1_POWER_LIMIT, value);
+ if(ret < 0)
+ {
+ RAPL_ERROR_PRINT("set_pp1_power_limit failed\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+int c_rapl_interface::get_pp1_power_policy(unsigned int *pp1_power_policy)
+{
+ int ret;
+ uint64_t value;
+
+ if (!pp1_domain_present()) {
+ return -1;
+ }
+
+ ret = read_msr(first_cpu, MSR_PP1_POLICY, &value);
+ if(ret < 0)
+ {
+ RAPL_ERROR_PRINT("get_pp1_power_policy failed\n");
+ return ret;
+ }
+
+ *pp1_power_policy = value & 0x0f;
+
+ return ret;
+}
+
+void c_rapl_interface::rapl_measure_energy()
+{
+#ifdef RAPL_TEST_MODE
+ int ret;
+ double energy_status;
+ double thermal_spec_power;
+ double max_power;
+ double min_power;
+ double max_time_window;
+ double pkg_watts = 0;
+ double dram_watts = 0;
+ double pp0_watts = 0;
+ double pp1_watts = 0;
+ double pkg_joules = 0;
+ double dram_joules = 0;
+ double pp0_joules = 0;
+ double pp1_joules = 0;
+
+ get_pkg_power_info(&thermal_spec_power, &max_power, &min_power, &max_time_window);
+ RAPL_DBG_PRINT("Pkg Power Info: Thermal spec %f watts, max %f watts, min %f watts, max time window %f seconds\n", thermal_spec_power, max_power, min_power, max_time_window);
+ get_dram_power_info(&thermal_spec_power, &max_power, &min_power, &max_time_window);
+ RAPL_DBG_PRINT("DRAM Power Info: Thermal spec %f watts, max %f watts, min %f watts, max time window %f seconds\n", thermal_spec_power, max_power, min_power, max_time_window);
+
+ for (;;) {
+ if (pkg_domain_present()) {
+ ret = get_pkg_energy_status(&energy_status);
+ if (last_pkg_energy_status == 0)
+ last_pkg_energy_status = energy_status;
+ if (ret > 0) {
+ pkg_joules = energy_status;
+ pkg_watts = (energy_status-last_pkg_energy_status)/measurment_interval;
+ }
+ last_pkg_energy_status = energy_status;
+ }
+ if (dram_domain_present()) {
+ ret = get_dram_energy_status(&energy_status);
+ if (last_dram_energy_status == 0)
+ last_dram_energy_status = energy_status;
+ if (ret > 0){
+ dram_joules = energy_status;
+ dram_watts = (energy_status-last_dram_energy_status)/measurment_interval;
+ }
+ last_dram_energy_status = energy_status;
+ }
+ if (pp0_domain_present()) {
+ ret = get_pp0_energy_status(&energy_status);
+ if (last_pp0_energy_status == 0)
+ last_pp0_energy_status = energy_status;
+ if (ret > 0){
+ pp0_joules = energy_status;
+ pp0_watts = (energy_status-last_pp0_energy_status)/measurment_interval;
+ }
+ last_pp0_energy_status = energy_status;
+ }
+ if (pp1_domain_present()) {
+ ret = get_pp1_energy_status(&energy_status);
+ if (last_pp1_energy_status == 0)
+ last_pp1_energy_status = energy_status;
+ if (ret > 0){
+ pp1_joules = energy_status;
+ pp1_watts = (energy_status-last_pp1_energy_status)/measurment_interval;
+ }
+ last_pp1_energy_status = energy_status;
+ }
+ RAPL_DBG_PRINT("%f, %f, %f, %f\n", pkg_watts, dram_watts, pp0_watts, pp1_watts);
+ sleep(measurment_interval);
+ }
+#endif
+}
diff --git a/src/cpu/rapl/rapl_interface.h b/src/cpu/rapl/rapl_interface.h
new file mode 100644
index 0000000..c8e9683
--- /dev/null
+++ b/src/cpu/rapl/rapl_interface.h
@@ -0,0 +1,91 @@
+/* rapl_interface.h: rapl interface for power top
+ *
+ * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ *
+ * Author Name <Srinivas.Pandruvada@linux.intel.com>
+ *
+ */
+
+#ifndef RAPL_INTERFACE_H
+#define RAPL_INTERFACE_H
+
+class c_rapl_interface
+{
+private:
+ static const int def_sampling_interval = 1; //In seconds
+ bool powercap_sysfs_present;
+ string powercap_core_path;
+ string powercap_uncore_path;
+ string powercap_dram_path;
+
+ unsigned char rapl_domains;
+ int first_cpu;
+
+ double power_units;
+ double energy_status_units;
+ double time_units;
+
+ int read_msr(int cpu, unsigned int idx, uint64_t *val);
+ int write_msr(int cpu, unsigned int idx, uint64_t val);
+
+protected:
+ int measurment_interval;
+ double last_pkg_energy_status;
+ double last_dram_energy_status;
+ double last_pp0_energy_status;
+ double last_pp1_energy_status;
+
+public:
+ c_rapl_interface(const char *dev_name = "package-0", int cpu = 0);
+
+ int get_rapl_power_unit(uint64_t *value);
+ double get_power_unit();
+ double get_energy_status_unit();
+ double get_time_unit();
+
+ int get_pkg_energy_status(double *status);
+ int get_pkg_power_info(double *thermal_spec_power,
+ double *max_power, double *min_power, double *max_time_window);
+ int get_pkg_power_limit(uint64_t *value);
+ int set_pkg_power_limit(uint64_t value);
+
+ int get_dram_energy_status(double *status);
+ int get_dram_power_info(double *thermal_spec_power,
+ double *max_power, double *min_power, double *max_time_window);
+ int get_dram_power_limit(uint64_t *value);
+ int set_dram_power_limit(uint64_t value);
+
+ int get_pp0_energy_status(double *status);
+ int get_pp0_power_limit(uint64_t *value);
+ int set_pp0_power_limit(uint64_t value);
+ int get_pp0_power_policy(unsigned int *pp0_power_policy);
+
+ int get_pp1_energy_status(double *status);
+ int get_pp1_power_limit(uint64_t *value);
+ int set_pp1_power_limit(uint64_t value);
+ int get_pp1_power_policy(unsigned int *pp1_power_policy);
+
+ bool pkg_domain_present();
+ bool dram_domain_present();
+ bool pp0_domain_present();
+ bool pp1_domain_present();
+
+ void rapl_measure_energy();
+};
+
+#endif