diff options
author | Tuukka Tikkanen <idlestat@tic0.net> | 2015-01-28 16:28:48 +0200 |
---|---|---|
committer | Amit Kucheria <amit.kucheria@linaro.org> | 2015-03-10 02:30:28 +0530 |
commit | fed11f249681a6770a1efed5cc2a9ccacf199882 (patch) | |
tree | 2cddacd42fbdf16dcfcb6bb7ef65c0ab3f96635c | |
parent | 10aa039b937e40ad08bb0207b5ad5eb05bd354c2 (diff) |
Handle offline cpus gracefully
Several parts of idlestat code did not cope with some cpu(s)
being offline. This patch adds information to cpu topology
data structure to record online status. Online-sensitive
parts of the code may query the status using is_cpu_online()
and skip performing activities related to offline cpus.
The following activities are skipped of cpu is offline:
- Trace: Obtaining initial frequency
- Trace: Storing initial frequency
- Trace: Adding pseudo pstate transition 0 Hz to end of trace
- Trace: Storing cpu C-state information
- Tracefile_idlestat: Reading cpu C-state information
- Topology: Mapping "datas" to "topology"
Signed-off-by: Tuukka Tikkanen <idlestat@tic0.net>
Signed-off-by: Amit Kucheria <amit.kucheria@linaro.org>
-rw-r--r-- | idlestat.c | 27 | ||||
-rw-r--r-- | topology.c | 63 | ||||
-rw-r--r-- | topology.h | 4 | ||||
-rw-r--r-- | tracefile_idlestat.c | 8 |
4 files changed, 92 insertions, 10 deletions
@@ -352,7 +352,7 @@ static void release_init_pstates(struct init_pstates *initp) free(initp); } -static struct init_pstates *build_init_pstates(void) +static struct init_pstates *build_init_pstates(struct cpu_topology *topo) { struct init_pstates *initp; int nrcpus, cpu; @@ -378,6 +378,9 @@ static struct init_pstates *build_init_pstates(void) char *fpath; unsigned int *freq = &(freqs[cpu]); + if (!cpu_is_online(topo, cpu)) + continue; + if (asprintf(&fpath, CPUFREQ_CURFREQ_PATH_FORMAT, cpu) < 0) { release_init_pstates(initp); return NULL; @@ -390,7 +393,8 @@ static struct init_pstates *build_init_pstates(void) return initp; } -static void output_pstates(FILE *f, struct init_pstates *initp, int nrcpus, +static void output_pstates(FILE *f, struct init_pstates *initp, + int nrcpus, struct cpu_topology *topo, double ts) { int cpu; @@ -401,7 +405,10 @@ static void output_pstates(FILE *f, struct init_pstates *initp, int nrcpus, ts_usec = (ts - ts_sec) * USEC_PER_SEC; for (cpu = 0; cpu < nrcpus; cpu++) { - freq = initp? initp->freqs[cpu] : 0; + if (!cpu_is_online(topo, cpu)) + continue; + + freq = initp ? initp->freqs[cpu] : 0; fprintf(f, "%16s-%-5d [%03d] .... %5lu.%06lu: cpu_frequency: " "state=%u cpu_id=%d\n", "idlestat", getpid(), cpu, ts_sec, ts_usec, freq, cpu); @@ -931,7 +938,8 @@ static void write_cstate_info(FILE *f, char *name, int target) fprintf(f, "\t%d\n", target); } -void output_cstate_info(FILE *f, int nrcpus) { +void output_cstate_info(FILE *f, struct cpu_topology * topo, int nrcpus) +{ struct cpuidle_cstates *cstates; int i, j; @@ -939,6 +947,9 @@ void output_cstate_info(FILE *f, int nrcpus) { assert(!is_err(cstates)); for (i=0; i < nrcpus; i++) { + if (!cpu_is_online(topo, i)) + continue; + fprintf(f, "cpuid %d:\n", i); for (j=0; j < MAXCSTATE ; j++) { write_cstate_info(f, cstates[i].cstate[j].name, @@ -1281,17 +1292,17 @@ static int idlestat_store(const char *path, double start_ts, double end_ts, output_cpu_topo_info(cpu_topo, f); /* output c-states information */ - output_cstate_info(f, ret); + output_cstate_info(f, cpu_topo, ret); /* emit initial pstate changes */ if (initp) - output_pstates(f, initp, initp->nrcpus, start_ts); + output_pstates(f, initp, initp->nrcpus, cpu_topo, 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); + output_pstates(f, NULL, initp->nrcpus, cpu_topo, end_ts); fclose(f); @@ -1494,7 +1505,7 @@ int main(int argc, char *argv[], char *const envp[]) if (get_trace_ts(&start_ts) == -1) goto err_restore_trace_options; - initp = build_init_pstates(); + initp = build_init_pstates(cpu_topo); /* Start the recording */ if (idlestat_trace_enable(true)) @@ -84,6 +84,12 @@ int add_topo_info(struct cpu_topology *topo_list, struct topology_info *info) struct cpu_core *s_core; struct cpu_cpu *s_cpu = NULL; struct list_head *ptr; + int *new_online_cpus; + + assert(info != NULL); + assert(info->physical_id >= 0); + assert(info->core_id >= 0); + assert(info->cpu_id >= 0); /* add cpu physical info */ ptr = check_exist_from_head(&topo_list->physical_head, @@ -149,9 +155,35 @@ int add_topo_info(struct cpu_topology *topo_list, struct topology_info *info) /* Add to the list (really a set) of all contained cpus in s_phy */ list_add_tail(&s_cpu->list_phy_enum, &s_phy->cpu_enum_head); + /* Add this cpu to the list of online cpus */ + if (topo_list->online_array_size <= info->cpu_id) { + new_online_cpus = realloc(topo_list->online_cpus, + sizeof(int) * (info->cpu_id + 1) ); + if (new_online_cpus == NULL) + return error(__func__); + + memset(new_online_cpus + topo_list->online_array_size, + 0, + sizeof(int) * + (info->cpu_id + 1 - topo_list->online_array_size)); + topo_list->online_cpus = new_online_cpus; + topo_list->online_array_size = info->cpu_id + 1; + } + topo_list->online_cpus[info->cpu_id] = 1; + return 0; } +int cpu_is_online(struct cpu_topology *topo, int cpuid) +{ + assert(cpuid >= 0); + + if (topo->online_array_size <= cpuid) + return 0; + + return topo->online_cpus[cpuid]; +} + struct cpu_physical *cpu_to_cluster(int cpuid, struct cpu_topology *topo) { struct cpu_physical *phy; @@ -302,6 +334,7 @@ static struct cpu_topology *topo_folder_scan(char *path, folder_filter_t filter) struct dirent dirent, *direntp; struct stat s; int ret; + int is_online; struct cpu_topology *result = NULL; dir = opendir(path); @@ -335,6 +368,32 @@ static struct cpu_topology *topo_folder_scan(char *path, folder_filter_t filter) if (strncmp(direntp->d_name, "cpu", 3)) continue; + /* + * Some cpu(s) may be offline. Before trying to figure + * out the topology entry, see if the cpu is online. + * The boot cpu (cpu0) is always online, so skip the check + * for that. + */ + if (!strcmp(direntp->d_name, "cpu0")) { + is_online = 1; + } else { + ret = asprintf(&newpath, "%s/%s/%s", basedir, + direntp->d_name, "online"); + if (ret < 0) + goto out_free_basedir; + + ret = read_int(newpath, &is_online); + free(newpath); + if (ret < 0) + goto out_free_basedir; + } + + if (!is_online) { + verbose_fprintf(stderr, 1, "Warning: %s is offline\n", + direntp->d_name); + continue; + } + ret = asprintf(&newpath, "%s/%s/%s", basedir, direntp->d_name, "topology"); if (ret < 0) @@ -483,6 +542,7 @@ int release_cpu_topo_info(struct cpu_topology *topo) /* Free alloced memory */ free_cpu_topology(&topo->physical_head); + free(topo->online_cpus); free(topo); return 0; @@ -818,6 +878,9 @@ int setup_topo_states(struct cpuidle_datas *datas) /* Map cpu state arrays into topology structures */ for (i = 0; i < datas->nrcpus; i++) { + if (!cpu_is_online(topo, i)) + continue; + s_cpu = find_cpu_point(topo, i); if (s_cpu) { s_cpu->cstates = &datas->cstates[i]; @@ -70,6 +70,8 @@ struct cpu_physical { struct cpu_topology { struct list_head physical_head; + int *online_cpus; + int online_array_size; }; extern struct cpu_topology *alloc_cpu_topo_info(void); @@ -81,6 +83,8 @@ extern void assign_baseline_in_topo(struct cpuidle_datas *datas); extern int release_cpu_topo_cstates(struct cpu_topology *topo); extern int dump_cpu_topo_info(struct report_ops *ops, void *report_data, int (*dump)(struct report_ops *, void *, void *, char *, void *), struct cpu_topology *topo, int cstate); +extern int cpu_is_online(struct cpu_topology *topo, int cpuid); + extern struct cpu_physical *cpu_to_cluster(int cpuid, struct cpu_topology *topo); extern struct cpu_core *cpu_to_core(int cpuid, struct cpu_topology *topo); diff --git a/tracefile_idlestat.c b/tracefile_idlestat.c index cb6f5bc..3430693 100644 --- a/tracefile_idlestat.c +++ b/tracefile_idlestat.c @@ -46,7 +46,7 @@ * * @return: per-CPU array of structs (success) or ptrerror() (error) */ -static struct cpuidle_cstates *load_and_build_cstate_info(FILE* f, char *buffer, int nrcpus) +static struct cpuidle_cstates *load_and_build_cstate_info(FILE* f, char *buffer, int nrcpus, struct cpu_topology * topo) { int cpu; struct cpuidle_cstates *cstates; @@ -66,6 +66,9 @@ static struct cpuidle_cstates *load_and_build_cstate_info(FILE* f, char *buffer, cstates[cpu].cstate_max = -1; cstates[cpu].current_cstate = -1; + if (!cpu_is_online(topo, cpu)) + continue; + if (sscanf(buffer, "cpuid %d:\n", &read_cpu) != 1 || read_cpu != cpu) { release_cstate_info(cstates, cpu); @@ -237,7 +240,8 @@ static struct cpuidle_datas * idlestat_native_load(const char *filename) goto propagate_error_free_datas; /* Read C-state information */ - datas->cstates = load_and_build_cstate_info(f, buffer, nrcpus); + datas->cstates = load_and_build_cstate_info(f, buffer, + nrcpus, datas->topo); if (is_err(datas->cstates)) goto propagate_error_free_datas; |