From: Patrick Bellasi patrick.bellasi@arm.com
To properly identify the initial PState of each CPU, the idlestat_wake_all function is used to force an idle state exit on all CPUs by pinning idlestat on each CPUs. However, this routine forgets to recover the original mask at the end of the pinning process.
This patch solve this issue, by properly recovering the original CPU affinity mask. Moreover, it avoids to wake up CPUs that will not be used to run the workload.
Signed-off-by: Patrick Bellasi patrick.bellasi@arm.com Signed-off-by: Daniel Lezcano daniel.lezcano@linaro.org --- idlestat.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
diff --git a/idlestat.c b/idlestat.c index 0e0e1df..2a0c549 100644 --- a/idlestat.c +++ b/idlestat.c @@ -1210,6 +1210,7 @@ static int idlestat_wake_all(void) { int rcpu, i, ret; cpu_set_t cpumask; + cpu_set_t original_cpumask;
ret = sysconf(_SC_NPROCESSORS_CONF); if (ret < 0) @@ -1219,18 +1220,28 @@ static int idlestat_wake_all(void) if (rcpu < 0) return -1;
+ /* Keep track of the CPUs we will run on */ + sched_getaffinity(0, sizeof(original_cpumask), &original_cpumask); + for (i = 0; i < ret; i++) {
/* Pointless to wake up ourself */ if (i == rcpu) continue;
+ /* Pointless to wake CPUs we will not run on */ + if (!CPU_ISSET(i, &original_cpumask)) + continue; + CPU_ZERO(&cpumask); CPU_SET(i, &cpumask);
sched_setaffinity(0, sizeof(cpumask), &cpumask); }
+ /* Enable all the CPUs of the original mask */ + sched_setaffinity(0, sizeof(original_cpumask), &original_cpumask); + return 0; }
Fix lines exceeding 80 chars, so fulfill the conventional coding style of the opensource projects.
Signed-off-by: Daniel Lezcano daniel.lezcano@linaro.org --- idlestat.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/idlestat.c b/idlestat.c index 2a0c549..30860db 100644 --- a/idlestat.c +++ b/idlestat.c @@ -1162,7 +1162,8 @@ static int idlestat_file_for_each_line(const char *path, void *data, f = fopen(path, "r");
if (!f) { - fprintf(stderr, "%s: failed to open '%s': %m\n", __func__, path); + fprintf(stderr, "%s: failed to open '%s': %m\n", + __func__, path); return -1; }
@@ -1189,7 +1190,8 @@ static int idlestat_store(const char *path) f = fopen(path, "w+");
if (!f) { - fprintf(stderr, "%s: failed to open '%s': %m\n", __func__, path); + fprintf(stderr, "%s: failed to open '%s': %m\n", + __func__, path); return -1; }
@@ -1320,7 +1322,8 @@ int main(int argc, char *argv[], char *const envp[]) if (args <= 0) return 1;
- /* Tracing requires manipulation of some files only accessible to root */ + /* Tracing requires manipulation of some files only accessible + * to root */ if ((options.mode == TRACE) && getuid()) { fprintf(stderr, "must be root to run traces\n"); return -1; @@ -1337,7 +1340,8 @@ int main(int argc, char *argv[], char *const envp[])
/* Stop tracing (just in case) */ if (idlestat_trace_enable(false)) { - fprintf(stderr, "idlestat requires kernel Ftrace and debugfs mounted on /sys/kernel/debug\n"); + fprintf(stderr, "idlestat requires kernel Ftrace and " + "debugfs mounted on /sys/kernel/debug\n"); return -1; }
This function is pointless. It was added initially for debugging purpose, remove it.
Signed-off-by: Daniel Lezcano daniel.lezcano@linaro.org --- idlestat.c | 16 ++-------------- idlestat.h | 1 - 2 files changed, 2 insertions(+), 15 deletions(-)
diff --git a/idlestat.c b/idlestat.c index 30860db..abbb787 100644 --- a/idlestat.c +++ b/idlestat.c @@ -1042,11 +1042,11 @@ static void help(const char *cmd) fprintf(stderr, "\nUsage:\nTrace mode: %s --trace -f|--trace-file <filename>" " -t|--duration <seconds> " - "[-z|--dump] [-i|--iterations <number>] [-d|--debug]\n", + "[-z|--dump] [-i|--iterations <number>]\n", basename(cmd)); fprintf(stderr, "\nReporting mode: %s --import -f|--trace-file <filename>" - "[-z|--dump] [-i|--iterations <number>] [-d|--debug]\n", + "[-z|--dump] [-i|--iterations <number>]\n", basename(cmd)); fprintf(stderr, "\nExample:\n%s --trace -f /tmp/myoutput -t 30\n", basename(cmd)); @@ -1064,7 +1064,6 @@ int getoptions(int argc, char *argv[], struct program_options *options) struct option long_options[] = { { "trace", no_argument, &options->mode, TRACE }, { "import", no_argument, &options->mode, IMPORT }, - { "debug", no_argument, NULL, 'd' }, { "trace-file", required_argument, NULL, 'f' }, { "help", no_argument, NULL, 'h' }, { "iterations", required_argument, NULL, 'i' }, @@ -1089,9 +1088,6 @@ int getoptions(int argc, char *argv[], struct program_options *options) break;
switch (c) { - case 'd': - options->debug = true; - break; case 'f': options->filename = optarg; break; @@ -1315,7 +1311,6 @@ int main(int argc, char *argv[], char *const envp[]) struct cpuidle_datas *datas; struct cpuidle_datas *cluster; struct program_options options; - struct rusage rusage; int args;
args = getoptions(argc, argv, &options); @@ -1420,13 +1415,6 @@ int main(int argc, char *argv[], char *const envp[]) free(cluster); }
- /* Computation could be heavy, let's give some information - * about the memory consumption */ - if (options.debug) { - getrusage(RUSAGE_SELF, &rusage); - printf("max rss : %ld kB\n", rusage.ru_maxrss); - } - release_cpu_topo_cstates(); release_cpu_topo_info(); release_pstate_info(datas->pstates, datas->nrcpus); diff --git a/idlestat.h b/idlestat.h index 4397984..3317a8f 100644 --- a/idlestat.h +++ b/idlestat.h @@ -127,7 +127,6 @@ enum formats { };
struct program_options { - bool debug; bool dump; int iterations; int mode;
The quilt tool is still widely used in conjunction with git, it needs a specific directory, by convention 'patches' to store the patches for the serie.
Add this directory in the .gitignore file, so we are no longer annoyed by this directory when we check the status of git reporting it as an untracked file.
Signed-off-by: Daniel Lezcano daniel.lezcano@linaro.org --- .gitignore | 1 + 1 file changed, 1 insertion(+)
diff --git a/.gitignore b/.gitignore index 968abde..4ee98b8 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,7 @@ *.orig *~ #*# +patches
# # Top-level files
This patch adds the '-v' option in the command line.
The level of verbosity is choosen by the number of time the -v occurs.
no -v option : verbosity 0 -v : verbosity 1 -vv : verbosity 2 -vvv : verbosity 3 etc ...
Note this option is not yet used in the code.
Signed-off-by: Daniel Lezcano daniel.lezcano@linaro.org --- idlestat.c | 6 +++++- idlestat.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/idlestat.c b/idlestat.c index abbb787..8138e35 100644 --- a/idlestat.c +++ b/idlestat.c @@ -1070,6 +1070,7 @@ int getoptions(int argc, char *argv[], struct program_options *options) { "duration", required_argument, NULL, 't' }, { "version", no_argument, NULL, 'V' }, { "dump", no_argument, NULL, 'z' }, + { "verbose", no_argument, NULL, 'v' }, { 0, 0, 0, 0 } }; int c; @@ -1082,7 +1083,7 @@ int getoptions(int argc, char *argv[], struct program_options *options)
int optindex = 0;
- c = getopt_long(argc, argv, ":df:hi:t:Vz", + c = getopt_long(argc, argv, ":df:hi:t:Vvz", long_options, &optindex); if (c == -1) break; @@ -1108,6 +1109,9 @@ int getoptions(int argc, char *argv[], struct program_options *options) case 'z': options->dump = true; break; + case 'v': + options->verbose++; + break; case 0: /* getopt_long() set a variable, just keep going */ break; case ':': /* missing option argument */ diff --git a/idlestat.h b/idlestat.h index 3317a8f..f874bb8 100644 --- a/idlestat.h +++ b/idlestat.h @@ -133,6 +133,7 @@ struct program_options { int format; unsigned int duration; char *filename; + int verbose; };
These options are pointless and not interesting. Removing them.
Signed-off-by: Daniel Lezcano daniel.lezcano@linaro.org --- idlestat.c | 72 ++++++++++-------------------------------------------------- idlestat.h | 2 -- topology.c | 12 +++++----- topology.h | 5 ++--- 4 files changed, 19 insertions(+), 72 deletions(-)
diff --git a/idlestat.c b/idlestat.c index 8138e35..3e5b4bc 100644 --- a/idlestat.c +++ b/idlestat.c @@ -68,34 +68,8 @@ static inline void *ptrerror(const char *str) return NULL; }
-static int dump_states(struct cpuidle_cstates *cstates, - struct cpufreq_pstates *pstates, - int count, char *str) -{ - int j, k, kmax; - struct cpuidle_cstate *cstate; - - for (j = 0; j < cstates->cstate_max + 1; j++) { - cstate = &cstates->cstate[j]; - - kmax = count > 0 ? MIN(count, cstate->nrdata) : cstate->nrdata; - for (k = 0; k < kmax; k++) { - printf("%lf: enter %s\n", cstate->data[k].begin, - cstate->name); - printf("%lf: exit %s\n", cstate->data[k].end, - cstate->name); - } - - /* add a break */ - printf("\n"); - } - - return 0; -} - static int display_states(struct cpuidle_cstates *cstates, - struct cpufreq_pstates *pstates, - int count, char *str) + struct cpufreq_pstates *pstates, char *str) { int j;
@@ -171,9 +145,9 @@ static int display_states(struct cpuidle_cstates *cstates, return 0; }
-int dump_all_data(struct cpuidle_datas *datas, int count, - int (*dump)(struct cpuidle_cstates *, - struct cpufreq_pstates *, int, char *)) +int dump_all_data(struct cpuidle_datas *datas, + int (*dump)(struct cpuidle_cstates *, + struct cpufreq_pstates *, char *)) { int i = 0, nrcpus = datas->nrcpus; struct cpuidle_cstates *cstates; @@ -188,7 +162,7 @@ int dump_all_data(struct cpuidle_datas *datas, int count, else sprintf(buffer, "cpu%d", i);
- dump(cstates, pstates, count, buffer); + dump(cstates, pstates, buffer);
i++;
@@ -1041,12 +1015,10 @@ static void help(const char *cmd) { fprintf(stderr, "\nUsage:\nTrace mode: %s --trace -f|--trace-file <filename>" - " -t|--duration <seconds> " - "[-z|--dump] [-i|--iterations <number>]\n", + " -t|--duration <seconds> ", basename(cmd)); fprintf(stderr, - "\nReporting mode: %s --import -f|--trace-file <filename>" - "[-z|--dump] [-i|--iterations <number>]\n", + "\nReporting mode: %s --import -f|--trace-file <filename>", basename(cmd)); fprintf(stderr, "\nExample:\n%s --trace -f /tmp/myoutput -t 30\n", basename(cmd)); @@ -1066,10 +1038,8 @@ int getoptions(int argc, char *argv[], struct program_options *options) { "import", no_argument, &options->mode, IMPORT }, { "trace-file", required_argument, NULL, 'f' }, { "help", no_argument, NULL, 'h' }, - { "iterations", required_argument, NULL, 'i' }, { "duration", required_argument, NULL, 't' }, { "version", no_argument, NULL, 'V' }, - { "dump", no_argument, NULL, 'z' }, { "verbose", no_argument, NULL, 'v' }, { 0, 0, 0, 0 } }; @@ -1083,7 +1053,7 @@ int getoptions(int argc, char *argv[], struct program_options *options)
int optindex = 0;
- c = getopt_long(argc, argv, ":df:hi:t:Vvz", + c = getopt_long(argc, argv, ":df:ht:Vv", long_options, &optindex); if (c == -1) break; @@ -1096,9 +1066,6 @@ int getoptions(int argc, char *argv[], struct program_options *options) help(argv[0]); exit(0); break; - case 'i': - options->iterations = atoi(optarg); - break; case 't': options->duration = atoi(optarg); break; @@ -1106,9 +1073,6 @@ int getoptions(int argc, char *argv[], struct program_options *options) version(argv[0]); exit(0); break; - case 'z': - options->dump = true; - break; case 'v': options->verbose++; break; @@ -1127,9 +1091,6 @@ int getoptions(int argc, char *argv[], struct program_options *options) } }
- if (options->iterations < 0) - fprintf(stderr, "dump values must be a positive value\n"); - if (options->mode < 0) { fprintf(stderr, "select a mode: --trace or --import\n"); return -1; @@ -1396,24 +1357,15 @@ int main(int argc, char *argv[], char *const envp[]) * the same cluster */ if (0 == establish_idledata_to_topo(datas)) { - if (options.dump > 0) - dump_cpu_topo_info(options.iterations, dump_states); - else - dump_cpu_topo_info(options.iterations, display_states); + dump_cpu_topo_info(display_states); } else { cluster = cluster_data(datas); if (!cluster) return 1;
- if (options.dump > 0) { - dump_all_data(datas, options.iterations, dump_states); - dump_all_data(cluster, options.iterations, dump_states); - } else { - dump_all_data(datas, - options.iterations, display_states); - dump_all_data(cluster, - options.iterations, display_states); - } + dump_all_data(datas, display_states); + + dump_all_data(cluster, display_states);
free(cluster->cstates); free(cluster); diff --git a/idlestat.h b/idlestat.h index f874bb8..31df587 100644 --- a/idlestat.h +++ b/idlestat.h @@ -127,8 +127,6 @@ enum formats { };
struct program_options { - bool dump; - int iterations; int mode; int format; unsigned int duration; diff --git a/topology.c b/topology.c index a088074..dc71b61 100644 --- a/topology.c +++ b/topology.c @@ -449,9 +449,8 @@ int establish_idledata_to_topo(struct cpuidle_datas *datas) return 0; }
-int dump_cpu_topo_info(int count, - int (*dump)(struct cpuidle_cstates *, struct cpufreq_pstates *, - int, char *)) +int dump_cpu_topo_info(int (*dump)(struct cpuidle_cstates *, + struct cpufreq_pstates *, char *)) { struct cpu_physical *s_phy; struct cpu_core *s_core; @@ -462,12 +461,12 @@ int dump_cpu_topo_info(int count, list_for_each_entry(s_phy, &g_cpu_topo_list.physical_head, list_physical) { sprintf(tmp, "cluster%c", s_phy->physical_id + 'A'); - dump(s_phy->cstates, NULL, count, tmp); + dump(s_phy->cstates, NULL, tmp);
list_for_each_entry(s_core, &s_phy->core_head, list_core) { if (s_core->is_ht) { sprintf(tmp, " core%d", s_core->core_id); - dump(s_core->cstates, NULL, count, tmp); + dump(s_core->cstates, NULL, tmp);
tab = 1; } else { @@ -478,8 +477,7 @@ int dump_cpu_topo_info(int count, list_cpu) { sprintf(tmp, "%*ccpu%d", (tab + 1) * 2, 0x20, s_cpu->cpu_id); - dump(s_cpu->cstates, s_cpu->pstates, - count, tmp); + dump(s_cpu->cstates, s_cpu->pstates, tmp); } } } diff --git a/topology.h b/topology.h index 7c43e0f..9e8eff8 100644 --- a/topology.h +++ b/topology.h @@ -66,9 +66,8 @@ extern int release_cpu_topo_info(void); extern int output_cpu_topo_info(FILE *f); extern int establish_idledata_to_topo(struct cpuidle_datas *datas); extern int release_cpu_topo_cstates(void); -extern int dump_cpu_topo_info(int count, - int (*dump)(struct cpuidle_cstates *, struct cpufreq_pstates *, - int, char *)); +extern int dump_cpu_topo_info(int (*dump)(struct cpuidle_cstates *, + struct cpufreq_pstates *, char *));
extern struct cpuidle_cstates *core_cluster_data(struct cpu_core *s_core);
Make some code separations to prepare the code for cleanup.
Signed-off-by: Daniel Lezcano daniel.lezcano@linaro.org --- idlestat.c | 84 ++++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 54 insertions(+), 30 deletions(-)
diff --git a/idlestat.c b/idlestat.c index 3e5b4bc..83655bd 100644 --- a/idlestat.c +++ b/idlestat.c @@ -68,10 +68,9 @@ static inline void *ptrerror(const char *str) return NULL; }
-static int display_states(struct cpuidle_cstates *cstates, - struct cpufreq_pstates *pstates, char *str) +static int display_cstates(struct cpuidle_cstates *cstates, char *str) { - int j; + int i;
/* If the first C-state does not have target_residency * chances are pretty high that we dont have it for any node. @@ -83,8 +82,8 @@ static int display_states(struct cpuidle_cstates *cstates, printf("%s@state hits\t\ttotal(us)\tavg(us)\tmin(us)\tmax(us)\n", str);
- for (j = 0; j < cstates->cstate_max + 1; j++) { - struct cpuidle_cstate *c = &cstates->cstate[j]; + for (i = 0; i < cstates->cstate_max + 1; i++) { + struct cpuidle_cstate *c = &cstates->cstate[i];
if (c->nrdata == 0) /* nothing to report for this state */ @@ -111,40 +110,65 @@ static int display_states(struct cpuidle_cstates *cstates, } }
- if (pstates) { - for (j = 0; j < pstates->max; j++) { - struct cpufreq_pstate *p = &(pstates->pstate[j]); + return 0; +}
- if (p->count == 0) - /* nothing to report for this state */ - continue; +static int display_pstates(struct cpufreq_pstates *pstates, char *str) +{ + int i;
- printf("%*c %-10d\t%d\t%15.2lf\t%15.2lf\t%.2lf\t%.2lf\n", - (int)strlen(str), ' ', - p->freq/1000, p->count, p->duration, - p->avg_time, - (p->min_time == DBL_MAX ? 0. : p->min_time), - p->max_time); - } + for (i = 0; i < pstates->max; i++) { + + struct cpufreq_pstate *p = &(pstates->pstate[i]); + + if (p->count == 0) + /* nothing to report for this state */ + continue; + + printf("%*c %-10d\t%d\t%15.2lf\t%15.2lf\t%.2lf\t%.2lf\n", + (int)strlen(str), ' ', + p->freq/1000, p->count, p->duration, + p->avg_time, + (p->min_time == DBL_MAX ? 0. : p->min_time), + p->max_time); }
- if (strstr(str, IRQ_WAKEUP_UNIT_NAME)) { - struct wakeup_info *wakeinfo = &cstates->wakeinfo; - struct wakeup_irq *irqinfo = wakeinfo->irqinfo; - printf("%s wakeups \tname \t\tcount\tunexpected\n", str); - for (j = 0; j < wakeinfo->nrdata; j++, irqinfo++) { - printf("%*c %s%03d\t%-15.15s\t%d\t%d\n", (int)strlen(str), - ' ', - (irqinfo->irq_type < IRQ_TYPE_MAX) ? - irq_type_name[irqinfo->irq_type] : "NULL", - irqinfo->id, irqinfo->name, irqinfo->count, - irqinfo->not_predicted); - } + return 0; +} + +static int display_wakeup_sources(struct wakeup_info *wakeinfo, char *str) +{ + int i; + struct wakeup_irq *irqinfo = wakeinfo->irqinfo; + + printf("%s wakeups \tname \t\tcount\tunexpected\n", str); + for (i = 0; i < wakeinfo->nrdata; i++, irqinfo++) { + printf("%*c %s%03d\t%-15.15s\t%d\t%d\n", (int)strlen(str), + ' ', + (irqinfo->irq_type < IRQ_TYPE_MAX) ? + irq_type_name[irqinfo->irq_type] : "NULL", + irqinfo->id, irqinfo->name, irqinfo->count, + irqinfo->not_predicted); }
return 0; }
+static int display_states(struct cpuidle_cstates *cstates, + struct cpufreq_pstates *pstates, char *str) +{ + if (cstates) + display_cstates(cstates, str); + + if (pstates) + display_pstates(pstates, str); + + if (strstr(str, IRQ_WAKEUP_UNIT_NAME)) + display_wakeup_sources(&cstates->wakeinfo, str); + + return 0; +} + int dump_all_data(struct cpuidle_datas *datas, int (*dump)(struct cpuidle_cstates *, struct cpufreq_pstates *, char *))
We want the output to be always the same even if the prediction accuracy is not possible because we are working on an old kernel.
Signed-off-by: Daniel Lezcano daniel.lezcano@linaro.org --- idlestat.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-)
diff --git a/idlestat.c b/idlestat.c index 83655bd..fc7a31a 100644 --- a/idlestat.c +++ b/idlestat.c @@ -72,15 +72,7 @@ static int display_cstates(struct cpuidle_cstates *cstates, char *str) { int i;
- /* If the first C-state does not have target_residency - * chances are pretty high that we dont have it for any node. - */ - if (cstates->cstate[0].target_residency >= 0) - printf("%s@state hits\tover\tunder\t\ttotal(us)\tavg(us)\tmin(us)\tmax(us)\n", - str); - else - printf("%s@state hits\t\ttotal(us)\tavg(us)\tmin(us)\tmax(us)\n", - str); + printf("%s@state hits\tover\tunder\t\ttotal(us)\tavg(us)\tmin(us)\tmax(us)\n", str);
for (i = 0; i < cstates->cstate_max + 1; i++) { struct cpuidle_cstate *c = &cstates->cstate[i];
The output is now in the form of:
---------------------------------------------------------------- | P-state | min | max | avg | total | hits | ---------------------------------------------------------------- | cpu0 | ---------------------------------------------------------------- | 2.90GHz | 0us | 37.93ms | 383us | 163.89ms | 428 | | 2.20GHz | 11us | 1.69ms | 160us | 3.83ms | 24 | | 1.80GHz | 8us | 2.72ms | 106us | 6.37ms | 60 | | 1.30GHz | 1us | 4.51ms | 1.13ms | 5.65ms | 5 | | 1.20GHz | 0us | 17.75ms | 292us | 3.55s | 12148 | ---------------------------------------------------------------- | cpu1 | ---------------------------------------------------------------- | 2.90GHz | 0us | 5.59ms | 447us | 118.06ms | 264 | | 1.20GHz | 0us | 13.83ms | 656us | 3.05s | 4649 | ---------------------------------------------------------------- | cpu2 | ---------------------------------------------------------------- | 2.90GHz | 1us | 118.77ms | 1.45ms | 326.93ms | 225 | | 2.80GHz | 24us | 1.34ms | 263us | 5.26ms | 20 | | 2.50GHz | 11us | 2.49ms | 327us | 9.49ms | 29 | | 1.20GHz | 1us | 21.24ms | 404us | 3.99s | 9891 | ---------------------------------------------------------------- | cpu3 | ---------------------------------------------------------------- | 2.90GHz | 3us | 21.07ms | 720us | 127.51ms | 177 | | 1.60GHz | 3us | 5.14ms | 120us | 12.03ms | 100 | | 1.20GHz | 1us | 18.07ms | 660us | 2.76s | 4190 | ----------------------------------------------------------------
-------------------------------------------------------------------------------- | C-state | min | max | avg | total | hits | over | under | -------------------------------------------------------------------------------- | clusterA | -------------------------------------------------------------------------------- | C1-IVB | 0us | 1.24ms | 1.24ms | 1.24ms | 1 | 0 | 0 | | C7-IVB | 0us | 10.07ms | 1.78ms | 19.10s | 10739 | 0 | 0 | -------------------------------------------------------------------------------- | core0 | -------------------------------------------------------------------------------- | C1-IVB | 0us | 2.02ms | 262us | 3.14ms | 12 | 0 | 0 | | C7-IVB | 0us | 15.92ms | 2.09ms | 23.30s | 11163 | 0 | 0 | -------------------------------------------------------------------------------- | cpu0 | -------------------------------------------------------------------------------- | POLL | 3us | 3us | 3us | 3us | 1 | 0 | 0 | | C1-IVB | 0us | 2.95ms | 179us | 162.03ms | 905 | 0 | 0 | | C3-IVB | 1us | 9.07ms | 555us | 192.47ms | 347 | 0 | 0 | | C6-IVB | 6us | 3.84ms | 1.18ms | 40.13ms | 34 | 0 | 0 | | C7-IVB | 1us | 16.35ms | 2.27ms | 25.83s | 11396 | 0 | 0 | -------------------------------------------------------------------------------- | cpu1 | -------------------------------------------------------------------------------- | C1-IVB | 1us | 11.12ms | 173us | 54.09ms | 313 | 0 | 0 | | C3-IVB | 2us | 1.39ms | 399us | 55.81ms | 140 | 0 | 0 | | C6-IVB | 20us | 1.04ms | 517us | 2.07ms | 4 | 0 | 0 | | C7-IVB | 1us | 41.48ms | 5.93ms | 26.67s | 4495 | 0 | 0 | -------------------------------------------------------------------------------- | core1 | -------------------------------------------------------------------------------- | C1-IVB | 0us | 1.25ms | 116us | 4.04ms | 35 | 0 | 0 | | C7-IVB | 0us | 22.25ms | 2.17ms | 22.97s | 10605 | 0 | 0 | -------------------------------------------------------------------------------- | cpu2 | -------------------------------------------------------------------------------- | POLL | 3us | 3us | 3us | 3us | 1 | 0 | 0 | | C1-IVB | 1us | 9.65ms | 265us | 133.88ms | 505 | 0 | 0 | | C3-IVB | 1us | 3.74ms | 440us | 127.48ms | 290 | 0 | 0 | | C6-IVB | 24us | 2.34ms | 1.01ms | 32.32ms | 32 | 0 | 0 | | C7-IVB | 1us | 31.43ms | 2.70ms | 25.33s | 9369 | 0 | 0 | -------------------------------------------------------------------------------- | cpu3 | -------------------------------------------------------------------------------- | POLL | 11us | 11us | 11us | 11us | 1 | 0 | 0 | | C1-IVB | 1us | 4.80ms | 94us | 42.66ms | 455 | 0 | 0 | | C3-IVB | 1us | 2.00ms | 420us | 28.59ms | 68 | 0 | 0 | | C6-IVB | 31us | 1.42ms | 800us | 8.00ms | 10 | 0 | 0 | | C7-IVB | 0us | 98.04ms | 6.92ms | 26.99s | 3899 | 0 | 0 | --------------------------------------------------------------------------------
Signed-off-by: Daniel Lezcano daniel.lezcano@linaro.org --- idlestat.c | 209 +++++++++++++++++++++++++++++++++++++----------------------- topology.c | 27 ++++---- topology.h | 4 +- 3 files changed, 143 insertions(+), 97 deletions(-)
diff --git a/idlestat.c b/idlestat.c index fc7a31a..3fe2af6 100644 --- a/idlestat.c +++ b/idlestat.c @@ -68,11 +68,88 @@ static inline void *ptrerror(const char *str) return NULL; }
-static int display_cstates(struct cpuidle_cstates *cstates, char *str) +static void charrep(char c, int count) { int i; + for (i = 0; i < count; i++) + printf("%c", c); +} + +static void display_cstates_header(void) +{ + charrep('-', 80); + printf("\n"); + + printf("| C-state | min | max | avg | total | hits | over | under |\n"); +} + +static void display_cstates_footer(void) +{ + charrep('-', 80); + printf("\n\n"); +} + +static void display_pstates_header(void) +{ + charrep('-', 64); + printf("\n"); + + printf("| P-state | min | max | avg | total | hits |\n"); +} + +static void display_pstates_footer(void) +{ + charrep('-', 64); + printf("\n\n"); +} + +static void display_cpu_header(char *cpu, int length) +{ + charrep('-', length); + printf("\n"); + + printf("|%*s%*s|\n", (length / 2) - 1, cpu, ((length / 2) - 1), ""); +} + +static void display_factored_time(double time, int align) +{ + char buffer[128]; + + if (time < 1000) { + sprintf(buffer, "%.0lfus", time); + printf("%*s", align, buffer); + } + else if (time < 1000000) { + sprintf(buffer, "%.2lfms", time / 1000.0); + printf("%*s", align, buffer); + } + else { + sprintf(buffer, "%.2lfs", time / 1000000.0); + printf("%*s", align, buffer); + } +} + +static void display_factored_freq(int freq, int align) +{ + char buffer[128]; + + if (freq < 1000) { + sprintf(buffer, "%dHz", freq); + printf("%*s", align, buffer); + } else if (freq < 1000000) { + sprintf(buffer, "%.2fMHz", (float)freq / 1000.0); + printf("%*s", align, buffer); + } else { + sprintf(buffer, "%.2fGHz", (float)freq / 1000000.0); + printf("%*s", align, buffer); + } +}
- printf("%s@state hits\tover\tunder\t\ttotal(us)\tavg(us)\tmin(us)\tmax(us)\n", str); +static int display_cstates(void *arg, char *cpu) +{ + int i; + bool cpu_header = false; + struct cpuidle_cstates *cstates = arg;
for (i = 0; i < cstates->cstate_max + 1; i++) { struct cpuidle_cstate *c = &cstates->cstate[i]; @@ -81,33 +158,37 @@ static int display_cstates(struct cpuidle_cstates *cstates, char *str) /* nothing to report for this state */ continue;
- if (c->target_residency >= 0) { - printf("%*c %-10s%d\t%d\t%d\t%15.2lf\t%15.2lf\t%.2lf\t%.2lf\n", - (int)strlen(str), ' ', - c->name, c->nrdata, - c->premature_wakeup, - c->could_sleep_more, - c->duration, - c->avg_time, - (c->min_time == DBL_MAX ? 0. : c->min_time), - c->max_time); - } else { - printf("%*c %-10s%d\t%15.2lf\t%15.2lf\t%.2lf\t%.2lf\n", - (int)strlen(str), ' ', - c->name, c->nrdata, - c->duration, - c->avg_time, - (c->min_time == DBL_MAX ? 0. : c->min_time), - c->max_time); + if (!cpu_header) { + display_cpu_header(cpu, 80); + cpu_header = true; + charrep('-', 80); + printf("\n"); } + + printf("| %8s | ", c->name); + display_factored_time(c->min_time == DBL_MAX ? 0. : + c->min_time, 8); + printf(" | "); + display_factored_time(c->max_time, 8); + printf(" | "); + display_factored_time(c->avg_time, 8); + printf(" | "); + display_factored_time(c->duration, 8); + printf(" | "); + printf("%5d | %5d | %5d |", c->nrdata, + c->premature_wakeup, c->could_sleep_more); + + printf("\n"); }
return 0; }
-static int display_pstates(struct cpufreq_pstates *pstates, char *str) +static int display_pstates(void *arg, char *cpu) { int i; + bool cpu_header = false; + struct cpufreq_pstates *pstates = arg;
for (i = 0; i < pstates->max; i++) {
@@ -117,12 +198,28 @@ static int display_pstates(struct cpufreq_pstates *pstates, char *str) /* nothing to report for this state */ continue;
- printf("%*c %-10d\t%d\t%15.2lf\t%15.2lf\t%.2lf\t%.2lf\n", - (int)strlen(str), ' ', - p->freq/1000, p->count, p->duration, - p->avg_time, - (p->min_time == DBL_MAX ? 0. : p->min_time), - p->max_time); + if (!cpu_header) { + display_cpu_header(cpu, 64); + cpu_header = true; + charrep('-', 64); + printf("\n"); + } + + printf("| "); + display_factored_freq(p->freq, 8); + printf(" | "); + display_factored_time(p->min_time == DBL_MAX ? 0. : + p->min_time, 8); + printf(" | "); + display_factored_time(p->max_time, 8); + printf(" | "); + display_factored_time(p->avg_time, 8); + printf(" | "); + display_factored_time(p->duration, 8); + printf(" | "); + printf("%5d", p->count); + printf(" | "); + printf("\n"); }
return 0; @@ -146,47 +243,6 @@ static int display_wakeup_sources(struct wakeup_info *wakeinfo, char *str) return 0; }
-static int display_states(struct cpuidle_cstates *cstates, - struct cpufreq_pstates *pstates, char *str) -{ - if (cstates) - display_cstates(cstates, str); - - if (pstates) - display_pstates(pstates, str); - - if (strstr(str, IRQ_WAKEUP_UNIT_NAME)) - display_wakeup_sources(&cstates->wakeinfo, str); - - return 0; -} - -int dump_all_data(struct cpuidle_datas *datas, - int (*dump)(struct cpuidle_cstates *, - struct cpufreq_pstates *, char *)) -{ - int i = 0, nrcpus = datas->nrcpus; - struct cpuidle_cstates *cstates; - struct cpufreq_pstates *pstates; - - do { - cstates = &datas->cstates[i]; - pstates = &datas->pstates[i]; - - if (nrcpus == -1) - sprintf(buffer, "cluster"); - else - sprintf(buffer, "cpu%d", i); - - dump(cstates, pstates, buffer); - - i++; - - } while (i < nrcpus && nrcpus != -1); - - return 0; -} - static struct cpuidle_data *intersection(struct cpuidle_data *data1, struct cpuidle_data *data2) { @@ -1290,7 +1346,6 @@ static int execute(int argc, char *argv[], char *const envp[], int main(int argc, char *argv[], char *const envp[]) { struct cpuidle_datas *datas; - struct cpuidle_datas *cluster; struct program_options options; int args;
@@ -1373,18 +1428,14 @@ int main(int argc, char *argv[], char *const envp[]) * the same cluster */ if (0 == establish_idledata_to_topo(datas)) { - dump_cpu_topo_info(display_states); - } else { - cluster = cluster_data(datas); - if (!cluster) - return 1; - - dump_all_data(datas, display_states);
- dump_all_data(cluster, display_states); + display_cstates_header(); + dump_cpu_topo_info(display_cstates, 0); + display_cstates_footer();
- free(cluster->cstates); - free(cluster); + display_pstates_header(); + dump_cpu_topo_info(display_pstates, 1); + display_pstates_footer(); }
release_cpu_topo_cstates(); diff --git a/topology.c b/topology.c index dc71b61..5bf88a1 100644 --- a/topology.c +++ b/topology.c @@ -449,35 +449,32 @@ int establish_idledata_to_topo(struct cpuidle_datas *datas) return 0; }
-int dump_cpu_topo_info(int (*dump)(struct cpuidle_cstates *, - struct cpufreq_pstates *, char *)) +int dump_cpu_topo_info(int (*dump)(void *, char *), int pstate) { struct cpu_physical *s_phy; struct cpu_core *s_core; struct cpu_cpu *s_cpu; - char tmp[30]; - int tab = 0; + char tmp[30];
list_for_each_entry(s_phy, &g_cpu_topo_list.physical_head, list_physical) { + sprintf(tmp, "cluster%c", s_phy->physical_id + 'A'); - dump(s_phy->cstates, NULL, tmp);
- list_for_each_entry(s_core, &s_phy->core_head, list_core) { - if (s_core->is_ht) { - sprintf(tmp, " core%d", s_core->core_id); - dump(s_core->cstates, NULL, tmp); + if (!pstate) + dump(s_phy->cstates, tmp);
- tab = 1; - } else { - tab = 0; + list_for_each_entry(s_core, &s_phy->core_head, list_core) { + if (s_core->is_ht && !pstate) { + sprintf(tmp, "core%d", s_core->core_id); + dump(s_core->cstates, tmp); }
list_for_each_entry(s_cpu, &s_core->cpu_head, list_cpu) { - sprintf(tmp, "%*ccpu%d", (tab + 1) * 2, 0x20, - s_cpu->cpu_id); - dump(s_cpu->cstates, s_cpu->pstates, tmp); + sprintf(tmp, "cpu%d", s_cpu->cpu_id); + dump(pstate ? s_cpu->pstates : + s_cpu->cstates, tmp); } } } diff --git a/topology.h b/topology.h index 9e8eff8..bf05201 100644 --- a/topology.h +++ b/topology.h @@ -66,9 +66,7 @@ extern int release_cpu_topo_info(void); extern int output_cpu_topo_info(FILE *f); extern int establish_idledata_to_topo(struct cpuidle_datas *datas); extern int release_cpu_topo_cstates(void); -extern int dump_cpu_topo_info(int (*dump)(struct cpuidle_cstates *, - struct cpufreq_pstates *, char *)); - +extern int dump_cpu_topo_info(int (*dump)(void *, char *), int pstate);
extern struct cpuidle_cstates *core_cluster_data(struct cpu_core *s_core); extern struct cpuidle_cstates *
Add the options to select c-states, p-states and wakeup output.
--idle, -c : show c-states --frequency, -p : show p-states --wakeup, -w : show wakeup sources
Signed-off-by: Daniel Lezcano daniel.lezcano@linaro.org --- README | 7 ++++++- idlestat.c | 35 +++++++++++++++++++++++++++-------- idlestat.h | 4 ++++ 3 files changed, 37 insertions(+), 9 deletions(-)
diff --git a/README b/README index b9edf4f..dccce36 100644 --- a/README +++ b/README @@ -38,9 +38,14 @@ Example Usage Trace mode: sudo ./idlestat --trace -f /tmp/mytrace -t 10
-Reporing mode (/tmp/mytrace already contains traces): +Reporting mode (/tmp/mytrace already contains traces): sudo ./idlestat --import -f /tmp/mytrace
Trace mode with workload (e.g. sleep, cyclictest): sudo ./idlestat --trace -f /tmp/mytrace -t 10 -- /bin/sleep 10 sudo ./idlestat --trace -f /tmp/myoutput -t 10 -- cyclictest -t 4 -i 2000 -q -D 5 + +Selective trace output +sudo ./idlestate --import -f /tmp/mytrace -w +sudo ./idlestate --import -f /tmp/mytrace -c -p +sudo ./idlestate --import -f /tmp/mytrace -p -w \ No newline at end of file diff --git a/idlestat.c b/idlestat.c index 3fe2af6..94e570a 100644 --- a/idlestat.c +++ b/idlestat.c @@ -1087,7 +1087,7 @@ static void help(const char *cmd) { fprintf(stderr, "\nUsage:\nTrace mode: %s --trace -f|--trace-file <filename>" - " -t|--duration <seconds> ", + " -t|--duration <seconds> -c|--idle -p|--frequency -w|--wakeup", basename(cmd)); fprintf(stderr, "\nReporting mode: %s --import -f|--trace-file <filename>", @@ -1113,6 +1113,9 @@ int getoptions(int argc, char *argv[], struct program_options *options) { "duration", required_argument, NULL, 't' }, { "version", no_argument, NULL, 'V' }, { "verbose", no_argument, NULL, 'v' }, + { "idle", no_argument, NULL, 'c' }, + { "frequency", no_argument, NULL, 'p' }, + { "wakeup", no_argument, NULL, 'w' }, { 0, 0, 0, 0 } }; int c; @@ -1125,7 +1128,7 @@ int getoptions(int argc, char *argv[], struct program_options *options)
int optindex = 0;
- c = getopt_long(argc, argv, ":df:ht:Vv", + c = getopt_long(argc, argv, ":df:ht:cpwVv", long_options, &optindex); if (c == -1) break; @@ -1141,6 +1144,15 @@ int getoptions(int argc, char *argv[], struct program_options *options) case 't': options->duration = atoi(optarg); break; + case 'c': + options->display |= IDLE_DISPLAY; + break; + case 'p': + options->display |= FREQUENCY_DISPLAY; + break; + case 'w': + options->display |= WAKEUP_DISPLAY; + break; case 'V': version(argv[0]); exit(0); @@ -1180,6 +1192,9 @@ int getoptions(int argc, char *argv[], struct program_options *options) } }
+ if (options->display == 0) + options->display = IDLE_DISPLAY; + return optind; }
@@ -1429,13 +1444,17 @@ int main(int argc, char *argv[], char *const envp[]) */ if (0 == establish_idledata_to_topo(datas)) {
- display_cstates_header(); - dump_cpu_topo_info(display_cstates, 0); - display_cstates_footer(); + if (options.display & IDLE_DISPLAY) { + display_cstates_header(); + dump_cpu_topo_info(display_cstates, 0); + display_cstates_footer(); + }
- display_pstates_header(); - dump_cpu_topo_info(display_pstates, 1); - display_pstates_footer(); + if (options.display & FREQUENCY_DISPLAY) { + display_pstates_header(); + dump_cpu_topo_info(display_pstates, 1); + display_pstates_footer(); + } }
release_cpu_topo_cstates(); diff --git a/idlestat.h b/idlestat.h index 31df587..1d5f961 100644 --- a/idlestat.h +++ b/idlestat.h @@ -129,10 +129,14 @@ enum formats { struct program_options { int mode; int format; + int display; unsigned int duration; char *filename; int verbose; };
+#define IDLE_DISPLAY 0x1 +#define FREQUENCY_DISPLAY 0x2 +#define WAKEUP_DISPLAY 0x4
#endif
The display functions are tied together in the code. Split this, so we can choose each subsystem to display separately.
Signed-off-by: Daniel Lezcano daniel.lezcano@linaro.org --- idlestat.c | 102 ++++++++++++++++++++++++++++++++++++++---------------------- topology.c | 11 ++++--- 2 files changed, 71 insertions(+), 42 deletions(-)
diff --git a/idlestat.c b/idlestat.c index 94e570a..77f6d0a 100644 --- a/idlestat.c +++ b/idlestat.c @@ -75,34 +75,6 @@ static void charrep(char c, int count) printf("%c", c); }
-static void display_cstates_header(void) -{ - charrep('-', 80); - printf("\n"); - - printf("| C-state | min | max | avg | total | hits | over | under |\n"); -} - -static void display_cstates_footer(void) -{ - charrep('-', 80); - printf("\n\n"); -} - -static void display_pstates_header(void) -{ - charrep('-', 64); - printf("\n"); - - printf("| P-state | min | max | avg | total | hits |\n"); -} - -static void display_pstates_footer(void) -{ - charrep('-', 64); - printf("\n\n"); -} - static void display_cpu_header(char *cpu, int length) { charrep('-', length); @@ -145,6 +117,20 @@ static void display_factored_freq(int freq, int align) } }
+static void display_cstates_header(void) +{ + charrep('-', 80); + printf("\n"); + + printf("| C-state | min | max | avg | total | hits | over | under |\n"); +} + +static void display_cstates_footer(void) +{ + charrep('-', 80); + printf("\n\n"); +} + static int display_cstates(void *arg, char *cpu) { int i; @@ -184,6 +170,20 @@ static int display_cstates(void *arg, char *cpu) return 0; }
+static void display_pstates_header(void) +{ + charrep('-', 64); + printf("\n"); + + printf("| P-state | min | max | avg | total | hits |\n"); +} + +static void display_pstates_footer(void) +{ + charrep('-', 64); + printf("\n\n"); +} + static int display_pstates(void *arg, char *cpu) { int i; @@ -225,19 +225,41 @@ static int display_pstates(void *arg, char *cpu) return 0; }
-static int display_wakeup_sources(struct wakeup_info *wakeinfo, char *str) +static void display_wakeup_header(void) +{ + charrep('-', 44); + printf("\n"); + + printf("| Wakeup | # | Name | Count |\n"); +} + +static void display_wakeup_footer(void) +{ + charrep('-', 44); + printf("\n\n"); +} + +static int display_wakeup(void *arg, char *cpu) { int i; + bool cpu_header = false; + struct cpuidle_cstates *cstates = arg; + struct wakeup_info *wakeinfo = &cstates->wakeinfo; struct wakeup_irq *irqinfo = wakeinfo->irqinfo;
- printf("%s wakeups \tname \t\tcount\tunexpected\n", str); for (i = 0; i < wakeinfo->nrdata; i++, irqinfo++) { - printf("%*c %s%03d\t%-15.15s\t%d\t%d\n", (int)strlen(str), - ' ', + + if (!cpu_header) { + display_cpu_header(cpu, 44); + cpu_header = true; + charrep('-', 44); + printf("\n"); + } + + printf("| %-6s | %-3d | %15.15s | %7d |\n", (irqinfo->irq_type < IRQ_TYPE_MAX) ? - irq_type_name[irqinfo->irq_type] : "NULL", - irqinfo->id, irqinfo->name, irqinfo->count, - irqinfo->not_predicted); + irq_type_name[irqinfo->irq_type] : "???", + irqinfo->id, irqinfo->name, irqinfo->count); }
return 0; @@ -1446,15 +1468,21 @@ int main(int argc, char *argv[], char *const envp[])
if (options.display & IDLE_DISPLAY) { display_cstates_header(); - dump_cpu_topo_info(display_cstates, 0); + dump_cpu_topo_info(display_cstates, 1); display_cstates_footer(); }
if (options.display & FREQUENCY_DISPLAY) { display_pstates_header(); - dump_cpu_topo_info(display_pstates, 1); + dump_cpu_topo_info(display_pstates, 0); display_pstates_footer(); } + + if (options.display & WAKEUP_DISPLAY) { + display_wakeup_header(); + dump_cpu_topo_info(display_wakeup, 1); + display_wakeup_footer(); + } }
release_cpu_topo_cstates(); diff --git a/topology.c b/topology.c index 5bf88a1..00c1fe1 100644 --- a/topology.c +++ b/topology.c @@ -449,7 +449,7 @@ int establish_idledata_to_topo(struct cpuidle_datas *datas) return 0; }
-int dump_cpu_topo_info(int (*dump)(void *, char *), int pstate) +int dump_cpu_topo_info(int (*dump)(void *, char *), int cstate) { struct cpu_physical *s_phy; struct cpu_core *s_core; @@ -461,11 +461,11 @@ int dump_cpu_topo_info(int (*dump)(void *, char *), int pstate)
sprintf(tmp, "cluster%c", s_phy->physical_id + 'A');
- if (!pstate) + if (cstate) dump(s_phy->cstates, tmp);
list_for_each_entry(s_core, &s_phy->core_head, list_core) { - if (s_core->is_ht && !pstate) { + if (s_core->is_ht && cstate) { sprintf(tmp, "core%d", s_core->core_id); dump(s_core->cstates, tmp); } @@ -473,8 +473,9 @@ int dump_cpu_topo_info(int (*dump)(void *, char *), int pstate) list_for_each_entry(s_cpu, &s_core->cpu_head, list_cpu) { sprintf(tmp, "cpu%d", s_cpu->cpu_id); - dump(pstate ? s_cpu->pstates : - s_cpu->cstates, tmp); + dump(cstate ? + (void *)s_cpu->cstates : + (void *)s_cpu->pstates, tmp); } } }
In case the application is killed by the timeout and it handles the SIGTERM, it may return an error, thus idlestat won't display the result.
Ignore the return code of the application.
Signed-off-by: Daniel Lezcano daniel.lezcano@linaro.org --- idlestat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/idlestat.c b/idlestat.c index 77f6d0a..a0ef2dd 100644 --- a/idlestat.c +++ b/idlestat.c @@ -1364,7 +1364,7 @@ static int execute(int argc, char *argv[], char *const envp[], goto again; }
- if (WIFEXITED(status) && !WEXITSTATUS(status)) { + if (WIFEXITED(status)) { /* * Cancel the timer in case the program * finished before the timeout