On 09/10/2014 09:33 AM, pi-cheng.chen wrote:
When using intel_pstate driver, "scaling_available_freqs" attr is not exported to sysfs. It causes assertion of idlestat due to memory of struct cpufreq_pstate was not allocated.
Allocate struct cpufreq_pstate dynamically when getting frequency information from trace file instead of parsing available frequencies from sysfs
Changes v1 to v2: Sort the cpufreq_pstate list when parsing events
Signed-off-by: Pi-Cheng Chen pi-cheng.chen@linaro.org
Tested on intel_pstate and legacy cpufreq driver.
In complement of this feature, I think the cpus cpufreq must be initialized with the 'cpuinfo_cur_freq' with the start time initialized to the beginning of the acquisition. If a cpu is in a specific freq without any changes (understand: ftrace transitions which trigger the p-state creation), we will have a long freq residency (the initial one).
Today we don't have this, so the cpus without freq changes are not displayed.
At least the minimal number of p-state should be '1' not '0' (except if cpufreq is disabled).
-- Daniel
idlestat.c | 118 +++++++++++++++++++++++++++++-------------------------------- 1 file changed, 56 insertions(+), 62 deletions(-)
diff --git a/idlestat.c b/idlestat.c index da615cb..d03f12e 100644 --- a/idlestat.c +++ b/idlestat.c @@ -561,8 +561,8 @@ static void release_pstate_info(struct cpufreq_pstates *pstates, int nrcpus) }
/**
- build_pstate_info - parse cpufreq sysfs entries and build per-CPU
- structs to maintain statistics of P-state transitions
- build_pstate_info - allocate and initialize per-CPU structs to
- maintain statistics of P-state transitions
- @nrcpus: number of CPUs
- Return: per-CPU array of structs (success) or NULL (error)
@@ -578,55 +578,8 @@ static struct cpufreq_pstates *build_pstate_info(int nrcpus) memset(pstates, 0, sizeof(*pstates) * nrcpus);
for (cpu = 0; cpu < nrcpus; cpu++) {
struct cpufreq_pstate *pstate;int nrfreq;char *fpath, *freq, line[256];FILE *sc_av_freq;if (asprintf(&fpath, CPUFREQ_AVFREQ_PATH_FORMAT, cpu) < 0)goto clean_exit;/* read scaling_available_frequencies for the CPU */sc_av_freq = fopen(fpath, "r");free(fpath);if (!sc_av_freq) {fprintf(stderr, "warning: P-states not supported for ""CPU%d\n", cpu);continue;}freq = fgets(line, sizeof(line)/sizeof(line[0]), sc_av_freq);fclose(sc_av_freq);if (!freq) {/* unlikely to be here, but just in case... */fprintf(stderr, "warning: P-state info not found for ""CPU%d\n", cpu);continue;}/* tokenize line and populate each frequency */nrfreq = 0;pstate = NULL;while ((freq = strtok(freq, "\n ")) != NULL) {struct cpufreq_pstate *tmp = realloc(pstate, sizeof(*pstate) * (nrfreq+1));if (!tmp)goto clean_exit;pstate = tmp;/* initialize pstate record */pstate[nrfreq].id = nrfreq;pstate[nrfreq].freq = atol(freq);pstate[nrfreq].count = 0;pstate[nrfreq].min_time = DBL_MAX;pstate[nrfreq].max_time = 0.;pstate[nrfreq].avg_time = 0.;pstate[nrfreq].duration = 0.;nrfreq++;freq = NULL;}/* now populate cpufreq_pstates for this CPU */pstates[cpu].pstate = pstate;pstates[cpu].max = nrfreq;
pstates[cpu].pstate = NULL; pstates[cpu].current = -1; /* unknown */ pstates[cpu].idle = -1; /* unknown */ pstates[cpu].time_enter = 0.;pstates[cpu].max = 0;@@ -634,10 +587,52 @@ static struct cpufreq_pstates *build_pstate_info(int nrcpus) }
return pstates; +}
-clean_exit:
- release_pstate_info(pstates, nrcpus);
- return NULL;
+/**
- alloc_pstate - allocate, sort, and initialize pstate struct
- to maintain statistics of P-state transitions
- @pstates: per-CPU P-state statistics struct
- @freq: frequency for which the newly pstate is allocated
- Return: the index of the newly allocated pstate struct
- */
+static int alloc_pstate(struct cpufreq_pstates *pstates, unsigned int freq) +{
struct cpufreq_pstate *pstate, *tmp;
int nrfreq, i, next = 0;
pstate = pstates->pstate;
nrfreq = pstates->max;
tmp = realloc(pstate, sizeof(*pstate) * (nrfreq + 1));
if (!tmp) {
perror("realloc pstate");return -1;}
pstate = tmp;
pstates->pstate = tmp;
pstates->max = nrfreq + 1;
for (i = 0; i < nrfreq && freq <= pstate[i].freq; i++)
;next = i;
for (i = nrfreq; i > next && i > 0; i--) {
pstate[i] = pstate[i - 1];pstate[i].id = i;pstates->current = (pstates->current == i - 1)? i : pstates->current;}
pstate[next].id = next;
pstate[next].freq = freq;
pstate[next].count = 0;
pstate[next].min_time = DBL_MAX;
pstate[next].max_time = 0;
pstate[next].avg_time = 0;
pstate[next].duration = 0;
return next; }
static int get_current_pstate(struct cpuidle_datas *datas, int cpu,
@@ -712,6 +707,9 @@ static void cpu_change_pstate(struct cpuidle_datas *datas, int cpu,
cur = get_current_pstate(datas, cpu, &ps, &p); next = freq_to_pstate_index(ps, freq);
if (next < 0)
next = alloc_pstate(ps, freq);assert(next >= 0);
switch (cur) { case 1:
@@ -763,7 +761,6 @@ static int store_data(double time, int state, int cpu, struct cpuidle_datas *datas, int count) { struct cpuidle_cstates *cstates = &datas->cstates[cpu];
- struct cpufreq_pstate *pstate = datas->pstates[cpu].pstate; struct cpuidle_cstate *cstate; struct cpuidle_data *data, *tmp; int nrdata, last_cstate = cstates->last_cstate;
@@ -826,9 +823,8 @@ static int store_data(double time, int state, int cpu, /* need indication if CPU is idle or not */ cstates->last_cstate = -1;
/* update P-state stats if supported */if (pstate)cpu_pstate_running(datas, cpu, time);
/* update P-state stats */cpu_pstate_running(datas, cpu, time);return 0; }
@@ -846,9 +842,8 @@ static int store_data(double time, int state, int cpu, cstates->cstate_max = MAX(cstates->cstate_max, state); cstates->last_cstate = state; cstates->wakeirq = NULL;
- /* update P-state stats if supported */
- if (pstate)
cpu_pstate_idle(datas, cpu, time);
/* update P-state stats*/
cpu_pstate_idle(datas, cpu, time);
return 0; }
@@ -1018,7 +1013,6 @@ static struct cpuidle_datas *idlestat_load(struct program_options *options) } else if (strstr(buffer, "cpu_frequency")) { assert(sscanf(buffer, TRACE_FORMAT, &time, &freq, &cpu) == 3);
assert(datas->pstates[cpu].pstate != NULL); cpu_change_pstate(datas, cpu, freq, time); count++; continue;