blob: d4f872f1750e68c9cd20bf8d52436a30cc5bd1dd [file] [log] [blame]
Xiao Guangrong0007ece2012-09-17 16:31:14 +08001#include <math.h>
Xiao Guangrong0007ece2012-09-17 16:31:14 +08002#include "stat.h"
Jiri Olsa24e34f62015-06-26 11:29:16 +02003#include "evlist.h"
Jiri Olsae2f56da2015-06-04 15:50:55 +02004#include "evsel.h"
Jiri Olsa24e34f62015-06-26 11:29:16 +02005#include "thread_map.h"
Xiao Guangrong0007ece2012-09-17 16:31:14 +08006
7void update_stats(struct stats *stats, u64 val)
8{
9 double delta;
10
11 stats->n++;
12 delta = val - stats->mean;
13 stats->mean += delta / stats->n;
14 stats->M2 += delta*(val - stats->mean);
David Ahernffe4f3c2013-08-02 14:05:40 -060015
16 if (val > stats->max)
17 stats->max = val;
18
19 if (val < stats->min)
20 stats->min = val;
Xiao Guangrong0007ece2012-09-17 16:31:14 +080021}
22
23double avg_stats(struct stats *stats)
24{
25 return stats->mean;
26}
27
28/*
29 * http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
30 *
31 * (\Sum n_i^2) - ((\Sum n_i)^2)/n
32 * s^2 = -------------------------------
33 * n - 1
34 *
35 * http://en.wikipedia.org/wiki/Stddev
36 *
37 * The std dev of the mean is related to the std dev by:
38 *
39 * s
40 * s_mean = -------
41 * sqrt(n)
42 *
43 */
44double stddev_stats(struct stats *stats)
45{
46 double variance, variance_mean;
47
David Ahern45528f72013-05-25 18:24:48 -060048 if (stats->n < 2)
Xiao Guangrong0007ece2012-09-17 16:31:14 +080049 return 0.0;
50
51 variance = stats->M2 / (stats->n - 1);
52 variance_mean = variance / stats->n;
53
54 return sqrt(variance_mean);
55}
56
57double rel_stddev_stats(double stddev, double avg)
58{
59 double pct = 0.0;
60
61 if (avg)
62 pct = 100.0 * stddev/avg;
63
64 return pct;
65}
Jiri Olsae2f56da2015-06-04 15:50:55 +020066
67bool __perf_evsel_stat__is(struct perf_evsel *evsel,
68 enum perf_stat_evsel_id id)
69{
Jiri Olsa581cc8a2015-10-16 12:41:03 +020070 struct perf_stat_evsel *ps = evsel->priv;
Jiri Olsae2f56da2015-06-04 15:50:55 +020071
72 return ps->id == id;
73}
74
75#define ID(id, name) [PERF_STAT_EVSEL_ID__##id] = #name
76static const char *id_str[PERF_STAT_EVSEL_ID__MAX] = {
Jiri Olsa4c358d52015-06-03 16:25:52 +020077 ID(NONE, x),
78 ID(CYCLES_IN_TX, cpu/cycles-t/),
79 ID(TRANSACTION_START, cpu/tx-start/),
80 ID(ELISION_START, cpu/el-start/),
81 ID(CYCLES_IN_TX_CP, cpu/cycles-ct/),
Andi Kleen239bd472016-05-24 12:52:37 -070082 ID(TOPDOWN_TOTAL_SLOTS, topdown-total-slots),
83 ID(TOPDOWN_SLOTS_ISSUED, topdown-slots-issued),
84 ID(TOPDOWN_SLOTS_RETIRED, topdown-slots-retired),
85 ID(TOPDOWN_FETCH_BUBBLES, topdown-fetch-bubbles),
86 ID(TOPDOWN_RECOVERY_BUBBLES, topdown-recovery-bubbles),
Jiri Olsae2f56da2015-06-04 15:50:55 +020087};
88#undef ID
89
90void perf_stat_evsel_id_init(struct perf_evsel *evsel)
91{
Jiri Olsa581cc8a2015-10-16 12:41:03 +020092 struct perf_stat_evsel *ps = evsel->priv;
Jiri Olsae2f56da2015-06-04 15:50:55 +020093 int i;
94
95 /* ps->id is 0 hence PERF_STAT_EVSEL_ID__NONE by default */
96
97 for (i = 0; i < PERF_STAT_EVSEL_ID__MAX; i++) {
98 if (!strcmp(perf_evsel__name(evsel), id_str[i])) {
99 ps->id = i;
100 break;
101 }
102 }
103}
Jiri Olsaa9a3a4d2015-06-14 10:19:26 +0200104
Jiri Olsa86a2cf32016-01-20 12:56:35 +0100105static void perf_evsel__reset_stat_priv(struct perf_evsel *evsel)
Jiri Olsa9689edf2015-06-26 11:29:14 +0200106{
107 int i;
Jiri Olsa581cc8a2015-10-16 12:41:03 +0200108 struct perf_stat_evsel *ps = evsel->priv;
Jiri Olsa9689edf2015-06-26 11:29:14 +0200109
110 for (i = 0; i < 3; i++)
111 init_stats(&ps->res_stats[i]);
112
113 perf_stat_evsel_id_init(evsel);
114}
115
Jiri Olsa86a2cf32016-01-20 12:56:35 +0100116static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel)
Jiri Olsa9689edf2015-06-26 11:29:14 +0200117{
Jiri Olsa581cc8a2015-10-16 12:41:03 +0200118 evsel->priv = zalloc(sizeof(struct perf_stat_evsel));
Jiri Olsa9689edf2015-06-26 11:29:14 +0200119 if (evsel->priv == NULL)
120 return -ENOMEM;
121 perf_evsel__reset_stat_priv(evsel);
122 return 0;
123}
124
Jiri Olsa86a2cf32016-01-20 12:56:35 +0100125static void perf_evsel__free_stat_priv(struct perf_evsel *evsel)
Jiri Olsa9689edf2015-06-26 11:29:14 +0200126{
127 zfree(&evsel->priv);
128}
Jiri Olsaa9395122015-06-26 11:29:15 +0200129
Jiri Olsa86a2cf32016-01-20 12:56:35 +0100130static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel,
131 int ncpus, int nthreads)
Jiri Olsaa9395122015-06-26 11:29:15 +0200132{
133 struct perf_counts *counts;
134
135 counts = perf_counts__new(ncpus, nthreads);
136 if (counts)
137 evsel->prev_raw_counts = counts;
138
139 return counts ? 0 : -ENOMEM;
140}
141
Jiri Olsa86a2cf32016-01-20 12:56:35 +0100142static void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel)
Jiri Olsaa9395122015-06-26 11:29:15 +0200143{
144 perf_counts__delete(evsel->prev_raw_counts);
145 evsel->prev_raw_counts = NULL;
146}
Jiri Olsa24e34f62015-06-26 11:29:16 +0200147
Srikar Dronamraju375cf9a2019-09-04 15:17:37 +0530148static void perf_evsel__reset_prev_raw_counts(struct perf_evsel *evsel)
149{
150 if (evsel->prev_raw_counts) {
151 evsel->prev_raw_counts->aggr.val = 0;
152 evsel->prev_raw_counts->aggr.ena = 0;
153 evsel->prev_raw_counts->aggr.run = 0;
154 }
155}
156
Jiri Olsa86a2cf32016-01-20 12:56:35 +0100157static int perf_evsel__alloc_stats(struct perf_evsel *evsel, bool alloc_raw)
Jiri Olsaa7d0a102015-06-26 11:29:17 +0200158{
159 int ncpus = perf_evsel__nr_cpus(evsel);
160 int nthreads = thread_map__nr(evsel->threads);
161
162 if (perf_evsel__alloc_stat_priv(evsel) < 0 ||
163 perf_evsel__alloc_counts(evsel, ncpus, nthreads) < 0 ||
164 (alloc_raw && perf_evsel__alloc_prev_raw_counts(evsel, ncpus, nthreads) < 0))
165 return -ENOMEM;
166
167 return 0;
168}
169
Jiri Olsa24e34f62015-06-26 11:29:16 +0200170int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw)
171{
172 struct perf_evsel *evsel;
Jiri Olsa24e34f62015-06-26 11:29:16 +0200173
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -0300174 evlist__for_each_entry(evlist, evsel) {
Jiri Olsaa7d0a102015-06-26 11:29:17 +0200175 if (perf_evsel__alloc_stats(evsel, alloc_raw))
Jiri Olsa24e34f62015-06-26 11:29:16 +0200176 goto out_free;
177 }
178
179 return 0;
180
181out_free:
182 perf_evlist__free_stats(evlist);
183 return -1;
184}
185
186void perf_evlist__free_stats(struct perf_evlist *evlist)
187{
188 struct perf_evsel *evsel;
189
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -0300190 evlist__for_each_entry(evlist, evsel) {
Jiri Olsa24e34f62015-06-26 11:29:16 +0200191 perf_evsel__free_stat_priv(evsel);
192 perf_evsel__free_counts(evsel);
193 perf_evsel__free_prev_raw_counts(evsel);
194 }
195}
196
197void perf_evlist__reset_stats(struct perf_evlist *evlist)
198{
199 struct perf_evsel *evsel;
200
Arnaldo Carvalho de Meloe5cadb92016-06-23 11:26:15 -0300201 evlist__for_each_entry(evlist, evsel) {
Jiri Olsa24e34f62015-06-26 11:29:16 +0200202 perf_evsel__reset_stat_priv(evsel);
203 perf_evsel__reset_counts(evsel);
204 }
205}
Jiri Olsaf80010e2015-07-21 14:31:27 +0200206
Srikar Dronamraju375cf9a2019-09-04 15:17:37 +0530207void perf_evlist__reset_prev_raw_counts(struct perf_evlist *evlist)
208{
209 struct perf_evsel *evsel;
210
211 evlist__for_each_entry(evlist, evsel)
212 perf_evsel__reset_prev_raw_counts(evsel);
213}
214
Jiri Olsaf80010e2015-07-21 14:31:27 +0200215static void zero_per_pkg(struct perf_evsel *counter)
216{
217 if (counter->per_pkg_mask)
218 memset(counter->per_pkg_mask, 0, MAX_NR_CPUS);
219}
220
Stephane Eranian02d8dab2015-09-03 15:23:40 +0200221static int check_per_pkg(struct perf_evsel *counter,
222 struct perf_counts_values *vals, int cpu, bool *skip)
Jiri Olsaf80010e2015-07-21 14:31:27 +0200223{
224 unsigned long *mask = counter->per_pkg_mask;
225 struct cpu_map *cpus = perf_evsel__cpus(counter);
226 int s;
227
228 *skip = false;
229
230 if (!counter->per_pkg)
231 return 0;
232
233 if (cpu_map__empty(cpus))
234 return 0;
235
236 if (!mask) {
237 mask = zalloc(MAX_NR_CPUS);
238 if (!mask)
239 return -ENOMEM;
240
241 counter->per_pkg_mask = mask;
242 }
243
Stephane Eranian02d8dab2015-09-03 15:23:40 +0200244 /*
245 * we do not consider an event that has not run as a good
246 * instance to mark a package as used (skip=1). Otherwise
247 * we may run into a situation where the first CPU in a package
248 * is not running anything, yet the second is, and this function
249 * would mark the package as used after the first CPU and would
250 * not read the values from the second CPU.
251 */
252 if (!(vals->run && vals->ena))
253 return 0;
254
Jiri Olsa1fe7a302015-10-16 12:41:15 +0200255 s = cpu_map__get_socket(cpus, cpu, NULL);
Jiri Olsaf80010e2015-07-21 14:31:27 +0200256 if (s < 0)
257 return -1;
258
259 *skip = test_and_set_bit(s, mask) == 1;
260 return 0;
261}
262
263static int
264process_counter_values(struct perf_stat_config *config, struct perf_evsel *evsel,
265 int cpu, int thread,
266 struct perf_counts_values *count)
267{
268 struct perf_counts_values *aggr = &evsel->counts->aggr;
269 static struct perf_counts_values zero;
270 bool skip = false;
271
Stephane Eranian02d8dab2015-09-03 15:23:40 +0200272 if (check_per_pkg(evsel, count, cpu, &skip)) {
Jiri Olsaf80010e2015-07-21 14:31:27 +0200273 pr_err("failed to read per-pkg counter\n");
274 return -1;
275 }
276
277 if (skip)
278 count = &zero;
279
280 switch (config->aggr_mode) {
281 case AGGR_THREAD:
282 case AGGR_CORE:
283 case AGGR_SOCKET:
284 case AGGR_NONE:
285 if (!evsel->snapshot)
286 perf_evsel__compute_deltas(evsel, cpu, thread, count);
287 perf_counts_values__scale(count, config->scale, NULL);
288 if (config->aggr_mode == AGGR_NONE)
289 perf_stat__update_shadow_stats(evsel, count->values, cpu);
290 break;
291 case AGGR_GLOBAL:
292 aggr->val += count->val;
293 if (config->scale) {
294 aggr->ena += count->ena;
295 aggr->run += count->run;
296 }
Jiri Olsa208df992015-10-16 12:41:04 +0200297 case AGGR_UNSET:
Jiri Olsaf80010e2015-07-21 14:31:27 +0200298 default:
299 break;
300 }
301
302 return 0;
303}
304
305static int process_counter_maps(struct perf_stat_config *config,
306 struct perf_evsel *counter)
307{
308 int nthreads = thread_map__nr(counter->threads);
309 int ncpus = perf_evsel__nr_cpus(counter);
310 int cpu, thread;
311
312 if (counter->system_wide)
313 nthreads = 1;
314
315 for (thread = 0; thread < nthreads; thread++) {
316 for (cpu = 0; cpu < ncpus; cpu++) {
317 if (process_counter_values(config, counter, cpu, thread,
318 perf_counts(counter->counts, cpu, thread)))
319 return -1;
320 }
321 }
322
323 return 0;
324}
325
326int perf_stat_process_counter(struct perf_stat_config *config,
327 struct perf_evsel *counter)
328{
329 struct perf_counts_values *aggr = &counter->counts->aggr;
Jiri Olsa581cc8a2015-10-16 12:41:03 +0200330 struct perf_stat_evsel *ps = counter->priv;
Jiri Olsaf80010e2015-07-21 14:31:27 +0200331 u64 *count = counter->counts->aggr.values;
Andi Kleenf340c5f2016-05-05 16:04:04 -0700332 u64 val;
Jiri Olsaf80010e2015-07-21 14:31:27 +0200333 int i, ret;
334
335 aggr->val = aggr->ena = aggr->run = 0;
Jiri Olsaf80010e2015-07-21 14:31:27 +0200336
Jiri Olsa51fd2df2016-02-03 08:43:56 +0100337 /*
338 * We calculate counter's data every interval,
339 * and the display code shows ps->res_stats
340 * avg value. We need to zero the stats for
341 * interval mode, otherwise overall avg running
342 * averages will be shown for each interval.
343 */
344 if (config->interval)
345 init_stats(ps->res_stats);
346
Jiri Olsaf80010e2015-07-21 14:31:27 +0200347 if (counter->per_pkg)
348 zero_per_pkg(counter);
349
350 ret = process_counter_maps(config, counter);
351 if (ret)
352 return ret;
353
354 if (config->aggr_mode != AGGR_GLOBAL)
355 return 0;
356
357 if (!counter->snapshot)
358 perf_evsel__compute_deltas(counter, -1, -1, aggr);
359 perf_counts_values__scale(aggr, config->scale, &counter->counts->scaled);
360
361 for (i = 0; i < 3; i++)
362 update_stats(&ps->res_stats[i], count[i]);
363
364 if (verbose) {
365 fprintf(config->output, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
366 perf_evsel__name(counter), count[0], count[1], count[2]);
367 }
368
369 /*
370 * Save the full runtime - to allow normalization during printout:
371 */
Andi Kleenf340c5f2016-05-05 16:04:04 -0700372 val = counter->scale * *count;
373 perf_stat__update_shadow_stats(counter, &val, 0);
Jiri Olsaf80010e2015-07-21 14:31:27 +0200374
375 return 0;
376}
Jiri Olsa0ea0e352015-10-25 15:51:32 +0100377
378int perf_event__process_stat_event(struct perf_tool *tool __maybe_unused,
379 union perf_event *event,
380 struct perf_session *session)
381{
382 struct perf_counts_values count;
383 struct stat_event *st = &event->stat;
384 struct perf_evsel *counter;
385
386 count.val = st->val;
387 count.ena = st->ena;
388 count.run = st->run;
389
390 counter = perf_evlist__id2evsel(session->evlist, st->id);
391 if (!counter) {
392 pr_err("Failed to resolve counter for stat event.\n");
393 return -EINVAL;
394 }
395
396 *perf_counts(counter->counts, st->cpu, st->thread) = count;
397 counter->supported = true;
398 return 0;
399}
Jiri Olsae08a4562015-10-25 15:51:35 +0100400
401size_t perf_event__fprintf_stat(union perf_event *event, FILE *fp)
402{
403 struct stat_event *st = (struct stat_event *) event;
404 size_t ret;
405
406 ret = fprintf(fp, "\n... id %" PRIu64 ", cpu %d, thread %d\n",
407 st->id, st->cpu, st->thread);
408 ret += fprintf(fp, "... value %" PRIu64 ", enabled %" PRIu64 ", running %" PRIu64 "\n",
409 st->val, st->ena, st->run);
410
411 return ret;
412}
413
414size_t perf_event__fprintf_stat_round(union perf_event *event, FILE *fp)
415{
416 struct stat_round_event *rd = (struct stat_round_event *)event;
417 size_t ret;
418
419 ret = fprintf(fp, "\n... time %" PRIu64 ", type %s\n", rd->time,
420 rd->type == PERF_STAT_ROUND_TYPE__FINAL ? "FINAL" : "INTERVAL");
421
422 return ret;
423}
424
425size_t perf_event__fprintf_stat_config(union perf_event *event, FILE *fp)
426{
427 struct perf_stat_config sc;
428 size_t ret;
429
430 perf_event__read_stat_config(&sc, &event->stat_config);
431
432 ret = fprintf(fp, "\n");
433 ret += fprintf(fp, "... aggr_mode %d\n", sc.aggr_mode);
434 ret += fprintf(fp, "... scale %d\n", sc.scale);
435 ret += fprintf(fp, "... interval %u\n", sc.interval);
436
437 return ret;
438}