aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTuukka Tikkanen <idlestat@tic0.net>2015-01-28 16:28:48 +0200
committerAmit Kucheria <amit.kucheria@linaro.org>2015-03-10 02:30:28 +0530
commitfed11f249681a6770a1efed5cc2a9ccacf199882 (patch)
tree2cddacd42fbdf16dcfcb6bb7ef65c0ab3f96635c
parent10aa039b937e40ad08bb0207b5ad5eb05bd354c2 (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.c27
-rw-r--r--topology.c63
-rw-r--r--topology.h4
-rw-r--r--tracefile_idlestat.c8
4 files changed, 92 insertions, 10 deletions
diff --git a/idlestat.c b/idlestat.c
index f52bd0b..22a9781 100644
--- a/idlestat.c
+++ b/idlestat.c
@@ -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))
diff --git a/topology.c b/topology.c
index 63d4899..39b07bd 100644
--- a/topology.c
+++ b/topology.c
@@ -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];
diff --git a/topology.h b/topology.h
index 5eba04e..84e5bc1 100644
--- a/topology.h
+++ b/topology.h
@@ -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;