at v4.13 425 lines 9.9 kB view raw
1#include <errno.h> 2#include <inttypes.h> 3#include <math.h> 4#include "stat.h" 5#include "evlist.h" 6#include "evsel.h" 7#include "thread_map.h" 8 9void update_stats(struct stats *stats, u64 val) 10{ 11 double delta; 12 13 stats->n++; 14 delta = val - stats->mean; 15 stats->mean += delta / stats->n; 16 stats->M2 += delta*(val - stats->mean); 17 18 if (val > stats->max) 19 stats->max = val; 20 21 if (val < stats->min) 22 stats->min = val; 23} 24 25double avg_stats(struct stats *stats) 26{ 27 return stats->mean; 28} 29 30/* 31 * http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance 32 * 33 * (\Sum n_i^2) - ((\Sum n_i)^2)/n 34 * s^2 = ------------------------------- 35 * n - 1 36 * 37 * http://en.wikipedia.org/wiki/Stddev 38 * 39 * The std dev of the mean is related to the std dev by: 40 * 41 * s 42 * s_mean = ------- 43 * sqrt(n) 44 * 45 */ 46double stddev_stats(struct stats *stats) 47{ 48 double variance, variance_mean; 49 50 if (stats->n < 2) 51 return 0.0; 52 53 variance = stats->M2 / (stats->n - 1); 54 variance_mean = variance / stats->n; 55 56 return sqrt(variance_mean); 57} 58 59double rel_stddev_stats(double stddev, double avg) 60{ 61 double pct = 0.0; 62 63 if (avg) 64 pct = 100.0 * stddev/avg; 65 66 return pct; 67} 68 69bool __perf_evsel_stat__is(struct perf_evsel *evsel, 70 enum perf_stat_evsel_id id) 71{ 72 struct perf_stat_evsel *ps = evsel->priv; 73 74 return ps->id == id; 75} 76 77#define ID(id, name) [PERF_STAT_EVSEL_ID__##id] = #name 78static const char *id_str[PERF_STAT_EVSEL_ID__MAX] = { 79 ID(NONE, x), 80 ID(CYCLES_IN_TX, cpu/cycles-t/), 81 ID(TRANSACTION_START, cpu/tx-start/), 82 ID(ELISION_START, cpu/el-start/), 83 ID(CYCLES_IN_TX_CP, cpu/cycles-ct/), 84 ID(TOPDOWN_TOTAL_SLOTS, topdown-total-slots), 85 ID(TOPDOWN_SLOTS_ISSUED, topdown-slots-issued), 86 ID(TOPDOWN_SLOTS_RETIRED, topdown-slots-retired), 87 ID(TOPDOWN_FETCH_BUBBLES, topdown-fetch-bubbles), 88 ID(TOPDOWN_RECOVERY_BUBBLES, topdown-recovery-bubbles), 89 ID(SMI_NUM, msr/smi/), 90 ID(APERF, msr/aperf/), 91}; 92#undef ID 93 94void perf_stat_evsel_id_init(struct perf_evsel *evsel) 95{ 96 struct perf_stat_evsel *ps = evsel->priv; 97 int i; 98 99 /* ps->id is 0 hence PERF_STAT_EVSEL_ID__NONE by default */ 100 101 for (i = 0; i < PERF_STAT_EVSEL_ID__MAX; i++) { 102 if (!strcmp(perf_evsel__name(evsel), id_str[i])) { 103 ps->id = i; 104 break; 105 } 106 } 107} 108 109static void perf_evsel__reset_stat_priv(struct perf_evsel *evsel) 110{ 111 int i; 112 struct perf_stat_evsel *ps = evsel->priv; 113 114 for (i = 0; i < 3; i++) 115 init_stats(&ps->res_stats[i]); 116 117 perf_stat_evsel_id_init(evsel); 118} 119 120static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel) 121{ 122 evsel->priv = zalloc(sizeof(struct perf_stat_evsel)); 123 if (evsel->priv == NULL) 124 return -ENOMEM; 125 perf_evsel__reset_stat_priv(evsel); 126 return 0; 127} 128 129static void perf_evsel__free_stat_priv(struct perf_evsel *evsel) 130{ 131 zfree(&evsel->priv); 132} 133 134static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel, 135 int ncpus, int nthreads) 136{ 137 struct perf_counts *counts; 138 139 counts = perf_counts__new(ncpus, nthreads); 140 if (counts) 141 evsel->prev_raw_counts = counts; 142 143 return counts ? 0 : -ENOMEM; 144} 145 146static void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel) 147{ 148 perf_counts__delete(evsel->prev_raw_counts); 149 evsel->prev_raw_counts = NULL; 150} 151 152static int perf_evsel__alloc_stats(struct perf_evsel *evsel, bool alloc_raw) 153{ 154 int ncpus = perf_evsel__nr_cpus(evsel); 155 int nthreads = thread_map__nr(evsel->threads); 156 157 if (perf_evsel__alloc_stat_priv(evsel) < 0 || 158 perf_evsel__alloc_counts(evsel, ncpus, nthreads) < 0 || 159 (alloc_raw && perf_evsel__alloc_prev_raw_counts(evsel, ncpus, nthreads) < 0)) 160 return -ENOMEM; 161 162 return 0; 163} 164 165int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw) 166{ 167 struct perf_evsel *evsel; 168 169 evlist__for_each_entry(evlist, evsel) { 170 if (perf_evsel__alloc_stats(evsel, alloc_raw)) 171 goto out_free; 172 } 173 174 return 0; 175 176out_free: 177 perf_evlist__free_stats(evlist); 178 return -1; 179} 180 181void perf_evlist__free_stats(struct perf_evlist *evlist) 182{ 183 struct perf_evsel *evsel; 184 185 evlist__for_each_entry(evlist, evsel) { 186 perf_evsel__free_stat_priv(evsel); 187 perf_evsel__free_counts(evsel); 188 perf_evsel__free_prev_raw_counts(evsel); 189 } 190} 191 192void perf_evlist__reset_stats(struct perf_evlist *evlist) 193{ 194 struct perf_evsel *evsel; 195 196 evlist__for_each_entry(evlist, evsel) { 197 perf_evsel__reset_stat_priv(evsel); 198 perf_evsel__reset_counts(evsel); 199 } 200} 201 202static void zero_per_pkg(struct perf_evsel *counter) 203{ 204 if (counter->per_pkg_mask) 205 memset(counter->per_pkg_mask, 0, MAX_NR_CPUS); 206} 207 208static int check_per_pkg(struct perf_evsel *counter, 209 struct perf_counts_values *vals, int cpu, bool *skip) 210{ 211 unsigned long *mask = counter->per_pkg_mask; 212 struct cpu_map *cpus = perf_evsel__cpus(counter); 213 int s; 214 215 *skip = false; 216 217 if (!counter->per_pkg) 218 return 0; 219 220 if (cpu_map__empty(cpus)) 221 return 0; 222 223 if (!mask) { 224 mask = zalloc(MAX_NR_CPUS); 225 if (!mask) 226 return -ENOMEM; 227 228 counter->per_pkg_mask = mask; 229 } 230 231 /* 232 * we do not consider an event that has not run as a good 233 * instance to mark a package as used (skip=1). Otherwise 234 * we may run into a situation where the first CPU in a package 235 * is not running anything, yet the second is, and this function 236 * would mark the package as used after the first CPU and would 237 * not read the values from the second CPU. 238 */ 239 if (!(vals->run && vals->ena)) 240 return 0; 241 242 s = cpu_map__get_socket(cpus, cpu, NULL); 243 if (s < 0) 244 return -1; 245 246 *skip = test_and_set_bit(s, mask) == 1; 247 return 0; 248} 249 250static int 251process_counter_values(struct perf_stat_config *config, struct perf_evsel *evsel, 252 int cpu, int thread, 253 struct perf_counts_values *count) 254{ 255 struct perf_counts_values *aggr = &evsel->counts->aggr; 256 static struct perf_counts_values zero; 257 bool skip = false; 258 259 if (check_per_pkg(evsel, count, cpu, &skip)) { 260 pr_err("failed to read per-pkg counter\n"); 261 return -1; 262 } 263 264 if (skip) 265 count = &zero; 266 267 switch (config->aggr_mode) { 268 case AGGR_THREAD: 269 case AGGR_CORE: 270 case AGGR_SOCKET: 271 case AGGR_NONE: 272 if (!evsel->snapshot) 273 perf_evsel__compute_deltas(evsel, cpu, thread, count); 274 perf_counts_values__scale(count, config->scale, NULL); 275 if (config->aggr_mode == AGGR_NONE) 276 perf_stat__update_shadow_stats(evsel, count->values, cpu); 277 break; 278 case AGGR_GLOBAL: 279 aggr->val += count->val; 280 if (config->scale) { 281 aggr->ena += count->ena; 282 aggr->run += count->run; 283 } 284 case AGGR_UNSET: 285 default: 286 break; 287 } 288 289 return 0; 290} 291 292static int process_counter_maps(struct perf_stat_config *config, 293 struct perf_evsel *counter) 294{ 295 int nthreads = thread_map__nr(counter->threads); 296 int ncpus = perf_evsel__nr_cpus(counter); 297 int cpu, thread; 298 299 if (counter->system_wide) 300 nthreads = 1; 301 302 for (thread = 0; thread < nthreads; thread++) { 303 for (cpu = 0; cpu < ncpus; cpu++) { 304 if (process_counter_values(config, counter, cpu, thread, 305 perf_counts(counter->counts, cpu, thread))) 306 return -1; 307 } 308 } 309 310 return 0; 311} 312 313int perf_stat_process_counter(struct perf_stat_config *config, 314 struct perf_evsel *counter) 315{ 316 struct perf_counts_values *aggr = &counter->counts->aggr; 317 struct perf_stat_evsel *ps = counter->priv; 318 u64 *count = counter->counts->aggr.values; 319 u64 val; 320 int i, ret; 321 322 aggr->val = aggr->ena = aggr->run = 0; 323 324 /* 325 * We calculate counter's data every interval, 326 * and the display code shows ps->res_stats 327 * avg value. We need to zero the stats for 328 * interval mode, otherwise overall avg running 329 * averages will be shown for each interval. 330 */ 331 if (config->interval) 332 init_stats(ps->res_stats); 333 334 if (counter->per_pkg) 335 zero_per_pkg(counter); 336 337 ret = process_counter_maps(config, counter); 338 if (ret) 339 return ret; 340 341 if (config->aggr_mode != AGGR_GLOBAL) 342 return 0; 343 344 if (!counter->snapshot) 345 perf_evsel__compute_deltas(counter, -1, -1, aggr); 346 perf_counts_values__scale(aggr, config->scale, &counter->counts->scaled); 347 348 for (i = 0; i < 3; i++) 349 update_stats(&ps->res_stats[i], count[i]); 350 351 if (verbose > 0) { 352 fprintf(config->output, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n", 353 perf_evsel__name(counter), count[0], count[1], count[2]); 354 } 355 356 /* 357 * Save the full runtime - to allow normalization during printout: 358 */ 359 val = counter->scale * *count; 360 perf_stat__update_shadow_stats(counter, &val, 0); 361 362 return 0; 363} 364 365int perf_event__process_stat_event(struct perf_tool *tool __maybe_unused, 366 union perf_event *event, 367 struct perf_session *session) 368{ 369 struct perf_counts_values count; 370 struct stat_event *st = &event->stat; 371 struct perf_evsel *counter; 372 373 count.val = st->val; 374 count.ena = st->ena; 375 count.run = st->run; 376 377 counter = perf_evlist__id2evsel(session->evlist, st->id); 378 if (!counter) { 379 pr_err("Failed to resolve counter for stat event.\n"); 380 return -EINVAL; 381 } 382 383 *perf_counts(counter->counts, st->cpu, st->thread) = count; 384 counter->supported = true; 385 return 0; 386} 387 388size_t perf_event__fprintf_stat(union perf_event *event, FILE *fp) 389{ 390 struct stat_event *st = (struct stat_event *) event; 391 size_t ret; 392 393 ret = fprintf(fp, "\n... id %" PRIu64 ", cpu %d, thread %d\n", 394 st->id, st->cpu, st->thread); 395 ret += fprintf(fp, "... value %" PRIu64 ", enabled %" PRIu64 ", running %" PRIu64 "\n", 396 st->val, st->ena, st->run); 397 398 return ret; 399} 400 401size_t perf_event__fprintf_stat_round(union perf_event *event, FILE *fp) 402{ 403 struct stat_round_event *rd = (struct stat_round_event *)event; 404 size_t ret; 405 406 ret = fprintf(fp, "\n... time %" PRIu64 ", type %s\n", rd->time, 407 rd->type == PERF_STAT_ROUND_TYPE__FINAL ? "FINAL" : "INTERVAL"); 408 409 return ret; 410} 411 412size_t perf_event__fprintf_stat_config(union perf_event *event, FILE *fp) 413{ 414 struct perf_stat_config sc; 415 size_t ret; 416 417 perf_event__read_stat_config(&sc, &event->stat_config); 418 419 ret = fprintf(fp, "\n"); 420 ret += fprintf(fp, "... aggr_mode %d\n", sc.aggr_mode); 421 ret += fprintf(fp, "... scale %d\n", sc.scale); 422 ret += fprintf(fp, "... interval %u\n", sc.interval); 423 424 return ret; 425}