diff options
Diffstat (limited to '')
-rw-r--r-- | src/cpu/cpu.cpp | 1075 |
1 files changed, 1075 insertions, 0 deletions
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]=" "; + 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=="" ? " " : tmp_str); + idx1+=1; + tmp_str=string(_package->fill_cstate_line(line, buffer2)); + pkg_data[idx1]=(tmp_str=="" ? " " : 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=="" ? " " : tmp_str); + idx2+=1; + tmp_str=string(_core->fill_cstate_line(line, buffer2)); + core_data[idx2]=(tmp_str=="" ? " " : 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=="" ? " " : tmp_str); + idx3+=1; + + if (line != LEVEL_C0){ + tmp_str=string(_cpu->fill_cstate_time(line, buffer)); + cpu_data[idx3]=(tmp_str=="" ? " " : tmp_str); + idx3+=1; + } else { + cpu_data[idx3]=" "; + 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]=" "; + 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=="" ? " " : tmp_str); + idx1+=1; + tmp_str=string(_package->fill_pstate_line(line, buffer2)); + pkg_data[idx1]=(tmp_str=="" ? " " : 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=="" ? " " : tmp_str); + idx2+=1; + tmp_str=string(_core->fill_pstate_line(line, buffer2)); + core_data[idx2]= (tmp_str=="" ? " " : 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=="" ? " " : tmp_str); + idx3+=1; + first_cpu = false; + } + + buffer[0] = 0; + tmp_str=string(_cpu->fill_pstate_line(line, buffer)); + cpu_data[idx3]=(tmp_str=="" ? " " : 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(); +} |