blob: c5c709cdc3ce7da55f450922bb5109da754d5db0 [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{
70 struct perf_stat *ps = evsel->priv;
71
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/),
Jiri Olsae2f56da2015-06-04 15:50:55 +020082};
83#undef ID
84
85void perf_stat_evsel_id_init(struct perf_evsel *evsel)
86{
87 struct perf_stat *ps = evsel->priv;
88 int i;
89
90 /* ps->id is 0 hence PERF_STAT_EVSEL_ID__NONE by default */
91
92 for (i = 0; i < PERF_STAT_EVSEL_ID__MAX; i++) {
93 if (!strcmp(perf_evsel__name(evsel), id_str[i])) {
94 ps->id = i;
95 break;
96 }
97 }
98}
Jiri Olsaa9a3a4d2015-06-14 10:19:26 +020099
Jiri Olsaa6fa0032015-06-26 11:29:11 +0200100struct perf_counts *perf_counts__new(int ncpus, int nthreads)
Jiri Olsa9df38e82015-06-14 10:19:27 +0200101{
Jiri Olsaa8e02322015-06-26 11:29:10 +0200102 struct perf_counts *counts = zalloc(sizeof(*counts));
Jiri Olsa9df38e82015-06-14 10:19:27 +0200103
Jiri Olsaa8e02322015-06-26 11:29:10 +0200104 if (counts) {
Jiri Olsa57b28912015-06-26 11:29:12 +0200105 struct xyarray *values;
Jiri Olsaa8e02322015-06-26 11:29:10 +0200106
Jiri Olsa57b28912015-06-26 11:29:12 +0200107 values = xyarray__new(ncpus, nthreads, sizeof(struct perf_counts_values));
108 if (!values) {
Jiri Olsaa8e02322015-06-26 11:29:10 +0200109 free(counts);
110 return NULL;
111 }
112
Jiri Olsa57b28912015-06-26 11:29:12 +0200113 counts->values = values;
Jiri Olsaa8e02322015-06-26 11:29:10 +0200114 }
115
116 return counts;
Jiri Olsa9df38e82015-06-14 10:19:27 +0200117}
118
119void perf_counts__delete(struct perf_counts *counts)
120{
Jiri Olsaa8e02322015-06-26 11:29:10 +0200121 if (counts) {
Jiri Olsa57b28912015-06-26 11:29:12 +0200122 xyarray__delete(counts->values);
Jiri Olsaa8e02322015-06-26 11:29:10 +0200123 free(counts);
124 }
Jiri Olsa9df38e82015-06-14 10:19:27 +0200125}
126
Jiri Olsaa8e02322015-06-26 11:29:10 +0200127static void perf_counts__reset(struct perf_counts *counts)
Jiri Olsa9df38e82015-06-14 10:19:27 +0200128{
Jiri Olsa57b28912015-06-26 11:29:12 +0200129 xyarray__reset(counts->values);
Jiri Olsa9df38e82015-06-14 10:19:27 +0200130}
131
Jiri Olsaa8e02322015-06-26 11:29:10 +0200132void perf_evsel__reset_counts(struct perf_evsel *evsel)
Jiri Olsaa9a3a4d2015-06-14 10:19:26 +0200133{
Jiri Olsaa8e02322015-06-26 11:29:10 +0200134 perf_counts__reset(evsel->counts);
Jiri Olsaa9a3a4d2015-06-14 10:19:26 +0200135}
136
Jiri Olsaa6fa0032015-06-26 11:29:11 +0200137int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus, int nthreads)
Jiri Olsaa9a3a4d2015-06-14 10:19:26 +0200138{
Jiri Olsaa6fa0032015-06-26 11:29:11 +0200139 evsel->counts = perf_counts__new(ncpus, nthreads);
Jiri Olsaa9a3a4d2015-06-14 10:19:26 +0200140 return evsel->counts != NULL ? 0 : -ENOMEM;
141}
142
143void perf_evsel__free_counts(struct perf_evsel *evsel)
144{
Jiri Olsa9df38e82015-06-14 10:19:27 +0200145 perf_counts__delete(evsel->counts);
146 evsel->counts = NULL;
Jiri Olsaa9a3a4d2015-06-14 10:19:26 +0200147}
Jiri Olsa9689edf2015-06-26 11:29:14 +0200148
149void perf_evsel__reset_stat_priv(struct perf_evsel *evsel)
150{
151 int i;
152 struct perf_stat *ps = evsel->priv;
153
154 for (i = 0; i < 3; i++)
155 init_stats(&ps->res_stats[i]);
156
157 perf_stat_evsel_id_init(evsel);
158}
159
160int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel)
161{
162 evsel->priv = zalloc(sizeof(struct perf_stat));
163 if (evsel->priv == NULL)
164 return -ENOMEM;
165 perf_evsel__reset_stat_priv(evsel);
166 return 0;
167}
168
169void perf_evsel__free_stat_priv(struct perf_evsel *evsel)
170{
171 zfree(&evsel->priv);
172}
Jiri Olsaa9395122015-06-26 11:29:15 +0200173
174int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel,
175 int ncpus, int nthreads)
176{
177 struct perf_counts *counts;
178
179 counts = perf_counts__new(ncpus, nthreads);
180 if (counts)
181 evsel->prev_raw_counts = counts;
182
183 return counts ? 0 : -ENOMEM;
184}
185
186void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel)
187{
188 perf_counts__delete(evsel->prev_raw_counts);
189 evsel->prev_raw_counts = NULL;
190}
Jiri Olsa24e34f62015-06-26 11:29:16 +0200191
Jiri Olsaa7d0a102015-06-26 11:29:17 +0200192int perf_evsel__alloc_stats(struct perf_evsel *evsel, bool alloc_raw)
193{
194 int ncpus = perf_evsel__nr_cpus(evsel);
195 int nthreads = thread_map__nr(evsel->threads);
196
197 if (perf_evsel__alloc_stat_priv(evsel) < 0 ||
198 perf_evsel__alloc_counts(evsel, ncpus, nthreads) < 0 ||
199 (alloc_raw && perf_evsel__alloc_prev_raw_counts(evsel, ncpus, nthreads) < 0))
200 return -ENOMEM;
201
202 return 0;
203}
204
Jiri Olsa24e34f62015-06-26 11:29:16 +0200205int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw)
206{
207 struct perf_evsel *evsel;
Jiri Olsa24e34f62015-06-26 11:29:16 +0200208
209 evlist__for_each(evlist, evsel) {
Jiri Olsaa7d0a102015-06-26 11:29:17 +0200210 if (perf_evsel__alloc_stats(evsel, alloc_raw))
Jiri Olsa24e34f62015-06-26 11:29:16 +0200211 goto out_free;
212 }
213
214 return 0;
215
216out_free:
217 perf_evlist__free_stats(evlist);
218 return -1;
219}
220
221void perf_evlist__free_stats(struct perf_evlist *evlist)
222{
223 struct perf_evsel *evsel;
224
225 evlist__for_each(evlist, evsel) {
226 perf_evsel__free_stat_priv(evsel);
227 perf_evsel__free_counts(evsel);
228 perf_evsel__free_prev_raw_counts(evsel);
229 }
230}
231
232void perf_evlist__reset_stats(struct perf_evlist *evlist)
233{
234 struct perf_evsel *evsel;
235
236 evlist__for_each(evlist, evsel) {
237 perf_evsel__reset_stat_priv(evsel);
238 perf_evsel__reset_counts(evsel);
239 }
240}
Jiri Olsaf80010e2015-07-21 14:31:27 +0200241
242static void zero_per_pkg(struct perf_evsel *counter)
243{
244 if (counter->per_pkg_mask)
245 memset(counter->per_pkg_mask, 0, MAX_NR_CPUS);
246}
247
248static int check_per_pkg(struct perf_evsel *counter, int cpu, bool *skip)
249{
250 unsigned long *mask = counter->per_pkg_mask;
251 struct cpu_map *cpus = perf_evsel__cpus(counter);
252 int s;
253
254 *skip = false;
255
256 if (!counter->per_pkg)
257 return 0;
258
259 if (cpu_map__empty(cpus))
260 return 0;
261
262 if (!mask) {
263 mask = zalloc(MAX_NR_CPUS);
264 if (!mask)
265 return -ENOMEM;
266
267 counter->per_pkg_mask = mask;
268 }
269
270 s = cpu_map__get_socket(cpus, cpu);
271 if (s < 0)
272 return -1;
273
274 *skip = test_and_set_bit(s, mask) == 1;
275 return 0;
276}
277
278static int
279process_counter_values(struct perf_stat_config *config, struct perf_evsel *evsel,
280 int cpu, int thread,
281 struct perf_counts_values *count)
282{
283 struct perf_counts_values *aggr = &evsel->counts->aggr;
284 static struct perf_counts_values zero;
285 bool skip = false;
286
287 if (check_per_pkg(evsel, cpu, &skip)) {
288 pr_err("failed to read per-pkg counter\n");
289 return -1;
290 }
291
292 if (skip)
293 count = &zero;
294
295 switch (config->aggr_mode) {
296 case AGGR_THREAD:
297 case AGGR_CORE:
298 case AGGR_SOCKET:
299 case AGGR_NONE:
300 if (!evsel->snapshot)
301 perf_evsel__compute_deltas(evsel, cpu, thread, count);
302 perf_counts_values__scale(count, config->scale, NULL);
303 if (config->aggr_mode == AGGR_NONE)
304 perf_stat__update_shadow_stats(evsel, count->values, cpu);
305 break;
306 case AGGR_GLOBAL:
307 aggr->val += count->val;
308 if (config->scale) {
309 aggr->ena += count->ena;
310 aggr->run += count->run;
311 }
312 default:
313 break;
314 }
315
316 return 0;
317}
318
319static int process_counter_maps(struct perf_stat_config *config,
320 struct perf_evsel *counter)
321{
322 int nthreads = thread_map__nr(counter->threads);
323 int ncpus = perf_evsel__nr_cpus(counter);
324 int cpu, thread;
325
326 if (counter->system_wide)
327 nthreads = 1;
328
329 for (thread = 0; thread < nthreads; thread++) {
330 for (cpu = 0; cpu < ncpus; cpu++) {
331 if (process_counter_values(config, counter, cpu, thread,
332 perf_counts(counter->counts, cpu, thread)))
333 return -1;
334 }
335 }
336
337 return 0;
338}
339
340int perf_stat_process_counter(struct perf_stat_config *config,
341 struct perf_evsel *counter)
342{
343 struct perf_counts_values *aggr = &counter->counts->aggr;
344 struct perf_stat *ps = counter->priv;
345 u64 *count = counter->counts->aggr.values;
346 int i, ret;
347
348 aggr->val = aggr->ena = aggr->run = 0;
349 init_stats(ps->res_stats);
350
351 if (counter->per_pkg)
352 zero_per_pkg(counter);
353
354 ret = process_counter_maps(config, counter);
355 if (ret)
356 return ret;
357
358 if (config->aggr_mode != AGGR_GLOBAL)
359 return 0;
360
361 if (!counter->snapshot)
362 perf_evsel__compute_deltas(counter, -1, -1, aggr);
363 perf_counts_values__scale(aggr, config->scale, &counter->counts->scaled);
364
365 for (i = 0; i < 3; i++)
366 update_stats(&ps->res_stats[i], count[i]);
367
368 if (verbose) {
369 fprintf(config->output, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
370 perf_evsel__name(counter), count[0], count[1], count[2]);
371 }
372
373 /*
374 * Save the full runtime - to allow normalization during printout:
375 */
376 perf_stat__update_shadow_stats(counter, count, 0);
377
378 return 0;
379}