aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTuukka Tikkanen <tuukka.tikkanen@linaro.org>2015-01-21 00:45:39 +0200
committerTuukka Tikkanen <tuukka.tikkanen@linaro.org>2015-01-21 00:45:39 +0200
commit8a2d14faa7e56b63b129394d26ed40745907e141 (patch)
tree7e8d7180f7dcd1e6e123670b36ef9d41f3e32130
parent6efac9bed0ec6b7a2e9abc8872e03245d4918f06 (diff)
Idlestat: P-state calculations for cores and clusters
The P-state (frequency) for cores and clusters was not calculated. This patch adds recording of core/cluster frequency as the highest frequency of all non-idle cpus contained within the core/ cluster. Signed-off-by: Tuukka Tikkanen <tuukka.tikkanen@linaro.org>
-rw-r--r--idlestat.c111
-rw-r--r--idlestat.h2
-rw-r--r--topology.c32
-rw-r--r--topology.h4
4 files changed, 124 insertions, 25 deletions
diff --git a/idlestat.c b/idlestat.c
index 1c1e8ac..9840a2e 100644
--- a/idlestat.c
+++ b/idlestat.c
@@ -531,10 +531,6 @@ static void open_current_pstate(struct cpufreq_pstates *ps, double time)
static void open_next_pstate(struct cpufreq_pstates *ps, int s, double time)
{
ps->current = s;
- if (ps->idle > 0) {
- fprintf(stderr, "Warning: opening P-state on an idle CPU\n");
- return;
- }
open_current_pstate(ps, time);
}
@@ -544,11 +540,10 @@ static void close_current_pstate(struct cpufreq_pstates *ps, double time)
struct cpufreq_pstate *p = &(ps->pstate[c]);
double elapsed;
- if (ps->idle > 0) {
- fprintf(stderr, "Warning: closing P-state on an idle CPU\n");
- return;
- }
elapsed = (time - ps->time_enter) * USEC_PER_SEC;
+ if (elapsed <= 0)
+ return;
+
p->min_time = MIN(p->min_time, elapsed);
p->max_time = MAX(p->max_time, elapsed);
p->avg_time = AVG(p->avg_time, elapsed, p->count + 1);
@@ -556,7 +551,69 @@ static void close_current_pstate(struct cpufreq_pstates *ps, double time)
p->count++;
}
-void cpu_change_pstate(struct cpuidle_datas *datas, int cpu,
+int record_group_freq(struct cpufreq_pstates *ps, double time,
+ unsigned int freq)
+{
+ int cur, next;
+
+ cur = ps->current;
+ if (freq > 0)
+ next = alloc_pstate(ps, freq);
+ else
+ next = -1;
+
+ if (cur == next)
+ return 0; /* No effective change */
+
+ if (cur == -1) {
+ /* The current pstate is -1, possibly leaving idle state */
+ if (next == -1)
+ return 0; /* No known frequency to open, still idle */
+ open_next_pstate(ps, next, time);
+ return 0;
+ }
+
+ /*
+ * The group was running, update all stats and open a new state
+ * if needed.
+ */
+ close_current_pstate(ps, time);
+
+ ps->current = next;
+ if (next == -1)
+ return 0;
+
+ open_current_pstate(ps, time);
+ return 0;
+}
+
+int check_pstate_composite(struct cpuidle_datas *datas, int cpu, double time)
+{
+ struct cpu_core *aff_core;
+ struct cpu_physical *aff_cluster;
+ unsigned int freq;
+
+ aff_core = cpu_to_core(cpu, datas->topo);
+ aff_cluster = cpu_to_cluster(cpu, datas->topo);
+
+ freq = core_get_highest_freq(aff_core);
+ if (aff_core->is_ht) {
+ verbose_fprintf(stderr, 5, "Core %c%d: freq %9u, time %f\n",
+ aff_cluster->physical_id + 'A',
+ aff_core->core_id,
+ freq, time);
+ }
+ if (record_group_freq(aff_core->pstates, time, freq) == -1)
+ return -1;
+
+ freq = cluster_get_highest_freq(aff_cluster);
+ verbose_fprintf(stderr, 5, "Cluster %c: freq %9u, time %f\n",
+ aff_cluster->physical_id + 'A', freq, time);
+ return record_group_freq(aff_cluster->pstates, time, freq);
+}
+
+
+int cpu_change_pstate(struct cpuidle_datas *datas, int cpu,
unsigned int freq, double time)
{
struct cpufreq_pstates *ps;
@@ -573,12 +630,12 @@ void cpu_change_pstate(struct cpuidle_datas *datas, int cpu,
* stats unchanged
*/
ps->current = next;
- return;
+ return 0;
case -1:
/* current pstate is -1, i.e. this is the first update */
open_next_pstate(ps, next, time);
- return;
+ break;
case 0:
/* running CPU, update all stats, but skip closing current
@@ -587,13 +644,16 @@ void cpu_change_pstate(struct cpuidle_datas *datas, int cpu,
if (p)
close_current_pstate(ps, time);
open_next_pstate(ps, next, time);
- return;
+ break;
default:
fprintf(stderr, "illegal pstate %d for cpu %d, exiting.\n",
cur, cpu);
exit(-1);
}
+
+ /* See if core or cluster highest frequency changed */
+ return check_pstate_composite(datas, cpu, time);
}
/**
@@ -644,6 +704,9 @@ static void cpu_pstate_idle(struct cpuidle_datas *datas, int cpu, double time)
if (ps->current != -1)
close_current_pstate(ps, time);
ps->idle = 1;
+
+ /* See if core or cluster highest frequency changed */
+ assert(check_pstate_composite(datas, cpu, time) != -1);
}
static void cpu_pstate_running(struct cpuidle_datas *datas, int cpu,
@@ -653,6 +716,9 @@ static void cpu_pstate_running(struct cpuidle_datas *datas, int cpu,
ps->idle = 0;
if (ps->current != -1)
open_current_pstate(ps, time);
+
+ /* See if core or cluster highest frequency changed */
+ assert(check_pstate_composite(datas, cpu, time) != -1);
}
static int cstate_begin(double time, int state, struct cpuidle_cstates *cstates)
@@ -684,12 +750,18 @@ static void cstate_end(double time, struct cpuidle_cstates *cstates)
data->end = time;
data->duration = data->end - data->begin;
- /* That happens when precision digit in the file exceed
+ /*
+ * Duration can be < 0 when precision digit in the file exceed
* 7 (eg. xxx.1000000). Ignoring the result because I don't
- * find a way to fix with the sscanf used in the caller
+ * find a way to fix with the sscanf used in the caller.
+ *
+ * For synthetic test material, the duration may be 0.
+ *
+ * In both cases, do not record the entry, but do end the state
+ * regardless.
*/
- if (data->duration < 0)
- data->duration = 0;
+ if (data->duration <= 0)
+ goto skip_entry;
/* convert to us */
data->duration *= USEC_PER_SEC;
@@ -717,6 +789,7 @@ static void cstate_end(double time, struct cpuidle_cstates *cstates)
cstate->duration += data->duration;
cstate->nrdata++;
+skip_entry:
/* CPU is no longer idle */
cstates->current_cstate = -1;
}
@@ -766,9 +839,13 @@ int store_data(double time, int state, int cpu,
state = core_get_least_cstate(aff_core);
if (record_cstate_event(aff_core->cstates, time, state) == -1)
return -1;
+
aff_cluster = cpu_to_cluster(cpu, datas->topo);
state = cluster_get_least_cstate(aff_cluster);
- return record_cstate_event(aff_cluster->cstates, time,state);
+ if (record_cstate_event(aff_cluster->cstates, time,state) == -1)
+ return -1;
+
+ return 0;
}
static void release_datas(struct cpuidle_datas *datas)
diff --git a/idlestat.h b/idlestat.h
index 076f6a5..966c762 100644
--- a/idlestat.h
+++ b/idlestat.h
@@ -191,7 +191,7 @@ struct init_pstates {
extern int store_data(double time, int state, int cpu, struct cpuidle_datas *datas);
extern struct cpuidle_cstates *build_cstate_info(int nrcpus);
extern struct cpufreq_pstates *build_pstate_info(int nrcpus);
-extern void cpu_change_pstate(struct cpuidle_datas *datas, int cpu, unsigned int freq, double time);
+extern int cpu_change_pstate(struct cpuidle_datas *datas, int cpu, unsigned int freq, double time);
extern int get_wakeup_irq(struct cpuidle_datas *datas, char *buffer, int count);
#endif
diff --git a/topology.c b/topology.c
index c43536d..7e44cf2 100644
--- a/topology.c
+++ b/topology.c
@@ -95,6 +95,7 @@ int add_topo_info(struct cpu_topology *topo_list, struct topology_info *info)
s_phy->core_num = 0;
s_phy->physical_id = info->physical_id;
+ s_phy->pstates = build_pstate_info(1);
INIT_LIST_HEAD(&s_phy->core_head);
INIT_LIST_HEAD(&s_phy->cpu_enum_head);
@@ -116,6 +117,7 @@ int add_topo_info(struct cpu_topology *topo_list, struct topology_info *info)
s_core->cpu_num = 0;
s_core->is_ht = false;
s_core->core_id = info->core_id;
+ s_core->pstates = build_pstate_info(1);
INIT_LIST_HEAD(&s_core->cpu_head);
ptr = check_pos_from_head(&s_phy->core_head, s_core->core_id);
@@ -206,6 +208,7 @@ void free_cpu_topology(struct list_head *head)
list_for_each_entry_safe(lphysical, n, head, list_physical) {
free_cpu_core_list(&lphysical->core_head);
list_del(&lphysical->list_physical);
+ free(lphysical->pstates->pstate);
free(lphysical);
}
}
@@ -503,11 +506,13 @@ void assign_baseline_in_topo(struct cpuidle_datas *datas)
struct cpu_physical, list_physical);
topo_for_each_cluster(main_phy, topo) {
main_phy->base_cstates = base_phy->cstates;
+ main_phy->base_pstates = base_phy->pstates;
/* Core loop */
base_core = list_first_entry(&base_phy->core_head,
struct cpu_core, list_core);
cluster_for_each_core(main_core, main_phy) {
main_core->base_cstates = base_core->cstates;
+ main_core->base_pstates = base_core->pstates;
/* Cpu loop */
base_cpu = list_first_entry(&base_core->cpu_head,
struct cpu_cpu, list_cpu);
@@ -541,16 +546,27 @@ int dump_cpu_topo_info(struct report_ops *ops, void *report_data, int (*dump)(st
sprintf(tmp, "cluster%c", s_phy->physical_id + 'A');
- if (cstate)
+ if (cstate) {
dump(ops, s_phy->cstates, s_phy->base_cstates,
tmp, report_data);
+ } else {
+ dump(ops, s_phy->pstates, s_phy->base_pstates,
+ tmp, report_data);
+ }
list_for_each_entry(s_core, &s_phy->core_head, list_core) {
- if (s_core->is_ht && cstate) {
+ if (s_core->is_ht) {
sprintf(tmp, "core%d", s_core->core_id);
- dump(ops, s_core->cstates,
- s_core->base_cstates,
- tmp, report_data);
+
+ if (cstate) {
+ dump(ops, s_core->cstates,
+ s_core->base_cstates,
+ tmp, report_data);
+ } else {
+ dump(ops, s_core->pstates,
+ s_core->base_pstates,
+ tmp, report_data);
+ }
}
list_for_each_entry(s_cpu, &s_core->cpu_head,
@@ -609,19 +625,21 @@ int cluster_get_highest_freq(struct cpu_physical *clust)
struct cpu_cpu *cpu;
int cpu_pstate_index;
unsigned int cpu_freq;
- unsigned int ret = ~0;
+ unsigned int ret = ~0U;
cluster_for_each_cpu(cpu, clust) {
cpu_pstate_index = cpu->pstates->current;
if (cpu_pstate_index < 0)
continue;
+ if (cpu->pstates->idle > 0)
+ continue;
cpu_freq = cpu->pstates->pstate[cpu_pstate_index].freq;
if (cpu_freq < ret)
ret = cpu_freq;
}
/* It is possible we don't know anything near the start of trace */
- if (ret == ~0)
+ if (ret == ~0U)
ret = 0;
return ret;
diff --git a/topology.h b/topology.h
index 71c3422..f0cabbc 100644
--- a/topology.h
+++ b/topology.h
@@ -51,7 +51,9 @@ struct cpu_core {
int cpu_num;
bool is_ht;
struct cpuidle_cstates *cstates;
+ struct cpufreq_pstates *pstates;
struct cpuidle_cstates *base_cstates;
+ struct cpufreq_pstates *base_pstates;
};
struct cpu_physical {
@@ -61,7 +63,9 @@ struct cpu_physical {
int core_num;
struct list_head cpu_enum_head;
struct cpuidle_cstates *cstates;
+ struct cpufreq_pstates *pstates;
struct cpuidle_cstates *base_cstates;
+ struct cpufreq_pstates *base_pstates;
};
struct cpu_topology {