Currently the serial terminal connected to the boards running idlestat are restricted to be at least 80 characters wide to output the report. Otherwise idlestat quits with message "The terminal must be at least 80 columns wide".
Fix it by adding a "-o" option to save report output to a file.
Signed-off-by: Pi-Cheng Chen pi-cheng.chen@linaro.org --- idlestat.c | 136 ++++++++++++++++++++++++++++++++++++++++--------------------- idlestat.h | 1 + 2 files changed, 90 insertions(+), 47 deletions(-)
diff --git a/idlestat.c b/idlestat.c index bba8951..fb0ae8f 100644 --- a/idlestat.c +++ b/idlestat.c @@ -51,6 +51,7 @@ #define USEC_PER_SEC 1000000
static char buffer[BUFSIZE]; +static FILE *output;
static inline int error(const char *str) { @@ -68,19 +69,40 @@ static void charrep(char c, int count) { int i; for (i = 0; i < count; i++) - printf("%c", c); + fprintf(output, "%c", c); +} + +static int open_report_file(const char *path) +{ + if (path) { + output = fopen(path, "w+"); + + if (!output) { + fprintf(stderr, "%s: failed to open '%s'\n", __func__, path); + return -1; + } + } else + output = stdout; + + return 0; +} + +static void close_report_file(void) +{ + if (output != stdout) + fclose(output); }
static void display_cpu_header(char *cpu, int length) { charrep('-', length); - printf("\n"); + fprintf(output, "\n");
if (strstr(cpu, "cluster")) - printf("| %-*s |\n", length - 4, cpu); + fprintf(output, "| %-*s |\n", length - 4, cpu); else if (strstr(cpu, "core")) - printf("| %-*s |\n", length - 9, cpu); - else printf("| %-*s |\n", length - 16, cpu); + fprintf(output, "| %-*s |\n", length - 9, cpu); + else fprintf(output, "| %-*s |\n", length - 16, cpu); }
static void display_factored_time(double time, int align) @@ -89,15 +111,15 @@ static void display_factored_time(double time, int align)
if (time < 1000) { sprintf(buffer, "%.0lfus", time); - printf("%*s", align, buffer); + fprintf(output, "%*s", align, buffer); } else if (time < 1000000) { sprintf(buffer, "%.2lfms", time / 1000.0); - printf("%*s", align, buffer); + fprintf(output, "%*s", align, buffer); } else { sprintf(buffer, "%.2lfs", time / 1000000.0); - printf("%*s", align, buffer); + fprintf(output, "%*s", align, buffer); } }
@@ -107,28 +129,29 @@ static void display_factored_freq(int freq, int align)
if (freq < 1000) { sprintf(buffer, "%dHz", freq); - printf("%*s", align, buffer); + fprintf(output, "%*s", align, buffer); } else if (freq < 1000000) { sprintf(buffer, "%.2fMHz", (float)freq / 1000.0); - printf("%*s", align, buffer); + fprintf(output, "%*s", align, buffer); } else { sprintf(buffer, "%.2fGHz", (float)freq / 1000000.0); - printf("%*s", align, buffer); + fprintf(output, "%*s", align, buffer); } }
static void display_cstates_header(void) { charrep('-', 80); - printf("\n"); + fprintf(output, "\n");
- printf("| C-state | min | max | avg | total | hits | over | under |\n"); + fprintf(output, "| C-state | min | max | avg | total" + " | hits | over | under |\n"); }
static void display_cstates_footer(void) { charrep('-', 80); - printf("\n\n"); + fprintf(output, "\n\n"); }
static int display_cstates(void *arg, char *cpu) @@ -148,23 +171,23 @@ static int display_cstates(void *arg, char *cpu) display_cpu_header(cpu, 80); cpu_header = true; charrep('-', 80); - printf("\n"); + fprintf(output, "\n"); }
- printf("| %8s | ", c->name); + fprintf(output, "| %8s | ", c->name); display_factored_time(c->min_time == DBL_MAX ? 0. : c->min_time, 8); - printf(" | "); + fprintf(output, " | "); display_factored_time(c->max_time, 8); - printf(" | "); + fprintf(output, " | "); display_factored_time(c->avg_time, 8); - printf(" | "); + fprintf(output, " | "); display_factored_time(c->duration, 8); - printf(" | "); - printf("%5d | %5d | %5d |", c->nrdata, + fprintf(output, " | "); + fprintf(output, "%5d | %5d | %5d |", c->nrdata, c->premature_wakeup, c->could_sleep_more);
- printf("\n"); + fprintf(output, "\n"); }
return 0; @@ -173,15 +196,16 @@ static int display_cstates(void *arg, char *cpu) static void display_pstates_header(void) { charrep('-', 64); - printf("\n"); + fprintf(output, "\n");
- printf("| P-state | min | max | avg | total | hits |\n"); + fprintf(output, "| P-state | min | max | avg | total" + " | hits |\n"); }
static void display_pstates_footer(void) { charrep('-', 64); - printf("\n\n"); + fprintf(output, "\n\n"); }
static int display_pstates(void *arg, char *cpu) @@ -202,24 +226,24 @@ static int display_pstates(void *arg, char *cpu) display_cpu_header(cpu, 64); cpu_header = true; charrep('-', 64); - printf("\n"); + fprintf(output, "\n"); }
- printf("| "); + fprintf(output, "| "); display_factored_freq(p->freq, 8); - printf(" | "); + fprintf(output, " | "); display_factored_time(p->min_time == DBL_MAX ? 0. : p->min_time, 8); - printf(" | "); + fprintf(output, " | "); display_factored_time(p->max_time, 8); - printf(" | "); + fprintf(output, " | "); display_factored_time(p->avg_time, 8); - printf(" | "); + fprintf(output, " | "); display_factored_time(p->duration, 8); - printf(" | "); - printf("%5d", p->count); - printf(" | "); - printf("\n"); + fprintf(output, " | "); + fprintf(output, "%5d", p->count); + fprintf(output, " | "); + fprintf(output, "\n"); }
return 0; @@ -228,15 +252,15 @@ static int display_pstates(void *arg, char *cpu) static void display_wakeup_header(void) { charrep('-', 44); - printf("\n"); + fprintf(output, "\n");
- printf("| Wakeup | # | Name | Count |\n"); + fprintf(output, "| Wakeup | # | Name | Count |\n"); }
static void display_wakeup_footer(void) { charrep('-', 44); - printf("\n\n"); + fprintf(output, "\n\n"); }
static int display_wakeup(void *arg, char *cpu) @@ -253,16 +277,16 @@ static int display_wakeup(void *arg, char *cpu) display_cpu_header(cpu, 44); cpu_header = true; charrep('-', 44); - printf("\n"); + fprintf(output, "\n"); }
if (irqinfo->irq_type == HARD_IRQ) - printf("| %-6s | %-3d | %15.15s | %7d |\n", + fprintf(output, "| %-6s | %-3d | %15.15s | %7d |\n", "irq", irqinfo->id, irqinfo->name, irqinfo->count);
if (irqinfo->irq_type == IPI_IRQ) - printf("| %-6s | --- | %15.15s | %7d |\n", + fprintf(output, "| %-6s | --- | %15.15s | %7d |\n", "ipi", irqinfo->name, irqinfo->count); }
@@ -1111,11 +1135,11 @@ static void help(const char *cmd) { fprintf(stderr, "\nUsage:\nTrace mode:\n\t%s --trace -f|--trace-file <filename>" - " -t|--duration <seconds> -c|--idle -p|--frequency -w|--wakeup", - basename(cmd)); + " -o|--output-file <filename> -t|--duration <seconds>" + " -c|--idle -p|--frequency -w|--wakeup", basename(cmd)); fprintf(stderr, - "\nReporting mode:\n\t%s --import -f|--trace-file <filename>", - basename(cmd)); + "\nReporting mode:\n\t%s --import -f|--trace-file <filename>" + " -o|--output-file <filename>", basename(cmd)); fprintf(stderr, "\n\nExamples:\n1. Run a trace, post-process the results" " (default is to show only C-state statistics):\n\tsudo " @@ -1131,6 +1155,15 @@ static void help(const char *cmd) fprintf(stderr, "\n4. Post-process a trace captured earlier:\n\tsudo ./%s" " --import -f /tmp/mytrace\n", basename(cmd)); + fprintf(stderr, + "\n5. Run a trace, post-process the results and print all" + " statistics into a file:\n\tsudo ./%s --trace -f /tmp/mytrace -t 10 -p -c -w" + " -o /tmp/myreport\n", basename(cmd)); + fprintf(stderr, + "\n6. Post-process a trace captured earlier and print all" + " statistics into a file:\n\tsudo ./%s --import -f /tmp/mytrace -p -c -w" + " -o /tmp/myreport\n", + basename(cmd)); }
static void version(const char *cmd) @@ -1144,6 +1177,7 @@ int getoptions(int argc, char *argv[], struct program_options *options) { "trace", no_argument, &options->mode, TRACE }, { "import", no_argument, &options->mode, IMPORT }, { "trace-file", required_argument, NULL, 'f' }, + { "output-file", required_argument, NULL, 'o' }, { "help", no_argument, NULL, 'h' }, { "duration", required_argument, NULL, 't' }, { "version", no_argument, NULL, 'V' }, @@ -1157,13 +1191,14 @@ int getoptions(int argc, char *argv[], struct program_options *options)
memset(options, 0, sizeof(*options)); options->filename = NULL; + options->outfilename = NULL; options->mode = -1; options->format = -1; while (1) {
int optindex = 0;
- c = getopt_long(argc, argv, ":df:ht:cpwVv", + c = getopt_long(argc, argv, ":df:o:ht:cpwVv", long_options, &optindex); if (c == -1) break; @@ -1172,6 +1207,9 @@ int getoptions(int argc, char *argv[], struct program_options *options) case 'f': options->filename = optarg; break; + case 'o': + options->outfilename = optarg; + break; case 'h': help(argv[0]); exit(0); @@ -1427,7 +1465,7 @@ int main(int argc, char *argv[], char *const envp[]) return -1; }
- if (check_window_size()) { + if (check_window_size() && !options.outfilename) { fprintf(stderr, "The terminal must be at least " "80 columns wide\n"); return -1; @@ -1501,6 +1539,8 @@ int main(int argc, char *argv[], char *const envp[]) * the same cluster */ if (0 == establish_idledata_to_topo(datas)) { + if (open_report_file(options.outfilename)) + return -1;
if (options.display & IDLE_DISPLAY) { display_cstates_header(); @@ -1519,6 +1559,8 @@ int main(int argc, char *argv[], char *const envp[]) dump_cpu_topo_info(display_wakeup, 1); display_wakeup_footer(); } + + close_report_file(); }
release_cpu_topo_cstates(); diff --git a/idlestat.h b/idlestat.h index 1d5f961..735f0fe 100644 --- a/idlestat.h +++ b/idlestat.h @@ -132,6 +132,7 @@ struct program_options { int display; unsigned int duration; char *filename; + char *outfilename; int verbose; };