xref: /openbmc/linux/tools/perf/util/stat.c (revision 1fe7a300)
10007eceaSXiao Guangrong #include <math.h>
20007eceaSXiao Guangrong #include "stat.h"
324e34f68SJiri Olsa #include "evlist.h"
4e2f56da1SJiri Olsa #include "evsel.h"
524e34f68SJiri Olsa #include "thread_map.h"
60007eceaSXiao Guangrong 
70007eceaSXiao Guangrong void update_stats(struct stats *stats, u64 val)
80007eceaSXiao Guangrong {
90007eceaSXiao Guangrong 	double delta;
100007eceaSXiao Guangrong 
110007eceaSXiao Guangrong 	stats->n++;
120007eceaSXiao Guangrong 	delta = val - stats->mean;
130007eceaSXiao Guangrong 	stats->mean += delta / stats->n;
140007eceaSXiao Guangrong 	stats->M2 += delta*(val - stats->mean);
15ffe4f3c0SDavid Ahern 
16ffe4f3c0SDavid Ahern 	if (val > stats->max)
17ffe4f3c0SDavid Ahern 		stats->max = val;
18ffe4f3c0SDavid Ahern 
19ffe4f3c0SDavid Ahern 	if (val < stats->min)
20ffe4f3c0SDavid Ahern 		stats->min = val;
210007eceaSXiao Guangrong }
220007eceaSXiao Guangrong 
230007eceaSXiao Guangrong double avg_stats(struct stats *stats)
240007eceaSXiao Guangrong {
250007eceaSXiao Guangrong 	return stats->mean;
260007eceaSXiao Guangrong }
270007eceaSXiao Guangrong 
280007eceaSXiao Guangrong /*
290007eceaSXiao Guangrong  * http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
300007eceaSXiao Guangrong  *
310007eceaSXiao Guangrong  *       (\Sum n_i^2) - ((\Sum n_i)^2)/n
320007eceaSXiao Guangrong  * s^2 = -------------------------------
330007eceaSXiao Guangrong  *                  n - 1
340007eceaSXiao Guangrong  *
350007eceaSXiao Guangrong  * http://en.wikipedia.org/wiki/Stddev
360007eceaSXiao Guangrong  *
370007eceaSXiao Guangrong  * The std dev of the mean is related to the std dev by:
380007eceaSXiao Guangrong  *
390007eceaSXiao Guangrong  *             s
400007eceaSXiao Guangrong  * s_mean = -------
410007eceaSXiao Guangrong  *          sqrt(n)
420007eceaSXiao Guangrong  *
430007eceaSXiao Guangrong  */
440007eceaSXiao Guangrong double stddev_stats(struct stats *stats)
450007eceaSXiao Guangrong {
460007eceaSXiao Guangrong 	double variance, variance_mean;
470007eceaSXiao Guangrong 
4845528f7cSDavid Ahern 	if (stats->n < 2)
490007eceaSXiao Guangrong 		return 0.0;
500007eceaSXiao Guangrong 
510007eceaSXiao Guangrong 	variance = stats->M2 / (stats->n - 1);
520007eceaSXiao Guangrong 	variance_mean = variance / stats->n;
530007eceaSXiao Guangrong 
540007eceaSXiao Guangrong 	return sqrt(variance_mean);
550007eceaSXiao Guangrong }
560007eceaSXiao Guangrong 
570007eceaSXiao Guangrong double rel_stddev_stats(double stddev, double avg)
580007eceaSXiao Guangrong {
590007eceaSXiao Guangrong 	double pct = 0.0;
600007eceaSXiao Guangrong 
610007eceaSXiao Guangrong 	if (avg)
620007eceaSXiao Guangrong 		pct = 100.0 * stddev/avg;
630007eceaSXiao Guangrong 
640007eceaSXiao Guangrong 	return pct;
650007eceaSXiao Guangrong }
66e2f56da1SJiri Olsa 
67e2f56da1SJiri Olsa bool __perf_evsel_stat__is(struct perf_evsel *evsel,
68e2f56da1SJiri Olsa 			   enum perf_stat_evsel_id id)
69e2f56da1SJiri Olsa {
70581cc8a2SJiri Olsa 	struct perf_stat_evsel *ps = evsel->priv;
71e2f56da1SJiri Olsa 
72e2f56da1SJiri Olsa 	return ps->id == id;
73e2f56da1SJiri Olsa }
74e2f56da1SJiri Olsa 
75e2f56da1SJiri Olsa #define ID(id, name) [PERF_STAT_EVSEL_ID__##id] = #name
76e2f56da1SJiri Olsa static const char *id_str[PERF_STAT_EVSEL_ID__MAX] = {
77e2f56da1SJiri Olsa 	ID(NONE,		x),
784c358d5cSJiri Olsa 	ID(CYCLES_IN_TX,	cpu/cycles-t/),
794c358d5cSJiri Olsa 	ID(TRANSACTION_START,	cpu/tx-start/),
804c358d5cSJiri Olsa 	ID(ELISION_START,	cpu/el-start/),
814c358d5cSJiri Olsa 	ID(CYCLES_IN_TX_CP,	cpu/cycles-ct/),
82e2f56da1SJiri Olsa };
83e2f56da1SJiri Olsa #undef ID
84e2f56da1SJiri Olsa 
85e2f56da1SJiri Olsa void perf_stat_evsel_id_init(struct perf_evsel *evsel)
86e2f56da1SJiri Olsa {
87581cc8a2SJiri Olsa 	struct perf_stat_evsel *ps = evsel->priv;
88e2f56da1SJiri Olsa 	int i;
89e2f56da1SJiri Olsa 
90e2f56da1SJiri Olsa 	/* ps->id is 0 hence PERF_STAT_EVSEL_ID__NONE by default */
91e2f56da1SJiri Olsa 
92e2f56da1SJiri Olsa 	for (i = 0; i < PERF_STAT_EVSEL_ID__MAX; i++) {
93e2f56da1SJiri Olsa 		if (!strcmp(perf_evsel__name(evsel), id_str[i])) {
94e2f56da1SJiri Olsa 			ps->id = i;
95e2f56da1SJiri Olsa 			break;
96e2f56da1SJiri Olsa 		}
97e2f56da1SJiri Olsa 	}
98e2f56da1SJiri Olsa }
99a9a3a4d9SJiri Olsa 
1009689edfaSJiri Olsa void perf_evsel__reset_stat_priv(struct perf_evsel *evsel)
1019689edfaSJiri Olsa {
1029689edfaSJiri Olsa 	int i;
103581cc8a2SJiri Olsa 	struct perf_stat_evsel *ps = evsel->priv;
1049689edfaSJiri Olsa 
1059689edfaSJiri Olsa 	for (i = 0; i < 3; i++)
1069689edfaSJiri Olsa 		init_stats(&ps->res_stats[i]);
1079689edfaSJiri Olsa 
1089689edfaSJiri Olsa 	perf_stat_evsel_id_init(evsel);
1099689edfaSJiri Olsa }
1109689edfaSJiri Olsa 
1119689edfaSJiri Olsa int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel)
1129689edfaSJiri Olsa {
113581cc8a2SJiri Olsa 	evsel->priv = zalloc(sizeof(struct perf_stat_evsel));
1149689edfaSJiri Olsa 	if (evsel->priv == NULL)
1159689edfaSJiri Olsa 		return -ENOMEM;
1169689edfaSJiri Olsa 	perf_evsel__reset_stat_priv(evsel);
1179689edfaSJiri Olsa 	return 0;
1189689edfaSJiri Olsa }
1199689edfaSJiri Olsa 
1209689edfaSJiri Olsa void perf_evsel__free_stat_priv(struct perf_evsel *evsel)
1219689edfaSJiri Olsa {
1229689edfaSJiri Olsa 	zfree(&evsel->priv);
1239689edfaSJiri Olsa }
124a939512dSJiri Olsa 
125a939512dSJiri Olsa int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel,
126a939512dSJiri Olsa 				      int ncpus, int nthreads)
127a939512dSJiri Olsa {
128a939512dSJiri Olsa 	struct perf_counts *counts;
129a939512dSJiri Olsa 
130a939512dSJiri Olsa 	counts = perf_counts__new(ncpus, nthreads);
131a939512dSJiri Olsa 	if (counts)
132a939512dSJiri Olsa 		evsel->prev_raw_counts = counts;
133a939512dSJiri Olsa 
134a939512dSJiri Olsa 	return counts ? 0 : -ENOMEM;
135a939512dSJiri Olsa }
136a939512dSJiri Olsa 
137a939512dSJiri Olsa void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel)
138a939512dSJiri Olsa {
139a939512dSJiri Olsa 	perf_counts__delete(evsel->prev_raw_counts);
140a939512dSJiri Olsa 	evsel->prev_raw_counts = NULL;
141a939512dSJiri Olsa }
14224e34f68SJiri Olsa 
143a7d0a102SJiri Olsa int perf_evsel__alloc_stats(struct perf_evsel *evsel, bool alloc_raw)
14424e34f68SJiri Olsa {
14524e34f68SJiri Olsa 	int ncpus = perf_evsel__nr_cpus(evsel);
146a7d0a102SJiri Olsa 	int nthreads = thread_map__nr(evsel->threads);
14724e34f68SJiri Olsa 
14824e34f68SJiri Olsa 	if (perf_evsel__alloc_stat_priv(evsel) < 0 ||
14924e34f68SJiri Olsa 	    perf_evsel__alloc_counts(evsel, ncpus, nthreads) < 0 ||
15024e34f68SJiri Olsa 	    (alloc_raw && perf_evsel__alloc_prev_raw_counts(evsel, ncpus, nthreads) < 0))
151a7d0a102SJiri Olsa 		return -ENOMEM;
152a7d0a102SJiri Olsa 
153a7d0a102SJiri Olsa 	return 0;
154a7d0a102SJiri Olsa }
155a7d0a102SJiri Olsa 
156a7d0a102SJiri Olsa int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw)
157a7d0a102SJiri Olsa {
158a7d0a102SJiri Olsa 	struct perf_evsel *evsel;
159a7d0a102SJiri Olsa 
160a7d0a102SJiri Olsa 	evlist__for_each(evlist, evsel) {
161a7d0a102SJiri Olsa 		if (perf_evsel__alloc_stats(evsel, alloc_raw))
16224e34f68SJiri Olsa 			goto out_free;
16324e34f68SJiri Olsa 	}
16424e34f68SJiri Olsa 
16524e34f68SJiri Olsa 	return 0;
16624e34f68SJiri Olsa 
16724e34f68SJiri Olsa out_free:
16824e34f68SJiri Olsa 	perf_evlist__free_stats(evlist);
16924e34f68SJiri Olsa 	return -1;
17024e34f68SJiri Olsa }
17124e34f68SJiri Olsa 
17224e34f68SJiri Olsa void perf_evlist__free_stats(struct perf_evlist *evlist)
17324e34f68SJiri Olsa {
17424e34f68SJiri Olsa 	struct perf_evsel *evsel;
17524e34f68SJiri Olsa 
17624e34f68SJiri Olsa 	evlist__for_each(evlist, evsel) {
17724e34f68SJiri Olsa 		perf_evsel__free_stat_priv(evsel);
17824e34f68SJiri Olsa 		perf_evsel__free_counts(evsel);
17924e34f68SJiri Olsa 		perf_evsel__free_prev_raw_counts(evsel);
18024e34f68SJiri Olsa 	}
18124e34f68SJiri Olsa }
18224e34f68SJiri Olsa 
18324e34f68SJiri Olsa void perf_evlist__reset_stats(struct perf_evlist *evlist)
18424e34f68SJiri Olsa {
18524e34f68SJiri Olsa 	struct perf_evsel *evsel;
18624e34f68SJiri Olsa 
18724e34f68SJiri Olsa 	evlist__for_each(evlist, evsel) {
18824e34f68SJiri Olsa 		perf_evsel__reset_stat_priv(evsel);
18924e34f68SJiri Olsa 		perf_evsel__reset_counts(evsel);
19024e34f68SJiri Olsa 	}
19124e34f68SJiri Olsa }
192f80010ebSJiri Olsa 
193f80010ebSJiri Olsa static void zero_per_pkg(struct perf_evsel *counter)
194f80010ebSJiri Olsa {
195f80010ebSJiri Olsa 	if (counter->per_pkg_mask)
196f80010ebSJiri Olsa 		memset(counter->per_pkg_mask, 0, MAX_NR_CPUS);
197f80010ebSJiri Olsa }
198f80010ebSJiri Olsa 
19902d8dabcSStephane Eranian static int check_per_pkg(struct perf_evsel *counter,
20002d8dabcSStephane Eranian 			 struct perf_counts_values *vals, int cpu, bool *skip)
201f80010ebSJiri Olsa {
202f80010ebSJiri Olsa 	unsigned long *mask = counter->per_pkg_mask;
203f80010ebSJiri Olsa 	struct cpu_map *cpus = perf_evsel__cpus(counter);
204f80010ebSJiri Olsa 	int s;
205f80010ebSJiri Olsa 
206f80010ebSJiri Olsa 	*skip = false;
207f80010ebSJiri Olsa 
208f80010ebSJiri Olsa 	if (!counter->per_pkg)
209f80010ebSJiri Olsa 		return 0;
210f80010ebSJiri Olsa 
211f80010ebSJiri Olsa 	if (cpu_map__empty(cpus))
212f80010ebSJiri Olsa 		return 0;
213f80010ebSJiri Olsa 
214f80010ebSJiri Olsa 	if (!mask) {
215f80010ebSJiri Olsa 		mask = zalloc(MAX_NR_CPUS);
216f80010ebSJiri Olsa 		if (!mask)
217f80010ebSJiri Olsa 			return -ENOMEM;
218f80010ebSJiri Olsa 
219f80010ebSJiri Olsa 		counter->per_pkg_mask = mask;
220f80010ebSJiri Olsa 	}
221f80010ebSJiri Olsa 
22202d8dabcSStephane Eranian 	/*
22302d8dabcSStephane Eranian 	 * we do not consider an event that has not run as a good
22402d8dabcSStephane Eranian 	 * instance to mark a package as used (skip=1). Otherwise
22502d8dabcSStephane Eranian 	 * we may run into a situation where the first CPU in a package
22602d8dabcSStephane Eranian 	 * is not running anything, yet the second is, and this function
22702d8dabcSStephane Eranian 	 * would mark the package as used after the first CPU and would
22802d8dabcSStephane Eranian 	 * not read the values from the second CPU.
22902d8dabcSStephane Eranian 	 */
23002d8dabcSStephane Eranian 	if (!(vals->run && vals->ena))
23102d8dabcSStephane Eranian 		return 0;
23202d8dabcSStephane Eranian 
2331fe7a300SJiri Olsa 	s = cpu_map__get_socket(cpus, cpu, NULL);
234f80010ebSJiri Olsa 	if (s < 0)
235f80010ebSJiri Olsa 		return -1;
236f80010ebSJiri Olsa 
237f80010ebSJiri Olsa 	*skip = test_and_set_bit(s, mask) == 1;
238f80010ebSJiri Olsa 	return 0;
239f80010ebSJiri Olsa }
240f80010ebSJiri Olsa 
241f80010ebSJiri Olsa static int
242f80010ebSJiri Olsa process_counter_values(struct perf_stat_config *config, struct perf_evsel *evsel,
243f80010ebSJiri Olsa 		       int cpu, int thread,
244f80010ebSJiri Olsa 		       struct perf_counts_values *count)
245f80010ebSJiri Olsa {
246f80010ebSJiri Olsa 	struct perf_counts_values *aggr = &evsel->counts->aggr;
247f80010ebSJiri Olsa 	static struct perf_counts_values zero;
248f80010ebSJiri Olsa 	bool skip = false;
249f80010ebSJiri Olsa 
25002d8dabcSStephane Eranian 	if (check_per_pkg(evsel, count, cpu, &skip)) {
251f80010ebSJiri Olsa 		pr_err("failed to read per-pkg counter\n");
252f80010ebSJiri Olsa 		return -1;
253f80010ebSJiri Olsa 	}
254f80010ebSJiri Olsa 
255f80010ebSJiri Olsa 	if (skip)
256f80010ebSJiri Olsa 		count = &zero;
257f80010ebSJiri Olsa 
258f80010ebSJiri Olsa 	switch (config->aggr_mode) {
259f80010ebSJiri Olsa 	case AGGR_THREAD:
260f80010ebSJiri Olsa 	case AGGR_CORE:
261f80010ebSJiri Olsa 	case AGGR_SOCKET:
262f80010ebSJiri Olsa 	case AGGR_NONE:
263f80010ebSJiri Olsa 		if (!evsel->snapshot)
264f80010ebSJiri Olsa 			perf_evsel__compute_deltas(evsel, cpu, thread, count);
265f80010ebSJiri Olsa 		perf_counts_values__scale(count, config->scale, NULL);
266f80010ebSJiri Olsa 		if (config->aggr_mode == AGGR_NONE)
267f80010ebSJiri Olsa 			perf_stat__update_shadow_stats(evsel, count->values, cpu);
268f80010ebSJiri Olsa 		break;
269f80010ebSJiri Olsa 	case AGGR_GLOBAL:
270f80010ebSJiri Olsa 		aggr->val += count->val;
271f80010ebSJiri Olsa 		if (config->scale) {
272f80010ebSJiri Olsa 			aggr->ena += count->ena;
273f80010ebSJiri Olsa 			aggr->run += count->run;
274f80010ebSJiri Olsa 		}
275208df99eSJiri Olsa 	case AGGR_UNSET:
276f80010ebSJiri Olsa 	default:
277f80010ebSJiri Olsa 		break;
278f80010ebSJiri Olsa 	}
279f80010ebSJiri Olsa 
280f80010ebSJiri Olsa 	return 0;
281f80010ebSJiri Olsa }
282f80010ebSJiri Olsa 
283f80010ebSJiri Olsa static int process_counter_maps(struct perf_stat_config *config,
284f80010ebSJiri Olsa 				struct perf_evsel *counter)
285f80010ebSJiri Olsa {
286f80010ebSJiri Olsa 	int nthreads = thread_map__nr(counter->threads);
287f80010ebSJiri Olsa 	int ncpus = perf_evsel__nr_cpus(counter);
288f80010ebSJiri Olsa 	int cpu, thread;
289f80010ebSJiri Olsa 
290f80010ebSJiri Olsa 	if (counter->system_wide)
291f80010ebSJiri Olsa 		nthreads = 1;
292f80010ebSJiri Olsa 
293f80010ebSJiri Olsa 	for (thread = 0; thread < nthreads; thread++) {
294f80010ebSJiri Olsa 		for (cpu = 0; cpu < ncpus; cpu++) {
295f80010ebSJiri Olsa 			if (process_counter_values(config, counter, cpu, thread,
296f80010ebSJiri Olsa 						   perf_counts(counter->counts, cpu, thread)))
297f80010ebSJiri Olsa 				return -1;
298f80010ebSJiri Olsa 		}
299f80010ebSJiri Olsa 	}
300f80010ebSJiri Olsa 
301f80010ebSJiri Olsa 	return 0;
302f80010ebSJiri Olsa }
303f80010ebSJiri Olsa 
304f80010ebSJiri Olsa int perf_stat_process_counter(struct perf_stat_config *config,
305f80010ebSJiri Olsa 			      struct perf_evsel *counter)
306f80010ebSJiri Olsa {
307f80010ebSJiri Olsa 	struct perf_counts_values *aggr = &counter->counts->aggr;
308581cc8a2SJiri Olsa 	struct perf_stat_evsel *ps = counter->priv;
309f80010ebSJiri Olsa 	u64 *count = counter->counts->aggr.values;
310f80010ebSJiri Olsa 	int i, ret;
311f80010ebSJiri Olsa 
312f80010ebSJiri Olsa 	aggr->val = aggr->ena = aggr->run = 0;
313f80010ebSJiri Olsa 	init_stats(ps->res_stats);
314f80010ebSJiri Olsa 
315f80010ebSJiri Olsa 	if (counter->per_pkg)
316f80010ebSJiri Olsa 		zero_per_pkg(counter);
317f80010ebSJiri Olsa 
318f80010ebSJiri Olsa 	ret = process_counter_maps(config, counter);
319f80010ebSJiri Olsa 	if (ret)
320f80010ebSJiri Olsa 		return ret;
321f80010ebSJiri Olsa 
322f80010ebSJiri Olsa 	if (config->aggr_mode != AGGR_GLOBAL)
323f80010ebSJiri Olsa 		return 0;
324f80010ebSJiri Olsa 
325f80010ebSJiri Olsa 	if (!counter->snapshot)
326f80010ebSJiri Olsa 		perf_evsel__compute_deltas(counter, -1, -1, aggr);
327f80010ebSJiri Olsa 	perf_counts_values__scale(aggr, config->scale, &counter->counts->scaled);
328f80010ebSJiri Olsa 
329f80010ebSJiri Olsa 	for (i = 0; i < 3; i++)
330f80010ebSJiri Olsa 		update_stats(&ps->res_stats[i], count[i]);
331f80010ebSJiri Olsa 
332f80010ebSJiri Olsa 	if (verbose) {
333f80010ebSJiri Olsa 		fprintf(config->output, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
334f80010ebSJiri Olsa 			perf_evsel__name(counter), count[0], count[1], count[2]);
335f80010ebSJiri Olsa 	}
336f80010ebSJiri Olsa 
337f80010ebSJiri Olsa 	/*
338f80010ebSJiri Olsa 	 * Save the full runtime - to allow normalization during printout:
339f80010ebSJiri Olsa 	 */
340f80010ebSJiri Olsa 	perf_stat__update_shadow_stats(counter, count, 0);
341f80010ebSJiri Olsa 
342f80010ebSJiri Olsa 	return 0;
343f80010ebSJiri Olsa }
344