diff options
Diffstat (limited to 'src/cpu/intel_cpus.cpp')
-rw-r--r-- | src/cpu/intel_cpus.cpp | 757 |
1 files changed, 757 insertions, 0 deletions
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); +} |