diff options
author | pi-cheng.chen <pi-cheng.chen@linaro.org> | 2014-10-31 15:59:46 +0800 |
---|---|---|
committer | Tuukka Tikkanen <tuukka.tikkanen@linaro.org> | 2014-11-13 13:19:20 +0200 |
commit | b330ac2fa60cde6b3284958b92f53439eee38383 (patch) | |
tree | 7661cd69db5a6ade2120b2a84f6441b3d60793ac | |
parent | 01754f032b3358e2170aeddec4d48a18d18ac1b2 (diff) |
idlestat: Emit initial and final P-state changes in the trace file
Write fake initail and final P-state change record in the trace file to complete
P-state statistics.
Signed-off-by: Pi-Cheng Chen <pi-cheng.chen@linaro.org>
-rw-r--r-- | idlestat.c | 117 | ||||
-rw-r--r-- | idlestat.h | 7 | ||||
-rw-r--r-- | trace.h | 1 |
3 files changed, 123 insertions, 2 deletions
@@ -124,6 +124,29 @@ static int open_report_file(const char *path) return 0; } +#define TRACE_TS_FORMAT "%*[^:]:%lf" + +static double get_trace_ts(void) +{ + FILE *f; + double ts; + + f = fopen(TRACE_STAT_FILE, "r"); + if (!f) + return -1; + + while (fgets(buffer, BUFSIZE, f)) { + if (!strstr(buffer, "now ts")) + continue; + if (!sscanf(buffer, TRACE_TS_FORMAT, &ts)) + ts = -1; + break; + } + fclose(f); + + return ts; +} + static void display_cpu_header(char *cpu, int length) { charrep('-', length); @@ -541,6 +564,71 @@ static struct cpuidle_cstates *build_cstate_info(int nrcpus) return cstates; } +static void release_init_pstates(struct init_pstates *initp) +{ + if (!initp) + return; + + free(initp->freqs); + free(initp); +} + +static struct init_pstates *build_init_pstates(void) +{ + struct init_pstates *initp; + int nrcpus, cpu; + unsigned int *freqs; + + nrcpus = sysconf(_SC_NPROCESSORS_CONF); + if (nrcpus < 0) + return NULL; + + initp = malloc(sizeof(*initp)); + if (!initp) + return NULL; + + freqs = calloc(nrcpus, sizeof(*freqs)); + if (!freqs) { + free(initp); + return NULL; + } + + initp->nrcpus = nrcpus; + initp->freqs = freqs; + for (cpu = 0; cpu < nrcpus; cpu++) { + char *fpath; + unsigned int *freq = &(freqs[cpu]); + + if (asprintf(&fpath, CPUFREQ_CURFREQ_PATH_FORMAT, cpu) < 0) { + release_init_pstates(initp); + return NULL; + } + if (read_int(fpath, (int *)freq)) + *freq = 0; + free(fpath); + } + + return initp; +} + +static void output_pstates(FILE *f, struct init_pstates *initp, int nrcpus, + double ts) +{ + int cpu; + unsigned int freq; + unsigned long ts_sec, ts_usec; + + ts_sec = (unsigned long)ts; + ts_usec = (ts - ts_sec) * USEC_PER_SEC; + + for (cpu = 0; cpu < nrcpus; cpu++) { + freq = initp? initp->freqs[cpu] : -1; + fprintf(f, "%16s-%-5d [%03d] .... %5lu.%06lu: cpu_frequency: " + "state=%u cpu_id=%d\n", "idlestat", getpid(), cpu, + ts_sec, ts_usec, freq, cpu); + } +} + /** * alloc_pstate - allocate, sort, and initialize pstate struct to maintain * statistics of P-state transitions @@ -1336,7 +1424,8 @@ static int idlestat_file_for_each_line(const char *path, void *data, return ret; } -static int idlestat_store(const char *path) +static int idlestat_store(const char *path, double start_ts, double end_ts, + struct init_pstates *initp) { FILE *f; int ret; @@ -1345,6 +1434,9 @@ static int idlestat_store(const char *path) if (ret < 0) return -1; + if (initp) + assert(ret == initp->nrcpus); + f = fopen(path, "w+"); if (!f) { @@ -1359,8 +1451,16 @@ static int idlestat_store(const char *path) /* output topology information */ output_cpu_topo_info(f); + /* emit initial pstate changes */ + if (initp) + output_pstates(f, initp, initp->nrcpus, start_ts); + ret = idlestat_file_for_each_line(TRACE_FILE, f, store_line); + /* emit final pstate changes */ + if (initp) + output_pstates(f, NULL, initp->nrcpus, end_ts); + fclose(f); return ret; @@ -1490,6 +1590,8 @@ int main(int argc, char *argv[], char *const envp[]) struct cpuidle_datas *datas; struct program_options options; int args; + double start_ts = 0, end_ts = 0; + struct init_pstates *initp = NULL; args = getoptions(argc, argv, &options); if (args <= 0) @@ -1541,6 +1643,12 @@ int main(int argc, char *argv[], char *const envp[]) if (idlestat_flush_trace()) return 1; + /* Get starting timestamp */ + if (options.display & FREQUENCY_DISPLAY) { + start_ts = get_trace_ts(); + initp = build_init_pstates(); + } + /* Start the recording */ if (idlestat_trace_enable(true)) return 1; @@ -1563,12 +1671,16 @@ int main(int argc, char *argv[], char *const envp[]) if (idlestat_trace_enable(false)) return 1; + /* Get ending timestamp */ + if (options.display & FREQUENCY_DISPLAY) + end_ts = get_trace_ts(); + /* At this point we should have some spurious wake up * at the beginning of the traces and at the end (wake * up all cpus and timer expiration for the timer * acquisition). We assume these will be lost in the number * of other traces and could be negligible. */ - if (idlestat_store(options.filename)) + if (idlestat_store(options.filename, start_ts, end_ts, initp)) return 1; } @@ -1607,6 +1719,7 @@ int main(int argc, char *argv[], char *const envp[]) calculate_energy_consumption(&options); } + release_init_pstates(initp); release_cpu_topo_cstates(); release_cpu_topo_info(); release_pstate_info(datas->pstates, datas->nrcpus); @@ -43,6 +43,8 @@ "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_available_frequencies" #define CPUIDLE_STATENAME_PATH_FORMAT \ "/sys/devices/system/cpu/cpu%d/cpuidle/state%d/name" +#define CPUFREQ_CURFREQ_PATH_FORMAT \ + "/sys/devices/system/cpu/cpu%d/cpufreq/cpuinfo_cur_freq" struct cpuidle_data { double begin; @@ -172,4 +174,9 @@ struct cluster_energy_info { enum energy_file_parse_state state; }; +struct init_pstates { + int nrcpus; + unsigned int *freqs; +}; + #endif @@ -33,6 +33,7 @@ #define TRACE_EVENT_PATH TRACE_PATH "/events/enable" #define TRACE_FREE TRACE_PATH "/free_buffer" #define TRACE_FILE TRACE_PATH "/trace" +#define TRACE_STAT_FILE TRACE_PATH "/per_cpu/cpu0/stats" #define TRACE_IDLE_NRHITS_PER_SEC 10000 #define TRACE_IDLE_LENGTH 196 #define TRACE_CPUFREQ_NRHITS_PER_SEC 100 |