This patch series is to optimize both power and performance on
big.LITTLE system. Almost optimization methodology are same with
RFCv2 version, so you can refer the detailed description in [1].
In this patch series, the new enhencemences for performance is
to spread tasks to more clusters when detect the highest capacity cores
are busy, the criteria for 'big core busy' is the big core is not idle,
this is because we have patch "sched/fair: avoid small task to migrate
to higher capacity CPU" to filter out to only migrate relative big
load task to big core, so if there have task is running on big core,
that means the big core utilization is not small. If all big cores have
task running, usually system is quite busy so we should go back to
select idlest CPU to replace "want_affine". So this is mainly finished
by patch "sched/fair: avoid migrate single task to busy big CPU" and
patch "sched/fair: select idle CPUs when big cluster is busy".
This patch series also optimize power for both PELT and WALT signals,
this is finished by patch "sched/fair: save power for when use walt
signals".
[1] https://lists.linaro.org/pipermail/eas-dev/2016-July/000522.html
Leo Yan (18):
sched/fair: optimize to more chance to select previous CPU
sched/fair: select CPU based on using lowest capacity
sched/fair: support to spread task in lowest schedule domain
sched/fair: add path to migrate to higher capacity CPU
sched/fair: force idle balance when busiest group is overloaded
sched/fair: avoid small task to migrate to higher capacity CPU
sched/fair: set imbalance for too many tasks on rq
sched/fair: kick nohz idle balance for misfit task
sched/fair: consider over utilized only for CPU is not idle
sched/fair: filter task for energy aware path
sched/fair: replace capacity_of by capacity_orig_of
sched/fair: refine when task is allowed only run one CPU
Documentation: EAS performance tunning for sysfs
sched/fair: avoid migrate single task to busy big CPU
sched/fair: fix building error for schedtune_task_margin
sched/fair: save power for when use walt signals
sched/fair: check task boosted value on destination CPU
sched/fair: select idle CPUs when big cluster is busy
Documentation/scheduler/sched-energy.txt | 87 ++++++++++
kernel/sched/fair.c | 286 ++++++++++++++++++++++++++++---
2 files changed, 348 insertions(+), 25 deletions(-)
--
1.9.1
This patch series implements an alternative window assisted load tracking
mechanism in lieu of PELT based cpu utilization tracking. Testing has
shown that a window based non-decaying metric such as WALT guiding cpu
frequency and task placement decisions can improve performance/power
especially when running workloads more commonly found on mobile devices.
The aim of this series is to incorporate WALT accounting into the
scheduler and feed WALT statistics to schedutil in order to guide cpu
frequency selection. The implementation is detailed in the commit text
of Patch 1. The eventual goal is to also guide placement decisions
based on WALT statistics.
WALT has existed in out-of-tree kernels for ARM/ARM64 commercialized
devices for a few years. This is an effort to bring WALT to mainline
as well as to test on multiple architectures and with varied workloads.
This RFC version is mainly to preview what the code will look like on
mainline. Future RFC revisions will include a theoretical discussion and
benchmark results.
Tested on an Intel x86_64 machine (on top of 4.7-rc6). (Benchmark
results will be sent out separately and as part of this message in the
next RFC version).
Patch 1: Adds WALT tracking to the scheduler
Patches 2-3: Temporary patches to bring in EAS/sched-freq like capacity
table and to use Intel PMC counters for more accurate
frequency invariant load tracking on X86. Included for
completeness but not meant for merging.
include/linux/sched.h | 35 ++++++++++
include/linux/sched/sysctl.h | 2 +
include/trace/events/sched.h | 76 +++++++++++++++++++++
init/Kconfig | 9 +++
kernel/sched/Makefile | 1 +
kernel/sched/core.c | 29 ++++++++-
kernel/sched/cpufreq_schedutil.c | 44 ++++++++++++-
kernel/sched/cputime.c | 11 +++-
kernel/sched/debug.c | 10 +++
kernel/sched/fair.c | 7 +-
kernel/sched/sched.h | 13 ++++
kernel/sched/walt.c | 580 ++++++++++++++++++++++++++++++++++
kernel/sched/walt.h | 75 +++++++++++++++++++++
kernel/sysctl.c | 18 +++++
14 files changed, 904 insertions(+), 6 deletions(-)
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
This patch series implements an alternative window assisted load tracking
mechanism in lieu of PELT based cpu utilization tracking. Testing has
shown that a window based non-decaying metric such as WALT guiding cpu
frequency and task placement decisions can improve performance/power
especially when running workloads more commonly found on mobile devices.
The aim of this series is to incorporate WALT accounting into the
scheduler and feed WALT statistics to schedutil in order to guide cpu
frequency selection. The implementation is detailed in the commit text
of Patch 1. The eventual goal is to also guide placement decisions
based on WALT statistics.
WALT has existed in out-of-tree kernels for ARM/ARM64 commercialized
devices for a few years. This is an effort to bring WALT to mainline
as well as to test on multiple architectures and with varied workloads.
This RFC version is mainly to preview what the code will look like on
mainline. Future RFC revisions will include a theoretical discussion and
benchmark results.
Tested on an Intel x86_64 machine (on top of 4.7-rc6). (Benchmark
results will be sent out separately and as part of this message in the
next RFC version).
Patch 1: Adds WALT tracking to the scheduler
Patches 2 and 3: Temporary patches to bring in EAS/sched-freq like capacity
table and to use Intel PMC counters for more accurate
frequency invariant load tracking on X86. Included for
completeness but not meant for merging.
include/linux/sched.h | 35 ++++++++++
include/linux/sched/sysctl.h | 2 +
include/trace/events/sched.h | 76 +++++++++++++++++++++
init/Kconfig | 9 +++
kernel/sched/Makefile | 1 +
kernel/sched/core.c | 29 ++++++++-
kernel/sched/cpufreq_schedutil.c | 44 ++++++++++++-
kernel/sched/cputime.c | 11 +++-
kernel/sched/debug.c | 10 +++
kernel/sched/fair.c | 7 +-
kernel/sched/sched.h | 13 ++++
kernel/sched/walt.c | 580 ++++++++++++++++++++++++++++++++++
kernel/sched/walt.h | 75 +++++++++++++++++++++
kernel/sysctl.c | 18 +++++
14 files changed, 904 insertions(+), 6 deletions(-)
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
This patch series is to optimize performance and refine patches
according to review comments.
- Patch 0001 is add more chance to select previous CPU for cache hot;
- In EAS code, the critical path is task waken up with function
energy_aware_wake_cpu(); this function is purposed to select one
possible target CPU with most energy saving. So it includes two
underlying functionality: the first one is to select most power
efficiency CPU for the task in one cluster, another is to migrate
task from big core to little core if little core can meet performance
requirement.
For first functionality for selection most power efficiency CPU
within cluster, EAS prefers to select a non-idle CPU so as result it
packs tasks into one CPU as possible. This is not an optimal solution
with two reasons: the first reason is this introduces long schedule
latency after multiple tasks on the same rq; the second reason is it
easily gets result as small tasks packing within one CPU with higher
operating point. Finally this is the observed foremost issue if there
have multiple tasks, neither power or performance can achieve optimal
result.
So patch 0002 is to solve this issue to try to select CPU if can keep
CPU at lowest OPP as possible.
- Current code has no mechanism to spread these tasks throughout the
little cluster so tasks are packed on one CPU when CPU is not
“over-utilized”. In this case, only one CPU is very busy but other
CPUs in the same cluster are in idle state.
Patch 0003 is to spread task in lowest schedule domain (in cluster
level) after add a medium state named "half-utilized". This may a
temperary solution, due this likely a better solution is to unify
flag for "over-utilized".
- In CFS, PELT signals take long time to increase to high value and
decay to small value; on the other hand, EAS does not take account
load_avg value (runnable time) but only focus on util_avg value
(running time). So these issues are really dependent on fundamental
signals.
So hope have advanced method to accelerate PELT signals and dismiss
the issue introduced by long runnable time. Patch 0004 we can take it
as a temperary solution, likely we can use the big difference between
load_avg and util_avg to change to use inflate value, also can use it
to reflect runnable time.
Patch 0004 also has side effects for misfit flag. If any CPU has
“misfit” task on it, then EAS will set imbalance value as CPU
capacity and migrate such load from little core to big core. So
“misfit” is quite good for there have only one big task on the
little CPU so the CPU cannot meet task’s performance requirement
with function “task_fits_max(p, rq->cpu)”; but if there have two
tasks on the little CPU, then the task’s utilization value just
half of CPU capacity value so finally EAS considers CPU can meet
task requirement. Patch 0004 can more easily to set true for
misfit: rq->misfit_task = !task_fits_max(p, rq->cpu)
- In function energy_aware_wake_cpu(), it is possible to directly
migrate task from little core to big core, but the conditions are
rigid: the condition 1 is CPU capacity cannot meet this task
requirement; the condition 2 is source CPU is “over-utilized”. If the
source CPU is not “over-utilized” for condition 2, then even little
CPU cannot meet task requirement but EAS will compare CPU energy and
as the end it still selects previous little CPU
Patch 0005 is to add extra path to directly migrate task from little
core to big core.
- For very heavily workload with multi-threads, we observed the tasks
are not migrated within big cluster, also tasks are hard to migrate
from big cluster to little cluster even little cluster have idle CPUs
are available to run. So need optimize EAS to handle this case likely
to go back with CFS behaviour.
Patch 0006 and 0008 are to fix this related issues.
- SMP load balance may migrate small task onto big core, but usually at
this time point we are only looking forward big tasks migration,
finally this hurts both power and performance. So patch 0007 it will
avoid small task to migrate to higher capacity CPU so it will give
more chance to real big task migration to higher capacity CPU.
Leo Yan (8):
sched/fair: optimize to more chance to select previous CPU
sched/fair: select CPU based on using lowest capacity
sched/fair: support to spread task in lowest schedule domain
sched/fair: use load metrics to replace util when have big difference
sched/fair: add path to migrate to higher capacity CPU
sched/fair: force idle balance when busiest group is overloaded
sched/fair: avoid small task to migrate to higher capacity CPU
sched/fair: set imbalance for too many tasks on rq
kernel/sched/fair.c | 193 ++++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 173 insertions(+), 20 deletions(-)
--
1.9.1
This patch series is to optimize performance.
Patch 0001 is to optimize CPU selection flow so let task has more
chance to stay on previous CPU. Patch 0002 actually is a big change
for EAS's policy for CPU selection, it trys to select idle CPU as
possible. From profiling result, 0002 have good effect that spread tasks
out if there have many tasks are running at the meantime.
Patches 0003~0004 are to optimize the scenario for single thread case.
In this case, the thread has relative high utilization value, but the
value cannot easily over tipping point. So patche 0004 try to set
criteria to in some condition change to use load_avg rather than
util_avg to boost the single thread.
Patch 0005 is to optimize the flow for spreading tasks within big
cluster.
Patches 0006~0007 is to fix the signal for avg_load.
Leo Yan (8):
sched/fair: optimize to more chance to select previous CPU
sched/fair: select idle CPU for waken up task
sched/fair: add path to migrate to higher capacity CPU
sched/fair: use load to replace util when have big difference
sched/fair: spread tasks in cluster when over tipping point
sched/fair: correct avg_load as CPU average load
sched/fair: fix to calculate average load cross cluster
sched/fair: set imbn to 1 for too many tasks on rq
include/linux/sched.h | 1 +
kernel/sched/fair.c | 93 +++++++++++++++++++++++++++++++++++++++++++++------
2 files changed, 84 insertions(+), 10 deletions(-)
--
1.9.1
Hi Patrick,
[ + eas-dev ]
Here have a common question for how to define schedTune threshold
array for payoff. So basically I want check below questions:
- When every CGroup has its own perf_boost_idx for PB region and
perf_constrain_idx for PC region. So do you have suggestion or
guideline to define these index?
And for difference CGroup like "backgroud", "foreground" or
"performance" every CGroup will have its dedicated index or the
platform can share the same index value?
- How to define the array value for "threshold_gains"?
IIUC this array is platform dependency, but what's the
reasonable method to generate this table? Here have some suggested
testing for generating this table?
Or my understanding is wrong so this array is fixed, then just need
ajust perf_boost_idx/perf_constrain_idx for platform is enough?
- So far we cannot set these payoff parameters (including
perf_boost_idx/perf_constrain_idx and threshold_gains) from sysfs
dynamically, so how we can initilizae these value for platform
specific? Suppose now we can only set these value when kernel's
init flow, right?
Thanks,
Leo Yan
Hi,
I am Amanda,
Would you be interested in acquiring an email list of "Moms Email List" from USA?
We have data for Mortgage Email List, New Homeowner Email List, Online Shoppers List, Travelers Email List and many more. Choose the best one that meets your need. We provide you with current and active contact on every list. Take advantage of that, let your marketing efforts be fruitful.
Each record in the list Contact Name( First, Middle, Last Name), Direct Mailing Address ( Address, City, State, Zip Code), List Type, Source, IP Address, and Email Address.
All the contacts are opt-in verified, 100% permission based and can be used for unlimited multi-channel marketing.
Please let me know your thoughts towards Moms Email List.
Best Regards,
Amanda Clark
---
This email has been checked for viruses by Avast antivirus software.
https://www.avast.com/antivirus
In current code the CPU's idle state cpufreq_pstates::idle is initialized
to '-1'; and until parse first "cpu_idle" event for the CPU then set CPU's
idle state to '0' or '1' corresponding to active or idle. This will cause
error for P-state's statistics: from the beginning to first "cpu_idle"
event, during this period the CPU's idle state is '-1' so function
cpu_change_pstate() will always think it's first update and finally abandon
previous time.
This will introduce very big error if the CPU is always running and never
run into idle state. So this patch is to fix this issue by initialize CPU's
corresponding C-state and P-state:
- Firstly gather every CPU's starting frequency and time stamp;
- Then gather CPU's idle state according to first cpu_idle log:
If the CPU first cpu_idle state is '-1', that means from the beginning
the CPU is stayed on idle state;
If the CPU first cpu_idle state is other value, means the CPU is active.
- With these info, finally initialize every CPU's C-state and P-state
before analyse trace logs.
Here should note one thing is: when CPU is idle at beginning, we don't know
exact idle state, so just assume CPU is in idle state 0; but this will not
impact too much for statistics, due usually idlestat will wakeup all CPUs
at the beginning. So it will introduce very small deviation.
Signed-off-by: Leo Yan <leo.yan(a)linaro.org>
---
tracefile_idlestat.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 123 insertions(+)
diff --git a/tracefile_idlestat.c b/tracefile_idlestat.c
index 3430693..d0cd366 100644
--- a/tracefile_idlestat.c
+++ b/tracefile_idlestat.c
@@ -152,6 +152,127 @@ int load_text_data_line(char *buffer, struct cpuidle_datas *datas, char *format,
return get_wakeup_irq(datas, buffer);
}
+
+/**
+ * init_cpu_idle_state - Init CPU's idle state according to first cpu_idle log.
+ * For a specific cpu_idle event, its state is '-1' then that means from the
+ * beginning the CPU is stayed on idle state; Otherwise means the CPU is active.
+ * So initilize per-CPU idle flag to get more accurate time.
+ *
+ * @datas: structure for P-state and C-state's statistics
+ * @f: the file handle of the idlestat trace file
+ */
+void init_cpu_idle_state(struct cpuidle_datas *datas, FILE *f)
+{
+ char buffer[BUFSIZE];
+ int state, cpu;
+ double time;
+ struct cpufreq_pstates *ps;
+
+ unsigned long *cpu_start_idle;
+ int *cpu_start_freq;
+ double cpu_start_time;
+
+ fseek(f, 0, SEEK_SET);
+
+ cpu_start_freq = malloc(sizeof(int) * datas->nrcpus);
+ for (cpu = 0; cpu < datas->nrcpus; cpu++)
+ cpu_start_freq[cpu] = 0xdeadbeef;
+
+ /*
+ * Find the start time stamp and the CPU's frequency at beginning;
+ * So we can use these info to add dummy info.
+ */
+ while (fgets(buffer, BUFSIZE, f)) {
+
+ if (strstr(buffer, "cpu_frequency")) {
+ if (sscanf(buffer, TRACE_FORMAT, &time, &state, &cpu)
+ != 3) {
+ fprintf(stderr, "warning: Unrecognized cpuidle "
+ "record. The result of analysis might "
+ "be wrong.\n");
+ return;
+ }
+ } else
+ continue;
+
+ if (cpu_start_freq[cpu] != 0xdeadbeef)
+ continue;
+
+ if (cpu == 0)
+ cpu_start_time = time;
+
+ cpu_start_freq[cpu] = state;
+
+ break;
+ }
+
+ /* After traverse file, reset offset */
+ fseek(f, 0, SEEK_SET);
+
+ /*
+ * Find the CPU's idle state at beginning
+ */
+ cpu_start_idle = malloc(sizeof(long) * datas->nrcpus);
+ for (cpu = 0; cpu < datas->nrcpus; cpu++)
+ cpu_start_idle[cpu] = 0xdeadbeef;
+
+ while (fgets(buffer, BUFSIZE, f)) {
+
+ if (strstr(buffer, "cpu_idle")) {
+ if (sscanf(buffer, TRACE_FORMAT, &time, &state, &cpu)
+ != 3) {
+ fprintf(stderr, "warning: Unrecognized cpuidle "
+ "record. The result of analysis might "
+ "be wrong.\n");
+ return;
+ }
+ } else
+ continue;
+
+ /* CPU's state has been initialized, skip it */
+ if (cpu_start_idle[cpu] != 0xdeadbeef)
+ continue;
+
+ /*
+ * The CPU's first cpu_idle is '-1', means CPU is staying in
+ * idle state and exit from idle until first cpu_idle event.
+ * Otherwise, means the CPU is active at beginning.
+ */
+ if (state == -1)
+ cpu_start_idle[cpu] = 0;
+ else
+ cpu_start_idle[cpu] = 4294967295;
+ }
+
+ /* After traverse file, reset offset */
+ fseek(f, 0, SEEK_SET);
+
+ /* Initialize every CPU's cstate and pstate */
+ for (cpu = 0; cpu < datas->nrcpus; cpu++) {
+
+ ps = &(datas->pstates[cpu]);
+
+ if (cpu_start_idle[cpu] == 0) {
+ /*
+ * CPU is idle at beginning, init cstate;
+ *
+ * here don't know exact idle state, so just assume CPU
+ * is in idle state 0; but this will not impace too much
+ * for statistics, due usually idlestat will wakeup all
+ * CPUs at the beginning.
+ */
+ ps->idle = 1;
+ store_data(cpu_start_time, 0, cpu, datas);
+ } else {
+ /* CPU is busy at beginning, init pstate */
+ ps->idle = 0;
+ cpu_change_pstate(datas, cpu, cpu_start_freq[cpu],
+ cpu_start_time);
+ }
+ }
+}
+
void load_text_data_lines(FILE *f, char *buffer, struct cpuidle_datas *datas)
{
double begin = 0, end = 0;
@@ -159,6 +280,8 @@ void load_text_data_lines(FILE *f, char *buffer, struct cpuidle_datas *datas)
setup_topo_states(datas);
+ init_cpu_idle_state(datas, f);
+
do {
if (load_text_data_line(buffer, datas, TRACE_FORMAT,
&begin, &end, &start) != -1) {
--
1.9.1
In current code the CPU's idle state cpufreq_pstates::idle is initialized
to '-1'; and until parse first "cpu_idle" event for the CPU then set CPU's
idle state to '0' or '1' corresponding to active or idle. This will cause
error for P-state's statistics: from the beginning to first "cpu_idle"
event, during this period the CPU's idle state is '-1' so function
cpu_change_pstate() will always think it's first update and finally abandon
previous time.
This will introduce very big error if the CPU is always running and never
run into idle state. So this patch is to fix this issue by initialize CPU's
corresponding C-state and P-state:
- Firstly gather every CPU's starting frequency and time stamp;
- Then gather CPU's idle state according to first cpu_idle log:
If the CPU first cpu_idle state is '-1', that means from the beginning
the CPU is stayed on idle state;
If the CPU first cpu_idle state is other value, means the CPU is active.
- With these info, finally initialize every CPU's C-state and P-state
before analyse trace logs.
Here should note one thing is: when CPU is idle at beginning, we don't know
exact idle state, so just assume CPU is in idle state 0; but this will not
impact too much for statistics, due usually idlestat will wakeup all CPUs
at the beginning. So it will introduce very small deviation.
Signed-off-by: Leo Yan <leo.yan(a)linaro.org>
---
tracefile_idlestat.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 152 insertions(+)
diff --git a/tracefile_idlestat.c b/tracefile_idlestat.c
index 3430693..2674478 100644
--- a/tracefile_idlestat.c
+++ b/tracefile_idlestat.c
@@ -152,6 +152,153 @@ int load_text_data_line(char *buffer, struct cpuidle_datas *datas, char *format,
return get_wakeup_irq(datas, buffer);
}
+
+/**
+ * init_cpu_idle_state - Init CPU's idle state according to first cpu_idle log.
+ * For a specific cpu_idle event, its state is '-1' then that means from the
+ * beginning the CPU is stayed on idle state; Otherwise means the CPU is active.
+ * So initilize per-CPU idle flag to get more accurate time.
+ *
+ * @datas: structure for P-state and C-state's statistics
+ * @f: the file handle of the idlestat trace file
+ */
+int init_cpu_idle_state(struct cpuidle_datas *datas, FILE *f)
+{
+ char buffer[BUFSIZE];
+ int state, cpu;
+ double time;
+ struct cpufreq_pstates *ps;
+
+ unsigned long *cpu_start_idle;
+ int *cpu_start_freq;
+ double cpu_start_time;
+
+ int ret;
+
+ ret = fseek(f, 0, SEEK_SET);
+ if (ret < 0) {
+ fprintf(stderr, "failed to set the start file position\n");
+ return ret;
+ }
+
+ cpu_start_freq = malloc(sizeof(int) * datas->nrcpus);
+ if (!cpu_start_freq) {
+ fprintf(stderr, "failed to alloc for start frequency states\n");
+ return -1;
+ }
+
+ for (cpu = 0; cpu < datas->nrcpus; cpu++)
+ cpu_start_freq[cpu] = 0xdeadbeef;
+
+ /*
+ * Find the start time stamp and the CPU's frequency at beginning;
+ * So we can use these info to add dummy info.
+ */
+ while (fgets(buffer, BUFSIZE, f)) {
+
+ if (strstr(buffer, "cpu_frequency")) {
+ if (sscanf(buffer, TRACE_FORMAT, &time, &state, &cpu)
+ != 3) {
+ fprintf(stderr, "warning: Unrecognized cpuidle "
+ "record. The result of analysis might "
+ "be wrong.\n");
+ return -1;
+ }
+ } else
+ continue;
+
+ if (cpu_start_freq[cpu] != 0xdeadbeef)
+ continue;
+
+ if (cpu == 0)
+ cpu_start_time = time;
+
+ cpu_start_freq[cpu] = state;
+
+ break;
+ }
+
+ /* After traverse file, reset offset */
+ ret = fseek(f, 0, SEEK_SET);
+ if (ret < 0) {
+ fprintf(stderr, "failed to set the start file position\n");
+ return ret;
+ }
+
+ /*
+ * Find the CPU's idle state at beginning
+ */
+ cpu_start_idle = malloc(sizeof(long) * datas->nrcpus);
+ if (!cpu_start_idle) {
+ fprintf(stderr, "failed to alloc for start idle states\n");
+ return -1;
+ }
+
+ for (cpu = 0; cpu < datas->nrcpus; cpu++)
+ cpu_start_idle[cpu] = 0xdeadbeef;
+
+ while (fgets(buffer, BUFSIZE, f)) {
+
+ if (strstr(buffer, "cpu_idle")) {
+ if (sscanf(buffer, TRACE_FORMAT, &time, &state, &cpu)
+ != 3) {
+ fprintf(stderr, "warning: Unrecognized cpuidle "
+ "record. The result of analysis might "
+ "be wrong.\n");
+ return -1;
+ }
+ } else
+ continue;
+
+ /* CPU's state has been initialized, skip it */
+ if (cpu_start_idle[cpu] != 0xdeadbeef)
+ continue;
+
+ /*
+ * The CPU's first cpu_idle is '-1', means CPU is staying in
+ * idle state and exit from idle until first cpu_idle event.
+ * Otherwise, means the CPU is active at beginning.
+ */
+ if (state == -1)
+ cpu_start_idle[cpu] = 0;
+ else
+ cpu_start_idle[cpu] = 4294967295;
+ }
+
+ /* After traverse file, reset offset */
+ ret = fseek(f, 0, SEEK_SET);
+ if (ret < 0) {
+ fprintf(stderr, "failed to set the start file position\n");
+ return ret;
+ }
+
+ /* Initialize every CPU's cstate and pstate */
+ for (cpu = 0; cpu < datas->nrcpus; cpu++) {
+
+ ps = &(datas->pstates[cpu]);
+
+ if (cpu_start_idle[cpu] == 0) {
+ /*
+ * CPU is idle at beginning, init cstate;
+ *
+ * here don't know exact idle state, so just assume CPU
+ * is in idle state 0; but this will not impace too much
+ * for statistics, due usually idlestat will wakeup all
+ * CPUs at the beginning.
+ */
+ ps->idle = 1;
+ store_data(cpu_start_time, 0, cpu, datas);
+ } else {
+ /* CPU is busy at beginning, init pstate */
+ ps->idle = 0;
+ cpu_change_pstate(datas, cpu, cpu_start_freq[cpu],
+ cpu_start_time);
+ }
+ }
+
+ return 0;
+}
+
void load_text_data_lines(FILE *f, char *buffer, struct cpuidle_datas *datas)
{
double begin = 0, end = 0;
@@ -159,6 +306,11 @@ void load_text_data_lines(FILE *f, char *buffer, struct cpuidle_datas *datas)
setup_topo_states(datas);
+ if (init_cpu_idle_state(datas, f) < 0) {
+ fprintf(stderr, "failed to initlized cpu states\n");
+ exit(-1);
+ }
+
do {
if (load_text_data_line(buffer, datas, TRACE_FORMAT,
&begin, &end, &start) != -1) {
--
1.9.1
subscribe
IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.