diff options
29 files changed, 318 insertions, 126 deletions
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.c b/arch/x86/kernel/cpu/perf_event_intel_uncore.c index 0a5571080e74..62ec3e6af7ea 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore.c +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c | |||
| @@ -2341,6 +2341,27 @@ int uncore_pmu_event_init(struct perf_event *event) | |||
| 2341 | return ret; | 2341 | return ret; |
| 2342 | } | 2342 | } |
| 2343 | 2343 | ||
| 2344 | static ssize_t uncore_get_attr_cpumask(struct device *dev, | ||
| 2345 | struct device_attribute *attr, char *buf) | ||
| 2346 | { | ||
| 2347 | int n = cpulist_scnprintf(buf, PAGE_SIZE - 2, &uncore_cpu_mask); | ||
| 2348 | |||
| 2349 | buf[n++] = '\n'; | ||
| 2350 | buf[n] = '\0'; | ||
| 2351 | return n; | ||
| 2352 | } | ||
| 2353 | |||
| 2354 | static DEVICE_ATTR(cpumask, S_IRUGO, uncore_get_attr_cpumask, NULL); | ||
| 2355 | |||
| 2356 | static struct attribute *uncore_pmu_attrs[] = { | ||
| 2357 | &dev_attr_cpumask.attr, | ||
| 2358 | NULL, | ||
| 2359 | }; | ||
| 2360 | |||
| 2361 | static struct attribute_group uncore_pmu_attr_group = { | ||
| 2362 | .attrs = uncore_pmu_attrs, | ||
| 2363 | }; | ||
| 2364 | |||
| 2344 | static int __init uncore_pmu_register(struct intel_uncore_pmu *pmu) | 2365 | static int __init uncore_pmu_register(struct intel_uncore_pmu *pmu) |
| 2345 | { | 2366 | { |
| 2346 | int ret; | 2367 | int ret; |
| @@ -2378,8 +2399,8 @@ static void __init uncore_type_exit(struct intel_uncore_type *type) | |||
| 2378 | free_percpu(type->pmus[i].box); | 2399 | free_percpu(type->pmus[i].box); |
| 2379 | kfree(type->pmus); | 2400 | kfree(type->pmus); |
| 2380 | type->pmus = NULL; | 2401 | type->pmus = NULL; |
| 2381 | kfree(type->attr_groups[1]); | 2402 | kfree(type->events_group); |
| 2382 | type->attr_groups[1] = NULL; | 2403 | type->events_group = NULL; |
| 2383 | } | 2404 | } |
| 2384 | 2405 | ||
| 2385 | static void __init uncore_types_exit(struct intel_uncore_type **types) | 2406 | static void __init uncore_types_exit(struct intel_uncore_type **types) |
| @@ -2431,9 +2452,10 @@ static int __init uncore_type_init(struct intel_uncore_type *type) | |||
| 2431 | for (j = 0; j < i; j++) | 2452 | for (j = 0; j < i; j++) |
| 2432 | attrs[j] = &type->event_descs[j].attr.attr; | 2453 | attrs[j] = &type->event_descs[j].attr.attr; |
| 2433 | 2454 | ||
| 2434 | type->attr_groups[1] = events_group; | 2455 | type->events_group = events_group; |
| 2435 | } | 2456 | } |
| 2436 | 2457 | ||
| 2458 | type->pmu_group = &uncore_pmu_attr_group; | ||
| 2437 | type->pmus = pmus; | 2459 | type->pmus = pmus; |
| 2438 | return 0; | 2460 | return 0; |
| 2439 | fail: | 2461 | fail: |
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.h b/arch/x86/kernel/cpu/perf_event_intel_uncore.h index 5b81c1856aac..e68a4550e952 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore.h +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.h | |||
| @@ -369,10 +369,12 @@ struct intel_uncore_type { | |||
| 369 | struct intel_uncore_pmu *pmus; | 369 | struct intel_uncore_pmu *pmus; |
| 370 | struct intel_uncore_ops *ops; | 370 | struct intel_uncore_ops *ops; |
| 371 | struct uncore_event_desc *event_descs; | 371 | struct uncore_event_desc *event_descs; |
| 372 | const struct attribute_group *attr_groups[3]; | 372 | const struct attribute_group *attr_groups[4]; |
| 373 | }; | 373 | }; |
| 374 | 374 | ||
| 375 | #define format_group attr_groups[0] | 375 | #define pmu_group attr_groups[0] |
| 376 | #define format_group attr_groups[1] | ||
| 377 | #define events_group attr_groups[2] | ||
| 376 | 378 | ||
| 377 | struct intel_uncore_ops { | 379 | struct intel_uncore_ops { |
| 378 | void (*init_box)(struct intel_uncore_box *); | 380 | void (*init_box)(struct intel_uncore_box *); |
diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile index 14131cb0522d..04d959fa0226 100644 --- a/tools/lib/traceevent/Makefile +++ b/tools/lib/traceevent/Makefile | |||
| @@ -129,7 +129,7 @@ CFLAGS ?= -g -Wall | |||
| 129 | 129 | ||
| 130 | # Append required CFLAGS | 130 | # Append required CFLAGS |
| 131 | override CFLAGS += $(CONFIG_FLAGS) $(INCLUDES) $(PLUGIN_DIR_SQ) | 131 | override CFLAGS += $(CONFIG_FLAGS) $(INCLUDES) $(PLUGIN_DIR_SQ) |
| 132 | override CFLAGS += $(udis86-flags) | 132 | override CFLAGS += $(udis86-flags) -D_GNU_SOURCE |
| 133 | 133 | ||
| 134 | ifeq ($(VERBOSE),1) | 134 | ifeq ($(VERBOSE),1) |
| 135 | Q = | 135 | Q = |
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index 2c54cdd8ae1b..77ebeb8266f4 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c | |||
| @@ -24,7 +24,6 @@ | |||
| 24 | * Frederic Weisbecker gave his permission to relicense the code to | 24 | * Frederic Weisbecker gave his permission to relicense the code to |
| 25 | * the Lesser General Public License. | 25 | * the Lesser General Public License. |
| 26 | */ | 26 | */ |
| 27 | #define _GNU_SOURCE | ||
| 28 | #include <stdio.h> | 27 | #include <stdio.h> |
| 29 | #include <stdlib.h> | 28 | #include <stdlib.h> |
| 30 | #include <string.h> | 29 | #include <string.h> |
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 209774bcee2e..5077f8e2ef72 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
| @@ -406,6 +406,7 @@ LIB_OBJS += $(OUTPUT)util/target.o | |||
| 406 | LIB_OBJS += $(OUTPUT)util/rblist.o | 406 | LIB_OBJS += $(OUTPUT)util/rblist.o |
| 407 | LIB_OBJS += $(OUTPUT)util/intlist.o | 407 | LIB_OBJS += $(OUTPUT)util/intlist.o |
| 408 | LIB_OBJS += $(OUTPUT)util/vdso.o | 408 | LIB_OBJS += $(OUTPUT)util/vdso.o |
| 409 | LIB_OBJS += $(OUTPUT)util/stat.o | ||
| 409 | 410 | ||
| 410 | LIB_OBJS += $(OUTPUT)ui/helpline.o | 411 | LIB_OBJS += $(OUTPUT)ui/helpline.o |
| 411 | LIB_OBJS += $(OUTPUT)ui/hist.o | 412 | LIB_OBJS += $(OUTPUT)ui/hist.o |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 97b2e6300f4c..1da243dfbc3e 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
| @@ -93,7 +93,7 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool, | |||
| 93 | struct annotation *notes; | 93 | struct annotation *notes; |
| 94 | err = -ENOMEM; | 94 | err = -ENOMEM; |
| 95 | bx = he->branch_info; | 95 | bx = he->branch_info; |
| 96 | if (bx->from.sym && use_browser > 0) { | 96 | if (bx->from.sym && use_browser == 1 && sort__has_sym) { |
| 97 | notes = symbol__annotation(bx->from.sym); | 97 | notes = symbol__annotation(bx->from.sym); |
| 98 | if (!notes->src | 98 | if (!notes->src |
| 99 | && symbol__alloc_hist(bx->from.sym) < 0) | 99 | && symbol__alloc_hist(bx->from.sym) < 0) |
| @@ -107,7 +107,7 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool, | |||
| 107 | goto out; | 107 | goto out; |
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | if (bx->to.sym && use_browser > 0) { | 110 | if (bx->to.sym && use_browser == 1 && sort__has_sym) { |
| 111 | notes = symbol__annotation(bx->to.sym); | 111 | notes = symbol__annotation(bx->to.sym); |
| 112 | if (!notes->src | 112 | if (!notes->src |
| 113 | && symbol__alloc_hist(bx->to.sym) < 0) | 113 | && symbol__alloc_hist(bx->to.sym) < 0) |
| @@ -162,7 +162,7 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel, | |||
| 162 | * so we don't allocated the extra space needed because the stdio | 162 | * so we don't allocated the extra space needed because the stdio |
| 163 | * code will not use it. | 163 | * code will not use it. |
| 164 | */ | 164 | */ |
| 165 | if (he->ms.sym != NULL && use_browser > 0) { | 165 | if (he->ms.sym != NULL && use_browser == 1 && sort__has_sym) { |
| 166 | struct annotation *notes = symbol__annotation(he->ms.sym); | 166 | struct annotation *notes = symbol__annotation(he->ms.sym); |
| 167 | 167 | ||
| 168 | assert(evsel != NULL); | 168 | assert(evsel != NULL); |
| @@ -689,15 +689,19 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
| 689 | 689 | ||
| 690 | if (strcmp(report.input_name, "-") != 0) | 690 | if (strcmp(report.input_name, "-") != 0) |
| 691 | setup_browser(true); | 691 | setup_browser(true); |
| 692 | else | 692 | else { |
| 693 | use_browser = 0; | 693 | use_browser = 0; |
| 694 | perf_hpp__init(false, false); | ||
| 695 | } | ||
| 696 | |||
| 697 | setup_sorting(report_usage, options); | ||
| 694 | 698 | ||
| 695 | /* | 699 | /* |
| 696 | * Only in the newt browser we are doing integrated annotation, | 700 | * Only in the newt browser we are doing integrated annotation, |
| 697 | * so don't allocate extra space that won't be used in the stdio | 701 | * so don't allocate extra space that won't be used in the stdio |
| 698 | * implementation. | 702 | * implementation. |
| 699 | */ | 703 | */ |
| 700 | if (use_browser > 0) { | 704 | if (use_browser == 1 && sort__has_sym) { |
| 701 | symbol_conf.priv_size = sizeof(struct annotation); | 705 | symbol_conf.priv_size = sizeof(struct annotation); |
| 702 | report.annotate_init = symbol__annotate_init; | 706 | report.annotate_init = symbol__annotate_init; |
| 703 | /* | 707 | /* |
| @@ -720,8 +724,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
| 720 | if (symbol__init() < 0) | 724 | if (symbol__init() < 0) |
| 721 | goto error; | 725 | goto error; |
| 722 | 726 | ||
| 723 | setup_sorting(report_usage, options); | ||
| 724 | |||
| 725 | if (parent_pattern != default_parent_pattern) { | 727 | if (parent_pattern != default_parent_pattern) { |
| 726 | if (sort_dimension__add("parent") < 0) | 728 | if (sort_dimension__add("parent") < 0) |
| 727 | goto error; | 729 | goto error; |
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index af305f57bd22..9b9e32eaa805 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c | |||
| @@ -438,8 +438,8 @@ static int self_open_counters(void) | |||
| 438 | fd = sys_perf_event_open(&attr, 0, -1, -1, 0); | 438 | fd = sys_perf_event_open(&attr, 0, -1, -1, 0); |
| 439 | 439 | ||
| 440 | if (fd < 0) | 440 | if (fd < 0) |
| 441 | pr_debug("Error: sys_perf_event_open() syscall returned" | 441 | pr_err("Error: sys_perf_event_open() syscall returned " |
| 442 | "with %d (%s)\n", fd, strerror(errno)); | 442 | "with %d (%s)\n", fd, strerror(errno)); |
| 443 | return fd; | 443 | return fd; |
| 444 | } | 444 | } |
| 445 | 445 | ||
| @@ -700,7 +700,7 @@ static int replay_switch_event(struct perf_sched *sched, | |||
| 700 | delta = 0; | 700 | delta = 0; |
| 701 | 701 | ||
| 702 | if (delta < 0) { | 702 | if (delta < 0) { |
| 703 | pr_debug("hm, delta: %" PRIu64 " < 0 ?\n", delta); | 703 | pr_err("hm, delta: %" PRIu64 " < 0 ?\n", delta); |
| 704 | return -1; | 704 | return -1; |
| 705 | } | 705 | } |
| 706 | 706 | ||
| @@ -990,7 +990,7 @@ static int latency_runtime_event(struct perf_sched *sched, | |||
| 990 | return -1; | 990 | return -1; |
| 991 | atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid); | 991 | atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid); |
| 992 | if (!atoms) { | 992 | if (!atoms) { |
| 993 | pr_debug("in-event: Internal tree error"); | 993 | pr_err("in-event: Internal tree error"); |
| 994 | return -1; | 994 | return -1; |
| 995 | } | 995 | } |
| 996 | if (add_sched_out_event(atoms, 'R', timestamp)) | 996 | if (add_sched_out_event(atoms, 'R', timestamp)) |
| @@ -1024,7 +1024,7 @@ static int latency_wakeup_event(struct perf_sched *sched, | |||
| 1024 | return -1; | 1024 | return -1; |
| 1025 | atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid); | 1025 | atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid); |
| 1026 | if (!atoms) { | 1026 | if (!atoms) { |
| 1027 | pr_debug("wakeup-event: Internal tree error"); | 1027 | pr_err("wakeup-event: Internal tree error"); |
| 1028 | return -1; | 1028 | return -1; |
| 1029 | } | 1029 | } |
| 1030 | if (add_sched_out_event(atoms, 'S', timestamp)) | 1030 | if (add_sched_out_event(atoms, 'S', timestamp)) |
| @@ -1079,7 +1079,7 @@ static int latency_migrate_task_event(struct perf_sched *sched, | |||
| 1079 | register_pid(sched, migrant->pid, migrant->comm); | 1079 | register_pid(sched, migrant->pid, migrant->comm); |
| 1080 | atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid); | 1080 | atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid); |
| 1081 | if (!atoms) { | 1081 | if (!atoms) { |
| 1082 | pr_debug("migration-event: Internal tree error"); | 1082 | pr_err("migration-event: Internal tree error"); |
| 1083 | return -1; | 1083 | return -1; |
| 1084 | } | 1084 | } |
| 1085 | if (add_sched_out_event(atoms, 'R', timestamp)) | 1085 | if (add_sched_out_event(atoms, 'R', timestamp)) |
| @@ -1286,7 +1286,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel, | |||
| 1286 | delta = 0; | 1286 | delta = 0; |
| 1287 | 1287 | ||
| 1288 | if (delta < 0) { | 1288 | if (delta < 0) { |
| 1289 | pr_debug("hm, delta: %" PRIu64 " < 0 ?\n", delta); | 1289 | pr_err("hm, delta: %" PRIu64 " < 0 ?\n", delta); |
| 1290 | return -1; | 1290 | return -1; |
| 1291 | } | 1291 | } |
| 1292 | 1292 | ||
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 6d98a83d5a60..1be843aa1546 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include "util/util.h" | 14 | #include "util/util.h" |
| 15 | #include "util/evlist.h" | 15 | #include "util/evlist.h" |
| 16 | #include "util/evsel.h" | 16 | #include "util/evsel.h" |
| 17 | #include "util/sort.h" | ||
| 17 | #include <linux/bitmap.h> | 18 | #include <linux/bitmap.h> |
| 18 | 19 | ||
| 19 | static char const *script_name; | 20 | static char const *script_name; |
| @@ -1031,6 +1032,61 @@ static int list_available_scripts(const struct option *opt __maybe_unused, | |||
| 1031 | exit(0); | 1032 | exit(0); |
| 1032 | } | 1033 | } |
| 1033 | 1034 | ||
| 1035 | /* | ||
| 1036 | * Return -1 if none is found, otherwise the actual scripts number. | ||
| 1037 | * | ||
| 1038 | * Currently the only user of this function is the script browser, which | ||
| 1039 | * will list all statically runnable scripts, select one, execute it and | ||
| 1040 | * show the output in a perf browser. | ||
| 1041 | */ | ||
| 1042 | int find_scripts(char **scripts_array, char **scripts_path_array) | ||
| 1043 | { | ||
| 1044 | struct dirent *script_next, *lang_next, script_dirent, lang_dirent; | ||
| 1045 | char scripts_path[MAXPATHLEN]; | ||
| 1046 | DIR *scripts_dir, *lang_dir; | ||
| 1047 | char lang_path[MAXPATHLEN]; | ||
| 1048 | char *temp; | ||
| 1049 | int i = 0; | ||
| 1050 | |||
| 1051 | snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path()); | ||
| 1052 | |||
| 1053 | scripts_dir = opendir(scripts_path); | ||
| 1054 | if (!scripts_dir) | ||
| 1055 | return -1; | ||
| 1056 | |||
| 1057 | for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next) { | ||
| 1058 | snprintf(lang_path, MAXPATHLEN, "%s/%s", scripts_path, | ||
| 1059 | lang_dirent.d_name); | ||
| 1060 | #ifdef NO_LIBPERL | ||
| 1061 | if (strstr(lang_path, "perl")) | ||
| 1062 | continue; | ||
| 1063 | #endif | ||
| 1064 | #ifdef NO_LIBPYTHON | ||
| 1065 | if (strstr(lang_path, "python")) | ||
| 1066 | continue; | ||
| 1067 | #endif | ||
| 1068 | |||
| 1069 | lang_dir = opendir(lang_path); | ||
| 1070 | if (!lang_dir) | ||
| 1071 | continue; | ||
| 1072 | |||
| 1073 | for_each_script(lang_path, lang_dir, script_dirent, script_next) { | ||
| 1074 | /* Skip those real time scripts: xxxtop.p[yl] */ | ||
| 1075 | if (strstr(script_dirent.d_name, "top.")) | ||
| 1076 | continue; | ||
| 1077 | sprintf(scripts_path_array[i], "%s/%s", lang_path, | ||
| 1078 | script_dirent.d_name); | ||
| 1079 | temp = strchr(script_dirent.d_name, '.'); | ||
| 1080 | snprintf(scripts_array[i], | ||
| 1081 | (temp - script_dirent.d_name) + 1, | ||
| 1082 | "%s", script_dirent.d_name); | ||
| 1083 | i++; | ||
| 1084 | } | ||
| 1085 | } | ||
| 1086 | |||
| 1087 | return i; | ||
| 1088 | } | ||
| 1089 | |||
| 1034 | static char *get_script_path(const char *script_root, const char *suffix) | 1090 | static char *get_script_path(const char *script_root, const char *suffix) |
| 1035 | { | 1091 | { |
| 1036 | struct dirent *script_next, *lang_next, script_dirent, lang_dirent; | 1092 | struct dirent *script_next, *lang_next, script_dirent, lang_dirent; |
| @@ -1143,6 +1199,8 @@ static const struct option options[] = { | |||
| 1143 | parse_output_fields), | 1199 | parse_output_fields), |
| 1144 | OPT_BOOLEAN('a', "all-cpus", &system_wide, | 1200 | OPT_BOOLEAN('a', "all-cpus", &system_wide, |
| 1145 | "system-wide collection from all CPUs"), | 1201 | "system-wide collection from all CPUs"), |
| 1202 | OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", | ||
| 1203 | "only consider these symbols"), | ||
| 1146 | OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"), | 1204 | OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"), |
| 1147 | OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]", | 1205 | OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]", |
| 1148 | "only display events for these comms"), | 1206 | "only display events for these comms"), |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index dab347d7b010..e0f65fe65944 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
| @@ -51,13 +51,13 @@ | |||
| 51 | #include "util/evsel.h" | 51 | #include "util/evsel.h" |
| 52 | #include "util/debug.h" | 52 | #include "util/debug.h" |
| 53 | #include "util/color.h" | 53 | #include "util/color.h" |
| 54 | #include "util/stat.h" | ||
| 54 | #include "util/header.h" | 55 | #include "util/header.h" |
| 55 | #include "util/cpumap.h" | 56 | #include "util/cpumap.h" |
| 56 | #include "util/thread.h" | 57 | #include "util/thread.h" |
| 57 | #include "util/thread_map.h" | 58 | #include "util/thread_map.h" |
| 58 | 59 | ||
| 59 | #include <sys/prctl.h> | 60 | #include <sys/prctl.h> |
| 60 | #include <math.h> | ||
| 61 | #include <locale.h> | 61 | #include <locale.h> |
| 62 | 62 | ||
| 63 | #define DEFAULT_SEPARATOR " " | 63 | #define DEFAULT_SEPARATOR " " |
| @@ -199,11 +199,6 @@ static int output_fd; | |||
| 199 | 199 | ||
| 200 | static volatile int done = 0; | 200 | static volatile int done = 0; |
| 201 | 201 | ||
| 202 | struct stats | ||
| 203 | { | ||
| 204 | double n, mean, M2; | ||
| 205 | }; | ||
| 206 | |||
| 207 | struct perf_stat { | 202 | struct perf_stat { |
| 208 | struct stats res_stats[3]; | 203 | struct stats res_stats[3]; |
| 209 | }; | 204 | }; |
| @@ -220,48 +215,14 @@ static void perf_evsel__free_stat_priv(struct perf_evsel *evsel) | |||
| 220 | evsel->priv = NULL; | 215 | evsel->priv = NULL; |
| 221 | } | 216 | } |
| 222 | 217 | ||
| 223 | static void update_stats(struct stats *stats, u64 val) | 218 | static inline struct cpu_map *perf_evsel__cpus(struct perf_evsel *evsel) |
| 224 | { | 219 | { |
| 225 | double delta; | 220 | return (evsel->cpus && !target.cpu_list) ? evsel->cpus : evsel_list->cpus; |
| 226 | |||
| 227 | stats->n++; | ||
| 228 | delta = val - stats->mean; | ||
| 229 | stats->mean += delta / stats->n; | ||
| 230 | stats->M2 += delta*(val - stats->mean); | ||
| 231 | } | 221 | } |
| 232 | 222 | ||
| 233 | static double avg_stats(struct stats *stats) | 223 | static inline int perf_evsel__nr_cpus(struct perf_evsel *evsel) |
| 234 | { | ||
| 235 | return stats->mean; | ||
| 236 | } | ||
| 237 | |||
| 238 | /* | ||
| 239 | * http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance | ||
| 240 | * | ||
| 241 | * (\Sum n_i^2) - ((\Sum n_i)^2)/n | ||
| 242 | * s^2 = ------------------------------- | ||
| 243 | * n - 1 | ||
| 244 | * | ||
| 245 | * http://en.wikipedia.org/wiki/Stddev | ||
| 246 | * | ||
| 247 | * The std dev of the mean is related to the std dev by: | ||
| 248 | * | ||
| 249 | * s | ||
| 250 | * s_mean = ------- | ||
| 251 | * sqrt(n) | ||
| 252 | * | ||
| 253 | */ | ||
| 254 | static double stddev_stats(struct stats *stats) | ||
| 255 | { | 224 | { |
| 256 | double variance, variance_mean; | 225 | return perf_evsel__cpus(evsel)->nr; |
| 257 | |||
| 258 | if (!stats->n) | ||
| 259 | return 0.0; | ||
| 260 | |||
| 261 | variance = stats->M2 / (stats->n - 1); | ||
| 262 | variance_mean = variance / stats->n; | ||
| 263 | |||
| 264 | return sqrt(variance_mean); | ||
| 265 | } | 226 | } |
| 266 | 227 | ||
| 267 | static struct stats runtime_nsecs_stats[MAX_NR_CPUS]; | 228 | static struct stats runtime_nsecs_stats[MAX_NR_CPUS]; |
| @@ -295,7 +256,7 @@ retry: | |||
| 295 | evsel->attr.exclude_guest = evsel->attr.exclude_host = 0; | 256 | evsel->attr.exclude_guest = evsel->attr.exclude_host = 0; |
| 296 | 257 | ||
| 297 | if (perf_target__has_cpu(&target)) { | 258 | if (perf_target__has_cpu(&target)) { |
| 298 | ret = perf_evsel__open_per_cpu(evsel, evsel_list->cpus); | 259 | ret = perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel)); |
| 299 | if (ret) | 260 | if (ret) |
| 300 | goto check_ret; | 261 | goto check_ret; |
| 301 | return 0; | 262 | return 0; |
| @@ -376,7 +337,7 @@ static int read_counter_aggr(struct perf_evsel *counter) | |||
| 376 | u64 *count = counter->counts->aggr.values; | 337 | u64 *count = counter->counts->aggr.values; |
| 377 | int i; | 338 | int i; |
| 378 | 339 | ||
| 379 | if (__perf_evsel__read(counter, evsel_list->cpus->nr, | 340 | if (__perf_evsel__read(counter, perf_evsel__nr_cpus(counter), |
| 380 | evsel_list->threads->nr, scale) < 0) | 341 | evsel_list->threads->nr, scale) < 0) |
| 381 | return -1; | 342 | return -1; |
| 382 | 343 | ||
| @@ -405,7 +366,7 @@ static int read_counter(struct perf_evsel *counter) | |||
| 405 | u64 *count; | 366 | u64 *count; |
| 406 | int cpu; | 367 | int cpu; |
| 407 | 368 | ||
| 408 | for (cpu = 0; cpu < evsel_list->cpus->nr; cpu++) { | 369 | for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { |
| 409 | if (__perf_evsel__read_on_cpu(counter, cpu, 0, scale) < 0) | 370 | if (__perf_evsel__read_on_cpu(counter, cpu, 0, scale) < 0) |
| 410 | return -1; | 371 | return -1; |
| 411 | 372 | ||
| @@ -544,12 +505,12 @@ static int run_perf_stat(int argc __maybe_unused, const char **argv) | |||
| 544 | if (no_aggr) { | 505 | if (no_aggr) { |
| 545 | list_for_each_entry(counter, &evsel_list->entries, node) { | 506 | list_for_each_entry(counter, &evsel_list->entries, node) { |
| 546 | read_counter(counter); | 507 | read_counter(counter); |
| 547 | perf_evsel__close_fd(counter, evsel_list->cpus->nr, 1); | 508 | perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), 1); |
| 548 | } | 509 | } |
| 549 | } else { | 510 | } else { |
| 550 | list_for_each_entry(counter, &evsel_list->entries, node) { | 511 | list_for_each_entry(counter, &evsel_list->entries, node) { |
| 551 | read_counter_aggr(counter); | 512 | read_counter_aggr(counter); |
| 552 | perf_evsel__close_fd(counter, evsel_list->cpus->nr, | 513 | perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), |
| 553 | evsel_list->threads->nr); | 514 | evsel_list->threads->nr); |
| 554 | } | 515 | } |
| 555 | } | 516 | } |
| @@ -559,10 +520,7 @@ static int run_perf_stat(int argc __maybe_unused, const char **argv) | |||
| 559 | 520 | ||
| 560 | static void print_noise_pct(double total, double avg) | 521 | static void print_noise_pct(double total, double avg) |
| 561 | { | 522 | { |
| 562 | double pct = 0.0; | 523 | double pct = rel_stddev_stats(total, avg); |
| 563 | |||
| 564 | if (avg) | ||
| 565 | pct = 100.0*total/avg; | ||
| 566 | 524 | ||
| 567 | if (csv_output) | 525 | if (csv_output) |
| 568 | fprintf(output, "%s%.2f%%", csv_sep, pct); | 526 | fprintf(output, "%s%.2f%%", csv_sep, pct); |
| @@ -590,7 +548,7 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg) | |||
| 590 | if (no_aggr) | 548 | if (no_aggr) |
| 591 | sprintf(cpustr, "CPU%*d%s", | 549 | sprintf(cpustr, "CPU%*d%s", |
| 592 | csv_output ? 0 : -4, | 550 | csv_output ? 0 : -4, |
| 593 | evsel_list->cpus->map[cpu], csv_sep); | 551 | perf_evsel__cpus(evsel)->map[cpu], csv_sep); |
| 594 | 552 | ||
| 595 | fprintf(output, fmt, cpustr, msecs, csv_sep, perf_evsel__name(evsel)); | 553 | fprintf(output, fmt, cpustr, msecs, csv_sep, perf_evsel__name(evsel)); |
| 596 | 554 | ||
| @@ -802,7 +760,7 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) | |||
| 802 | if (no_aggr) | 760 | if (no_aggr) |
| 803 | sprintf(cpustr, "CPU%*d%s", | 761 | sprintf(cpustr, "CPU%*d%s", |
| 804 | csv_output ? 0 : -4, | 762 | csv_output ? 0 : -4, |
| 805 | evsel_list->cpus->map[cpu], csv_sep); | 763 | perf_evsel__cpus(evsel)->map[cpu], csv_sep); |
| 806 | else | 764 | else |
| 807 | cpu = 0; | 765 | cpu = 0; |
| 808 | 766 | ||
| @@ -963,14 +921,14 @@ static void print_counter(struct perf_evsel *counter) | |||
| 963 | u64 ena, run, val; | 921 | u64 ena, run, val; |
| 964 | int cpu; | 922 | int cpu; |
| 965 | 923 | ||
| 966 | for (cpu = 0; cpu < evsel_list->cpus->nr; cpu++) { | 924 | for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { |
| 967 | val = counter->counts->cpu[cpu].val; | 925 | val = counter->counts->cpu[cpu].val; |
| 968 | ena = counter->counts->cpu[cpu].ena; | 926 | ena = counter->counts->cpu[cpu].ena; |
| 969 | run = counter->counts->cpu[cpu].run; | 927 | run = counter->counts->cpu[cpu].run; |
| 970 | if (run == 0 || ena == 0) { | 928 | if (run == 0 || ena == 0) { |
| 971 | fprintf(output, "CPU%*d%s%*s%s%*s", | 929 | fprintf(output, "CPU%*d%s%*s%s%*s", |
| 972 | csv_output ? 0 : -4, | 930 | csv_output ? 0 : -4, |
| 973 | evsel_list->cpus->map[cpu], csv_sep, | 931 | perf_evsel__cpus(counter)->map[cpu], csv_sep, |
| 974 | csv_output ? 0 : 18, | 932 | csv_output ? 0 : 18, |
| 975 | counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, | 933 | counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, |
| 976 | csv_sep, | 934 | csv_sep, |
| @@ -1269,7 +1227,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) | |||
| 1269 | 1227 | ||
| 1270 | list_for_each_entry(pos, &evsel_list->entries, node) { | 1228 | list_for_each_entry(pos, &evsel_list->entries, node) { |
| 1271 | if (perf_evsel__alloc_stat_priv(pos) < 0 || | 1229 | if (perf_evsel__alloc_stat_priv(pos) < 0 || |
| 1272 | perf_evsel__alloc_counts(pos, evsel_list->cpus->nr) < 0) | 1230 | perf_evsel__alloc_counts(pos, perf_evsel__nr_cpus(pos)) < 0) |
| 1273 | goto out_free_fd; | 1231 | goto out_free_fd; |
| 1274 | } | 1232 | } |
| 1275 | 1233 | ||
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index d33143efefce..4aed1553db56 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c | |||
| @@ -1026,15 +1026,15 @@ static int __test__rdpmc(void) | |||
| 1026 | 1026 | ||
| 1027 | fd = sys_perf_event_open(&attr, 0, -1, -1, 0); | 1027 | fd = sys_perf_event_open(&attr, 0, -1, -1, 0); |
| 1028 | if (fd < 0) { | 1028 | if (fd < 0) { |
| 1029 | pr_debug("Error: sys_perf_event_open() syscall returned " | 1029 | pr_err("Error: sys_perf_event_open() syscall returned " |
| 1030 | "with %d (%s)\n", fd, strerror(errno)); | 1030 | "with %d (%s)\n", fd, strerror(errno)); |
| 1031 | return -1; | 1031 | return -1; |
| 1032 | } | 1032 | } |
| 1033 | 1033 | ||
| 1034 | addr = mmap(NULL, page_size, PROT_READ, MAP_SHARED, fd, 0); | 1034 | addr = mmap(NULL, page_size, PROT_READ, MAP_SHARED, fd, 0); |
| 1035 | if (addr == (void *)(-1)) { | 1035 | if (addr == (void *)(-1)) { |
| 1036 | pr_debug("Error: mmap() syscall returned with (%s)\n", | 1036 | pr_err("Error: mmap() syscall returned with (%s)\n", |
| 1037 | strerror(errno)); | 1037 | strerror(errno)); |
| 1038 | goto out_close; | 1038 | goto out_close; |
| 1039 | } | 1039 | } |
| 1040 | 1040 | ||
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h index b382bd551aac..3ea74ed1b26b 100644 --- a/tools/perf/builtin.h +++ b/tools/perf/builtin.h | |||
| @@ -36,4 +36,5 @@ extern int cmd_kvm(int argc, const char **argv, const char *prefix); | |||
| 36 | extern int cmd_test(int argc, const char **argv, const char *prefix); | 36 | extern int cmd_test(int argc, const char **argv, const char *prefix); |
| 37 | extern int cmd_inject(int argc, const char **argv, const char *prefix); | 37 | extern int cmd_inject(int argc, const char **argv, const char *prefix); |
| 38 | 38 | ||
| 39 | extern int find_scripts(char **scripts_array, char **scripts_path_array); | ||
| 39 | #endif | 40 | #endif |
diff --git a/tools/perf/perf-archive.sh b/tools/perf/perf-archive.sh index 95b6f8b6177a..e91930620269 100644 --- a/tools/perf/perf-archive.sh +++ b/tools/perf/perf-archive.sh | |||
| @@ -24,7 +24,7 @@ NOBUILDID=0000000000000000000000000000000000000000 | |||
| 24 | perf buildid-list -i $PERF_DATA --with-hits | grep -v "^$NOBUILDID " > $BUILDIDS | 24 | perf buildid-list -i $PERF_DATA --with-hits | grep -v "^$NOBUILDID " > $BUILDIDS |
| 25 | if [ ! -s $BUILDIDS ] ; then | 25 | if [ ! -s $BUILDIDS ] ; then |
| 26 | echo "perf archive: no build-ids found" | 26 | echo "perf archive: no build-ids found" |
| 27 | rm -f $BUILDIDS | 27 | rm $BUILDIDS || true |
| 28 | exit 1 | 28 | exit 1 |
| 29 | fi | 29 | fi |
| 30 | 30 | ||
| @@ -39,8 +39,8 @@ while read build_id ; do | |||
| 39 | echo ${filename#$PERF_BUILDID_LINKDIR} >> $MANIFEST | 39 | echo ${filename#$PERF_BUILDID_LINKDIR} >> $MANIFEST |
| 40 | done | 40 | done |
| 41 | 41 | ||
| 42 | tar cfj $PERF_DATA.tar.bz2 -C $PERF_BUILDID_DIR -T $MANIFEST | 42 | tar cjf $PERF_DATA.tar.bz2 -C $PERF_BUILDID_DIR -T $MANIFEST |
| 43 | rm -f $MANIFEST $BUILDIDS | 43 | rm $MANIFEST $BUILDIDS || true |
| 44 | echo -e "Now please run:\n" | 44 | echo -e "Now please run:\n" |
| 45 | echo -e "$ tar xvf $PERF_DATA.tar.bz2 -C ~/.debug\n" | 45 | echo -e "$ tar xvf $PERF_DATA.tar.bz2 -C ~/.debug\n" |
| 46 | echo "wherever you need to run 'perf report' on." | 46 | echo "wherever you need to run 'perf report' on." |
diff --git a/tools/perf/scripts/python/bin/event_analyzing_sample-record b/tools/perf/scripts/python/bin/event_analyzing_sample-record new file mode 100644 index 000000000000..5ce652dabd02 --- /dev/null +++ b/tools/perf/scripts/python/bin/event_analyzing_sample-record | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | #!/bin/bash | ||
| 2 | |||
| 3 | # | ||
| 4 | # event_analyzing_sample.py can cover all type of perf samples including | ||
| 5 | # the tracepoints, so no special record requirements, just record what | ||
| 6 | # you want to analyze. | ||
| 7 | # | ||
| 8 | perf record $@ | ||
diff --git a/tools/perf/scripts/python/bin/event_analyzing_sample-report b/tools/perf/scripts/python/bin/event_analyzing_sample-report new file mode 100644 index 000000000000..0941fc94e158 --- /dev/null +++ b/tools/perf/scripts/python/bin/event_analyzing_sample-report | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | #!/bin/bash | ||
| 2 | # description: analyze all perf samples | ||
| 3 | perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/event_analyzing_sample.py | ||
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 5a5739bbe6ac..a21f40bebbac 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c | |||
| @@ -571,7 +571,7 @@ static int hist_browser__hpp_color_ ## _name(struct perf_hpp *hpp, \ | |||
| 571 | { \ | 571 | { \ |
| 572 | double percent = 100.0 * he->_field / hpp->total_period; \ | 572 | double percent = 100.0 * he->_field / hpp->total_period; \ |
| 573 | *(double *)hpp->ptr = percent; \ | 573 | *(double *)hpp->ptr = percent; \ |
| 574 | return scnprintf(hpp->buf, hpp->size, "%5.2f%%", percent); \ | 574 | return scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent); \ |
| 575 | } | 575 | } |
| 576 | 576 | ||
| 577 | HPP__COLOR_FN(overhead, period) | 577 | HPP__COLOR_FN(overhead, period) |
| @@ -605,7 +605,7 @@ static int hist_browser__show_entry(struct hist_browser *browser, | |||
| 605 | char s[256]; | 605 | char s[256]; |
| 606 | double percent; | 606 | double percent; |
| 607 | int i, printed = 0; | 607 | int i, printed = 0; |
| 608 | int width = browser->b.width - 1; | 608 | int width = browser->b.width; |
| 609 | char folded_sign = ' '; | 609 | char folded_sign = ' '; |
| 610 | bool current_entry = ui_browser__is_current_entry(&browser->b, row); | 610 | bool current_entry = ui_browser__is_current_entry(&browser->b, row); |
| 611 | off_t row_offset = entry->row_offset; | 611 | off_t row_offset = entry->row_offset; |
| @@ -627,7 +627,7 @@ static int hist_browser__show_entry(struct hist_browser *browser, | |||
| 627 | .total_period = browser->hists->stats.total_period, | 627 | .total_period = browser->hists->stats.total_period, |
| 628 | }; | 628 | }; |
| 629 | 629 | ||
| 630 | ui_browser__gotorc(&browser->b, row, 1); | 630 | ui_browser__gotorc(&browser->b, row, 0); |
| 631 | 631 | ||
| 632 | for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { | 632 | for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { |
| 633 | if (!perf_hpp__format[i].cond) | 633 | if (!perf_hpp__format[i].cond) |
diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c index 55acba6e0df4..7ff99ec1d95e 100644 --- a/tools/perf/ui/gtk/browser.c +++ b/tools/perf/ui/gtk/browser.c | |||
| @@ -56,7 +56,7 @@ static int perf_gtk__hpp_color_ ## _name(struct perf_hpp *hpp, \ | |||
| 56 | markup = perf_gtk__get_percent_color(percent); \ | 56 | markup = perf_gtk__get_percent_color(percent); \ |
| 57 | if (markup) \ | 57 | if (markup) \ |
| 58 | ret += scnprintf(hpp->buf, hpp->size, "%s", markup); \ | 58 | ret += scnprintf(hpp->buf, hpp->size, "%s", markup); \ |
| 59 | ret += scnprintf(hpp->buf + ret, hpp->size - ret, "%5.2f%%", percent); \ | 59 | ret += scnprintf(hpp->buf + ret, hpp->size - ret, "%6.2f%%", percent); \ |
| 60 | if (markup) \ | 60 | if (markup) \ |
| 61 | ret += scnprintf(hpp->buf + ret, hpp->size - ret, "</span>"); \ | 61 | ret += scnprintf(hpp->buf + ret, hpp->size - ret, "</span>"); \ |
| 62 | \ | 62 | \ |
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index 407e855cccb8..e3f8cd46e7d7 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c | |||
| @@ -33,13 +33,13 @@ static int hpp__color_overhead(struct perf_hpp *hpp, struct hist_entry *he) | |||
| 33 | percent = 0.0; | 33 | percent = 0.0; |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | return percent_color_snprintf(hpp->buf, hpp->size, " %5.2f%%", percent); | 36 | return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent); |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | static int hpp__entry_overhead(struct perf_hpp *hpp, struct hist_entry *he) | 39 | static int hpp__entry_overhead(struct perf_hpp *hpp, struct hist_entry *he) |
| 40 | { | 40 | { |
| 41 | double percent = 100.0 * he->period / hpp->total_period; | 41 | double percent = 100.0 * he->period / hpp->total_period; |
| 42 | const char *fmt = symbol_conf.field_sep ? "%.2f" : " %5.2f%%"; | 42 | const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%"; |
| 43 | 43 | ||
| 44 | if (hpp->ptr) { | 44 | if (hpp->ptr) { |
| 45 | struct hists *old_hists = hpp->ptr; | 45 | struct hists *old_hists = hpp->ptr; |
| @@ -57,52 +57,52 @@ static int hpp__entry_overhead(struct perf_hpp *hpp, struct hist_entry *he) | |||
| 57 | 57 | ||
| 58 | static int hpp__header_overhead_sys(struct perf_hpp *hpp) | 58 | static int hpp__header_overhead_sys(struct perf_hpp *hpp) |
| 59 | { | 59 | { |
| 60 | const char *fmt = symbol_conf.field_sep ? "%s" : "%6s"; | 60 | const char *fmt = symbol_conf.field_sep ? "%s" : "%7s"; |
| 61 | 61 | ||
| 62 | return scnprintf(hpp->buf, hpp->size, fmt, "sys"); | 62 | return scnprintf(hpp->buf, hpp->size, fmt, "sys"); |
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | static int hpp__width_overhead_sys(struct perf_hpp *hpp __maybe_unused) | 65 | static int hpp__width_overhead_sys(struct perf_hpp *hpp __maybe_unused) |
| 66 | { | 66 | { |
| 67 | return 6; | 67 | return 7; |
| 68 | } | 68 | } |
| 69 | 69 | ||
| 70 | static int hpp__color_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he) | 70 | static int hpp__color_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he) |
| 71 | { | 71 | { |
| 72 | double percent = 100.0 * he->period_sys / hpp->total_period; | 72 | double percent = 100.0 * he->period_sys / hpp->total_period; |
| 73 | return percent_color_snprintf(hpp->buf, hpp->size, "%5.2f%%", percent); | 73 | return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent); |
| 74 | } | 74 | } |
| 75 | 75 | ||
| 76 | static int hpp__entry_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he) | 76 | static int hpp__entry_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he) |
| 77 | { | 77 | { |
| 78 | double percent = 100.0 * he->period_sys / hpp->total_period; | 78 | double percent = 100.0 * he->period_sys / hpp->total_period; |
| 79 | const char *fmt = symbol_conf.field_sep ? "%.2f" : "%5.2f%%"; | 79 | const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%"; |
| 80 | 80 | ||
| 81 | return scnprintf(hpp->buf, hpp->size, fmt, percent); | 81 | return scnprintf(hpp->buf, hpp->size, fmt, percent); |
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | static int hpp__header_overhead_us(struct perf_hpp *hpp) | 84 | static int hpp__header_overhead_us(struct perf_hpp *hpp) |
| 85 | { | 85 | { |
| 86 | const char *fmt = symbol_conf.field_sep ? "%s" : "%6s"; | 86 | const char *fmt = symbol_conf.field_sep ? "%s" : "%7s"; |
| 87 | 87 | ||
| 88 | return scnprintf(hpp->buf, hpp->size, fmt, "user"); | 88 | return scnprintf(hpp->buf, hpp->size, fmt, "user"); |
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | static int hpp__width_overhead_us(struct perf_hpp *hpp __maybe_unused) | 91 | static int hpp__width_overhead_us(struct perf_hpp *hpp __maybe_unused) |
| 92 | { | 92 | { |
| 93 | return 6; | 93 | return 7; |
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | static int hpp__color_overhead_us(struct perf_hpp *hpp, struct hist_entry *he) | 96 | static int hpp__color_overhead_us(struct perf_hpp *hpp, struct hist_entry *he) |
| 97 | { | 97 | { |
| 98 | double percent = 100.0 * he->period_us / hpp->total_period; | 98 | double percent = 100.0 * he->period_us / hpp->total_period; |
| 99 | return percent_color_snprintf(hpp->buf, hpp->size, "%5.2f%%", percent); | 99 | return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent); |
| 100 | } | 100 | } |
| 101 | 101 | ||
| 102 | static int hpp__entry_overhead_us(struct perf_hpp *hpp, struct hist_entry *he) | 102 | static int hpp__entry_overhead_us(struct perf_hpp *hpp, struct hist_entry *he) |
| 103 | { | 103 | { |
| 104 | double percent = 100.0 * he->period_us / hpp->total_period; | 104 | double percent = 100.0 * he->period_us / hpp->total_period; |
| 105 | const char *fmt = symbol_conf.field_sep ? "%.2f" : "%5.2f%%"; | 105 | const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%"; |
| 106 | 106 | ||
| 107 | return scnprintf(hpp->buf, hpp->size, fmt, percent); | 107 | return scnprintf(hpp->buf, hpp->size, fmt, percent); |
| 108 | } | 108 | } |
| @@ -121,14 +121,14 @@ static int hpp__color_overhead_guest_sys(struct perf_hpp *hpp, | |||
| 121 | struct hist_entry *he) | 121 | struct hist_entry *he) |
| 122 | { | 122 | { |
| 123 | double percent = 100.0 * he->period_guest_sys / hpp->total_period; | 123 | double percent = 100.0 * he->period_guest_sys / hpp->total_period; |
| 124 | return percent_color_snprintf(hpp->buf, hpp->size, " %5.2f%% ", percent); | 124 | return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent); |
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | static int hpp__entry_overhead_guest_sys(struct perf_hpp *hpp, | 127 | static int hpp__entry_overhead_guest_sys(struct perf_hpp *hpp, |
| 128 | struct hist_entry *he) | 128 | struct hist_entry *he) |
| 129 | { | 129 | { |
| 130 | double percent = 100.0 * he->period_guest_sys / hpp->total_period; | 130 | double percent = 100.0 * he->period_guest_sys / hpp->total_period; |
| 131 | const char *fmt = symbol_conf.field_sep ? "%.2f" : " %5.2f%% "; | 131 | const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% "; |
| 132 | 132 | ||
| 133 | return scnprintf(hpp->buf, hpp->size, fmt, percent); | 133 | return scnprintf(hpp->buf, hpp->size, fmt, percent); |
| 134 | } | 134 | } |
| @@ -147,14 +147,14 @@ static int hpp__color_overhead_guest_us(struct perf_hpp *hpp, | |||
| 147 | struct hist_entry *he) | 147 | struct hist_entry *he) |
| 148 | { | 148 | { |
| 149 | double percent = 100.0 * he->period_guest_us / hpp->total_period; | 149 | double percent = 100.0 * he->period_guest_us / hpp->total_period; |
| 150 | return percent_color_snprintf(hpp->buf, hpp->size, " %5.2f%% ", percent); | 150 | return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent); |
| 151 | } | 151 | } |
| 152 | 152 | ||
| 153 | static int hpp__entry_overhead_guest_us(struct perf_hpp *hpp, | 153 | static int hpp__entry_overhead_guest_us(struct perf_hpp *hpp, |
| 154 | struct hist_entry *he) | 154 | struct hist_entry *he) |
| 155 | { | 155 | { |
| 156 | double percent = 100.0 * he->period_guest_us / hpp->total_period; | 156 | double percent = 100.0 * he->period_guest_us / hpp->total_period; |
| 157 | const char *fmt = symbol_conf.field_sep ? "%.2f" : " %5.2f%% "; | 157 | const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% "; |
| 158 | 158 | ||
| 159 | return scnprintf(hpp->buf, hpp->size, fmt, percent); | 159 | return scnprintf(hpp->buf, hpp->size, fmt, percent); |
| 160 | } | 160 | } |
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c index adc72f09914d..2b32ffa9ebdb 100644 --- a/tools/perf/util/cpumap.c +++ b/tools/perf/util/cpumap.c | |||
| @@ -38,24 +38,19 @@ static struct cpu_map *cpu_map__trim_new(int nr_cpus, int *tmp_cpus) | |||
| 38 | return cpus; | 38 | return cpus; |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | static struct cpu_map *cpu_map__read_all_cpu_map(void) | 41 | struct cpu_map *cpu_map__read(FILE *file) |
| 42 | { | 42 | { |
| 43 | struct cpu_map *cpus = NULL; | 43 | struct cpu_map *cpus = NULL; |
| 44 | FILE *onlnf; | ||
| 45 | int nr_cpus = 0; | 44 | int nr_cpus = 0; |
| 46 | int *tmp_cpus = NULL, *tmp; | 45 | int *tmp_cpus = NULL, *tmp; |
| 47 | int max_entries = 0; | 46 | int max_entries = 0; |
| 48 | int n, cpu, prev; | 47 | int n, cpu, prev; |
| 49 | char sep; | 48 | char sep; |
| 50 | 49 | ||
| 51 | onlnf = fopen("/sys/devices/system/cpu/online", "r"); | ||
| 52 | if (!onlnf) | ||
| 53 | return cpu_map__default_new(); | ||
| 54 | |||
| 55 | sep = 0; | 50 | sep = 0; |
| 56 | prev = -1; | 51 | prev = -1; |
| 57 | for (;;) { | 52 | for (;;) { |
| 58 | n = fscanf(onlnf, "%u%c", &cpu, &sep); | 53 | n = fscanf(file, "%u%c", &cpu, &sep); |
| 59 | if (n <= 0) | 54 | if (n <= 0) |
| 60 | break; | 55 | break; |
| 61 | if (prev >= 0) { | 56 | if (prev >= 0) { |
| @@ -95,6 +90,19 @@ static struct cpu_map *cpu_map__read_all_cpu_map(void) | |||
| 95 | cpus = cpu_map__default_new(); | 90 | cpus = cpu_map__default_new(); |
| 96 | out_free_tmp: | 91 | out_free_tmp: |
| 97 | free(tmp_cpus); | 92 | free(tmp_cpus); |
| 93 | return cpus; | ||
| 94 | } | ||
| 95 | |||
| 96 | static struct cpu_map *cpu_map__read_all_cpu_map(void) | ||
| 97 | { | ||
| 98 | struct cpu_map *cpus = NULL; | ||
| 99 | FILE *onlnf; | ||
| 100 | |||
| 101 | onlnf = fopen("/sys/devices/system/cpu/online", "r"); | ||
| 102 | if (!onlnf) | ||
| 103 | return cpu_map__default_new(); | ||
| 104 | |||
| 105 | cpus = cpu_map__read(onlnf); | ||
| 98 | fclose(onlnf); | 106 | fclose(onlnf); |
| 99 | return cpus; | 107 | return cpus; |
| 100 | } | 108 | } |
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h index c41518573c6a..17b5264f6436 100644 --- a/tools/perf/util/cpumap.h +++ b/tools/perf/util/cpumap.h | |||
| @@ -11,7 +11,7 @@ struct cpu_map { | |||
| 11 | struct cpu_map *cpu_map__new(const char *cpu_list); | 11 | struct cpu_map *cpu_map__new(const char *cpu_list); |
| 12 | struct cpu_map *cpu_map__dummy_new(void); | 12 | struct cpu_map *cpu_map__dummy_new(void); |
| 13 | void cpu_map__delete(struct cpu_map *map); | 13 | void cpu_map__delete(struct cpu_map *map); |
| 14 | 14 | struct cpu_map *cpu_map__read(FILE *file); | |
| 15 | size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); | 15 | size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); |
| 16 | 16 | ||
| 17 | #endif /* __PERF_CPUMAP_H */ | 17 | #endif /* __PERF_CPUMAP_H */ |
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 8202f5ca0483..6715b1938725 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
| @@ -904,8 +904,9 @@ int perf_event__preprocess_sample(const union perf_event *event, | |||
| 904 | al->sym = map__find_symbol(al->map, al->addr, filter); | 904 | al->sym = map__find_symbol(al->map, al->addr, filter); |
| 905 | } | 905 | } |
| 906 | 906 | ||
| 907 | if (symbol_conf.sym_list && al->sym && | 907 | if (symbol_conf.sym_list && |
| 908 | !strlist__has_entry(symbol_conf.sym_list, al->sym->name)) | 908 | (!al->sym || !strlist__has_entry(symbol_conf.sym_list, |
| 909 | al->sym->name))) | ||
| 909 | goto out_filtered; | 910 | goto out_filtered; |
| 910 | 911 | ||
| 911 | return 0; | 912 | return 0; |
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index dc40fe32210b..93876bad2e52 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
| @@ -66,6 +66,7 @@ struct perf_evsel { | |||
| 66 | void *func; | 66 | void *func; |
| 67 | void *data; | 67 | void *data; |
| 68 | } handler; | 68 | } handler; |
| 69 | struct cpu_map *cpus; | ||
| 69 | unsigned int sample_size; | 70 | unsigned int sample_size; |
| 70 | bool supported; | 71 | bool supported; |
| 71 | /* parse modifier helper */ | 72 | /* parse modifier helper */ |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 44afcf40f796..bf5d033ee1b4 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
| @@ -239,8 +239,11 @@ const char *event_type(int type) | |||
| 239 | return "unknown"; | 239 | return "unknown"; |
| 240 | } | 240 | } |
| 241 | 241 | ||
| 242 | static int add_event(struct list_head **_list, int *idx, | 242 | |
| 243 | struct perf_event_attr *attr, char *name) | 243 | |
| 244 | static int __add_event(struct list_head **_list, int *idx, | ||
| 245 | struct perf_event_attr *attr, | ||
| 246 | char *name, struct cpu_map *cpus) | ||
| 244 | { | 247 | { |
| 245 | struct perf_evsel *evsel; | 248 | struct perf_evsel *evsel; |
| 246 | struct list_head *list = *_list; | 249 | struct list_head *list = *_list; |
| @@ -260,6 +263,7 @@ static int add_event(struct list_head **_list, int *idx, | |||
| 260 | return -ENOMEM; | 263 | return -ENOMEM; |
| 261 | } | 264 | } |
| 262 | 265 | ||
| 266 | evsel->cpus = cpus; | ||
| 263 | if (name) | 267 | if (name) |
| 264 | evsel->name = strdup(name); | 268 | evsel->name = strdup(name); |
| 265 | list_add_tail(&evsel->node, list); | 269 | list_add_tail(&evsel->node, list); |
| @@ -267,6 +271,12 @@ static int add_event(struct list_head **_list, int *idx, | |||
| 267 | return 0; | 271 | return 0; |
| 268 | } | 272 | } |
| 269 | 273 | ||
| 274 | static int add_event(struct list_head **_list, int *idx, | ||
| 275 | struct perf_event_attr *attr, char *name) | ||
| 276 | { | ||
| 277 | return __add_event(_list, idx, attr, name, NULL); | ||
| 278 | } | ||
| 279 | |||
| 270 | static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size) | 280 | static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size) |
| 271 | { | 281 | { |
| 272 | int i, j; | 282 | int i, j; |
| @@ -607,8 +617,8 @@ int parse_events_add_pmu(struct list_head **list, int *idx, | |||
| 607 | if (perf_pmu__config(pmu, &attr, head_config)) | 617 | if (perf_pmu__config(pmu, &attr, head_config)) |
| 608 | return -EINVAL; | 618 | return -EINVAL; |
| 609 | 619 | ||
| 610 | return add_event(list, idx, &attr, | 620 | return __add_event(list, idx, &attr, pmu_event_name(head_config), |
| 611 | pmu_event_name(head_config)); | 621 | pmu->cpus); |
| 612 | } | 622 | } |
| 613 | 623 | ||
| 614 | int parse_events__modifier_group(struct list_head *list, | 624 | int parse_events__modifier_group(struct list_head *list, |
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 6631d828db3d..8a2229da594f 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "util.h" | 9 | #include "util.h" |
| 10 | #include "pmu.h" | 10 | #include "pmu.h" |
| 11 | #include "parse-events.h" | 11 | #include "parse-events.h" |
| 12 | #include "cpumap.h" | ||
| 12 | 13 | ||
| 13 | #define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/" | 14 | #define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/" |
| 14 | 15 | ||
| @@ -253,6 +254,33 @@ static void pmu_read_sysfs(void) | |||
| 253 | closedir(dir); | 254 | closedir(dir); |
| 254 | } | 255 | } |
| 255 | 256 | ||
| 257 | static struct cpu_map *pmu_cpumask(char *name) | ||
| 258 | { | ||
| 259 | struct stat st; | ||
| 260 | char path[PATH_MAX]; | ||
| 261 | const char *sysfs; | ||
| 262 | FILE *file; | ||
| 263 | struct cpu_map *cpus; | ||
| 264 | |||
| 265 | sysfs = sysfs_find_mountpoint(); | ||
| 266 | if (!sysfs) | ||
| 267 | return NULL; | ||
| 268 | |||
| 269 | snprintf(path, PATH_MAX, | ||
| 270 | "%s/bus/event_source/devices/%s/cpumask", sysfs, name); | ||
| 271 | |||
| 272 | if (stat(path, &st) < 0) | ||
| 273 | return NULL; | ||
| 274 | |||
| 275 | file = fopen(path, "r"); | ||
| 276 | if (!file) | ||
| 277 | return NULL; | ||
| 278 | |||
| 279 | cpus = cpu_map__read(file); | ||
| 280 | fclose(file); | ||
| 281 | return cpus; | ||
| 282 | } | ||
| 283 | |||
| 256 | static struct perf_pmu *pmu_lookup(char *name) | 284 | static struct perf_pmu *pmu_lookup(char *name) |
| 257 | { | 285 | { |
| 258 | struct perf_pmu *pmu; | 286 | struct perf_pmu *pmu; |
| @@ -275,6 +303,8 @@ static struct perf_pmu *pmu_lookup(char *name) | |||
| 275 | if (!pmu) | 303 | if (!pmu) |
| 276 | return NULL; | 304 | return NULL; |
| 277 | 305 | ||
| 306 | pmu->cpus = pmu_cpumask(name); | ||
| 307 | |||
| 278 | pmu_aliases(name, &aliases); | 308 | pmu_aliases(name, &aliases); |
| 279 | 309 | ||
| 280 | INIT_LIST_HEAD(&pmu->format); | 310 | INIT_LIST_HEAD(&pmu->format); |
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index 47f68d3cc5d1..53c7794fc4be 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h | |||
| @@ -28,6 +28,7 @@ struct perf_pmu__alias { | |||
| 28 | struct perf_pmu { | 28 | struct perf_pmu { |
| 29 | char *name; | 29 | char *name; |
| 30 | __u32 type; | 30 | __u32 type; |
| 31 | struct cpu_map *cpus; | ||
| 31 | struct list_head format; | 32 | struct list_head format; |
| 32 | struct list_head aliases; | 33 | struct list_head aliases; |
| 33 | struct list_head list; | 34 | struct list_head list; |
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 526ba56e720b..1daf5c14e751 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
| @@ -525,8 +525,10 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, | |||
| 525 | return -ENOENT; | 525 | return -ENOENT; |
| 526 | } | 526 | } |
| 527 | /* Verify it is a data structure */ | 527 | /* Verify it is a data structure */ |
| 528 | if (dwarf_tag(&type) != DW_TAG_structure_type) { | 528 | tag = dwarf_tag(&type); |
| 529 | pr_warning("%s is not a data structure.\n", varname); | 529 | if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) { |
| 530 | pr_warning("%s is not a data structure nor an union.\n", | ||
| 531 | varname); | ||
| 530 | return -EINVAL; | 532 | return -EINVAL; |
| 531 | } | 533 | } |
| 532 | 534 | ||
| @@ -539,8 +541,9 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, | |||
| 539 | *ref_ptr = ref; | 541 | *ref_ptr = ref; |
| 540 | } else { | 542 | } else { |
| 541 | /* Verify it is a data structure */ | 543 | /* Verify it is a data structure */ |
| 542 | if (tag != DW_TAG_structure_type) { | 544 | if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) { |
| 543 | pr_warning("%s is not a data structure.\n", varname); | 545 | pr_warning("%s is not a data structure nor an union.\n", |
| 546 | varname); | ||
| 544 | return -EINVAL; | 547 | return -EINVAL; |
| 545 | } | 548 | } |
| 546 | if (field->name[0] == '[') { | 549 | if (field->name[0] == '[') { |
| @@ -567,10 +570,15 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, | |||
| 567 | } | 570 | } |
| 568 | 571 | ||
| 569 | /* Get the offset of the field */ | 572 | /* Get the offset of the field */ |
| 570 | ret = die_get_data_member_location(die_mem, &offs); | 573 | if (tag == DW_TAG_union_type) { |
| 571 | if (ret < 0) { | 574 | offs = 0; |
| 572 | pr_warning("Failed to get the offset of %s.\n", field->name); | 575 | } else { |
| 573 | return ret; | 576 | ret = die_get_data_member_location(die_mem, &offs); |
| 577 | if (ret < 0) { | ||
| 578 | pr_warning("Failed to get the offset of %s.\n", | ||
| 579 | field->name); | ||
| 580 | return ret; | ||
| 581 | } | ||
| 574 | } | 582 | } |
| 575 | ref->offset += (long)offs; | 583 | ref->offset += (long)offs; |
| 576 | 584 | ||
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 0981bc7a2917..b5b1b9211960 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
| @@ -8,6 +8,7 @@ const char default_sort_order[] = "comm,dso,symbol"; | |||
| 8 | const char *sort_order = default_sort_order; | 8 | const char *sort_order = default_sort_order; |
| 9 | int sort__need_collapse = 0; | 9 | int sort__need_collapse = 0; |
| 10 | int sort__has_parent = 0; | 10 | int sort__has_parent = 0; |
| 11 | int sort__has_sym = 0; | ||
| 11 | int sort__branch_mode = -1; /* -1 = means not set */ | 12 | int sort__branch_mode = -1; /* -1 = means not set */ |
| 12 | 13 | ||
| 13 | enum sort_type sort__first_dimension; | 14 | enum sort_type sort__first_dimension; |
| @@ -511,6 +512,10 @@ int sort_dimension__add(const char *tok) | |||
| 511 | return -EINVAL; | 512 | return -EINVAL; |
| 512 | } | 513 | } |
| 513 | sort__has_parent = 1; | 514 | sort__has_parent = 1; |
| 515 | } else if (sd->entry == &sort_sym || | ||
| 516 | sd->entry == &sort_sym_from || | ||
| 517 | sd->entry == &sort_sym_to) { | ||
| 518 | sort__has_sym = 1; | ||
| 514 | } | 519 | } |
| 515 | 520 | ||
| 516 | if (sd->taken) | 521 | if (sd->taken) |
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index e459c981b039..12d634792de5 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h | |||
| @@ -31,6 +31,7 @@ extern const char *parent_pattern; | |||
| 31 | extern const char default_sort_order[]; | 31 | extern const char default_sort_order[]; |
| 32 | extern int sort__need_collapse; | 32 | extern int sort__need_collapse; |
| 33 | extern int sort__has_parent; | 33 | extern int sort__has_parent; |
| 34 | extern int sort__has_sym; | ||
| 34 | extern int sort__branch_mode; | 35 | extern int sort__branch_mode; |
| 35 | extern struct sort_entry sort_comm; | 36 | extern struct sort_entry sort_comm; |
| 36 | extern struct sort_entry sort_dso; | 37 | extern struct sort_entry sort_dso; |
diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c new file mode 100644 index 000000000000..23742126f47c --- /dev/null +++ b/tools/perf/util/stat.c | |||
| @@ -0,0 +1,57 @@ | |||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | #include "stat.h" | ||
| 4 | |||
| 5 | void update_stats(struct stats *stats, u64 val) | ||
| 6 | { | ||
| 7 | double delta; | ||
| 8 | |||
| 9 | stats->n++; | ||
| 10 | delta = val - stats->mean; | ||
| 11 | stats->mean += delta / stats->n; | ||
| 12 | stats->M2 += delta*(val - stats->mean); | ||
| 13 | } | ||
| 14 | |||
| 15 | double avg_stats(struct stats *stats) | ||
| 16 | { | ||
| 17 | return stats->mean; | ||
| 18 | } | ||
| 19 | |||
| 20 | /* | ||
| 21 | * http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance | ||
| 22 | * | ||
| 23 | * (\Sum n_i^2) - ((\Sum n_i)^2)/n | ||
| 24 | * s^2 = ------------------------------- | ||
| 25 | * n - 1 | ||
| 26 | * | ||
| 27 | * http://en.wikipedia.org/wiki/Stddev | ||
| 28 | * | ||
| 29 | * The std dev of the mean is related to the std dev by: | ||
| 30 | * | ||
| 31 | * s | ||
| 32 | * s_mean = ------- | ||
| 33 | * sqrt(n) | ||
| 34 | * | ||
| 35 | */ | ||
| 36 | double stddev_stats(struct stats *stats) | ||
| 37 | { | ||
| 38 | double variance, variance_mean; | ||
| 39 | |||
| 40 | if (!stats->n) | ||
| 41 | return 0.0; | ||
| 42 | |||
| 43 | variance = stats->M2 / (stats->n - 1); | ||
| 44 | variance_mean = variance / stats->n; | ||
| 45 | |||
| 46 | return sqrt(variance_mean); | ||
| 47 | } | ||
| 48 | |||
| 49 | double rel_stddev_stats(double stddev, double avg) | ||
| 50 | { | ||
| 51 | double pct = 0.0; | ||
| 52 | |||
| 53 | if (avg) | ||
| 54 | pct = 100.0 * stddev/avg; | ||
| 55 | |||
| 56 | return pct; | ||
| 57 | } | ||
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h new file mode 100644 index 000000000000..588367c3c767 --- /dev/null +++ b/tools/perf/util/stat.h | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | #ifndef __PERF_STATS_H | ||
| 2 | #define __PERF_STATS_H | ||
| 3 | |||
| 4 | #include "types.h" | ||
| 5 | |||
| 6 | struct stats | ||
| 7 | { | ||
| 8 | double n, mean, M2; | ||
| 9 | }; | ||
| 10 | |||
| 11 | void update_stats(struct stats *stats, u64 val); | ||
| 12 | double avg_stats(struct stats *stats); | ||
| 13 | double stddev_stats(struct stats *stats); | ||
| 14 | double rel_stddev_stats(double stddev, double avg); | ||
| 15 | |||
| 16 | #endif | ||
