mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-27 17:11:46 +00:00
perf/core improvements and fixes
. Fix handling of unresolved samples when --symbols is used in 'report', from Feng Tang. . Add --symbols to 'script', similar to the one in 'report', from Feng Tang. . Add union member access support to 'probe', from Hyeoncheol Lee. . Make 'archive' work on Android, tweaking some of the utility parameters used (tar, rm), from Irina Tirdea. . Fixups to die() removal, from Namhyung Kim. . Render fixes for the TUI, from Namhyung Kim. . Don't enable annotation in non symbolic view, from Namhyung Kim. . Fix pipe mode in 'report', from Namhyung Kim. . Move related stats code from stat to util/, will be used by the 'stat' kvm tool, from Xiao Guangrong. . Add cpumask for uncore pmu, use it in 'stat', from Yan, Zheng. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.14 (GNU/Linux) iQIcBAABAgAGBQJQV1jtAAoJENZQFvNTUqpAt0QP/2NsqgW3L/ewwzf5Eb2j5ao+ K/5utQQ40xCuceEyMTqWkzDNAy8iQcd5ScEOSU3VSTC90NS68EofnZsh7Xb500M2 KIyFPAT+SSS6Zn0DpM2cRheRrH0GzARaIypxyTt2i0pU3BUrfZLyzhdHr2jsNt45 LpTzrpnNEHWdKZ7Q9dPDuV74UP+F+978p41XRo8YeNZTIWpeMji9IK16Z1QWBeDr 1ZmWgSbJ6yrVD2M1nVXczN+ELUn9knLBR6DGY3CuFvMgGRW6Gd9uV7iyXHy08R5L WE3mlwRb/XHNFTFveKfZ8tIi+pjhR9rfA5a2bmPEi8xHoxyDjQyWnj1nn8qlpf1m c/AZA3VK8PWJwUpkvbvpVAfEODMQMUK8DxE7x5lMBmtCET51VLLEFc5xwqk/j8R+ 0d/t5GUhov/Ppw+FIUYd6Me7noYn3vfA65lPJ14Wixxo/9CVdpBkB86sE9BNER+b ygofV3mAtB/Hs+fyFxQQaN6WzcSVEucoG8NUyHjsng2pqGydvIC+FeW6zqdYD5AZ Bq4LASkmy2yNI3xHLq7W6lMyBGFNs+g7xAurdM4AiqUBknt2Ku3zPcNWM7EdKbNs wbyAPqEUiI2+usMfSxHG43ostCZDBBtPrM1lnj2LRQ1lua6pjMT+ob3XedX+x04/ tRJafv7c9h5d5jURqDIR =Z6R1 -----END PGP SIGNATURE----- Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo: * Fix handling of unresolved samples when --symbols is used in 'report', from Feng Tang. * Add --symbols to 'script', similar to the one in 'report', from Feng Tang. * Add union member access support to 'probe', from Hyeoncheol Lee. * Make 'archive' work on Android, tweaking some of the utility parameters used (tar, rm), from Irina Tirdea. * Fixups to die() removal, from Namhyung Kim. * Render fixes for the TUI, from Namhyung Kim. * Don't enable annotation in non symbolic view, from Namhyung Kim. * Fix pipe mode in 'report', from Namhyung Kim. * Move related stats code from stat to util/, will be used by the 'stat' kvm tool, from Xiao Guangrong. * Add cpumask for uncore pmu, use it in 'stat', from Yan, Zheng. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
bea8f35421
29 changed files with 318 additions and 126 deletions
|
@ -2341,6 +2341,27 @@ int uncore_pmu_event_init(struct perf_event *event)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ssize_t uncore_get_attr_cpumask(struct device *dev,
|
||||||
|
struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
int n = cpulist_scnprintf(buf, PAGE_SIZE - 2, &uncore_cpu_mask);
|
||||||
|
|
||||||
|
buf[n++] = '\n';
|
||||||
|
buf[n] = '\0';
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEVICE_ATTR(cpumask, S_IRUGO, uncore_get_attr_cpumask, NULL);
|
||||||
|
|
||||||
|
static struct attribute *uncore_pmu_attrs[] = {
|
||||||
|
&dev_attr_cpumask.attr,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute_group uncore_pmu_attr_group = {
|
||||||
|
.attrs = uncore_pmu_attrs,
|
||||||
|
};
|
||||||
|
|
||||||
static int __init uncore_pmu_register(struct intel_uncore_pmu *pmu)
|
static int __init uncore_pmu_register(struct intel_uncore_pmu *pmu)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -2378,8 +2399,8 @@ static void __init uncore_type_exit(struct intel_uncore_type *type)
|
||||||
free_percpu(type->pmus[i].box);
|
free_percpu(type->pmus[i].box);
|
||||||
kfree(type->pmus);
|
kfree(type->pmus);
|
||||||
type->pmus = NULL;
|
type->pmus = NULL;
|
||||||
kfree(type->attr_groups[1]);
|
kfree(type->events_group);
|
||||||
type->attr_groups[1] = NULL;
|
type->events_group = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __init uncore_types_exit(struct intel_uncore_type **types)
|
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)
|
||||||
for (j = 0; j < i; j++)
|
for (j = 0; j < i; j++)
|
||||||
attrs[j] = &type->event_descs[j].attr.attr;
|
attrs[j] = &type->event_descs[j].attr.attr;
|
||||||
|
|
||||||
type->attr_groups[1] = events_group;
|
type->events_group = events_group;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type->pmu_group = &uncore_pmu_attr_group;
|
||||||
type->pmus = pmus;
|
type->pmus = pmus;
|
||||||
return 0;
|
return 0;
|
||||||
fail:
|
fail:
|
||||||
|
|
|
@ -369,10 +369,12 @@ struct intel_uncore_type {
|
||||||
struct intel_uncore_pmu *pmus;
|
struct intel_uncore_pmu *pmus;
|
||||||
struct intel_uncore_ops *ops;
|
struct intel_uncore_ops *ops;
|
||||||
struct uncore_event_desc *event_descs;
|
struct uncore_event_desc *event_descs;
|
||||||
const struct attribute_group *attr_groups[3];
|
const struct attribute_group *attr_groups[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
#define format_group attr_groups[0]
|
#define pmu_group attr_groups[0]
|
||||||
|
#define format_group attr_groups[1]
|
||||||
|
#define events_group attr_groups[2]
|
||||||
|
|
||||||
struct intel_uncore_ops {
|
struct intel_uncore_ops {
|
||||||
void (*init_box)(struct intel_uncore_box *);
|
void (*init_box)(struct intel_uncore_box *);
|
||||||
|
|
|
@ -129,7 +129,7 @@ CFLAGS ?= -g -Wall
|
||||||
|
|
||||||
# Append required CFLAGS
|
# Append required CFLAGS
|
||||||
override CFLAGS += $(CONFIG_FLAGS) $(INCLUDES) $(PLUGIN_DIR_SQ)
|
override CFLAGS += $(CONFIG_FLAGS) $(INCLUDES) $(PLUGIN_DIR_SQ)
|
||||||
override CFLAGS += $(udis86-flags)
|
override CFLAGS += $(udis86-flags) -D_GNU_SOURCE
|
||||||
|
|
||||||
ifeq ($(VERBOSE),1)
|
ifeq ($(VERBOSE),1)
|
||||||
Q =
|
Q =
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
* Frederic Weisbecker gave his permission to relicense the code to
|
* Frederic Weisbecker gave his permission to relicense the code to
|
||||||
* the Lesser General Public License.
|
* the Lesser General Public License.
|
||||||
*/
|
*/
|
||||||
#define _GNU_SOURCE
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
|
@ -406,6 +406,7 @@ LIB_OBJS += $(OUTPUT)util/target.o
|
||||||
LIB_OBJS += $(OUTPUT)util/rblist.o
|
LIB_OBJS += $(OUTPUT)util/rblist.o
|
||||||
LIB_OBJS += $(OUTPUT)util/intlist.o
|
LIB_OBJS += $(OUTPUT)util/intlist.o
|
||||||
LIB_OBJS += $(OUTPUT)util/vdso.o
|
LIB_OBJS += $(OUTPUT)util/vdso.o
|
||||||
|
LIB_OBJS += $(OUTPUT)util/stat.o
|
||||||
|
|
||||||
LIB_OBJS += $(OUTPUT)ui/helpline.o
|
LIB_OBJS += $(OUTPUT)ui/helpline.o
|
||||||
LIB_OBJS += $(OUTPUT)ui/hist.o
|
LIB_OBJS += $(OUTPUT)ui/hist.o
|
||||||
|
|
|
@ -93,7 +93,7 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
|
||||||
struct annotation *notes;
|
struct annotation *notes;
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
bx = he->branch_info;
|
bx = he->branch_info;
|
||||||
if (bx->from.sym && use_browser > 0) {
|
if (bx->from.sym && use_browser == 1 && sort__has_sym) {
|
||||||
notes = symbol__annotation(bx->from.sym);
|
notes = symbol__annotation(bx->from.sym);
|
||||||
if (!notes->src
|
if (!notes->src
|
||||||
&& symbol__alloc_hist(bx->from.sym) < 0)
|
&& symbol__alloc_hist(bx->from.sym) < 0)
|
||||||
|
@ -107,7 +107,7 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bx->to.sym && use_browser > 0) {
|
if (bx->to.sym && use_browser == 1 && sort__has_sym) {
|
||||||
notes = symbol__annotation(bx->to.sym);
|
notes = symbol__annotation(bx->to.sym);
|
||||||
if (!notes->src
|
if (!notes->src
|
||||||
&& symbol__alloc_hist(bx->to.sym) < 0)
|
&& symbol__alloc_hist(bx->to.sym) < 0)
|
||||||
|
@ -162,7 +162,7 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,
|
||||||
* so we don't allocated the extra space needed because the stdio
|
* so we don't allocated the extra space needed because the stdio
|
||||||
* code will not use it.
|
* code will not use it.
|
||||||
*/
|
*/
|
||||||
if (he->ms.sym != NULL && use_browser > 0) {
|
if (he->ms.sym != NULL && use_browser == 1 && sort__has_sym) {
|
||||||
struct annotation *notes = symbol__annotation(he->ms.sym);
|
struct annotation *notes = symbol__annotation(he->ms.sym);
|
||||||
|
|
||||||
assert(evsel != NULL);
|
assert(evsel != NULL);
|
||||||
|
@ -689,15 +689,19 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||||
|
|
||||||
if (strcmp(report.input_name, "-") != 0)
|
if (strcmp(report.input_name, "-") != 0)
|
||||||
setup_browser(true);
|
setup_browser(true);
|
||||||
else
|
else {
|
||||||
use_browser = 0;
|
use_browser = 0;
|
||||||
|
perf_hpp__init(false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_sorting(report_usage, options);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Only in the newt browser we are doing integrated annotation,
|
* Only in the newt browser we are doing integrated annotation,
|
||||||
* so don't allocate extra space that won't be used in the stdio
|
* so don't allocate extra space that won't be used in the stdio
|
||||||
* implementation.
|
* implementation.
|
||||||
*/
|
*/
|
||||||
if (use_browser > 0) {
|
if (use_browser == 1 && sort__has_sym) {
|
||||||
symbol_conf.priv_size = sizeof(struct annotation);
|
symbol_conf.priv_size = sizeof(struct annotation);
|
||||||
report.annotate_init = symbol__annotate_init;
|
report.annotate_init = symbol__annotate_init;
|
||||||
/*
|
/*
|
||||||
|
@ -720,8 +724,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||||
if (symbol__init() < 0)
|
if (symbol__init() < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
setup_sorting(report_usage, options);
|
|
||||||
|
|
||||||
if (parent_pattern != default_parent_pattern) {
|
if (parent_pattern != default_parent_pattern) {
|
||||||
if (sort_dimension__add("parent") < 0)
|
if (sort_dimension__add("parent") < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
|
@ -438,7 +438,7 @@ static int self_open_counters(void)
|
||||||
fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
|
fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
|
||||||
|
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
pr_debug("Error: sys_perf_event_open() syscall returned"
|
pr_err("Error: sys_perf_event_open() syscall returned "
|
||||||
"with %d (%s)\n", fd, strerror(errno));
|
"with %d (%s)\n", fd, strerror(errno));
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
@ -700,7 +700,7 @@ static int replay_switch_event(struct perf_sched *sched,
|
||||||
delta = 0;
|
delta = 0;
|
||||||
|
|
||||||
if (delta < 0) {
|
if (delta < 0) {
|
||||||
pr_debug("hm, delta: %" PRIu64 " < 0 ?\n", delta);
|
pr_err("hm, delta: %" PRIu64 " < 0 ?\n", delta);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -990,7 +990,7 @@ static int latency_runtime_event(struct perf_sched *sched,
|
||||||
return -1;
|
return -1;
|
||||||
atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid);
|
atoms = thread_atoms_search(&sched->atom_root, thread, &sched->cmp_pid);
|
||||||
if (!atoms) {
|
if (!atoms) {
|
||||||
pr_debug("in-event: Internal tree error");
|
pr_err("in-event: Internal tree error");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (add_sched_out_event(atoms, 'R', timestamp))
|
if (add_sched_out_event(atoms, 'R', timestamp))
|
||||||
|
@ -1024,7 +1024,7 @@ static int latency_wakeup_event(struct perf_sched *sched,
|
||||||
return -1;
|
return -1;
|
||||||
atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid);
|
atoms = thread_atoms_search(&sched->atom_root, wakee, &sched->cmp_pid);
|
||||||
if (!atoms) {
|
if (!atoms) {
|
||||||
pr_debug("wakeup-event: Internal tree error");
|
pr_err("wakeup-event: Internal tree error");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (add_sched_out_event(atoms, 'S', timestamp))
|
if (add_sched_out_event(atoms, 'S', timestamp))
|
||||||
|
@ -1079,7 +1079,7 @@ static int latency_migrate_task_event(struct perf_sched *sched,
|
||||||
register_pid(sched, migrant->pid, migrant->comm);
|
register_pid(sched, migrant->pid, migrant->comm);
|
||||||
atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid);
|
atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid);
|
||||||
if (!atoms) {
|
if (!atoms) {
|
||||||
pr_debug("migration-event: Internal tree error");
|
pr_err("migration-event: Internal tree error");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (add_sched_out_event(atoms, 'R', timestamp))
|
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,
|
||||||
delta = 0;
|
delta = 0;
|
||||||
|
|
||||||
if (delta < 0) {
|
if (delta < 0) {
|
||||||
pr_debug("hm, delta: %" PRIu64 " < 0 ?\n", delta);
|
pr_err("hm, delta: %" PRIu64 " < 0 ?\n", delta);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "util/util.h"
|
#include "util/util.h"
|
||||||
#include "util/evlist.h"
|
#include "util/evlist.h"
|
||||||
#include "util/evsel.h"
|
#include "util/evsel.h"
|
||||||
|
#include "util/sort.h"
|
||||||
#include <linux/bitmap.h>
|
#include <linux/bitmap.h>
|
||||||
|
|
||||||
static char const *script_name;
|
static char const *script_name;
|
||||||
|
@ -1031,6 +1032,61 @@ static int list_available_scripts(const struct option *opt __maybe_unused,
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return -1 if none is found, otherwise the actual scripts number.
|
||||||
|
*
|
||||||
|
* Currently the only user of this function is the script browser, which
|
||||||
|
* will list all statically runnable scripts, select one, execute it and
|
||||||
|
* show the output in a perf browser.
|
||||||
|
*/
|
||||||
|
int find_scripts(char **scripts_array, char **scripts_path_array)
|
||||||
|
{
|
||||||
|
struct dirent *script_next, *lang_next, script_dirent, lang_dirent;
|
||||||
|
char scripts_path[MAXPATHLEN];
|
||||||
|
DIR *scripts_dir, *lang_dir;
|
||||||
|
char lang_path[MAXPATHLEN];
|
||||||
|
char *temp;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
|
||||||
|
|
||||||
|
scripts_dir = opendir(scripts_path);
|
||||||
|
if (!scripts_dir)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next) {
|
||||||
|
snprintf(lang_path, MAXPATHLEN, "%s/%s", scripts_path,
|
||||||
|
lang_dirent.d_name);
|
||||||
|
#ifdef NO_LIBPERL
|
||||||
|
if (strstr(lang_path, "perl"))
|
||||||
|
continue;
|
||||||
|
#endif
|
||||||
|
#ifdef NO_LIBPYTHON
|
||||||
|
if (strstr(lang_path, "python"))
|
||||||
|
continue;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
lang_dir = opendir(lang_path);
|
||||||
|
if (!lang_dir)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for_each_script(lang_path, lang_dir, script_dirent, script_next) {
|
||||||
|
/* Skip those real time scripts: xxxtop.p[yl] */
|
||||||
|
if (strstr(script_dirent.d_name, "top."))
|
||||||
|
continue;
|
||||||
|
sprintf(scripts_path_array[i], "%s/%s", lang_path,
|
||||||
|
script_dirent.d_name);
|
||||||
|
temp = strchr(script_dirent.d_name, '.');
|
||||||
|
snprintf(scripts_array[i],
|
||||||
|
(temp - script_dirent.d_name) + 1,
|
||||||
|
"%s", script_dirent.d_name);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
static char *get_script_path(const char *script_root, const char *suffix)
|
static char *get_script_path(const char *script_root, const char *suffix)
|
||||||
{
|
{
|
||||||
struct dirent *script_next, *lang_next, script_dirent, lang_dirent;
|
struct dirent *script_next, *lang_next, script_dirent, lang_dirent;
|
||||||
|
@ -1143,6 +1199,8 @@ static const struct option options[] = {
|
||||||
parse_output_fields),
|
parse_output_fields),
|
||||||
OPT_BOOLEAN('a', "all-cpus", &system_wide,
|
OPT_BOOLEAN('a', "all-cpus", &system_wide,
|
||||||
"system-wide collection from all CPUs"),
|
"system-wide collection from all CPUs"),
|
||||||
|
OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
|
||||||
|
"only consider these symbols"),
|
||||||
OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
|
OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"),
|
||||||
OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
|
OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
|
||||||
"only display events for these comms"),
|
"only display events for these comms"),
|
||||||
|
|
|
@ -51,13 +51,13 @@
|
||||||
#include "util/evsel.h"
|
#include "util/evsel.h"
|
||||||
#include "util/debug.h"
|
#include "util/debug.h"
|
||||||
#include "util/color.h"
|
#include "util/color.h"
|
||||||
|
#include "util/stat.h"
|
||||||
#include "util/header.h"
|
#include "util/header.h"
|
||||||
#include "util/cpumap.h"
|
#include "util/cpumap.h"
|
||||||
#include "util/thread.h"
|
#include "util/thread.h"
|
||||||
#include "util/thread_map.h"
|
#include "util/thread_map.h"
|
||||||
|
|
||||||
#include <sys/prctl.h>
|
#include <sys/prctl.h>
|
||||||
#include <math.h>
|
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
|
|
||||||
#define DEFAULT_SEPARATOR " "
|
#define DEFAULT_SEPARATOR " "
|
||||||
|
@ -199,11 +199,6 @@ static int output_fd;
|
||||||
|
|
||||||
static volatile int done = 0;
|
static volatile int done = 0;
|
||||||
|
|
||||||
struct stats
|
|
||||||
{
|
|
||||||
double n, mean, M2;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct perf_stat {
|
struct perf_stat {
|
||||||
struct stats res_stats[3];
|
struct stats res_stats[3];
|
||||||
};
|
};
|
||||||
|
@ -220,48 +215,14 @@ static void perf_evsel__free_stat_priv(struct perf_evsel *evsel)
|
||||||
evsel->priv = NULL;
|
evsel->priv = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void update_stats(struct stats *stats, u64 val)
|
static inline struct cpu_map *perf_evsel__cpus(struct perf_evsel *evsel)
|
||||||
{
|
{
|
||||||
double delta;
|
return (evsel->cpus && !target.cpu_list) ? evsel->cpus : evsel_list->cpus;
|
||||||
|
|
||||||
stats->n++;
|
|
||||||
delta = val - stats->mean;
|
|
||||||
stats->mean += delta / stats->n;
|
|
||||||
stats->M2 += delta*(val - stats->mean);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static double avg_stats(struct stats *stats)
|
static inline int perf_evsel__nr_cpus(struct perf_evsel *evsel)
|
||||||
{
|
{
|
||||||
return stats->mean;
|
return perf_evsel__cpus(evsel)->nr;
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
|
|
||||||
*
|
|
||||||
* (\Sum n_i^2) - ((\Sum n_i)^2)/n
|
|
||||||
* s^2 = -------------------------------
|
|
||||||
* n - 1
|
|
||||||
*
|
|
||||||
* http://en.wikipedia.org/wiki/Stddev
|
|
||||||
*
|
|
||||||
* The std dev of the mean is related to the std dev by:
|
|
||||||
*
|
|
||||||
* s
|
|
||||||
* s_mean = -------
|
|
||||||
* sqrt(n)
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static double stddev_stats(struct stats *stats)
|
|
||||||
{
|
|
||||||
double variance, variance_mean;
|
|
||||||
|
|
||||||
if (!stats->n)
|
|
||||||
return 0.0;
|
|
||||||
|
|
||||||
variance = stats->M2 / (stats->n - 1);
|
|
||||||
variance_mean = variance / stats->n;
|
|
||||||
|
|
||||||
return sqrt(variance_mean);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct stats runtime_nsecs_stats[MAX_NR_CPUS];
|
static struct stats runtime_nsecs_stats[MAX_NR_CPUS];
|
||||||
|
@ -295,7 +256,7 @@ retry:
|
||||||
evsel->attr.exclude_guest = evsel->attr.exclude_host = 0;
|
evsel->attr.exclude_guest = evsel->attr.exclude_host = 0;
|
||||||
|
|
||||||
if (perf_target__has_cpu(&target)) {
|
if (perf_target__has_cpu(&target)) {
|
||||||
ret = perf_evsel__open_per_cpu(evsel, evsel_list->cpus);
|
ret = perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel));
|
||||||
if (ret)
|
if (ret)
|
||||||
goto check_ret;
|
goto check_ret;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -376,7 +337,7 @@ static int read_counter_aggr(struct perf_evsel *counter)
|
||||||
u64 *count = counter->counts->aggr.values;
|
u64 *count = counter->counts->aggr.values;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (__perf_evsel__read(counter, evsel_list->cpus->nr,
|
if (__perf_evsel__read(counter, perf_evsel__nr_cpus(counter),
|
||||||
evsel_list->threads->nr, scale) < 0)
|
evsel_list->threads->nr, scale) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -405,7 +366,7 @@ static int read_counter(struct perf_evsel *counter)
|
||||||
u64 *count;
|
u64 *count;
|
||||||
int cpu;
|
int cpu;
|
||||||
|
|
||||||
for (cpu = 0; cpu < evsel_list->cpus->nr; cpu++) {
|
for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
|
||||||
if (__perf_evsel__read_on_cpu(counter, cpu, 0, scale) < 0)
|
if (__perf_evsel__read_on_cpu(counter, cpu, 0, scale) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -544,12 +505,12 @@ static int run_perf_stat(int argc __maybe_unused, const char **argv)
|
||||||
if (no_aggr) {
|
if (no_aggr) {
|
||||||
list_for_each_entry(counter, &evsel_list->entries, node) {
|
list_for_each_entry(counter, &evsel_list->entries, node) {
|
||||||
read_counter(counter);
|
read_counter(counter);
|
||||||
perf_evsel__close_fd(counter, evsel_list->cpus->nr, 1);
|
perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), 1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
list_for_each_entry(counter, &evsel_list->entries, node) {
|
list_for_each_entry(counter, &evsel_list->entries, node) {
|
||||||
read_counter_aggr(counter);
|
read_counter_aggr(counter);
|
||||||
perf_evsel__close_fd(counter, evsel_list->cpus->nr,
|
perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter),
|
||||||
evsel_list->threads->nr);
|
evsel_list->threads->nr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -559,10 +520,7 @@ static int run_perf_stat(int argc __maybe_unused, const char **argv)
|
||||||
|
|
||||||
static void print_noise_pct(double total, double avg)
|
static void print_noise_pct(double total, double avg)
|
||||||
{
|
{
|
||||||
double pct = 0.0;
|
double pct = rel_stddev_stats(total, avg);
|
||||||
|
|
||||||
if (avg)
|
|
||||||
pct = 100.0*total/avg;
|
|
||||||
|
|
||||||
if (csv_output)
|
if (csv_output)
|
||||||
fprintf(output, "%s%.2f%%", csv_sep, pct);
|
fprintf(output, "%s%.2f%%", csv_sep, pct);
|
||||||
|
@ -590,7 +548,7 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg)
|
||||||
if (no_aggr)
|
if (no_aggr)
|
||||||
sprintf(cpustr, "CPU%*d%s",
|
sprintf(cpustr, "CPU%*d%s",
|
||||||
csv_output ? 0 : -4,
|
csv_output ? 0 : -4,
|
||||||
evsel_list->cpus->map[cpu], csv_sep);
|
perf_evsel__cpus(evsel)->map[cpu], csv_sep);
|
||||||
|
|
||||||
fprintf(output, fmt, cpustr, msecs, csv_sep, perf_evsel__name(evsel));
|
fprintf(output, fmt, cpustr, msecs, csv_sep, perf_evsel__name(evsel));
|
||||||
|
|
||||||
|
@ -802,7 +760,7 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
|
||||||
if (no_aggr)
|
if (no_aggr)
|
||||||
sprintf(cpustr, "CPU%*d%s",
|
sprintf(cpustr, "CPU%*d%s",
|
||||||
csv_output ? 0 : -4,
|
csv_output ? 0 : -4,
|
||||||
evsel_list->cpus->map[cpu], csv_sep);
|
perf_evsel__cpus(evsel)->map[cpu], csv_sep);
|
||||||
else
|
else
|
||||||
cpu = 0;
|
cpu = 0;
|
||||||
|
|
||||||
|
@ -963,14 +921,14 @@ static void print_counter(struct perf_evsel *counter)
|
||||||
u64 ena, run, val;
|
u64 ena, run, val;
|
||||||
int cpu;
|
int cpu;
|
||||||
|
|
||||||
for (cpu = 0; cpu < evsel_list->cpus->nr; cpu++) {
|
for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
|
||||||
val = counter->counts->cpu[cpu].val;
|
val = counter->counts->cpu[cpu].val;
|
||||||
ena = counter->counts->cpu[cpu].ena;
|
ena = counter->counts->cpu[cpu].ena;
|
||||||
run = counter->counts->cpu[cpu].run;
|
run = counter->counts->cpu[cpu].run;
|
||||||
if (run == 0 || ena == 0) {
|
if (run == 0 || ena == 0) {
|
||||||
fprintf(output, "CPU%*d%s%*s%s%*s",
|
fprintf(output, "CPU%*d%s%*s%s%*s",
|
||||||
csv_output ? 0 : -4,
|
csv_output ? 0 : -4,
|
||||||
evsel_list->cpus->map[cpu], csv_sep,
|
perf_evsel__cpus(counter)->map[cpu], csv_sep,
|
||||||
csv_output ? 0 : 18,
|
csv_output ? 0 : 18,
|
||||||
counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
|
counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
|
||||||
csv_sep,
|
csv_sep,
|
||||||
|
@ -1269,7 +1227,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||||
|
|
||||||
list_for_each_entry(pos, &evsel_list->entries, node) {
|
list_for_each_entry(pos, &evsel_list->entries, node) {
|
||||||
if (perf_evsel__alloc_stat_priv(pos) < 0 ||
|
if (perf_evsel__alloc_stat_priv(pos) < 0 ||
|
||||||
perf_evsel__alloc_counts(pos, evsel_list->cpus->nr) < 0)
|
perf_evsel__alloc_counts(pos, perf_evsel__nr_cpus(pos)) < 0)
|
||||||
goto out_free_fd;
|
goto out_free_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1026,14 +1026,14 @@ static int __test__rdpmc(void)
|
||||||
|
|
||||||
fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
|
fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
pr_debug("Error: sys_perf_event_open() syscall returned "
|
pr_err("Error: sys_perf_event_open() syscall returned "
|
||||||
"with %d (%s)\n", fd, strerror(errno));
|
"with %d (%s)\n", fd, strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
addr = mmap(NULL, page_size, PROT_READ, MAP_SHARED, fd, 0);
|
addr = mmap(NULL, page_size, PROT_READ, MAP_SHARED, fd, 0);
|
||||||
if (addr == (void *)(-1)) {
|
if (addr == (void *)(-1)) {
|
||||||
pr_debug("Error: mmap() syscall returned with (%s)\n",
|
pr_err("Error: mmap() syscall returned with (%s)\n",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
goto out_close;
|
goto out_close;
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,4 +36,5 @@ extern int cmd_kvm(int argc, const char **argv, const char *prefix);
|
||||||
extern int cmd_test(int argc, const char **argv, const char *prefix);
|
extern int cmd_test(int argc, const char **argv, const char *prefix);
|
||||||
extern int cmd_inject(int argc, const char **argv, const char *prefix);
|
extern int cmd_inject(int argc, const char **argv, const char *prefix);
|
||||||
|
|
||||||
|
extern int find_scripts(char **scripts_array, char **scripts_path_array);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -24,7 +24,7 @@ NOBUILDID=0000000000000000000000000000000000000000
|
||||||
perf buildid-list -i $PERF_DATA --with-hits | grep -v "^$NOBUILDID " > $BUILDIDS
|
perf buildid-list -i $PERF_DATA --with-hits | grep -v "^$NOBUILDID " > $BUILDIDS
|
||||||
if [ ! -s $BUILDIDS ] ; then
|
if [ ! -s $BUILDIDS ] ; then
|
||||||
echo "perf archive: no build-ids found"
|
echo "perf archive: no build-ids found"
|
||||||
rm -f $BUILDIDS
|
rm $BUILDIDS || true
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -39,8 +39,8 @@ while read build_id ; do
|
||||||
echo ${filename#$PERF_BUILDID_LINKDIR} >> $MANIFEST
|
echo ${filename#$PERF_BUILDID_LINKDIR} >> $MANIFEST
|
||||||
done
|
done
|
||||||
|
|
||||||
tar cfj $PERF_DATA.tar.bz2 -C $PERF_BUILDID_DIR -T $MANIFEST
|
tar cjf $PERF_DATA.tar.bz2 -C $PERF_BUILDID_DIR -T $MANIFEST
|
||||||
rm -f $MANIFEST $BUILDIDS
|
rm $MANIFEST $BUILDIDS || true
|
||||||
echo -e "Now please run:\n"
|
echo -e "Now please run:\n"
|
||||||
echo -e "$ tar xvf $PERF_DATA.tar.bz2 -C ~/.debug\n"
|
echo -e "$ tar xvf $PERF_DATA.tar.bz2 -C ~/.debug\n"
|
||||||
echo "wherever you need to run 'perf report' on."
|
echo "wherever you need to run 'perf report' on."
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
#
|
||||||
|
# event_analyzing_sample.py can cover all type of perf samples including
|
||||||
|
# the tracepoints, so no special record requirements, just record what
|
||||||
|
# you want to analyze.
|
||||||
|
#
|
||||||
|
perf record $@
|
|
@ -0,0 +1,3 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# description: analyze all perf samples
|
||||||
|
perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/event_analyzing_sample.py
|
|
@ -571,7 +571,7 @@ static int hist_browser__hpp_color_ ## _name(struct perf_hpp *hpp, \
|
||||||
{ \
|
{ \
|
||||||
double percent = 100.0 * he->_field / hpp->total_period; \
|
double percent = 100.0 * he->_field / hpp->total_period; \
|
||||||
*(double *)hpp->ptr = percent; \
|
*(double *)hpp->ptr = percent; \
|
||||||
return scnprintf(hpp->buf, hpp->size, "%5.2f%%", percent); \
|
return scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent); \
|
||||||
}
|
}
|
||||||
|
|
||||||
HPP__COLOR_FN(overhead, period)
|
HPP__COLOR_FN(overhead, period)
|
||||||
|
@ -605,7 +605,7 @@ static int hist_browser__show_entry(struct hist_browser *browser,
|
||||||
char s[256];
|
char s[256];
|
||||||
double percent;
|
double percent;
|
||||||
int i, printed = 0;
|
int i, printed = 0;
|
||||||
int width = browser->b.width - 1;
|
int width = browser->b.width;
|
||||||
char folded_sign = ' ';
|
char folded_sign = ' ';
|
||||||
bool current_entry = ui_browser__is_current_entry(&browser->b, row);
|
bool current_entry = ui_browser__is_current_entry(&browser->b, row);
|
||||||
off_t row_offset = entry->row_offset;
|
off_t row_offset = entry->row_offset;
|
||||||
|
@ -627,7 +627,7 @@ static int hist_browser__show_entry(struct hist_browser *browser,
|
||||||
.total_period = browser->hists->stats.total_period,
|
.total_period = browser->hists->stats.total_period,
|
||||||
};
|
};
|
||||||
|
|
||||||
ui_browser__gotorc(&browser->b, row, 1);
|
ui_browser__gotorc(&browser->b, row, 0);
|
||||||
|
|
||||||
for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
|
for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
|
||||||
if (!perf_hpp__format[i].cond)
|
if (!perf_hpp__format[i].cond)
|
||||||
|
|
|
@ -56,7 +56,7 @@ static int perf_gtk__hpp_color_ ## _name(struct perf_hpp *hpp, \
|
||||||
markup = perf_gtk__get_percent_color(percent); \
|
markup = perf_gtk__get_percent_color(percent); \
|
||||||
if (markup) \
|
if (markup) \
|
||||||
ret += scnprintf(hpp->buf, hpp->size, "%s", markup); \
|
ret += scnprintf(hpp->buf, hpp->size, "%s", markup); \
|
||||||
ret += scnprintf(hpp->buf + ret, hpp->size - ret, "%5.2f%%", percent); \
|
ret += scnprintf(hpp->buf + ret, hpp->size - ret, "%6.2f%%", percent); \
|
||||||
if (markup) \
|
if (markup) \
|
||||||
ret += scnprintf(hpp->buf + ret, hpp->size - ret, "</span>"); \
|
ret += scnprintf(hpp->buf + ret, hpp->size - ret, "</span>"); \
|
||||||
\
|
\
|
||||||
|
|
|
@ -33,13 +33,13 @@ static int hpp__color_overhead(struct perf_hpp *hpp, struct hist_entry *he)
|
||||||
percent = 0.0;
|
percent = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return percent_color_snprintf(hpp->buf, hpp->size, " %5.2f%%", percent);
|
return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hpp__entry_overhead(struct perf_hpp *hpp, struct hist_entry *he)
|
static int hpp__entry_overhead(struct perf_hpp *hpp, struct hist_entry *he)
|
||||||
{
|
{
|
||||||
double percent = 100.0 * he->period / hpp->total_period;
|
double percent = 100.0 * he->period / hpp->total_period;
|
||||||
const char *fmt = symbol_conf.field_sep ? "%.2f" : " %5.2f%%";
|
const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%";
|
||||||
|
|
||||||
if (hpp->ptr) {
|
if (hpp->ptr) {
|
||||||
struct hists *old_hists = hpp->ptr;
|
struct hists *old_hists = hpp->ptr;
|
||||||
|
@ -57,52 +57,52 @@ static int hpp__entry_overhead(struct perf_hpp *hpp, struct hist_entry *he)
|
||||||
|
|
||||||
static int hpp__header_overhead_sys(struct perf_hpp *hpp)
|
static int hpp__header_overhead_sys(struct perf_hpp *hpp)
|
||||||
{
|
{
|
||||||
const char *fmt = symbol_conf.field_sep ? "%s" : "%6s";
|
const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
|
||||||
|
|
||||||
return scnprintf(hpp->buf, hpp->size, fmt, "sys");
|
return scnprintf(hpp->buf, hpp->size, fmt, "sys");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hpp__width_overhead_sys(struct perf_hpp *hpp __maybe_unused)
|
static int hpp__width_overhead_sys(struct perf_hpp *hpp __maybe_unused)
|
||||||
{
|
{
|
||||||
return 6;
|
return 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hpp__color_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he)
|
static int hpp__color_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he)
|
||||||
{
|
{
|
||||||
double percent = 100.0 * he->period_sys / hpp->total_period;
|
double percent = 100.0 * he->period_sys / hpp->total_period;
|
||||||
return percent_color_snprintf(hpp->buf, hpp->size, "%5.2f%%", percent);
|
return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hpp__entry_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he)
|
static int hpp__entry_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he)
|
||||||
{
|
{
|
||||||
double percent = 100.0 * he->period_sys / hpp->total_period;
|
double percent = 100.0 * he->period_sys / hpp->total_period;
|
||||||
const char *fmt = symbol_conf.field_sep ? "%.2f" : "%5.2f%%";
|
const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
|
||||||
|
|
||||||
return scnprintf(hpp->buf, hpp->size, fmt, percent);
|
return scnprintf(hpp->buf, hpp->size, fmt, percent);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hpp__header_overhead_us(struct perf_hpp *hpp)
|
static int hpp__header_overhead_us(struct perf_hpp *hpp)
|
||||||
{
|
{
|
||||||
const char *fmt = symbol_conf.field_sep ? "%s" : "%6s";
|
const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
|
||||||
|
|
||||||
return scnprintf(hpp->buf, hpp->size, fmt, "user");
|
return scnprintf(hpp->buf, hpp->size, fmt, "user");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hpp__width_overhead_us(struct perf_hpp *hpp __maybe_unused)
|
static int hpp__width_overhead_us(struct perf_hpp *hpp __maybe_unused)
|
||||||
{
|
{
|
||||||
return 6;
|
return 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hpp__color_overhead_us(struct perf_hpp *hpp, struct hist_entry *he)
|
static int hpp__color_overhead_us(struct perf_hpp *hpp, struct hist_entry *he)
|
||||||
{
|
{
|
||||||
double percent = 100.0 * he->period_us / hpp->total_period;
|
double percent = 100.0 * he->period_us / hpp->total_period;
|
||||||
return percent_color_snprintf(hpp->buf, hpp->size, "%5.2f%%", percent);
|
return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hpp__entry_overhead_us(struct perf_hpp *hpp, struct hist_entry *he)
|
static int hpp__entry_overhead_us(struct perf_hpp *hpp, struct hist_entry *he)
|
||||||
{
|
{
|
||||||
double percent = 100.0 * he->period_us / hpp->total_period;
|
double percent = 100.0 * he->period_us / hpp->total_period;
|
||||||
const char *fmt = symbol_conf.field_sep ? "%.2f" : "%5.2f%%";
|
const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
|
||||||
|
|
||||||
return scnprintf(hpp->buf, hpp->size, fmt, percent);
|
return scnprintf(hpp->buf, hpp->size, fmt, percent);
|
||||||
}
|
}
|
||||||
|
@ -121,14 +121,14 @@ static int hpp__color_overhead_guest_sys(struct perf_hpp *hpp,
|
||||||
struct hist_entry *he)
|
struct hist_entry *he)
|
||||||
{
|
{
|
||||||
double percent = 100.0 * he->period_guest_sys / hpp->total_period;
|
double percent = 100.0 * he->period_guest_sys / hpp->total_period;
|
||||||
return percent_color_snprintf(hpp->buf, hpp->size, " %5.2f%% ", percent);
|
return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hpp__entry_overhead_guest_sys(struct perf_hpp *hpp,
|
static int hpp__entry_overhead_guest_sys(struct perf_hpp *hpp,
|
||||||
struct hist_entry *he)
|
struct hist_entry *he)
|
||||||
{
|
{
|
||||||
double percent = 100.0 * he->period_guest_sys / hpp->total_period;
|
double percent = 100.0 * he->period_guest_sys / hpp->total_period;
|
||||||
const char *fmt = symbol_conf.field_sep ? "%.2f" : " %5.2f%% ";
|
const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% ";
|
||||||
|
|
||||||
return scnprintf(hpp->buf, hpp->size, fmt, percent);
|
return scnprintf(hpp->buf, hpp->size, fmt, percent);
|
||||||
}
|
}
|
||||||
|
@ -147,14 +147,14 @@ static int hpp__color_overhead_guest_us(struct perf_hpp *hpp,
|
||||||
struct hist_entry *he)
|
struct hist_entry *he)
|
||||||
{
|
{
|
||||||
double percent = 100.0 * he->period_guest_us / hpp->total_period;
|
double percent = 100.0 * he->period_guest_us / hpp->total_period;
|
||||||
return percent_color_snprintf(hpp->buf, hpp->size, " %5.2f%% ", percent);
|
return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hpp__entry_overhead_guest_us(struct perf_hpp *hpp,
|
static int hpp__entry_overhead_guest_us(struct perf_hpp *hpp,
|
||||||
struct hist_entry *he)
|
struct hist_entry *he)
|
||||||
{
|
{
|
||||||
double percent = 100.0 * he->period_guest_us / hpp->total_period;
|
double percent = 100.0 * he->period_guest_us / hpp->total_period;
|
||||||
const char *fmt = symbol_conf.field_sep ? "%.2f" : " %5.2f%% ";
|
const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% ";
|
||||||
|
|
||||||
return scnprintf(hpp->buf, hpp->size, fmt, percent);
|
return scnprintf(hpp->buf, hpp->size, fmt, percent);
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,24 +38,19 @@ static struct cpu_map *cpu_map__trim_new(int nr_cpus, int *tmp_cpus)
|
||||||
return cpus;
|
return cpus;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct cpu_map *cpu_map__read_all_cpu_map(void)
|
struct cpu_map *cpu_map__read(FILE *file)
|
||||||
{
|
{
|
||||||
struct cpu_map *cpus = NULL;
|
struct cpu_map *cpus = NULL;
|
||||||
FILE *onlnf;
|
|
||||||
int nr_cpus = 0;
|
int nr_cpus = 0;
|
||||||
int *tmp_cpus = NULL, *tmp;
|
int *tmp_cpus = NULL, *tmp;
|
||||||
int max_entries = 0;
|
int max_entries = 0;
|
||||||
int n, cpu, prev;
|
int n, cpu, prev;
|
||||||
char sep;
|
char sep;
|
||||||
|
|
||||||
onlnf = fopen("/sys/devices/system/cpu/online", "r");
|
|
||||||
if (!onlnf)
|
|
||||||
return cpu_map__default_new();
|
|
||||||
|
|
||||||
sep = 0;
|
sep = 0;
|
||||||
prev = -1;
|
prev = -1;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
n = fscanf(onlnf, "%u%c", &cpu, &sep);
|
n = fscanf(file, "%u%c", &cpu, &sep);
|
||||||
if (n <= 0)
|
if (n <= 0)
|
||||||
break;
|
break;
|
||||||
if (prev >= 0) {
|
if (prev >= 0) {
|
||||||
|
@ -95,6 +90,19 @@ static struct cpu_map *cpu_map__read_all_cpu_map(void)
|
||||||
cpus = cpu_map__default_new();
|
cpus = cpu_map__default_new();
|
||||||
out_free_tmp:
|
out_free_tmp:
|
||||||
free(tmp_cpus);
|
free(tmp_cpus);
|
||||||
|
return cpus;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct cpu_map *cpu_map__read_all_cpu_map(void)
|
||||||
|
{
|
||||||
|
struct cpu_map *cpus = NULL;
|
||||||
|
FILE *onlnf;
|
||||||
|
|
||||||
|
onlnf = fopen("/sys/devices/system/cpu/online", "r");
|
||||||
|
if (!onlnf)
|
||||||
|
return cpu_map__default_new();
|
||||||
|
|
||||||
|
cpus = cpu_map__read(onlnf);
|
||||||
fclose(onlnf);
|
fclose(onlnf);
|
||||||
return cpus;
|
return cpus;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ struct cpu_map {
|
||||||
struct cpu_map *cpu_map__new(const char *cpu_list);
|
struct cpu_map *cpu_map__new(const char *cpu_list);
|
||||||
struct cpu_map *cpu_map__dummy_new(void);
|
struct cpu_map *cpu_map__dummy_new(void);
|
||||||
void cpu_map__delete(struct cpu_map *map);
|
void cpu_map__delete(struct cpu_map *map);
|
||||||
|
struct cpu_map *cpu_map__read(FILE *file);
|
||||||
size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
|
size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
|
||||||
|
|
||||||
#endif /* __PERF_CPUMAP_H */
|
#endif /* __PERF_CPUMAP_H */
|
||||||
|
|
|
@ -904,8 +904,9 @@ int perf_event__preprocess_sample(const union perf_event *event,
|
||||||
al->sym = map__find_symbol(al->map, al->addr, filter);
|
al->sym = map__find_symbol(al->map, al->addr, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (symbol_conf.sym_list && al->sym &&
|
if (symbol_conf.sym_list &&
|
||||||
!strlist__has_entry(symbol_conf.sym_list, al->sym->name))
|
(!al->sym || !strlist__has_entry(symbol_conf.sym_list,
|
||||||
|
al->sym->name)))
|
||||||
goto out_filtered;
|
goto out_filtered;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -66,6 +66,7 @@ struct perf_evsel {
|
||||||
void *func;
|
void *func;
|
||||||
void *data;
|
void *data;
|
||||||
} handler;
|
} handler;
|
||||||
|
struct cpu_map *cpus;
|
||||||
unsigned int sample_size;
|
unsigned int sample_size;
|
||||||
bool supported;
|
bool supported;
|
||||||
/* parse modifier helper */
|
/* parse modifier helper */
|
||||||
|
|
|
@ -239,8 +239,11 @@ const char *event_type(int type)
|
||||||
return "unknown";
|
return "unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
static int add_event(struct list_head **_list, int *idx,
|
|
||||||
struct perf_event_attr *attr, char *name)
|
|
||||||
|
static int __add_event(struct list_head **_list, int *idx,
|
||||||
|
struct perf_event_attr *attr,
|
||||||
|
char *name, struct cpu_map *cpus)
|
||||||
{
|
{
|
||||||
struct perf_evsel *evsel;
|
struct perf_evsel *evsel;
|
||||||
struct list_head *list = *_list;
|
struct list_head *list = *_list;
|
||||||
|
@ -260,6 +263,7 @@ static int add_event(struct list_head **_list, int *idx,
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
evsel->cpus = cpus;
|
||||||
if (name)
|
if (name)
|
||||||
evsel->name = strdup(name);
|
evsel->name = strdup(name);
|
||||||
list_add_tail(&evsel->node, list);
|
list_add_tail(&evsel->node, list);
|
||||||
|
@ -267,6 +271,12 @@ static int add_event(struct list_head **_list, int *idx,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int add_event(struct list_head **_list, int *idx,
|
||||||
|
struct perf_event_attr *attr, char *name)
|
||||||
|
{
|
||||||
|
return __add_event(_list, idx, attr, name, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size)
|
static int parse_aliases(char *str, const char *names[][PERF_EVSEL__MAX_ALIASES], int size)
|
||||||
{
|
{
|
||||||
int i, j;
|
int i, j;
|
||||||
|
@ -607,8 +617,8 @@ int parse_events_add_pmu(struct list_head **list, int *idx,
|
||||||
if (perf_pmu__config(pmu, &attr, head_config))
|
if (perf_pmu__config(pmu, &attr, head_config))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
return add_event(list, idx, &attr,
|
return __add_event(list, idx, &attr, pmu_event_name(head_config),
|
||||||
pmu_event_name(head_config));
|
pmu->cpus);
|
||||||
}
|
}
|
||||||
|
|
||||||
int parse_events__modifier_group(struct list_head *list,
|
int parse_events__modifier_group(struct list_head *list,
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "pmu.h"
|
#include "pmu.h"
|
||||||
#include "parse-events.h"
|
#include "parse-events.h"
|
||||||
|
#include "cpumap.h"
|
||||||
|
|
||||||
#define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/"
|
#define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/"
|
||||||
|
|
||||||
|
@ -253,6 +254,33 @@ static void pmu_read_sysfs(void)
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct cpu_map *pmu_cpumask(char *name)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
char path[PATH_MAX];
|
||||||
|
const char *sysfs;
|
||||||
|
FILE *file;
|
||||||
|
struct cpu_map *cpus;
|
||||||
|
|
||||||
|
sysfs = sysfs_find_mountpoint();
|
||||||
|
if (!sysfs)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
snprintf(path, PATH_MAX,
|
||||||
|
"%s/bus/event_source/devices/%s/cpumask", sysfs, name);
|
||||||
|
|
||||||
|
if (stat(path, &st) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
file = fopen(path, "r");
|
||||||
|
if (!file)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
cpus = cpu_map__read(file);
|
||||||
|
fclose(file);
|
||||||
|
return cpus;
|
||||||
|
}
|
||||||
|
|
||||||
static struct perf_pmu *pmu_lookup(char *name)
|
static struct perf_pmu *pmu_lookup(char *name)
|
||||||
{
|
{
|
||||||
struct perf_pmu *pmu;
|
struct perf_pmu *pmu;
|
||||||
|
@ -275,6 +303,8 @@ static struct perf_pmu *pmu_lookup(char *name)
|
||||||
if (!pmu)
|
if (!pmu)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
pmu->cpus = pmu_cpumask(name);
|
||||||
|
|
||||||
pmu_aliases(name, &aliases);
|
pmu_aliases(name, &aliases);
|
||||||
|
|
||||||
INIT_LIST_HEAD(&pmu->format);
|
INIT_LIST_HEAD(&pmu->format);
|
||||||
|
|
|
@ -28,6 +28,7 @@ struct perf_pmu__alias {
|
||||||
struct perf_pmu {
|
struct perf_pmu {
|
||||||
char *name;
|
char *name;
|
||||||
__u32 type;
|
__u32 type;
|
||||||
|
struct cpu_map *cpus;
|
||||||
struct list_head format;
|
struct list_head format;
|
||||||
struct list_head aliases;
|
struct list_head aliases;
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
|
|
|
@ -525,8 +525,10 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
/* Verify it is a data structure */
|
/* Verify it is a data structure */
|
||||||
if (dwarf_tag(&type) != DW_TAG_structure_type) {
|
tag = dwarf_tag(&type);
|
||||||
pr_warning("%s is not a data structure.\n", varname);
|
if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) {
|
||||||
|
pr_warning("%s is not a data structure nor an union.\n",
|
||||||
|
varname);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -539,8 +541,9 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
|
||||||
*ref_ptr = ref;
|
*ref_ptr = ref;
|
||||||
} else {
|
} else {
|
||||||
/* Verify it is a data structure */
|
/* Verify it is a data structure */
|
||||||
if (tag != DW_TAG_structure_type) {
|
if (tag != DW_TAG_structure_type && tag != DW_TAG_union_type) {
|
||||||
pr_warning("%s is not a data structure.\n", varname);
|
pr_warning("%s is not a data structure nor an union.\n",
|
||||||
|
varname);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
if (field->name[0] == '[') {
|
if (field->name[0] == '[') {
|
||||||
|
@ -567,11 +570,16 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the offset of the field */
|
/* Get the offset of the field */
|
||||||
|
if (tag == DW_TAG_union_type) {
|
||||||
|
offs = 0;
|
||||||
|
} else {
|
||||||
ret = die_get_data_member_location(die_mem, &offs);
|
ret = die_get_data_member_location(die_mem, &offs);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
pr_warning("Failed to get the offset of %s.\n", field->name);
|
pr_warning("Failed to get the offset of %s.\n",
|
||||||
|
field->name);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
ref->offset += (long)offs;
|
ref->offset += (long)offs;
|
||||||
|
|
||||||
next:
|
next:
|
||||||
|
|
|
@ -8,6 +8,7 @@ const char default_sort_order[] = "comm,dso,symbol";
|
||||||
const char *sort_order = default_sort_order;
|
const char *sort_order = default_sort_order;
|
||||||
int sort__need_collapse = 0;
|
int sort__need_collapse = 0;
|
||||||
int sort__has_parent = 0;
|
int sort__has_parent = 0;
|
||||||
|
int sort__has_sym = 0;
|
||||||
int sort__branch_mode = -1; /* -1 = means not set */
|
int sort__branch_mode = -1; /* -1 = means not set */
|
||||||
|
|
||||||
enum sort_type sort__first_dimension;
|
enum sort_type sort__first_dimension;
|
||||||
|
@ -511,6 +512,10 @@ int sort_dimension__add(const char *tok)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
sort__has_parent = 1;
|
sort__has_parent = 1;
|
||||||
|
} else if (sd->entry == &sort_sym ||
|
||||||
|
sd->entry == &sort_sym_from ||
|
||||||
|
sd->entry == &sort_sym_to) {
|
||||||
|
sort__has_sym = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sd->taken)
|
if (sd->taken)
|
||||||
|
|
|
@ -31,6 +31,7 @@ extern const char *parent_pattern;
|
||||||
extern const char default_sort_order[];
|
extern const char default_sort_order[];
|
||||||
extern int sort__need_collapse;
|
extern int sort__need_collapse;
|
||||||
extern int sort__has_parent;
|
extern int sort__has_parent;
|
||||||
|
extern int sort__has_sym;
|
||||||
extern int sort__branch_mode;
|
extern int sort__branch_mode;
|
||||||
extern struct sort_entry sort_comm;
|
extern struct sort_entry sort_comm;
|
||||||
extern struct sort_entry sort_dso;
|
extern struct sort_entry sort_dso;
|
||||||
|
|
57
tools/perf/util/stat.c
Normal file
57
tools/perf/util/stat.c
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "stat.h"
|
||||||
|
|
||||||
|
void update_stats(struct stats *stats, u64 val)
|
||||||
|
{
|
||||||
|
double delta;
|
||||||
|
|
||||||
|
stats->n++;
|
||||||
|
delta = val - stats->mean;
|
||||||
|
stats->mean += delta / stats->n;
|
||||||
|
stats->M2 += delta*(val - stats->mean);
|
||||||
|
}
|
||||||
|
|
||||||
|
double avg_stats(struct stats *stats)
|
||||||
|
{
|
||||||
|
return stats->mean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
|
||||||
|
*
|
||||||
|
* (\Sum n_i^2) - ((\Sum n_i)^2)/n
|
||||||
|
* s^2 = -------------------------------
|
||||||
|
* n - 1
|
||||||
|
*
|
||||||
|
* http://en.wikipedia.org/wiki/Stddev
|
||||||
|
*
|
||||||
|
* The std dev of the mean is related to the std dev by:
|
||||||
|
*
|
||||||
|
* s
|
||||||
|
* s_mean = -------
|
||||||
|
* sqrt(n)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
double stddev_stats(struct stats *stats)
|
||||||
|
{
|
||||||
|
double variance, variance_mean;
|
||||||
|
|
||||||
|
if (!stats->n)
|
||||||
|
return 0.0;
|
||||||
|
|
||||||
|
variance = stats->M2 / (stats->n - 1);
|
||||||
|
variance_mean = variance / stats->n;
|
||||||
|
|
||||||
|
return sqrt(variance_mean);
|
||||||
|
}
|
||||||
|
|
||||||
|
double rel_stddev_stats(double stddev, double avg)
|
||||||
|
{
|
||||||
|
double pct = 0.0;
|
||||||
|
|
||||||
|
if (avg)
|
||||||
|
pct = 100.0 * stddev/avg;
|
||||||
|
|
||||||
|
return pct;
|
||||||
|
}
|
16
tools/perf/util/stat.h
Normal file
16
tools/perf/util/stat.h
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#ifndef __PERF_STATS_H
|
||||||
|
#define __PERF_STATS_H
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
struct stats
|
||||||
|
{
|
||||||
|
double n, mean, M2;
|
||||||
|
};
|
||||||
|
|
||||||
|
void update_stats(struct stats *stats, u64 val);
|
||||||
|
double avg_stats(struct stats *stats);
|
||||||
|
double stddev_stats(struct stats *stats);
|
||||||
|
double rel_stddev_stats(double stddev, double avg);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Add table
Add a link
Reference in a new issue