5 #include "thread_map.h"
7 void update_stats(struct stats
*stats
, u64 val
)
12 delta
= val
- stats
->mean
;
13 stats
->mean
+= delta
/ stats
->n
;
14 stats
->M2
+= delta
*(val
- stats
->mean
);
23 double avg_stats(struct stats
*stats
)
29 * http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
31 * (\Sum n_i^2) - ((\Sum n_i)^2)/n
32 * s^2 = -------------------------------
35 * http://en.wikipedia.org/wiki/Stddev
37 * The std dev of the mean is related to the std dev by:
44 double stddev_stats(struct stats
*stats
)
46 double variance
, variance_mean
;
51 variance
= stats
->M2
/ (stats
->n
- 1);
52 variance_mean
= variance
/ stats
->n
;
54 return sqrt(variance_mean
);
57 double rel_stddev_stats(double stddev
, double avg
)
62 pct
= 100.0 * stddev
/avg
;
67 bool __perf_evsel_stat__is(struct perf_evsel
*evsel
,
68 enum perf_stat_evsel_id id
)
70 struct perf_stat_evsel
*ps
= evsel
->priv
;
75 #define ID(id, name) [PERF_STAT_EVSEL_ID__##id] = #name
76 static const char *id_str
[PERF_STAT_EVSEL_ID__MAX
] = {
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
/),
85 void perf_stat_evsel_id_init(struct perf_evsel
*evsel
)
87 struct perf_stat_evsel
*ps
= evsel
->priv
;
90 /* ps->id is 0 hence PERF_STAT_EVSEL_ID__NONE by default */
92 for (i
= 0; i
< PERF_STAT_EVSEL_ID__MAX
; i
++) {
93 if (!strcmp(perf_evsel__name(evsel
), id_str
[i
])) {
100 void perf_evsel__reset_stat_priv(struct perf_evsel
*evsel
)
103 struct perf_stat_evsel
*ps
= evsel
->priv
;
105 for (i
= 0; i
< 3; i
++)
106 init_stats(&ps
->res_stats
[i
]);
108 perf_stat_evsel_id_init(evsel
);
111 int perf_evsel__alloc_stat_priv(struct perf_evsel
*evsel
)
113 evsel
->priv
= zalloc(sizeof(struct perf_stat_evsel
));
114 if (evsel
->priv
== NULL
)
116 perf_evsel__reset_stat_priv(evsel
);
120 void perf_evsel__free_stat_priv(struct perf_evsel
*evsel
)
125 int perf_evsel__alloc_prev_raw_counts(struct perf_evsel
*evsel
,
126 int ncpus
, int nthreads
)
128 struct perf_counts
*counts
;
130 counts
= perf_counts__new(ncpus
, nthreads
);
132 evsel
->prev_raw_counts
= counts
;
134 return counts
? 0 : -ENOMEM
;
137 void perf_evsel__free_prev_raw_counts(struct perf_evsel
*evsel
)
139 perf_counts__delete(evsel
->prev_raw_counts
);
140 evsel
->prev_raw_counts
= NULL
;
143 int perf_evsel__alloc_stats(struct perf_evsel
*evsel
, bool alloc_raw
)
145 int ncpus
= perf_evsel__nr_cpus(evsel
);
146 int nthreads
= thread_map__nr(evsel
->threads
);
148 if (perf_evsel__alloc_stat_priv(evsel
) < 0 ||
149 perf_evsel__alloc_counts(evsel
, ncpus
, nthreads
) < 0 ||
150 (alloc_raw
&& perf_evsel__alloc_prev_raw_counts(evsel
, ncpus
, nthreads
) < 0))
156 int perf_evlist__alloc_stats(struct perf_evlist
*evlist
, bool alloc_raw
)
158 struct perf_evsel
*evsel
;
160 evlist__for_each(evlist
, evsel
) {
161 if (perf_evsel__alloc_stats(evsel
, alloc_raw
))
168 perf_evlist__free_stats(evlist
);
172 void perf_evlist__free_stats(struct perf_evlist
*evlist
)
174 struct perf_evsel
*evsel
;
176 evlist__for_each(evlist
, evsel
) {
177 perf_evsel__free_stat_priv(evsel
);
178 perf_evsel__free_counts(evsel
);
179 perf_evsel__free_prev_raw_counts(evsel
);
183 void perf_evlist__reset_stats(struct perf_evlist
*evlist
)
185 struct perf_evsel
*evsel
;
187 evlist__for_each(evlist
, evsel
) {
188 perf_evsel__reset_stat_priv(evsel
);
189 perf_evsel__reset_counts(evsel
);
193 static void zero_per_pkg(struct perf_evsel
*counter
)
195 if (counter
->per_pkg_mask
)
196 memset(counter
->per_pkg_mask
, 0, MAX_NR_CPUS
);
199 static int check_per_pkg(struct perf_evsel
*counter
,
200 struct perf_counts_values
*vals
, int cpu
, bool *skip
)
202 unsigned long *mask
= counter
->per_pkg_mask
;
203 struct cpu_map
*cpus
= perf_evsel__cpus(counter
);
208 if (!counter
->per_pkg
)
211 if (cpu_map__empty(cpus
))
215 mask
= zalloc(MAX_NR_CPUS
);
219 counter
->per_pkg_mask
= mask
;
223 * we do not consider an event that has not run as a good
224 * instance to mark a package as used (skip=1). Otherwise
225 * we may run into a situation where the first CPU in a package
226 * is not running anything, yet the second is, and this function
227 * would mark the package as used after the first CPU and would
228 * not read the values from the second CPU.
230 if (!(vals
->run
&& vals
->ena
))
233 s
= cpu_map__get_socket(cpus
, cpu
, NULL
);
237 *skip
= test_and_set_bit(s
, mask
) == 1;
242 process_counter_values(struct perf_stat_config
*config
, struct perf_evsel
*evsel
,
244 struct perf_counts_values
*count
)
246 struct perf_counts_values
*aggr
= &evsel
->counts
->aggr
;
247 static struct perf_counts_values zero
;
250 if (check_per_pkg(evsel
, count
, cpu
, &skip
)) {
251 pr_err("failed to read per-pkg counter\n");
258 switch (config
->aggr_mode
) {
263 if (!evsel
->snapshot
)
264 perf_evsel__compute_deltas(evsel
, cpu
, thread
, count
);
265 perf_counts_values__scale(count
, config
->scale
, NULL
);
266 if (config
->aggr_mode
== AGGR_NONE
)
267 perf_stat__update_shadow_stats(evsel
, count
->values
, cpu
);
270 aggr
->val
+= count
->val
;
272 aggr
->ena
+= count
->ena
;
273 aggr
->run
+= count
->run
;
283 static int process_counter_maps(struct perf_stat_config
*config
,
284 struct perf_evsel
*counter
)
286 int nthreads
= thread_map__nr(counter
->threads
);
287 int ncpus
= perf_evsel__nr_cpus(counter
);
290 if (counter
->system_wide
)
293 for (thread
= 0; thread
< nthreads
; thread
++) {
294 for (cpu
= 0; cpu
< ncpus
; cpu
++) {
295 if (process_counter_values(config
, counter
, cpu
, thread
,
296 perf_counts(counter
->counts
, cpu
, thread
)))
304 int perf_stat_process_counter(struct perf_stat_config
*config
,
305 struct perf_evsel
*counter
)
307 struct perf_counts_values
*aggr
= &counter
->counts
->aggr
;
308 struct perf_stat_evsel
*ps
= counter
->priv
;
309 u64
*count
= counter
->counts
->aggr
.values
;
312 aggr
->val
= aggr
->ena
= aggr
->run
= 0;
313 init_stats(ps
->res_stats
);
315 if (counter
->per_pkg
)
316 zero_per_pkg(counter
);
318 ret
= process_counter_maps(config
, counter
);
322 if (config
->aggr_mode
!= AGGR_GLOBAL
)
325 if (!counter
->snapshot
)
326 perf_evsel__compute_deltas(counter
, -1, -1, aggr
);
327 perf_counts_values__scale(aggr
, config
->scale
, &counter
->counts
->scaled
);
329 for (i
= 0; i
< 3; i
++)
330 update_stats(&ps
->res_stats
[i
], count
[i
]);
333 fprintf(config
->output
, "%s: %" PRIu64
" %" PRIu64
" %" PRIu64
"\n",
334 perf_evsel__name(counter
), count
[0], count
[1], count
[2]);
338 * Save the full runtime - to allow normalization during printout:
340 perf_stat__update_shadow_stats(counter
, count
, 0);
345 int perf_event__process_stat_event(struct perf_tool
*tool __maybe_unused
,
346 union perf_event
*event
,
347 struct perf_session
*session
)
349 struct perf_counts_values count
;
350 struct stat_event
*st
= &event
->stat
;
351 struct perf_evsel
*counter
;
357 counter
= perf_evlist__id2evsel(session
->evlist
, st
->id
);
359 pr_err("Failed to resolve counter for stat event.\n");
363 *perf_counts(counter
->counts
, st
->cpu
, st
->thread
) = count
;
364 counter
->supported
= true;
368 size_t perf_event__fprintf_stat(union perf_event
*event
, FILE *fp
)
370 struct stat_event
*st
= (struct stat_event
*) event
;
373 ret
= fprintf(fp
, "\n... id %" PRIu64
", cpu %d, thread %d\n",
374 st
->id
, st
->cpu
, st
->thread
);
375 ret
+= fprintf(fp
, "... value %" PRIu64
", enabled %" PRIu64
", running %" PRIu64
"\n",
376 st
->val
, st
->ena
, st
->run
);
381 size_t perf_event__fprintf_stat_round(union perf_event
*event
, FILE *fp
)
383 struct stat_round_event
*rd
= (struct stat_round_event
*)event
;
386 ret
= fprintf(fp
, "\n... time %" PRIu64
", type %s\n", rd
->time
,
387 rd
->type
== PERF_STAT_ROUND_TYPE__FINAL
? "FINAL" : "INTERVAL");
392 size_t perf_event__fprintf_stat_config(union perf_event
*event
, FILE *fp
)
394 struct perf_stat_config sc
;
397 perf_event__read_stat_config(&sc
, &event
->stat_config
);
399 ret
= fprintf(fp
, "\n");
400 ret
+= fprintf(fp
, "... aggr_mode %d\n", sc
.aggr_mode
);
401 ret
+= fprintf(fp
, "... scale %d\n", sc
.scale
);
402 ret
+= fprintf(fp
, "... interval %u\n", sc
.interval
);