This is the commit 0f7e6dd0ab7b1b02ef7e55749d6a34d6801c3973 from Linaro's
PowerTOP repository.
Author: John Mathew <johnx.mathew(a)intel.com>
Intel hyperthreaded cores does not exactly behave like if it was 2 real cores.
- Actual HW cstate is roughly minimal cstate of the 2 threads.
As most of the resources are shared, HW resources are only really powered
down when both threads are idle.
- Interrupts always wakes up the 2 threads. i.e. terminate the 2 mwait.
So in case of an hyperthreaded core a wakeup event is affecting power only when
both the threads are asleep. A wakeup event that occurs when one of
the thread is active should not be considered as a wakeup event.
In case of hyperthreaded cores the thread ids that execute on the same core
will be reported in the sys/devices/system/cpu/cpu%i/topology/thread_siblings_list.
A table is initially created with this thread sibling information corresponding to
a cpu. When powertop gets a power_end event on a thread the thread_sibling table
is looked up to identify the siblings of the cpu and each sibling is checked it
has a wakeup pending. If any one sibling does not have a wakeup event pending
the power end event is ignored.
---
src/cpu/cpu.cpp | 28 ++++++++++++++++++++++++++++
src/cpu/cpu.h | 7 +++++++
src/process/do_process.cpp | 24 ++++++++++++++++++++++++
3 files changed, 59 insertions(+), 0 deletions(-)
diff --git a/src/cpu/cpu.cpp b/src/cpu/cpu.cpp
index 941bcff..ab7e724 100644
--- a/src/cpu/cpu.cpp
+++ b/src/cpu/cpu.cpp
@@ -28,6 +28,7 @@
#include <string.h>
#include <stdlib.h>
#include <ncurses.h>
+#include <sstream>
#include "cpu.h"
#include "cpudevice.h"
@@ -38,12 +39,15 @@
#include "../display.h"
#include "../report.h"
+using namespace std;
+
static class abstract_cpu system_level;
vector<class abstract_cpu *> all_cpus;
static class perf_bundle * perf_events;
+vector<struct thread_sibling_info *> thread_sibling_table;
class perf_power_bundle: public perf_bundle
@@ -163,6 +167,7 @@ static void handle_one_cpu(unsigned int number, char *vendor, int
family, int mo
unsigned int package_number = 0;
unsigned int core_number = 0;
class abstract_cpu *package, *core, *cpu;
+ vector<unsigned int> thread_siblings;
sprintf(filename, "/sys/devices/system/cpu/cpu%i/topology/core_id", number);
file.open(filename, ios::in);
@@ -180,6 +185,29 @@ static void handle_one_cpu(unsigned int number, char *vendor, int
family, int mo
file.close();
}
+ sprintf(filename,
+ "/sys/devices/system/cpu/cpu%i/topology/thread_siblings_list",
+ number);
+ file.open(filename, ios::in);
+ if (file) {
+ string line;
+ getline(file,line);
+ istringstream linestream(line);
+ string item;
+ struct thread_sibling_info *info;
+
+ while (getline(linestream, item, '-'))
+ thread_siblings.push_back(atoi(item.c_str()));
+
+ if (thread_siblings.size() > 1) {
+ info = new struct thread_sibling_info;
+ info->cpunum = number;
+ info->thread_siblings = thread_siblings;
+ thread_sibling_table.push_back(info);
+ }
+
+ file.close();
+ }
if (system_level.children.size() <= package_number)
system_level.children.resize(package_number + 1, NULL);
diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h
index b48ada9..54da093 100644
--- a/src/cpu/cpu.h
+++ b/src/cpu/cpu.h
@@ -39,6 +39,13 @@ class abstract_cpu;
#define LEVEL_C0 -1
#define LEVEL_HEADER -2
+struct thread_sibling_info {
+ unsigned int cpunum;
+ vector<unsigned int> thread_siblings;
+};
+
+extern vector<struct thread_sibling_info *> thread_sibling_table;
+
#define PSTATE 1
#define CSTATE 2
diff --git a/src/process/do_process.cpp b/src/process/do_process.cpp
index 731fe3e..60bc790 100644
--- a/src/process/do_process.cpp
+++ b/src/process/do_process.cpp
@@ -44,6 +44,7 @@
#include "../parameters/parameters.h"
#include "../display.h"
#include "../measurement/measurement.h"
+#include "../cpu/cpu.h"
static class perf_bundle * perf_events;
@@ -147,6 +148,27 @@ static void change_blame(unsigned int cpu, class power_consumer
*consumer, int l
cpu_level[cpu] = level;
}
+static bool sibling_wakeup_pending(unsigned int cpu)
+{
+ unsigned int i, j;
+ struct thread_sibling_info *info;
+ bool wakeup_pending = true;
+
+ for (i = 0; i < thread_sibling_table.size(); i++) {
+ info = thread_sibling_table[i];
+ if (cpu != info->cpunum)
+ continue;
+
+ for (j = 0; j < info->thread_siblings.size(); j++)
+ if (!get_wakeup_pending(info->thread_siblings[j])) {
+ wakeup_pending = false;
+ break;
+ }
+ }
+
+ return wakeup_pending;
+}
+
static void consume_blame(unsigned int cpu)
{
if (!get_wakeup_pending(cpu))
@@ -157,6 +179,8 @@ static void consume_blame(unsigned int cpu)
return;
if (!cpu_blame[cpu])
return;
+ if (!sibling_wakeup_pending(cpu))
+ return;
cpu_blame[cpu]->wake_ups++;
cpu_blame[cpu] = NULL;
--
1.7.5.4