blob: 151e9efd728623328d22bffb280f2948ff79591e [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Arnaldo Carvalho de Meloa43783a2017-04-18 10:46:11 -03002#include <errno.h>
Arnaldo Carvalho de Melofd20e812017-04-17 15:23:08 -03003#include <inttypes.h>
Xiao Guangrong0007ece2012-09-17 16:31:14 +08004#include <math.h>
Xiao Guangrong0007ece2012-09-17 16:31:14 +08005#include "stat.h"
Jiri Olsa24e34f62015-06-26 11:29:16 +02006#include "evlist.h"
Jiri Olsae2f56da2015-06-04 15:50:55 +02007#include "evsel.h"
Jiri Olsa24e34f62015-06-26 11:29:16 +02008#include "thread_map.h"
Xiao Guangrong0007ece2012-09-17 16:31:14 +08009
10void update_stats(struct stats *stats, u64 val)
11{
12 double delta;
13
14 stats->n++;
15 delta = val - stats->mean;
16 stats->mean += delta / stats->n;
17 stats->M2 += delta*(val - stats->mean);
David Ahernffe4f3c2013-08-02 14:05:40 -060018
19 if (val > stats->max)
20 stats->max = val;
21
22 if (val < stats->min)
23 stats->min = val;
Xiao Guangrong0007ece2012-09-17 16:31:14 +080024}
25
26double avg_stats(struct stats *stats)
27{
28 return stats->mean;
29}
30
31/*
32 * http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
33 *
34 * (\Sum n_i^2) - ((\Sum n_i)^2)/n
35 * s^2 = -------------------------------
36 * n - 1
37 *
38 * http://en.wikipedia.org/wiki/Stddev
39 *
40 * The std dev of the mean is related to the std dev by:
41 *
42 * s
43 * s_mean = -------
44 * sqrt(n)
45 *
46 */
47double stddev_stats(struct stats *stats)
48{
49 double variance, variance_mean;
50
David Ahern45528f72013-05-25 18:24:48 -060051 if (stats->n < 2)
Xiao Guangrong0007ece2012-09-17 16:31:14 +080052 return 0.0;
53
54 variance = stats->M2 / (stats->n - 1);
55 variance_mean = variance / stats->n;
56
57 return sqrt(variance_mean);
58}
59
60double rel_stddev_stats(double stddev, double avg)
61{
62 double pct = 0.0;
63
64 if (avg)
65 pct = 100.0 * stddev/avg;
66
67 return pct;
68}
Jiri Olsae2f56da2015-06-04 15:50:55 +020069
70bool __perf_evsel_stat__is(struct perf_evsel *evsel,
71 enum perf_stat_evsel_id id)
72{
Arnaldo Carvalho de Meloe669e832017-10-26 14:22:34 -030073 struct perf_stat_evsel *ps = evsel->stats;
Jiri Olsae2f56da2015-06-04 15:50:55 +020074
75 return ps->id == id;
76}
77
78#define ID(id, name) [PERF_STAT_EVSEL_ID__##id] = #name
79static const char *id_str[PERF_STAT_EVSEL_ID__MAX] = {
Jiri Olsa4c358d52015-06-03 16:25:52 +020080 ID(NONE, x),
81 ID(CYCLES_IN_TX, cpu/cycles-t/),
82 ID(TRANSACTION_START, cpu/tx-start/),
83 ID(ELISION_START, cpu/el-start/),
84 ID(CYCLES_IN_TX_CP, cpu/cycles-ct/),
Andi Kleen239bd472016-05-24 12:52:37 -070085 ID(TOPDOWN_TOTAL_SLOTS, topdown-total-slots),
86 ID(TOPDOWN_SLOTS_ISSUED, topdown-slots-issued),
87 ID(TOPDOWN_SLOTS_RETIRED, topdown-slots-retired),
88 ID(TOPDOWN_FETCH_BUBBLES, topdown-fetch-bubbles),
89 ID(TOPDOWN_RECOVERY_BUBBLES, topdown-recovery-bubbles),
Kan Liangdaefd0b2017-05-26 12:05:38 -070090 ID(SMI_NUM, msr/smi/),
91 ID(APERF, msr/aperf/),
Jiri Olsae2f56da2015-06-04 15:50:55 +020092};
93#undef ID
94
95void perf_stat_evsel_id_init(struct perf_evsel *evsel)
96{
Arnaldo Carvalho de Meloe669e832017-10-26 14:22:34 -030097 struct perf_stat_evsel *ps = evsel->stats;
Jiri Olsae2f56da2015-06-04 15:50:55 +020098 int i;
99
100 /* ps->id is 0 hence PERF_STAT_EVSEL_ID__NONE by default */
101
102 for (i = 0; i < PERF_STAT_EVSEL_ID__MAX; i++) {
103 if (!strcmp(perf_evsel__name(evsel), id_str[i])) {
104 ps->id = i;
105 break;
106 }
107 }
108}
Jiri Olsaa9a3a4d2015-06-14 10:19:26 +0200109
Jiri Olsa86a2cf32016-01-20 12:56:35 +0100110static void perf_evsel__reset_stat_priv(struct perf_evsel *evsel)
Jiri Olsa9689edf2015-06-26 11:29:14 +0200111{
112 int i;
Arnaldo Carvalho de Meloe669e832017-10-26 14:22:34 -0300113 struct perf_stat_evsel *ps = evsel->stats;
Jiri Olsa9689edf2015-06-26 11:29:14 +0200114
115 for (i = 0; i < 3; i++)
116 init_stats(&ps->res_stats[i]);
117
118 perf_stat_evsel_id_init(evsel);
119}
120
Jiri Olsa86a2cf32016-01-20 12:56:35 +0100121static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel)
Jiri Olsa9689edf2015-06-26 11:29:14 +0200122{
Arnaldo Carvalho de Meloe669e832017-10-26 14:22:34 -0300123 evsel->stats = zalloc(sizeof(struct perf_stat_evsel));
124 if (evsel->stats == NULL)
Jiri Olsa9689edf2015-06-26 11:29:14 +0200125 return -ENOMEM;
126 perf_evsel__reset_stat_priv(evsel);
127 return 0;
128}
129
Jiri Olsa86a2cf32016-01-20 12:56:35 +0100130static void perf_evsel__free_stat_priv(struct perf_evsel *evsel)
Jiri Olsa9689edf2015-06-26 11:29:14 +0200131{
Arnaldo Carvalho de Meloe669e832017-10-26 14:22:34 -0300132 struct perf_stat_evsel *ps = evsel->stats;
Jiri Olsaf7794d52017-07-26 14:02:05 +0200133
134 if (ps)
135 free(ps->group_data);
Arnaldo Carvalho de Meloe669e832017-10-26 14:22:34 -0300136 zfree(&evsel->stats);
Jiri Olsa9689edf2015-06-26 11:29:14 +0200137}
Jiri Olsaa9395122015-06-26 11:29:15 +0200138
Jiri Olsa86a2cf32016-01-20 12:56:35 +0100139static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel,
140 int ncpus, int nthreads)
Jiri Olsaa9395122015-06-26 11:29:15 +0200141{
142 struct perf_counts *counts;
143
144 counts = perf_counts__new(ncpus, nthreads);
145 if (counts)
146 evsel->prev_raw_counts = counts;
147
148 return counts ? 0 : -ENOMEM;
149}
150
Jiri Olsa86a2cf32016-01-20 12:56:35 +0100151static void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel)
Jiri Olsaa9395122015-06-26 11:29:15 +0200152{
153 perf_counts__delete(evsel->prev_raw_counts);
154 evsel->prev_raw_counts = NULL;
155}
Jiri Olsa24e34f62015-06-26 11:29:16 +0200156
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
207static void zero_per_pkg(struct perf_evsel *counter)
208{
209 if (counter->per_pkg_mask)
210 memset(counter->per_pkg_mask, 0, MAX_NR_CPUS);
211}
212
Stephane Eranian02d8dab2015-09-03 15:23:40 +0200213static int check_per_pkg(struct perf_evsel *counter,
214 struct perf_counts_values *vals, int cpu, bool *skip)
Jiri Olsaf80010e2015-07-21 14:31:27 +0200215{
216 unsigned long *mask = counter->per_pkg_mask;
217 struct cpu_map *cpus = perf_evsel__cpus(counter);
218 int s;
219
220 *skip = false;
221
222 if (!counter->per_pkg)
223 return 0;
224
225 if (cpu_map__empty(cpus))
226 return 0;
227
228 if (!mask) {
229 mask = zalloc(MAX_NR_CPUS);
230 if (!mask)
231 return -ENOMEM;
232
233 counter->per_pkg_mask = mask;
234 }
235
Stephane Eranian02d8dab2015-09-03 15:23:40 +0200236 /*
237 * we do not consider an event that has not run as a good
238 * instance to mark a package as used (skip=1). Otherwise
239 * we may run into a situation where the first CPU in a package
240 * is not running anything, yet the second is, and this function
241 * would mark the package as used after the first CPU and would
242 * not read the values from the second CPU.
243 */
244 if (!(vals->run && vals->ena))
245 return 0;
246
Jiri Olsa1fe7a302015-10-16 12:41:15 +0200247 s = cpu_map__get_socket(cpus, cpu, NULL);
Jiri Olsaf80010e2015-07-21 14:31:27 +0200248 if (s < 0)
249 return -1;
250
251 *skip = test_and_set_bit(s, mask) == 1;
252 return 0;
253}
254
255static int
256process_counter_values(struct perf_stat_config *config, struct perf_evsel *evsel,
257 int cpu, int thread,
258 struct perf_counts_values *count)
259{
260 struct perf_counts_values *aggr = &evsel->counts->aggr;
261 static struct perf_counts_values zero;
262 bool skip = false;
263
Stephane Eranian02d8dab2015-09-03 15:23:40 +0200264 if (check_per_pkg(evsel, count, cpu, &skip)) {
Jiri Olsaf80010e2015-07-21 14:31:27 +0200265 pr_err("failed to read per-pkg counter\n");
266 return -1;
267 }
268
269 if (skip)
270 count = &zero;
271
272 switch (config->aggr_mode) {
273 case AGGR_THREAD:
274 case AGGR_CORE:
275 case AGGR_SOCKET:
276 case AGGR_NONE:
277 if (!evsel->snapshot)
278 perf_evsel__compute_deltas(evsel, cpu, thread, count);
279 perf_counts_values__scale(count, config->scale, NULL);
280 if (config->aggr_mode == AGGR_NONE)
Jiri Olsa54830dd2017-01-23 22:42:56 +0100281 perf_stat__update_shadow_stats(evsel, count->val, cpu);
Jiri Olsa021b4622017-10-12 13:21:01 +0200282 if (config->aggr_mode == AGGR_THREAD)
283 perf_stat__update_shadow_stats(evsel, count->val, 0);
Jiri Olsaf80010e2015-07-21 14:31:27 +0200284 break;
285 case AGGR_GLOBAL:
286 aggr->val += count->val;
287 if (config->scale) {
288 aggr->ena += count->ena;
289 aggr->run += count->run;
290 }
Jiri Olsa208df992015-10-16 12:41:04 +0200291 case AGGR_UNSET:
Jiri Olsaf80010e2015-07-21 14:31:27 +0200292 default:
293 break;
294 }
295
296 return 0;
297}
298
299static int process_counter_maps(struct perf_stat_config *config,
300 struct perf_evsel *counter)
301{
302 int nthreads = thread_map__nr(counter->threads);
303 int ncpus = perf_evsel__nr_cpus(counter);
304 int cpu, thread;
305
306 if (counter->system_wide)
307 nthreads = 1;
308
309 for (thread = 0; thread < nthreads; thread++) {
310 for (cpu = 0; cpu < ncpus; cpu++) {
311 if (process_counter_values(config, counter, cpu, thread,
312 perf_counts(counter->counts, cpu, thread)))
313 return -1;
314 }
315 }
316
317 return 0;
318}
319
320int perf_stat_process_counter(struct perf_stat_config *config,
321 struct perf_evsel *counter)
322{
323 struct perf_counts_values *aggr = &counter->counts->aggr;
Arnaldo Carvalho de Meloe669e832017-10-26 14:22:34 -0300324 struct perf_stat_evsel *ps = counter->stats;
Jiri Olsaf80010e2015-07-21 14:31:27 +0200325 u64 *count = counter->counts->aggr.values;
326 int i, ret;
327
328 aggr->val = aggr->ena = aggr->run = 0;
Jiri Olsaf80010e2015-07-21 14:31:27 +0200329
Jiri Olsa51fd2df2016-02-03 08:43:56 +0100330 /*
331 * We calculate counter's data every interval,
332 * and the display code shows ps->res_stats
333 * avg value. We need to zero the stats for
334 * interval mode, otherwise overall avg running
335 * averages will be shown for each interval.
336 */
337 if (config->interval)
338 init_stats(ps->res_stats);
339
Jiri Olsaf80010e2015-07-21 14:31:27 +0200340 if (counter->per_pkg)
341 zero_per_pkg(counter);
342
343 ret = process_counter_maps(config, counter);
344 if (ret)
345 return ret;
346
347 if (config->aggr_mode != AGGR_GLOBAL)
348 return 0;
349
350 if (!counter->snapshot)
351 perf_evsel__compute_deltas(counter, -1, -1, aggr);
352 perf_counts_values__scale(aggr, config->scale, &counter->counts->scaled);
353
354 for (i = 0; i < 3; i++)
355 update_stats(&ps->res_stats[i], count[i]);
356
Namhyung Kimbb963e12017-02-17 17:17:38 +0900357 if (verbose > 0) {
Jiri Olsaf80010e2015-07-21 14:31:27 +0200358 fprintf(config->output, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
359 perf_evsel__name(counter), count[0], count[1], count[2]);
360 }
361
362 /*
363 * Save the full runtime - to allow normalization during printout:
364 */
Jiri Olsa54830dd2017-01-23 22:42:56 +0100365 perf_stat__update_shadow_stats(counter, *count, 0);
Jiri Olsaf80010e2015-07-21 14:31:27 +0200366
367 return 0;
368}
Jiri Olsa0ea0e352015-10-25 15:51:32 +0100369
370int perf_event__process_stat_event(struct perf_tool *tool __maybe_unused,
371 union perf_event *event,
372 struct perf_session *session)
373{
374 struct perf_counts_values count;
375 struct stat_event *st = &event->stat;
376 struct perf_evsel *counter;
377
378 count.val = st->val;
379 count.ena = st->ena;
380 count.run = st->run;
381
382 counter = perf_evlist__id2evsel(session->evlist, st->id);
383 if (!counter) {
384 pr_err("Failed to resolve counter for stat event.\n");
385 return -EINVAL;
386 }
387
388 *perf_counts(counter->counts, st->cpu, st->thread) = count;
389 counter->supported = true;
390 return 0;
391}
Jiri Olsae08a4562015-10-25 15:51:35 +0100392
393size_t perf_event__fprintf_stat(union perf_event *event, FILE *fp)
394{
395 struct stat_event *st = (struct stat_event *) event;
396 size_t ret;
397
398 ret = fprintf(fp, "\n... id %" PRIu64 ", cpu %d, thread %d\n",
399 st->id, st->cpu, st->thread);
400 ret += fprintf(fp, "... value %" PRIu64 ", enabled %" PRIu64 ", running %" PRIu64 "\n",
401 st->val, st->ena, st->run);
402
403 return ret;
404}
405
406size_t perf_event__fprintf_stat_round(union perf_event *event, FILE *fp)
407{
408 struct stat_round_event *rd = (struct stat_round_event *)event;
409 size_t ret;
410
411 ret = fprintf(fp, "\n... time %" PRIu64 ", type %s\n", rd->time,
412 rd->type == PERF_STAT_ROUND_TYPE__FINAL ? "FINAL" : "INTERVAL");
413
414 return ret;
415}
416
417size_t perf_event__fprintf_stat_config(union perf_event *event, FILE *fp)
418{
419 struct perf_stat_config sc;
420 size_t ret;
421
422 perf_event__read_stat_config(&sc, &event->stat_config);
423
424 ret = fprintf(fp, "\n");
425 ret += fprintf(fp, "... aggr_mode %d\n", sc.aggr_mode);
426 ret += fprintf(fp, "... scale %d\n", sc.scale);
427 ret += fprintf(fp, "... interval %u\n", sc.interval);
428
429 return ret;
430}