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