Commit 2f5e9880 authored by Ingo Molnar's avatar Ingo Molnar

Merge tag 'perf-core-for-mingo' of...

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:

  * Show progress on histogram collapsing, that can take a long time, from
    Namhyung Kim.

  * Support "$vars" meta argument syntax for local variables, allowing
    asking for all possible variables at a given probe point to be
    collected when it hits, from Masami Hiramatsu.

  * Address the root cause of that 'perf sched' stack initialization build
    slowdown, by programmatically setting a big array after moving the
    global variable back to the stack. Fix from Adrian Hunter.

  * Do not repipe attributes to a perf.data file in 'perf inject',
    fix from Adrian Hunter

  * Change the procps visible command-name of invididual benchmark tests
    plus cleanups, from Ingo Molnar.

  * Do not accept parse_tag_value() overflow, fix from Adrian Hunter.

  * Validate that mmap_pages is not too big. From Adrian Hunter.

  * Fix non-debug build, from Adrian Hunter.

  * Clarify the "sample parsing" test entry, from Arnaldo Carvalho de Melo.

  * Consider PERF_SAMPLE_TRANSACTION in the "sample parsing" test,
    from Arnaldo Carvalho de Melo.
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents aa30a2e0 c1fb5651
...@@ -487,6 +487,7 @@ ifndef NO_SLANG ...@@ -487,6 +487,7 @@ ifndef NO_SLANG
LIB_OBJS += $(OUTPUT)ui/tui/util.o LIB_OBJS += $(OUTPUT)ui/tui/util.o
LIB_OBJS += $(OUTPUT)ui/tui/helpline.o LIB_OBJS += $(OUTPUT)ui/tui/helpline.o
LIB_OBJS += $(OUTPUT)ui/tui/progress.o LIB_OBJS += $(OUTPUT)ui/tui/progress.o
LIB_H += ui/tui/tui.h
LIB_H += ui/browser.h LIB_H += ui/browser.h
LIB_H += ui/browsers/map.h LIB_H += ui/browsers/map.h
LIB_H += ui/keysyms.h LIB_H += ui/keysyms.h
......
...@@ -118,11 +118,11 @@ static int hist_entry__tty_annotate(struct hist_entry *he, ...@@ -118,11 +118,11 @@ static int hist_entry__tty_annotate(struct hist_entry *he,
ann->print_line, ann->full_paths, 0, 0); ann->print_line, ann->full_paths, 0, 0);
} }
static void hists__find_annotations(struct hists *self, static void hists__find_annotations(struct hists *hists,
struct perf_evsel *evsel, struct perf_evsel *evsel,
struct perf_annotate *ann) struct perf_annotate *ann)
{ {
struct rb_node *nd = rb_first(&self->entries), *next; struct rb_node *nd = rb_first(&hists->entries), *next;
int key = K_RIGHT; int key = K_RIGHT;
while (nd) { while (nd) {
...@@ -247,7 +247,7 @@ static int __cmd_annotate(struct perf_annotate *ann) ...@@ -247,7 +247,7 @@ static int __cmd_annotate(struct perf_annotate *ann)
if (nr_samples > 0) { if (nr_samples > 0) {
total_nr_samples += nr_samples; total_nr_samples += nr_samples;
hists__collapse_resort(hists); hists__collapse_resort(hists, NULL);
hists__output_resort(hists); hists__output_resort(hists);
if (symbol_conf.event_group && if (symbol_conf.event_group &&
......
/* /*
*
* builtin-bench.c * builtin-bench.c
* *
* General benchmarking subsystem provided by perf * General benchmarking collections provided by perf
* *
* Copyright (C) 2009, Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp> * Copyright (C) 2009, Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp>
*
*/ */
/* /*
* Available benchmark collection list:
* *
* Available subsystem list: * sched ... scheduler and IPC performance
* sched ... scheduler and IPC mechanism
* mem ... memory access performance * mem ... memory access performance
* * numa ... NUMA scheduling and MM performance
*/ */
#include "perf.h" #include "perf.h"
#include "util/util.h" #include "util/util.h"
#include "util/parse-options.h" #include "util/parse-options.h"
...@@ -25,112 +22,92 @@ ...@@ -25,112 +22,92 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/prctl.h>
struct bench_suite { typedef int (*bench_fn_t)(int argc, const char **argv, const char *prefix);
const char *name;
const char *summary; struct bench {
int (*fn)(int, const char **, const char *); const char *name;
const char *summary;
bench_fn_t fn;
}; };
\
/* sentinel: easy for help */
#define suite_all { "all", "Test all benchmark suites", NULL }
#ifdef HAVE_LIBNUMA_SUPPORT #ifdef HAVE_LIBNUMA_SUPPORT
static struct bench_suite numa_suites[] = { static struct bench numa_benchmarks[] = {
{ "mem", { "mem", "Benchmark for NUMA workloads", bench_numa },
"Benchmark for NUMA workloads", { "all", "Test all NUMA benchmarks", NULL },
bench_numa }, { NULL, NULL, NULL }
suite_all,
{ NULL,
NULL,
NULL }
}; };
#endif #endif
static struct bench_suite sched_suites[] = { static struct bench sched_benchmarks[] = {
{ "messaging", { "messaging", "Benchmark for scheduling and IPC", bench_sched_messaging },
"Benchmark for scheduler and IPC mechanisms", { "pipe", "Benchmark for pipe() between two processes", bench_sched_pipe },
bench_sched_messaging }, { "all", "Test all scheduler benchmarks", NULL },
{ "pipe", { NULL, NULL, NULL }
"Flood of communication over pipe() between two processes",
bench_sched_pipe },
suite_all,
{ NULL,
NULL,
NULL }
}; };
static struct bench_suite mem_suites[] = { static struct bench mem_benchmarks[] = {
{ "memcpy", { "memcpy", "Benchmark for memcpy()", bench_mem_memcpy },
"Simple memory copy in various ways", { "memset", "Benchmark for memset() tests", bench_mem_memset },
bench_mem_memcpy }, { "all", "Test all memory benchmarks", NULL },
{ "memset", { NULL, NULL, NULL }
"Simple memory set in various ways",
bench_mem_memset },
suite_all,
{ NULL,
NULL,
NULL }
}; };
struct bench_subsys { struct collection {
const char *name; const char *name;
const char *summary; const char *summary;
struct bench_suite *suites; struct bench *benchmarks;
}; };
static struct bench_subsys subsystems[] = { static struct collection collections[] = {
{ "sched", "Scheduler and IPC benchmarks", sched_benchmarks },
{ "mem", "Memory access benchmarks", mem_benchmarks },
#ifdef HAVE_LIBNUMA_SUPPORT #ifdef HAVE_LIBNUMA_SUPPORT
{ "numa", { "numa", "NUMA scheduling and MM benchmarks", numa_benchmarks },
"NUMA scheduling and MM behavior",
numa_suites },
#endif #endif
{ "sched", { "all", "All benchmarks", NULL },
"scheduler and IPC mechanism", { NULL, NULL, NULL }
sched_suites },
{ "mem",
"memory access performance",
mem_suites },
{ "all", /* sentinel: easy for help */
"all benchmark subsystem",
NULL },
{ NULL,
NULL,
NULL }
}; };
static void dump_suites(int subsys_index) /* Iterate over all benchmark collections: */
#define for_each_collection(coll) \
for (coll = collections; coll->name; coll++)
/* Iterate over all benchmarks within a collection: */
#define for_each_bench(coll, bench) \
for (bench = coll->benchmarks; bench->name; bench++)
static void dump_benchmarks(struct collection *coll)
{ {
int i; struct bench *bench;
printf("# List of available suites for %s...\n\n", printf("\n # List of available benchmarks for collection '%s':\n\n", coll->name);
subsystems[subsys_index].name);
for (i = 0; subsystems[subsys_index].suites[i].name; i++) for_each_bench(coll, bench)
printf("%14s: %s\n", printf("%14s: %s\n", bench->name, bench->summary);
subsystems[subsys_index].suites[i].name,
subsystems[subsys_index].suites[i].summary);
printf("\n"); printf("\n");
return;
} }
static const char *bench_format_str; static const char *bench_format_str;
/* Output/formatting style, exported to benchmark modules: */
int bench_format = BENCH_FORMAT_DEFAULT; int bench_format = BENCH_FORMAT_DEFAULT;
static const struct option bench_options[] = { static const struct option bench_options[] = {
OPT_STRING('f', "format", &bench_format_str, "default", OPT_STRING('f', "format", &bench_format_str, "default", "Specify format style"),
"Specify format style"),
OPT_END() OPT_END()
}; };
static const char * const bench_usage[] = { static const char * const bench_usage[] = {
"perf bench [<common options>] <subsystem> <suite> [<options>]", "perf bench [<common options>] <collection> <benchmark> [<options>]",
NULL NULL
}; };
static void print_usage(void) static void print_usage(void)
{ {
struct collection *coll;
int i; int i;
printf("Usage: \n"); printf("Usage: \n");
...@@ -138,11 +115,10 @@ static void print_usage(void) ...@@ -138,11 +115,10 @@ static void print_usage(void)
printf("\t%s\n", bench_usage[i]); printf("\t%s\n", bench_usage[i]);
printf("\n"); printf("\n");
printf("# List of available subsystems...\n\n"); printf(" # List of all available benchmark collections:\n\n");
for (i = 0; subsystems[i].name; i++) for_each_collection(coll)
printf("%14s: %s\n", printf("%14s: %s\n", coll->name, coll->summary);
subsystems[i].name, subsystems[i].summary);
printf("\n"); printf("\n");
} }
...@@ -159,44 +135,74 @@ static int bench_str2int(const char *str) ...@@ -159,44 +135,74 @@ static int bench_str2int(const char *str)
return BENCH_FORMAT_UNKNOWN; return BENCH_FORMAT_UNKNOWN;
} }
static void all_suite(struct bench_subsys *subsys) /* FROM HERE */ /*
* Run a specific benchmark but first rename the running task's ->comm[]
* to something meaningful:
*/
static int run_bench(const char *coll_name, const char *bench_name, bench_fn_t fn,
int argc, const char **argv, const char *prefix)
{ {
int i; int size;
char *name;
int ret;
size = strlen(coll_name) + 1 + strlen(bench_name) + 1;
name = zalloc(size);
BUG_ON(!name);
scnprintf(name, size, "%s-%s", coll_name, bench_name);
prctl(PR_SET_NAME, name);
argv[0] = name;
ret = fn(argc, argv, prefix);
free(name);
return ret;
}
static void run_collection(struct collection *coll)
{
struct bench *bench;
const char *argv[2]; const char *argv[2];
struct bench_suite *suites = subsys->suites;
argv[1] = NULL; argv[1] = NULL;
/* /*
* TODO: * TODO:
* preparing preset parameters for *
* Preparing preset parameters for
* embedded, ordinary PC, HPC, etc... * embedded, ordinary PC, HPC, etc...
* will be helpful * would be helpful.
*/ */
for (i = 0; suites[i].fn; i++) { for_each_bench(coll, bench) {
printf("# Running %s/%s benchmark...\n", if (!bench->fn)
subsys->name, break;
suites[i].name); printf("# Running %s/%s benchmark...\n", coll->name, bench->name);
fflush(stdout); fflush(stdout);
argv[1] = suites[i].name; argv[1] = bench->name;
suites[i].fn(1, argv, NULL); run_bench(coll->name, bench->name, bench->fn, 1, argv, NULL);
printf("\n"); printf("\n");
} }
} }
static void all_subsystem(void) static void run_all_collections(void)
{ {
int i; struct collection *coll;
for (i = 0; subsystems[i].suites; i++)
all_suite(&subsystems[i]); for_each_collection(coll)
run_collection(coll);
} }
int cmd_bench(int argc, const char **argv, const char *prefix __maybe_unused) int cmd_bench(int argc, const char **argv, const char *prefix __maybe_unused)
{ {
int i, j, status = 0; struct collection *coll;
int ret = 0;
if (argc < 2) { if (argc < 2) {
/* No subsystem specified. */ /* No collection specified. */
print_usage(); print_usage();
goto end; goto end;
} }
...@@ -206,7 +212,7 @@ int cmd_bench(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -206,7 +212,7 @@ int cmd_bench(int argc, const char **argv, const char *prefix __maybe_unused)
bench_format = bench_str2int(bench_format_str); bench_format = bench_str2int(bench_format_str);
if (bench_format == BENCH_FORMAT_UNKNOWN) { if (bench_format == BENCH_FORMAT_UNKNOWN) {
printf("Unknown format descriptor:%s\n", bench_format_str); printf("Unknown format descriptor: '%s'\n", bench_format_str);
goto end; goto end;
} }
...@@ -216,52 +222,51 @@ int cmd_bench(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -216,52 +222,51 @@ int cmd_bench(int argc, const char **argv, const char *prefix __maybe_unused)
} }
if (!strcmp(argv[0], "all")) { if (!strcmp(argv[0], "all")) {
all_subsystem(); run_all_collections();
goto end; goto end;
} }
for (i = 0; subsystems[i].name; i++) { for_each_collection(coll) {
if (strcmp(subsystems[i].name, argv[0])) struct bench *bench;
if (strcmp(coll->name, argv[0]))
continue; continue;
if (argc < 2) { if (argc < 2) {
/* No suite specified. */ /* No bench specified. */
dump_suites(i); dump_benchmarks(coll);
goto end; goto end;
} }
if (!strcmp(argv[1], "all")) { if (!strcmp(argv[1], "all")) {
all_suite(&subsystems[i]); run_collection(coll);
goto end; goto end;
} }
for (j = 0; subsystems[i].suites[j].name; j++) { for_each_bench(coll, bench) {
if (strcmp(subsystems[i].suites[j].name, argv[1])) if (strcmp(bench->name, argv[1]))
continue; continue;
if (bench_format == BENCH_FORMAT_DEFAULT) if (bench_format == BENCH_FORMAT_DEFAULT)
printf("# Running %s/%s benchmark...\n", printf("# Running '%s/%s' benchmark:\n", coll->name, bench->name);
subsystems[i].name,
subsystems[i].suites[j].name);
fflush(stdout); fflush(stdout);
status = subsystems[i].suites[j].fn(argc - 1, ret = run_bench(coll->name, bench->name, bench->fn, argc-1, argv+1, prefix);
argv + 1, prefix);
goto end; goto end;
} }
if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
dump_suites(i); dump_benchmarks(coll);
goto end; goto end;
} }
printf("Unknown suite:%s for %s\n", argv[1], argv[0]); printf("Unknown benchmark: '%s' for collection '%s'\n", argv[1], argv[0]);
status = 1; ret = 1;
goto end; goto end;
} }
printf("Unknown subsystem:%s\n", argv[0]); printf("Unknown collection: '%s'\n", argv[0]);
status = 1; ret = 1;
end: end:
return status; return ret;
} }
...@@ -303,12 +303,11 @@ static int formula_fprintf(struct hist_entry *he, struct hist_entry *pair, ...@@ -303,12 +303,11 @@ static int formula_fprintf(struct hist_entry *he, struct hist_entry *pair,
return -1; return -1;
} }
static int hists__add_entry(struct hists *self, static int hists__add_entry(struct hists *hists,
struct addr_location *al, u64 period, struct addr_location *al, u64 period,
u64 weight, u64 transaction) u64 weight, u64 transaction)
{ {
if (__hists__add_entry(self, al, NULL, period, weight, transaction) if (__hists__add_entry(hists, al, NULL, period, weight, transaction) != NULL)
!= NULL)
return 0; return 0;
return -ENOMEM; return -ENOMEM;
} }
...@@ -370,7 +369,7 @@ static void perf_evlist__collapse_resort(struct perf_evlist *evlist) ...@@ -370,7 +369,7 @@ static void perf_evlist__collapse_resort(struct perf_evlist *evlist)
list_for_each_entry(evsel, &evlist->entries, node) { list_for_each_entry(evsel, &evlist->entries, node) {
struct hists *hists = &evsel->hists; struct hists *hists = &evsel->hists;
hists__collapse_resort(hists); hists__collapse_resort(hists, NULL);
} }
} }
......
...@@ -72,12 +72,17 @@ static int perf_event__repipe_attr(struct perf_tool *tool, ...@@ -72,12 +72,17 @@ static int perf_event__repipe_attr(struct perf_tool *tool,
union perf_event *event, union perf_event *event,
struct perf_evlist **pevlist) struct perf_evlist **pevlist)
{ {
struct perf_inject *inject = container_of(tool, struct perf_inject,
tool);
int ret; int ret;
ret = perf_event__process_attr(tool, event, pevlist); ret = perf_event__process_attr(tool, event, pevlist);
if (ret) if (ret)
return ret; return ret;
if (!inject->pipe_output)
return 0;
return perf_event__repipe_synth(tool, event); return perf_event__repipe_synth(tool, event);
} }
...@@ -162,38 +167,38 @@ static int perf_event__repipe_tracing_data(struct perf_tool *tool, ...@@ -162,38 +167,38 @@ static int perf_event__repipe_tracing_data(struct perf_tool *tool,
return err; return err;
} }
static int dso__read_build_id(struct dso *self) static int dso__read_build_id(struct dso *dso)
{ {
if (self->has_build_id) if (dso->has_build_id)
return 0; return 0;
if (filename__read_build_id(self->long_name, self->build_id, if (filename__read_build_id(dso->long_name, dso->build_id,
sizeof(self->build_id)) > 0) { sizeof(dso->build_id)) > 0) {
self->has_build_id = true; dso->has_build_id = true;
return 0; return 0;
} }
return -1; return -1;
} }
static int dso__inject_build_id(struct dso *self, struct perf_tool *tool, static int dso__inject_build_id(struct dso *dso, struct perf_tool *tool,
struct machine *machine) struct machine *machine)
{ {
u16 misc = PERF_RECORD_MISC_USER; u16 misc = PERF_RECORD_MISC_USER;
int err; int err;
if (dso__read_build_id(self) < 0) { if (dso__read_build_id(dso) < 0) {
pr_debug("no build_id found for %s\n", self->long_name); pr_debug("no build_id found for %s\n", dso->long_name);
return -1; return -1;
} }
if (self->kernel) if (dso->kernel)
misc = PERF_RECORD_MISC_KERNEL; misc = PERF_RECORD_MISC_KERNEL;
err = perf_event__synthesize_build_id(tool, self, misc, perf_event__repipe, err = perf_event__synthesize_build_id(tool, dso, misc, perf_event__repipe,
machine); machine);
if (err) { if (err) {
pr_err("Can't synthesize build_id event for %s\n", self->long_name); pr_err("Can't synthesize build_id event for %s\n", dso->long_name);
return -1; return -1;
} }
......
...@@ -373,9 +373,9 @@ static int process_read_event(struct perf_tool *tool, ...@@ -373,9 +373,9 @@ static int process_read_event(struct perf_tool *tool,
/* For pipe mode, sample_type is not currently set */ /* For pipe mode, sample_type is not currently set */
static int perf_report__setup_sample_type(struct perf_report *rep) static int perf_report__setup_sample_type(struct perf_report *rep)
{ {
struct perf_session *self = rep->session; struct perf_session *session = rep->session;
u64 sample_type = perf_evlist__combined_sample_type(self->evlist); u64 sample_type = perf_evlist__combined_sample_type(session->evlist);
bool is_pipe = perf_data_file__is_pipe(self->file); bool is_pipe = perf_data_file__is_pipe(session->file);
if (!is_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) { if (!is_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) {
if (sort__has_parent) { if (sort__has_parent) {
...@@ -417,14 +417,14 @@ static void sig_handler(int sig __maybe_unused) ...@@ -417,14 +417,14 @@ static void sig_handler(int sig __maybe_unused)
} }
static size_t hists__fprintf_nr_sample_events(struct perf_report *rep, static size_t hists__fprintf_nr_sample_events(struct perf_report *rep,
struct hists *self, struct hists *hists,
const char *evname, FILE *fp) const char *evname, FILE *fp)
{ {
size_t ret; size_t ret;
char unit; char unit;
unsigned long nr_samples = self->stats.nr_events[PERF_RECORD_SAMPLE]; unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
u64 nr_events = self->stats.total_period; u64 nr_events = hists->stats.total_period;
struct perf_evsel *evsel = hists_to_evsel(self); struct perf_evsel *evsel = hists_to_evsel(hists);
char buf[512]; char buf[512];
size_t size = sizeof(buf); size_t size = sizeof(buf);
...@@ -496,6 +496,7 @@ static int __cmd_report(struct perf_report *rep) ...@@ -496,6 +496,7 @@ static int __cmd_report(struct perf_report *rep)
struct map *kernel_map; struct map *kernel_map;
struct kmap *kernel_kmap; struct kmap *kernel_kmap;
const char *help = "For a higher level overview, try: perf report --sort comm,dso"; const char *help = "For a higher level overview, try: perf report --sort comm,dso";
struct ui_progress prog;
struct perf_data_file *file = session->file; struct perf_data_file *file = session->file;
signal(SIGINT, sig_handler); signal(SIGINT, sig_handler);
...@@ -557,6 +558,12 @@ static int __cmd_report(struct perf_report *rep) ...@@ -557,6 +558,12 @@ static int __cmd_report(struct perf_report *rep)
return 0; return 0;
} }
nr_samples = 0;
list_for_each_entry(pos, &session->evlist->entries, node)
nr_samples += pos->hists.nr_entries;
ui_progress__init(&prog, nr_samples, "Merging related events...");
nr_samples = 0; nr_samples = 0;
list_for_each_entry(pos, &session->evlist->entries, node) { list_for_each_entry(pos, &session->evlist->entries, node) {
struct hists *hists = &pos->hists; struct hists *hists = &pos->hists;
...@@ -564,7 +571,7 @@ static int __cmd_report(struct perf_report *rep) ...@@ -564,7 +571,7 @@ static int __cmd_report(struct perf_report *rep)
if (pos->idx == 0) if (pos->idx == 0)
hists->symbol_filter_str = rep->symbol_filter_str; hists->symbol_filter_str = rep->symbol_filter_str;
hists__collapse_resort(hists); hists__collapse_resort(hists, &prog);
nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE]; nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE];
/* Non-group events are considered as leader */ /* Non-group events are considered as leader */
...@@ -576,6 +583,7 @@ static int __cmd_report(struct perf_report *rep) ...@@ -576,6 +583,7 @@ static int __cmd_report(struct perf_report *rep)
hists__link(leader_hists, hists); hists__link(leader_hists, hists);
} }
} }
ui_progress__finish();
if (session_done()) if (session_done())
return 0; return 0;
......
...@@ -1655,29 +1655,27 @@ static int __cmd_record(int argc, const char **argv) ...@@ -1655,29 +1655,27 @@ static int __cmd_record(int argc, const char **argv)
return cmd_record(i, rec_argv, NULL); return cmd_record(i, rec_argv, NULL);
} }
static const char default_sort_order[] = "avg, max, switch, runtime";
static struct perf_sched sched = {
.tool = {
.sample = perf_sched__process_tracepoint_sample,
.comm = perf_event__process_comm,
.lost = perf_event__process_lost,
.fork = perf_sched__process_fork_event,
.ordered_samples = true,
},
.cmp_pid = LIST_HEAD_INIT(sched.cmp_pid),
.sort_list = LIST_HEAD_INIT(sched.sort_list),
.start_work_mutex = PTHREAD_MUTEX_INITIALIZER,
.work_done_wait_mutex = PTHREAD_MUTEX_INITIALIZER,
.curr_pid = { [0 ... MAX_CPUS - 1] = -1 },
.sort_order = default_sort_order,
.replay_repeat = 10,
.profile_cpu = -1,
.next_shortname1 = 'A',
.next_shortname2 = '0',
};
int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
{ {
const char default_sort_order[] = "avg, max, switch, runtime";
struct perf_sched sched = {
.tool = {
.sample = perf_sched__process_tracepoint_sample,
.comm = perf_event__process_comm,
.lost = perf_event__process_lost,
.fork = perf_sched__process_fork_event,
.ordered_samples = true,
},
.cmp_pid = LIST_HEAD_INIT(sched.cmp_pid),
.sort_list = LIST_HEAD_INIT(sched.sort_list),
.start_work_mutex = PTHREAD_MUTEX_INITIALIZER,
.work_done_wait_mutex = PTHREAD_MUTEX_INITIALIZER,
.sort_order = default_sort_order,
.replay_repeat = 10,
.profile_cpu = -1,
.next_shortname1 = 'A',
.next_shortname2 = '0',
};
const struct option latency_options[] = { const struct option latency_options[] = {
OPT_STRING('s', "sort", &sched.sort_order, "key[,key2...]", OPT_STRING('s', "sort", &sched.sort_order, "key[,key2...]",
"sort by key(s): runtime, switch, avg, max"), "sort by key(s): runtime, switch, avg, max"),
...@@ -1733,6 +1731,10 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -1733,6 +1731,10 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
.switch_event = replay_switch_event, .switch_event = replay_switch_event,
.fork_event = replay_fork_event, .fork_event = replay_fork_event,
}; };
unsigned int i;
for (i = 0; i < ARRAY_SIZE(sched.curr_pid); i++)
sched.curr_pid[i] = -1;
argc = parse_options(argc, argv, sched_options, sched_usage, argc = parse_options(argc, argv, sched_options, sched_usage,
PARSE_OPT_STOP_AT_NON_OPTION); PARSE_OPT_STOP_AT_NON_OPTION);
......
...@@ -542,18 +542,9 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, ...@@ -542,18 +542,9 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
return 0; return 0;
} }
static struct perf_tool perf_script = { struct perf_script {
.sample = process_sample_event, struct perf_tool tool;
.mmap = perf_event__process_mmap, struct perf_session *session;
.mmap2 = perf_event__process_mmap2,
.comm = perf_event__process_comm,
.exit = perf_event__process_exit,
.fork = perf_event__process_fork,
.attr = perf_event__process_attr,
.tracing_data = perf_event__process_tracing_data,
.build_id = perf_event__process_build_id,
.ordered_samples = true,
.ordering_requires_timestamps = true,
}; };
static void sig_handler(int sig __maybe_unused) static void sig_handler(int sig __maybe_unused)
...@@ -561,13 +552,13 @@ static void sig_handler(int sig __maybe_unused) ...@@ -561,13 +552,13 @@ static void sig_handler(int sig __maybe_unused)
session_done = 1; session_done = 1;
} }
static int __cmd_script(struct perf_session *session) static int __cmd_script(struct perf_script *script)
{ {
int ret; int ret;
signal(SIGINT, sig_handler); signal(SIGINT, sig_handler);
ret = perf_session__process_events(session, &perf_script); ret = perf_session__process_events(script->session, &script->tool);
if (debug_mode) if (debug_mode)
pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered); pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered);
...@@ -1273,6 +1264,21 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -1273,6 +1264,21 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
char *script_path = NULL; char *script_path = NULL;
const char **__argv; const char **__argv;
int i, j, err; int i, j, err;
struct perf_script script = {
.tool = {
.sample = process_sample_event,
.mmap = perf_event__process_mmap,
.mmap2 = perf_event__process_mmap2,
.comm = perf_event__process_comm,
.exit = perf_event__process_exit,
.fork = perf_event__process_fork,
.attr = perf_event__process_attr,
.tracing_data = perf_event__process_tracing_data,
.build_id = perf_event__process_build_id,
.ordered_samples = true,
.ordering_requires_timestamps = true,
},
};
const struct option options[] = { const struct option options[] = {
OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace, OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
"dump raw trace in ASCII"), "dump raw trace in ASCII"),
...@@ -1498,10 +1504,12 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -1498,10 +1504,12 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
if (!script_name) if (!script_name)
setup_pager(); setup_pager();
session = perf_session__new(&file, false, &perf_script); session = perf_session__new(&file, false, &script.tool);
if (session == NULL) if (session == NULL)
return -ENOMEM; return -ENOMEM;
script.session = session;
if (cpu_list) { if (cpu_list) {
if (perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap)) if (perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap))
return -1; return -1;
...@@ -1565,7 +1573,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -1565,7 +1573,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
if (err < 0) if (err < 0)
goto out; goto out;
err = __cmd_script(session); err = __cmd_script(&script);
perf_session__delete(session); perf_session__delete(session);
cleanup_scripting(); cleanup_scripting();
......
...@@ -286,7 +286,7 @@ static void perf_top__print_sym_table(struct perf_top *top) ...@@ -286,7 +286,7 @@ static void perf_top__print_sym_table(struct perf_top *top)
return; return;
} }
hists__collapse_resort(&top->sym_evsel->hists); hists__collapse_resort(&top->sym_evsel->hists, NULL);
hists__output_resort(&top->sym_evsel->hists); hists__output_resort(&top->sym_evsel->hists);
hists__decay_entries(&top->sym_evsel->hists, hists__decay_entries(&top->sym_evsel->hists,
top->hide_user_symbols, top->hide_user_symbols,
...@@ -552,7 +552,7 @@ static void perf_top__sort_new_samples(void *arg) ...@@ -552,7 +552,7 @@ static void perf_top__sort_new_samples(void *arg)
if (t->evlist->selected != NULL) if (t->evlist->selected != NULL)
t->sym_evsel = t->evlist->selected; t->sym_evsel = t->evlist->selected;
hists__collapse_resort(&t->sym_evsel->hists); hists__collapse_resort(&t->sym_evsel->hists, NULL);
hists__output_resort(&t->sym_evsel->hists); hists__output_resort(&t->sym_evsel->hists);
hists__decay_entries(&t->sym_evsel->hists, hists__decay_entries(&t->sym_evsel->hists,
t->hide_user_symbols, t->hide_user_symbols,
......
...@@ -66,6 +66,10 @@ ifneq ($(WERROR),0) ...@@ -66,6 +66,10 @@ ifneq ($(WERROR),0)
CFLAGS += -Werror CFLAGS += -Werror
endif endif
ifndef DEBUG
DEBUG := 0
endif
ifeq ($(DEBUG),0) ifeq ($(DEBUG),0)
CFLAGS += -O6 CFLAGS += -O6
endif endif
......
...@@ -467,7 +467,7 @@ int test__hists_link(void) ...@@ -467,7 +467,7 @@ int test__hists_link(void)
goto out; goto out;
list_for_each_entry(evsel, &evlist->entries, node) { list_for_each_entry(evsel, &evlist->entries, node) {
hists__collapse_resort(&evsel->hists); hists__collapse_resort(&evsel->hists, NULL);
if (verbose > 2) if (verbose > 2)
print_hists(&evsel->hists); print_hists(&evsel->hists);
......
...@@ -275,8 +275,8 @@ int test__sample_parsing(void) ...@@ -275,8 +275,8 @@ int test__sample_parsing(void)
* Fail the test if it has not been updated when new sample format bits * Fail the test if it has not been updated when new sample format bits
* were added. * were added.
*/ */
if (PERF_SAMPLE_MAX > PERF_SAMPLE_IDENTIFIER << 1) { if (PERF_SAMPLE_MAX > PERF_SAMPLE_TRANSACTION << 1) {
pr_debug("sample format has changed - test needs updating\n"); pr_debug("sample format has changed, some new PERF_SAMPLE_ bit was introduced - test needs updating\n");
return -1; return -1;
} }
......
...@@ -34,7 +34,7 @@ struct perf_gtk_context *perf_gtk__activate_context(GtkWidget *window); ...@@ -34,7 +34,7 @@ struct perf_gtk_context *perf_gtk__activate_context(GtkWidget *window);
int perf_gtk__deactivate_context(struct perf_gtk_context **ctx); int perf_gtk__deactivate_context(struct perf_gtk_context **ctx);
void perf_gtk__init_helpline(void); void perf_gtk__init_helpline(void);
void perf_gtk__init_progress(void); void gtk_ui_progress__init(void);
void perf_gtk__init_hpp(void); void perf_gtk__init_hpp(void);
void perf_gtk__signal(int sig); void perf_gtk__signal(int sig);
......
...@@ -7,14 +7,14 @@ ...@@ -7,14 +7,14 @@
static GtkWidget *dialog; static GtkWidget *dialog;
static GtkWidget *progress; static GtkWidget *progress;
static void gtk_progress_update(u64 curr, u64 total, const char *title) static void gtk_ui_progress__update(struct ui_progress *p)
{ {
double fraction = total ? 1.0 * curr / total : 0.0; double fraction = p->total ? 1.0 * p->curr / p->total : 0.0;
char buf[1024]; char buf[1024];
if (dialog == NULL) { if (dialog == NULL) {
GtkWidget *vbox = gtk_vbox_new(TRUE, 5); GtkWidget *vbox = gtk_vbox_new(TRUE, 5);
GtkWidget *label = gtk_label_new(title); GtkWidget *label = gtk_label_new(p->title);
dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL); dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL);
progress = gtk_progress_bar_new(); progress = gtk_progress_bar_new();
...@@ -32,7 +32,7 @@ static void gtk_progress_update(u64 curr, u64 total, const char *title) ...@@ -32,7 +32,7 @@ static void gtk_progress_update(u64 curr, u64 total, const char *title)
} }
gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress), fraction); gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress), fraction);
snprintf(buf, sizeof(buf), "%"PRIu64" / %"PRIu64, curr, total); snprintf(buf, sizeof(buf), "%"PRIu64" / %"PRIu64, p->curr, p->total);
gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progress), buf); gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progress), buf);
/* we didn't call gtk_main yet, so do it manually */ /* we didn't call gtk_main yet, so do it manually */
...@@ -40,7 +40,7 @@ static void gtk_progress_update(u64 curr, u64 total, const char *title) ...@@ -40,7 +40,7 @@ static void gtk_progress_update(u64 curr, u64 total, const char *title)
gtk_main_iteration(); gtk_main_iteration();
} }
static void gtk_progress_finish(void) static void gtk_ui_progress__finish(void)
{ {
/* this will also destroy all of its children */ /* this will also destroy all of its children */
gtk_widget_destroy(dialog); gtk_widget_destroy(dialog);
...@@ -48,12 +48,12 @@ static void gtk_progress_finish(void) ...@@ -48,12 +48,12 @@ static void gtk_progress_finish(void)
dialog = NULL; dialog = NULL;
} }
static struct ui_progress gtk_progress_fns = { static struct ui_progress_ops gtk_ui_progress__ops = {
.update = gtk_progress_update, .update = gtk_ui_progress__update,
.finish = gtk_progress_finish, .finish = gtk_ui_progress__finish,
}; };
void perf_gtk__init_progress(void) void gtk_ui_progress__init(void)
{ {
progress_fns = &gtk_progress_fns; ui_progress__ops = &gtk_ui_progress__ops;
} }
...@@ -8,7 +8,7 @@ int perf_gtk__init(void) ...@@ -8,7 +8,7 @@ int perf_gtk__init(void)
{ {
perf_error__register(&perf_gtk_eops); perf_error__register(&perf_gtk_eops);
perf_gtk__init_helpline(); perf_gtk__init_helpline();
perf_gtk__init_progress(); gtk_ui_progress__init();
perf_gtk__init_hpp(); perf_gtk__init_hpp();
return gtk_init_check(NULL, NULL) ? 0 : -1; return gtk_init_check(NULL, NULL) ? 0 : -1;
......
#include "../cache.h" #include "../cache.h"
#include "progress.h" #include "progress.h"
static void nop_progress_update(u64 curr __maybe_unused, static void null_progress__update(struct ui_progress *p __maybe_unused)
u64 total __maybe_unused,
const char *title __maybe_unused)
{ {
} }
static struct ui_progress default_progress_fns = static struct ui_progress_ops null_progress__ops =
{ {
.update = nop_progress_update, .update = null_progress__update,
}; };
struct ui_progress *progress_fns = &default_progress_fns; struct ui_progress_ops *ui_progress__ops = &null_progress__ops;
void ui_progress__update(u64 curr, u64 total, const char *title) void ui_progress__update(struct ui_progress *p, u64 adv)
{ {
return progress_fns->update(curr, total, title); p->curr += adv;
if (p->curr >= p->next) {
p->next += p->step;
ui_progress__ops->update(p);
}
}
void ui_progress__init(struct ui_progress *p, u64 total, const char *title)
{
p->curr = 0;
p->next = p->step = total / 16;
p->total = total;
p->title = title;
} }
void ui_progress__finish(void) void ui_progress__finish(void)
{ {
if (progress_fns->finish) if (ui_progress__ops->finish)
progress_fns->finish(); ui_progress__ops->finish();
} }
...@@ -3,16 +3,21 @@ ...@@ -3,16 +3,21 @@
#include <../types.h> #include <../types.h>
void ui_progress__finish(void);
struct ui_progress { struct ui_progress {
void (*update)(u64, u64, const char *); const char *title;
void (*finish)(void); u64 curr, next, step, total;
}; };
void ui_progress__init(struct ui_progress *p, u64 total, const char *title);
void ui_progress__update(struct ui_progress *p, u64 adv);
extern struct ui_progress *progress_fns; struct ui_progress_ops {
void (*update)(struct ui_progress *p);
void ui_progress__init(void); void (*finish)(void);
};
void ui_progress__update(u64 curr, u64 total, const char *title); extern struct ui_progress_ops *ui_progress__ops;
void ui_progress__finish(void);
#endif #endif
...@@ -2,9 +2,10 @@ ...@@ -2,9 +2,10 @@
#include "../progress.h" #include "../progress.h"
#include "../libslang.h" #include "../libslang.h"
#include "../ui.h" #include "../ui.h"
#include "tui.h"
#include "../browser.h" #include "../browser.h"
static void tui_progress__update(u64 curr, u64 total, const char *title) static void tui_progress__update(struct ui_progress *p)
{ {
int bar, y; int bar, y;
/* /*
...@@ -14,7 +15,7 @@ static void tui_progress__update(u64 curr, u64 total, const char *title) ...@@ -14,7 +15,7 @@ static void tui_progress__update(u64 curr, u64 total, const char *title)
if (use_browser <= 0) if (use_browser <= 0)
return; return;
if (total == 0) if (p->total == 0)
return; return;
ui__refresh_dimensions(true); ui__refresh_dimensions(true);
...@@ -23,20 +24,20 @@ static void tui_progress__update(u64 curr, u64 total, const char *title) ...@@ -23,20 +24,20 @@ static void tui_progress__update(u64 curr, u64 total, const char *title)
SLsmg_set_color(0); SLsmg_set_color(0);
SLsmg_draw_box(y, 0, 3, SLtt_Screen_Cols); SLsmg_draw_box(y, 0, 3, SLtt_Screen_Cols);
SLsmg_gotorc(y++, 1); SLsmg_gotorc(y++, 1);
SLsmg_write_string((char *)title); SLsmg_write_string((char *)p->title);
SLsmg_set_color(HE_COLORSET_SELECTED); SLsmg_set_color(HE_COLORSET_SELECTED);
bar = ((SLtt_Screen_Cols - 2) * curr) / total; bar = ((SLtt_Screen_Cols - 2) * p->curr) / p->total;
SLsmg_fill_region(y, 1, 1, bar, ' '); SLsmg_fill_region(y, 1, 1, bar, ' ');
SLsmg_refresh(); SLsmg_refresh();
pthread_mutex_unlock(&ui__lock); pthread_mutex_unlock(&ui__lock);
} }
static struct ui_progress tui_progress_fns = static struct ui_progress_ops tui_progress__ops =
{ {
.update = tui_progress__update, .update = tui_progress__update,
}; };
void ui_progress__init(void) void tui_progress__init(void)
{ {
progress_fns = &tui_progress_fns; ui_progress__ops = &tui_progress__ops;
} }
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "../util.h" #include "../util.h"
#include "../libslang.h" #include "../libslang.h"
#include "../keysyms.h" #include "../keysyms.h"
#include "tui.h"
static volatile int ui__need_resize; static volatile int ui__need_resize;
...@@ -119,7 +120,7 @@ int ui__init(void) ...@@ -119,7 +120,7 @@ int ui__init(void)
ui_helpline__init(); ui_helpline__init();
ui_browser__init(); ui_browser__init();
ui_progress__init(); tui_progress__init();
signal(SIGSEGV, ui__signal); signal(SIGSEGV, ui__signal);
signal(SIGFPE, ui__signal); signal(SIGFPE, ui__signal);
......
#ifndef _PERF_TUI_H_
#define _PERF_TUI_H_ 1
void tui_progress__init(void);
#endif /* _PERF_TUI_H_ */
...@@ -89,14 +89,14 @@ int build_id__sprintf(const u8 *build_id, int len, char *bf) ...@@ -89,14 +89,14 @@ int build_id__sprintf(const u8 *build_id, int len, char *bf)
return raw - build_id; return raw - build_id;
} }
char *dso__build_id_filename(struct dso *self, char *bf, size_t size) char *dso__build_id_filename(struct dso *dso, char *bf, size_t size)
{ {
char build_id_hex[BUILD_ID_SIZE * 2 + 1]; char build_id_hex[BUILD_ID_SIZE * 2 + 1];
if (!self->has_build_id) if (!dso->has_build_id)
return NULL; return NULL;
build_id__sprintf(self->build_id, sizeof(self->build_id), build_id_hex); build_id__sprintf(dso->build_id, sizeof(dso->build_id), build_id_hex);
if (bf == NULL) { if (bf == NULL) {
if (asprintf(&bf, "%s/.build-id/%.2s/%s", buildid_dir, if (asprintf(&bf, "%s/.build-id/%.2s/%s", buildid_dir,
build_id_hex, build_id_hex + 2) < 0) build_id_hex, build_id_hex + 2) < 0)
......
...@@ -698,7 +698,8 @@ static size_t perf_evlist__mmap_size(unsigned long pages) ...@@ -698,7 +698,8 @@ static size_t perf_evlist__mmap_size(unsigned long pages)
int perf_evlist__parse_mmap_pages(const struct option *opt, const char *str, int perf_evlist__parse_mmap_pages(const struct option *opt, const char *str,
int unset __maybe_unused) int unset __maybe_unused)
{ {
unsigned int pages, val, *mmap_pages = opt->value; unsigned int *mmap_pages = opt->value;
unsigned long pages, val;
size_t size; size_t size;
static struct parse_tag tags[] = { static struct parse_tag tags[] = {
{ .tag = 'B', .mult = 1 }, { .tag = 'B', .mult = 1 },
...@@ -709,12 +710,12 @@ int perf_evlist__parse_mmap_pages(const struct option *opt, const char *str, ...@@ -709,12 +710,12 @@ int perf_evlist__parse_mmap_pages(const struct option *opt, const char *str,
}; };
val = parse_tag_value(str, tags); val = parse_tag_value(str, tags);
if (val != (unsigned int) -1) { if (val != (unsigned long) -1) {
/* we got file size value */ /* we got file size value */
pages = PERF_ALIGN(val, page_size) / page_size; pages = PERF_ALIGN(val, page_size) / page_size;
if (!is_power_of_2(pages)) { if (pages < (1UL << 31) && !is_power_of_2(pages)) {
pages = next_pow2(pages); pages = next_pow2(pages);
pr_info("rounding mmap pages size to %u (%u pages)\n", pr_info("rounding mmap pages size to %lu (%lu pages)\n",
pages * page_size, pages); pages * page_size, pages);
} }
} else { } else {
...@@ -727,6 +728,11 @@ int perf_evlist__parse_mmap_pages(const struct option *opt, const char *str, ...@@ -727,6 +728,11 @@ int perf_evlist__parse_mmap_pages(const struct option *opt, const char *str,
} }
} }
if (pages > UINT_MAX || pages > SIZE_MAX / page_size) {
pr_err("--mmap_pages/-m value too big\n");
return -1;
}
size = perf_evlist__mmap_size(pages); size = perf_evlist__mmap_size(pages);
if (!size) { if (!size) {
pr_err("--mmap_pages/-m value must be a power of two."); pr_err("--mmap_pages/-m value must be a power of two.");
......
...@@ -399,6 +399,7 @@ static struct hist_entry *add_hist_entry(struct hists *hists, ...@@ -399,6 +399,7 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
if (!he) if (!he)
return NULL; return NULL;
hists->nr_entries++;
rb_link_node(&he->rb_node_in, parent, p); rb_link_node(&he->rb_node_in, parent, p);
rb_insert_color(&he->rb_node_in, hists->entries_in); rb_insert_color(&he->rb_node_in, hists->entries_in);
out: out:
...@@ -406,7 +407,7 @@ static struct hist_entry *add_hist_entry(struct hists *hists, ...@@ -406,7 +407,7 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
return he; return he;
} }
struct hist_entry *__hists__add_mem_entry(struct hists *self, struct hist_entry *__hists__add_mem_entry(struct hists *hists,
struct addr_location *al, struct addr_location *al,
struct symbol *sym_parent, struct symbol *sym_parent,
struct mem_info *mi, struct mem_info *mi,
...@@ -429,14 +430,14 @@ struct hist_entry *__hists__add_mem_entry(struct hists *self, ...@@ -429,14 +430,14 @@ struct hist_entry *__hists__add_mem_entry(struct hists *self,
.level = al->level, .level = al->level,
.parent = sym_parent, .parent = sym_parent,
.filtered = symbol__parent_filter(sym_parent), .filtered = symbol__parent_filter(sym_parent),
.hists = self, .hists = hists,
.mem_info = mi, .mem_info = mi,
.branch_info = NULL, .branch_info = NULL,
}; };
return add_hist_entry(self, &entry, al, period, weight); return add_hist_entry(hists, &entry, al, period, weight);
} }
struct hist_entry *__hists__add_branch_entry(struct hists *self, struct hist_entry *__hists__add_branch_entry(struct hists *hists,
struct addr_location *al, struct addr_location *al,
struct symbol *sym_parent, struct symbol *sym_parent,
struct branch_info *bi, struct branch_info *bi,
...@@ -460,14 +461,14 @@ struct hist_entry *__hists__add_branch_entry(struct hists *self, ...@@ -460,14 +461,14 @@ struct hist_entry *__hists__add_branch_entry(struct hists *self,
.parent = sym_parent, .parent = sym_parent,
.filtered = symbol__parent_filter(sym_parent), .filtered = symbol__parent_filter(sym_parent),
.branch_info = bi, .branch_info = bi,
.hists = self, .hists = hists,
.mem_info = NULL, .mem_info = NULL,
}; };
return add_hist_entry(self, &entry, al, period, weight); return add_hist_entry(hists, &entry, al, period, weight);
} }
struct hist_entry *__hists__add_entry(struct hists *self, struct hist_entry *__hists__add_entry(struct hists *hists,
struct addr_location *al, struct addr_location *al,
struct symbol *sym_parent, u64 period, struct symbol *sym_parent, u64 period,
u64 weight, u64 transaction) u64 weight, u64 transaction)
...@@ -488,13 +489,13 @@ struct hist_entry *__hists__add_entry(struct hists *self, ...@@ -488,13 +489,13 @@ struct hist_entry *__hists__add_entry(struct hists *self,
}, },
.parent = sym_parent, .parent = sym_parent,
.filtered = symbol__parent_filter(sym_parent), .filtered = symbol__parent_filter(sym_parent),
.hists = self, .hists = hists,
.branch_info = NULL, .branch_info = NULL,
.mem_info = NULL, .mem_info = NULL,
.transaction = transaction, .transaction = transaction,
}; };
return add_hist_entry(self, &entry, al, period, weight); return add_hist_entry(hists, &entry, al, period, weight);
} }
int64_t int64_t
...@@ -604,7 +605,7 @@ static void hists__apply_filters(struct hists *hists, struct hist_entry *he) ...@@ -604,7 +605,7 @@ static void hists__apply_filters(struct hists *hists, struct hist_entry *he)
hists__filter_entry_by_symbol(hists, he); hists__filter_entry_by_symbol(hists, he);
} }
void hists__collapse_resort(struct hists *hists) void hists__collapse_resort(struct hists *hists, struct ui_progress *prog)
{ {
struct rb_root *root; struct rb_root *root;
struct rb_node *next; struct rb_node *next;
...@@ -631,6 +632,8 @@ void hists__collapse_resort(struct hists *hists) ...@@ -631,6 +632,8 @@ void hists__collapse_resort(struct hists *hists)
*/ */
hists__apply_filters(hists, n); hists__apply_filters(hists, n);
} }
if (prog)
ui_progress__update(prog, 1);
} }
} }
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include <pthread.h> #include <pthread.h>
#include "callchain.h" #include "callchain.h"
#include "header.h" #include "header.h"
#include "ui/progress.h"
extern struct callchain_param callchain_param; extern struct callchain_param callchain_param;
...@@ -108,7 +109,7 @@ struct hist_entry *__hists__add_mem_entry(struct hists *self, ...@@ -108,7 +109,7 @@ struct hist_entry *__hists__add_mem_entry(struct hists *self,
u64 weight); u64 weight);
void hists__output_resort(struct hists *self); void hists__output_resort(struct hists *self);
void hists__collapse_resort(struct hists *self); void hists__collapse_resort(struct hists *self, struct ui_progress *prog);
void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel); void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel);
void hists__output_recalc_col_len(struct hists *hists, int max_rows); void hists__output_recalc_col_len(struct hists *hists, int max_rows);
......
...@@ -47,7 +47,6 @@ ...@@ -47,7 +47,6 @@
#include "session.h" #include "session.h"
#define MAX_CMDLEN 256 #define MAX_CMDLEN 256
#define MAX_PROBE_ARGS 128
#define PERFPROBE_GROUP "probe" #define PERFPROBE_GROUP "probe"
bool probe_event_dry_run; /* Dry run flag */ bool probe_event_dry_run; /* Dry run flag */
......
...@@ -273,12 +273,15 @@ static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs) ...@@ -273,12 +273,15 @@ static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs)
/* /*
* Convert a location into trace_arg. * Convert a location into trace_arg.
* If tvar == NULL, this just checks variable can be converted. * If tvar == NULL, this just checks variable can be converted.
* If fentry == true and vr_die is a parameter, do huristic search
* for the location fuzzed by function entry mcount.
*/ */
static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr, static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr,
Dwarf_Op *fb_ops, Dwarf_Op *fb_ops, Dwarf_Die *sp_die,
struct probe_trace_arg *tvar) struct probe_trace_arg *tvar)
{ {
Dwarf_Attribute attr; Dwarf_Attribute attr;
Dwarf_Addr tmp = 0;
Dwarf_Op *op; Dwarf_Op *op;
size_t nops; size_t nops;
unsigned int regn; unsigned int regn;
...@@ -291,12 +294,29 @@ static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr, ...@@ -291,12 +294,29 @@ static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr,
goto static_var; goto static_var;
/* TODO: handle more than 1 exprs */ /* TODO: handle more than 1 exprs */
if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL || if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL)
dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0 || return -EINVAL; /* Broken DIE ? */
nops == 0) { if (dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0) {
/* TODO: Support const_value */ ret = dwarf_entrypc(sp_die, &tmp);
if (ret || addr != tmp ||
dwarf_tag(vr_die) != DW_TAG_formal_parameter ||
dwarf_highpc(sp_die, &tmp))
return -ENOENT;
/*
* This is fuzzed by fentry mcount. We try to find the
* parameter location at the earliest address.
*/
for (addr += 1; addr <= tmp; addr++) {
if (dwarf_getlocation_addr(&attr, addr, &op,
&nops, 1) > 0)
goto found;
}
return -ENOENT; return -ENOENT;
} }
found:
if (nops == 0)
/* TODO: Support const_value */
return -ENOENT;
if (op->atom == DW_OP_addr) { if (op->atom == DW_OP_addr) {
static_var: static_var:
...@@ -600,7 +620,7 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) ...@@ -600,7 +620,7 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
dwarf_diename(vr_die)); dwarf_diename(vr_die));
ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops, ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops,
pf->tvar); &pf->sp_die, pf->tvar);
if (ret == -ENOENT) if (ret == -ENOENT)
pr_err("Failed to find the location of %s at this address.\n" pr_err("Failed to find the location of %s at this address.\n"
" Perhaps, it has been optimized out.\n", pf->pvar->var); " Perhaps, it has been optimized out.\n", pf->pvar->var);
...@@ -1136,12 +1156,80 @@ static int debuginfo__find_probes(struct debuginfo *self, ...@@ -1136,12 +1156,80 @@ static int debuginfo__find_probes(struct debuginfo *self,
return ret; return ret;
} }
struct local_vars_finder {
struct probe_finder *pf;
struct perf_probe_arg *args;
int max_args;
int nargs;
int ret;
};
/* Collect available variables in this scope */
static int copy_variables_cb(Dwarf_Die *die_mem, void *data)
{
struct local_vars_finder *vf = data;
struct probe_finder *pf = vf->pf;
int tag;
tag = dwarf_tag(die_mem);
if (tag == DW_TAG_formal_parameter ||
tag == DW_TAG_variable) {
if (convert_variable_location(die_mem, vf->pf->addr,
vf->pf->fb_ops, &pf->sp_die,
NULL) == 0) {
vf->args[vf->nargs].var = (char *)dwarf_diename(die_mem);
if (vf->args[vf->nargs].var == NULL) {
vf->ret = -ENOMEM;
return DIE_FIND_CB_END;
}
pr_debug(" %s", vf->args[vf->nargs].var);
vf->nargs++;
}
}
if (dwarf_haspc(die_mem, vf->pf->addr))
return DIE_FIND_CB_CONTINUE;
else
return DIE_FIND_CB_SIBLING;
}
static int expand_probe_args(Dwarf_Die *sc_die, struct probe_finder *pf,
struct perf_probe_arg *args)
{
Dwarf_Die die_mem;
int i;
int n = 0;
struct local_vars_finder vf = {.pf = pf, .args = args,
.max_args = MAX_PROBE_ARGS, .ret = 0};
for (i = 0; i < pf->pev->nargs; i++) {
/* var never be NULL */
if (strcmp(pf->pev->args[i].var, "$vars") == 0) {
pr_debug("Expanding $vars into:");
vf.nargs = n;
/* Special local variables */
die_find_child(sc_die, copy_variables_cb, (void *)&vf,
&die_mem);
pr_debug(" (%d)\n", vf.nargs - n);
if (vf.ret < 0)
return vf.ret;
n = vf.nargs;
} else {
/* Copy normal argument */
args[n] = pf->pev->args[i];
n++;
}
}
return n;
}
/* Add a found probe point into trace event list */ /* Add a found probe point into trace event list */
static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
{ {
struct trace_event_finder *tf = struct trace_event_finder *tf =
container_of(pf, struct trace_event_finder, pf); container_of(pf, struct trace_event_finder, pf);
struct probe_trace_event *tev; struct probe_trace_event *tev;
struct perf_probe_arg *args;
int ret, i; int ret, i;
/* Check number of tevs */ /* Check number of tevs */
...@@ -1161,21 +1249,35 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) ...@@ -1161,21 +1249,35 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
pr_debug("Probe point found: %s+%lu\n", tev->point.symbol, pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
tev->point.offset); tev->point.offset);
/* Find each argument */ /* Expand special probe argument if exist */
tev->nargs = pf->pev->nargs; args = zalloc(sizeof(struct perf_probe_arg) * MAX_PROBE_ARGS);
tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs); if (args == NULL)
if (tev->args == NULL)
return -ENOMEM; return -ENOMEM;
for (i = 0; i < pf->pev->nargs; i++) {
pf->pvar = &pf->pev->args[i]; ret = expand_probe_args(sc_die, pf, args);
if (ret < 0)
goto end;
tev->nargs = ret;
tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
if (tev->args == NULL) {
ret = -ENOMEM;
goto end;
}
/* Find each argument */
for (i = 0; i < tev->nargs; i++) {
pf->pvar = &args[i];
pf->tvar = &tev->args[i]; pf->tvar = &tev->args[i];
/* Variable should be found from scope DIE */ /* Variable should be found from scope DIE */
ret = find_variable(sc_die, pf); ret = find_variable(sc_die, pf);
if (ret != 0) if (ret != 0)
return ret; break;
} }
return 0; end:
free(args);
return ret;
} }
/* Find probe_trace_events specified by perf_probe_event from debuginfo */ /* Find probe_trace_events specified by perf_probe_event from debuginfo */
...@@ -1222,7 +1324,8 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data) ...@@ -1222,7 +1324,8 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data)
if (tag == DW_TAG_formal_parameter || if (tag == DW_TAG_formal_parameter ||
tag == DW_TAG_variable) { tag == DW_TAG_variable) {
ret = convert_variable_location(die_mem, af->pf.addr, ret = convert_variable_location(die_mem, af->pf.addr,
af->pf.fb_ops, NULL); af->pf.fb_ops, &af->pf.sp_die,
NULL);
if (ret == 0) { if (ret == 0) {
ret = die_get_varname(die_mem, buf, MAX_VAR_LEN); ret = die_get_varname(die_mem, buf, MAX_VAR_LEN);
pr_debug2("Add new var: %s\n", buf); pr_debug2("Add new var: %s\n", buf);
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#define MAX_PROBE_BUFFER 1024 #define MAX_PROBE_BUFFER 1024
#define MAX_PROBES 128 #define MAX_PROBES 128
#define MAX_PROBE_ARGS 128
static inline int is_c_varname(const char *name) static inline int is_c_varname(const char *name)
{ {
......
...@@ -503,13 +503,16 @@ static int flush_sample_queue(struct perf_session *s, ...@@ -503,13 +503,16 @@ static int flush_sample_queue(struct perf_session *s,
struct perf_sample sample; struct perf_sample sample;
u64 limit = os->next_flush; u64 limit = os->next_flush;
u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL; u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL;
unsigned idx = 0, progress_next = os->nr_samples / 16;
bool show_progress = limit == ULLONG_MAX; bool show_progress = limit == ULLONG_MAX;
struct ui_progress prog;
int ret; int ret;
if (!tool->ordered_samples || !limit) if (!tool->ordered_samples || !limit)
return 0; return 0;
if (show_progress)
ui_progress__init(&prog, os->nr_samples, "Processing time ordered events...");
list_for_each_entry_safe(iter, tmp, head, list) { list_for_each_entry_safe(iter, tmp, head, list) {
if (session_done()) if (session_done())
return 0; return 0;
...@@ -530,11 +533,9 @@ static int flush_sample_queue(struct perf_session *s, ...@@ -530,11 +533,9 @@ static int flush_sample_queue(struct perf_session *s,
os->last_flush = iter->timestamp; os->last_flush = iter->timestamp;
list_del(&iter->list); list_del(&iter->list);
list_add(&iter->list, &os->sample_cache); list_add(&iter->list, &os->sample_cache);
if (show_progress && (++idx >= progress_next)) {
progress_next += os->nr_samples / 16; if (show_progress)
ui_progress__update(idx, os->nr_samples, ui_progress__update(&prog, 1);
"Processing time ordered events...");
}
} }
if (list_empty(head)) { if (list_empty(head)) {
...@@ -1285,12 +1286,13 @@ int __perf_session__process_events(struct perf_session *session, ...@@ -1285,12 +1286,13 @@ int __perf_session__process_events(struct perf_session *session,
u64 file_size, struct perf_tool *tool) u64 file_size, struct perf_tool *tool)
{ {
int fd = perf_data_file__fd(session->file); int fd = perf_data_file__fd(session->file);
u64 head, page_offset, file_offset, file_pos, progress_next; u64 head, page_offset, file_offset, file_pos;
int err, mmap_prot, mmap_flags, map_idx = 0; int err, mmap_prot, mmap_flags, map_idx = 0;
size_t mmap_size; size_t mmap_size;
char *buf, *mmaps[NUM_MMAPS]; char *buf, *mmaps[NUM_MMAPS];
union perf_event *event; union perf_event *event;
uint32_t size; uint32_t size;
struct ui_progress prog;
perf_tool__fill_defaults(tool); perf_tool__fill_defaults(tool);
...@@ -1301,7 +1303,7 @@ int __perf_session__process_events(struct perf_session *session, ...@@ -1301,7 +1303,7 @@ int __perf_session__process_events(struct perf_session *session,
if (data_size && (data_offset + data_size < file_size)) if (data_size && (data_offset + data_size < file_size))
file_size = data_offset + data_size; file_size = data_offset + data_size;
progress_next = file_size / 16; ui_progress__init(&prog, file_size, "Processing events...");
mmap_size = MMAP_SIZE; mmap_size = MMAP_SIZE;
if (mmap_size > file_size) if (mmap_size > file_size)
...@@ -1356,11 +1358,7 @@ int __perf_session__process_events(struct perf_session *session, ...@@ -1356,11 +1358,7 @@ int __perf_session__process_events(struct perf_session *session,
head += size; head += size;
file_pos += size; file_pos += size;
if (file_pos >= progress_next) { ui_progress__update(&prog, size);
progress_next += file_size / 16;
ui_progress__update(file_pos, file_size,
"Processing events...");
}
if (session_done()) if (session_done())
goto out; goto out;
......
...@@ -60,11 +60,11 @@ sort__thread_cmp(struct hist_entry *left, struct hist_entry *right) ...@@ -60,11 +60,11 @@ sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
return right->thread->tid - left->thread->tid; return right->thread->tid - left->thread->tid;
} }
static int hist_entry__thread_snprintf(struct hist_entry *self, char *bf, static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width) size_t size, unsigned int width)
{ {
return repsep_snprintf(bf, size, "%*s:%5d", width - 6, return repsep_snprintf(bf, size, "%*s:%5d", width - 6,
self->thread->comm ?: "", self->thread->tid); he->thread->comm ?: "", he->thread->tid);
} }
struct sort_entry sort_thread = { struct sort_entry sort_thread = {
...@@ -94,10 +94,10 @@ sort__comm_collapse(struct hist_entry *left, struct hist_entry *right) ...@@ -94,10 +94,10 @@ sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
return strcmp(comm_l, comm_r); return strcmp(comm_l, comm_r);
} }
static int hist_entry__comm_snprintf(struct hist_entry *self, char *bf, static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width) size_t size, unsigned int width)
{ {
return repsep_snprintf(bf, size, "%*s", width, self->thread->comm); return repsep_snprintf(bf, size, "%*s", width, he->thread->comm);
} }
struct sort_entry sort_comm = { struct sort_entry sort_comm = {
...@@ -148,10 +148,10 @@ static int _hist_entry__dso_snprintf(struct map *map, char *bf, ...@@ -148,10 +148,10 @@ static int _hist_entry__dso_snprintf(struct map *map, char *bf,
return repsep_snprintf(bf, size, "%-*s", width, "[unknown]"); return repsep_snprintf(bf, size, "%-*s", width, "[unknown]");
} }
static int hist_entry__dso_snprintf(struct hist_entry *self, char *bf, static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width) size_t size, unsigned int width)
{ {
return _hist_entry__dso_snprintf(self->ms.map, bf, size, width); return _hist_entry__dso_snprintf(he->ms.map, bf, size, width);
} }
struct sort_entry sort_dso = { struct sort_entry sort_dso = {
...@@ -234,11 +234,11 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym, ...@@ -234,11 +234,11 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
return ret; return ret;
} }
static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf, static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width) size_t size, unsigned int width)
{ {
return _hist_entry__sym_snprintf(self->ms.map, self->ms.sym, self->ip, return _hist_entry__sym_snprintf(he->ms.map, he->ms.sym, he->ip,
self->level, bf, size, width); he->level, bf, size, width);
} }
struct sort_entry sort_sym = { struct sort_entry sort_sym = {
...@@ -274,11 +274,11 @@ sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right) ...@@ -274,11 +274,11 @@ sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
return strcmp(left->srcline, right->srcline); return strcmp(left->srcline, right->srcline);
} }
static int hist_entry__srcline_snprintf(struct hist_entry *self, char *bf, static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
size_t size, size_t size,
unsigned int width __maybe_unused) unsigned int width __maybe_unused)
{ {
return repsep_snprintf(bf, size, "%s", self->srcline); return repsep_snprintf(bf, size, "%s", he->srcline);
} }
struct sort_entry sort_srcline = { struct sort_entry sort_srcline = {
...@@ -302,11 +302,11 @@ sort__parent_cmp(struct hist_entry *left, struct hist_entry *right) ...@@ -302,11 +302,11 @@ sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
return strcmp(sym_l->name, sym_r->name); return strcmp(sym_l->name, sym_r->name);
} }
static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf, static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width) size_t size, unsigned int width)
{ {
return repsep_snprintf(bf, size, "%-*s", width, return repsep_snprintf(bf, size, "%-*s", width,
self->parent ? self->parent->name : "[other]"); he->parent ? he->parent->name : "[other]");
} }
struct sort_entry sort_parent = { struct sort_entry sort_parent = {
...@@ -324,10 +324,10 @@ sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right) ...@@ -324,10 +324,10 @@ sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
return right->cpu - left->cpu; return right->cpu - left->cpu;
} }
static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf, static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width) size_t size, unsigned int width)
{ {
return repsep_snprintf(bf, size, "%*d", width, self->cpu); return repsep_snprintf(bf, size, "%*d", width, he->cpu);
} }
struct sort_entry sort_cpu = { struct sort_entry sort_cpu = {
...@@ -346,10 +346,10 @@ sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right) ...@@ -346,10 +346,10 @@ sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
right->branch_info->from.map); right->branch_info->from.map);
} }
static int hist_entry__dso_from_snprintf(struct hist_entry *self, char *bf, static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width) size_t size, unsigned int width)
{ {
return _hist_entry__dso_snprintf(self->branch_info->from.map, return _hist_entry__dso_snprintf(he->branch_info->from.map,
bf, size, width); bf, size, width);
} }
...@@ -360,10 +360,10 @@ sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right) ...@@ -360,10 +360,10 @@ sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
right->branch_info->to.map); right->branch_info->to.map);
} }
static int hist_entry__dso_to_snprintf(struct hist_entry *self, char *bf, static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width) size_t size, unsigned int width)
{ {
return _hist_entry__dso_snprintf(self->branch_info->to.map, return _hist_entry__dso_snprintf(he->branch_info->to.map,
bf, size, width); bf, size, width);
} }
...@@ -391,21 +391,21 @@ sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right) ...@@ -391,21 +391,21 @@ sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
return _sort__sym_cmp(to_l->sym, to_r->sym); return _sort__sym_cmp(to_l->sym, to_r->sym);
} }
static int hist_entry__sym_from_snprintf(struct hist_entry *self, char *bf, static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width) size_t size, unsigned int width)
{ {
struct addr_map_symbol *from = &self->branch_info->from; struct addr_map_symbol *from = &he->branch_info->from;
return _hist_entry__sym_snprintf(from->map, from->sym, from->addr, return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
self->level, bf, size, width); he->level, bf, size, width);
} }
static int hist_entry__sym_to_snprintf(struct hist_entry *self, char *bf, static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width) size_t size, unsigned int width)
{ {
struct addr_map_symbol *to = &self->branch_info->to; struct addr_map_symbol *to = &he->branch_info->to;
return _hist_entry__sym_snprintf(to->map, to->sym, to->addr, return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
self->level, bf, size, width); he->level, bf, size, width);
} }
...@@ -448,13 +448,13 @@ sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right) ...@@ -448,13 +448,13 @@ sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
return mp || p; return mp || p;
} }
static int hist_entry__mispredict_snprintf(struct hist_entry *self, char *bf, static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width){ size_t size, unsigned int width){
static const char *out = "N/A"; static const char *out = "N/A";
if (self->branch_info->flags.predicted) if (he->branch_info->flags.predicted)
out = "N"; out = "N";
else if (self->branch_info->flags.mispred) else if (he->branch_info->flags.mispred)
out = "Y"; out = "Y";
return repsep_snprintf(bf, size, "%-*s", width, out); return repsep_snprintf(bf, size, "%-*s", width, out);
...@@ -474,19 +474,19 @@ sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right) ...@@ -474,19 +474,19 @@ sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
return (int64_t)(r - l); return (int64_t)(r - l);
} }
static int hist_entry__daddr_snprintf(struct hist_entry *self, char *bf, static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width) size_t size, unsigned int width)
{ {
uint64_t addr = 0; uint64_t addr = 0;
struct map *map = NULL; struct map *map = NULL;
struct symbol *sym = NULL; struct symbol *sym = NULL;
if (self->mem_info) { if (he->mem_info) {
addr = self->mem_info->daddr.addr; addr = he->mem_info->daddr.addr;
map = self->mem_info->daddr.map; map = he->mem_info->daddr.map;
sym = self->mem_info->daddr.sym; sym = he->mem_info->daddr.sym;
} }
return _hist_entry__sym_snprintf(map, sym, addr, self->level, bf, size, return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
width); width);
} }
...@@ -504,13 +504,13 @@ sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right) ...@@ -504,13 +504,13 @@ sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
return _sort__dso_cmp(map_l, map_r); return _sort__dso_cmp(map_l, map_r);
} }
static int hist_entry__dso_daddr_snprintf(struct hist_entry *self, char *bf, static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width) size_t size, unsigned int width)
{ {
struct map *map = NULL; struct map *map = NULL;
if (self->mem_info) if (he->mem_info)
map = self->mem_info->daddr.map; map = he->mem_info->daddr.map;
return _hist_entry__dso_snprintf(map, bf, size, width); return _hist_entry__dso_snprintf(map, bf, size, width);
} }
...@@ -534,14 +534,14 @@ sort__locked_cmp(struct hist_entry *left, struct hist_entry *right) ...@@ -534,14 +534,14 @@ sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock); return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
} }
static int hist_entry__locked_snprintf(struct hist_entry *self, char *bf, static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width) size_t size, unsigned int width)
{ {
const char *out; const char *out;
u64 mask = PERF_MEM_LOCK_NA; u64 mask = PERF_MEM_LOCK_NA;
if (self->mem_info) if (he->mem_info)
mask = self->mem_info->data_src.mem_lock; mask = he->mem_info->data_src.mem_lock;
if (mask & PERF_MEM_LOCK_NA) if (mask & PERF_MEM_LOCK_NA)
out = "N/A"; out = "N/A";
...@@ -583,7 +583,7 @@ static const char * const tlb_access[] = { ...@@ -583,7 +583,7 @@ static const char * const tlb_access[] = {
}; };
#define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *)) #define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *))
static int hist_entry__tlb_snprintf(struct hist_entry *self, char *bf, static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width) size_t size, unsigned int width)
{ {
char out[64]; char out[64];
...@@ -594,8 +594,8 @@ static int hist_entry__tlb_snprintf(struct hist_entry *self, char *bf, ...@@ -594,8 +594,8 @@ static int hist_entry__tlb_snprintf(struct hist_entry *self, char *bf,
out[0] = '\0'; out[0] = '\0';
if (self->mem_info) if (he->mem_info)
m = self->mem_info->data_src.mem_dtlb; m = he->mem_info->data_src.mem_dtlb;
hit = m & PERF_MEM_TLB_HIT; hit = m & PERF_MEM_TLB_HIT;
miss = m & PERF_MEM_TLB_MISS; miss = m & PERF_MEM_TLB_MISS;
...@@ -660,7 +660,7 @@ static const char * const mem_lvl[] = { ...@@ -660,7 +660,7 @@ static const char * const mem_lvl[] = {
}; };
#define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *)) #define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *))
static int hist_entry__lvl_snprintf(struct hist_entry *self, char *bf, static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width) size_t size, unsigned int width)
{ {
char out[64]; char out[64];
...@@ -669,8 +669,8 @@ static int hist_entry__lvl_snprintf(struct hist_entry *self, char *bf, ...@@ -669,8 +669,8 @@ static int hist_entry__lvl_snprintf(struct hist_entry *self, char *bf,
u64 m = PERF_MEM_LVL_NA; u64 m = PERF_MEM_LVL_NA;
u64 hit, miss; u64 hit, miss;
if (self->mem_info) if (he->mem_info)
m = self->mem_info->data_src.mem_lvl; m = he->mem_info->data_src.mem_lvl;
out[0] = '\0'; out[0] = '\0';
...@@ -728,7 +728,7 @@ static const char * const snoop_access[] = { ...@@ -728,7 +728,7 @@ static const char * const snoop_access[] = {
}; };
#define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *)) #define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *))
static int hist_entry__snoop_snprintf(struct hist_entry *self, char *bf, static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width) size_t size, unsigned int width)
{ {
char out[64]; char out[64];
...@@ -738,8 +738,8 @@ static int hist_entry__snoop_snprintf(struct hist_entry *self, char *bf, ...@@ -738,8 +738,8 @@ static int hist_entry__snoop_snprintf(struct hist_entry *self, char *bf,
out[0] = '\0'; out[0] = '\0';
if (self->mem_info) if (he->mem_info)
m = self->mem_info->data_src.mem_snoop; m = he->mem_info->data_src.mem_snoop;
for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) { for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) {
if (!(m & 0x1)) if (!(m & 0x1))
...@@ -776,10 +776,10 @@ sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right) ...@@ -776,10 +776,10 @@ sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
return he_weight(left) - he_weight(right); return he_weight(left) - he_weight(right);
} }
static int hist_entry__local_weight_snprintf(struct hist_entry *self, char *bf, static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width) size_t size, unsigned int width)
{ {
return repsep_snprintf(bf, size, "%-*llu", width, he_weight(self)); return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
} }
struct sort_entry sort_local_weight = { struct sort_entry sort_local_weight = {
...@@ -795,10 +795,10 @@ sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right) ...@@ -795,10 +795,10 @@ sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
return left->stat.weight - right->stat.weight; return left->stat.weight - right->stat.weight;
} }
static int hist_entry__global_weight_snprintf(struct hist_entry *self, char *bf, static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width) size_t size, unsigned int width)
{ {
return repsep_snprintf(bf, size, "%-*llu", width, self->stat.weight); return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
} }
struct sort_entry sort_global_weight = { struct sort_entry sort_global_weight = {
...@@ -857,12 +857,12 @@ sort__abort_cmp(struct hist_entry *left, struct hist_entry *right) ...@@ -857,12 +857,12 @@ sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
right->branch_info->flags.abort; right->branch_info->flags.abort;
} }
static int hist_entry__abort_snprintf(struct hist_entry *self, char *bf, static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width) size_t size, unsigned int width)
{ {
static const char *out = "."; static const char *out = ".";
if (self->branch_info->flags.abort) if (he->branch_info->flags.abort)
out = "A"; out = "A";
return repsep_snprintf(bf, size, "%-*s", width, out); return repsep_snprintf(bf, size, "%-*s", width, out);
} }
...@@ -881,12 +881,12 @@ sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right) ...@@ -881,12 +881,12 @@ sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
right->branch_info->flags.in_tx; right->branch_info->flags.in_tx;
} }
static int hist_entry__in_tx_snprintf(struct hist_entry *self, char *bf, static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width) size_t size, unsigned int width)
{ {
static const char *out = "."; static const char *out = ".";
if (self->branch_info->flags.in_tx) if (he->branch_info->flags.in_tx)
out = "T"; out = "T";
return repsep_snprintf(bf, size, "%-*s", width, out); return repsep_snprintf(bf, size, "%-*s", width, out);
...@@ -940,10 +940,10 @@ int hist_entry__transaction_len(void) ...@@ -940,10 +940,10 @@ int hist_entry__transaction_len(void)
return len; return len;
} }
static int hist_entry__transaction_snprintf(struct hist_entry *self, char *bf, static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width) size_t size, unsigned int width)
{ {
u64 t = self->transaction; u64 t = he->transaction;
char buf[128]; char buf[128];
char *p = buf; char *p = buf;
int i; int i;
...@@ -1125,7 +1125,7 @@ int setup_sorting(void) ...@@ -1125,7 +1125,7 @@ int setup_sorting(void)
return ret; return ret;
} }
static void sort_entry__setup_elide(struct sort_entry *self, static void sort_entry__setup_elide(struct sort_entry *se,
struct strlist *list, struct strlist *list,
const char *list_name, FILE *fp) const char *list_name, FILE *fp)
{ {
...@@ -1133,7 +1133,7 @@ static void sort_entry__setup_elide(struct sort_entry *self, ...@@ -1133,7 +1133,7 @@ static void sort_entry__setup_elide(struct sort_entry *self,
if (fp != NULL) if (fp != NULL)
fprintf(fp, "# %s: %s\n", list_name, fprintf(fp, "# %s: %s\n", list_name,
strlist__entry(list, 0)->s); strlist__entry(list, 0)->s);
self->elide = true; se->elide = true;
} }
} }
......
...@@ -10,22 +10,22 @@ static const char *OP_not = "!"; /* Logical NOT */ ...@@ -10,22 +10,22 @@ static const char *OP_not = "!"; /* Logical NOT */
#define is_operator(c) ((c) == '|' || (c) == '&' || (c) == '!') #define is_operator(c) ((c) == '|' || (c) == '&' || (c) == '!')
#define is_separator(c) (is_operator(c) || (c) == '(' || (c) == ')') #define is_separator(c) (is_operator(c) || (c) == '(' || (c) == ')')
static void strfilter_node__delete(struct strfilter_node *self) static void strfilter_node__delete(struct strfilter_node *node)
{ {
if (self) { if (node) {
if (self->p && !is_operator(*self->p)) if (node->p && !is_operator(*node->p))
free((char *)self->p); free((char *)node->p);
strfilter_node__delete(self->l); strfilter_node__delete(node->l);
strfilter_node__delete(self->r); strfilter_node__delete(node->r);
free(self); free(node);
} }
} }
void strfilter__delete(struct strfilter *self) void strfilter__delete(struct strfilter *filter)
{ {
if (self) { if (filter) {
strfilter_node__delete(self->root); strfilter_node__delete(filter->root);
free(self); free(filter);
} }
} }
...@@ -170,30 +170,30 @@ struct strfilter *strfilter__new(const char *rules, const char **err) ...@@ -170,30 +170,30 @@ struct strfilter *strfilter__new(const char *rules, const char **err)
return ret; return ret;
} }
static bool strfilter_node__compare(struct strfilter_node *self, static bool strfilter_node__compare(struct strfilter_node *node,
const char *str) const char *str)
{ {
if (!self || !self->p) if (!node || !node->p)
return false; return false;
switch (*self->p) { switch (*node->p) {
case '|': /* OR */ case '|': /* OR */
return strfilter_node__compare(self->l, str) || return strfilter_node__compare(node->l, str) ||
strfilter_node__compare(self->r, str); strfilter_node__compare(node->r, str);
case '&': /* AND */ case '&': /* AND */
return strfilter_node__compare(self->l, str) && return strfilter_node__compare(node->l, str) &&
strfilter_node__compare(self->r, str); strfilter_node__compare(node->r, str);
case '!': /* NOT */ case '!': /* NOT */
return !strfilter_node__compare(self->r, str); return !strfilter_node__compare(node->r, str);
default: default:
return strglobmatch(str, self->p); return strglobmatch(str, node->p);
} }
} }
/* Return true if STR matches the filter rules */ /* Return true if STR matches the filter rules */
bool strfilter__compare(struct strfilter *self, const char *str) bool strfilter__compare(struct strfilter *node, const char *str)
{ {
if (!self) if (!node)
return false; return false;
return strfilter_node__compare(self->root, str); return strfilter_node__compare(node->root, str);
} }
...@@ -9,51 +9,51 @@ ...@@ -9,51 +9,51 @@
struct thread *thread__new(pid_t pid, pid_t tid) struct thread *thread__new(pid_t pid, pid_t tid)
{ {
struct thread *self = zalloc(sizeof(*self)); struct thread *thread = zalloc(sizeof(*thread));
if (self != NULL) { if (thread != NULL) {
map_groups__init(&self->mg); map_groups__init(&thread->mg);
self->pid_ = pid; thread->pid_ = pid;
self->tid = tid; thread->tid = tid;
self->ppid = -1; thread->ppid = -1;
self->comm = malloc(32); thread->comm = malloc(32);
if (self->comm) if (thread->comm)
snprintf(self->comm, 32, ":%d", self->tid); snprintf(thread->comm, 32, ":%d", thread->tid);
} }
return self; return thread;
} }
void thread__delete(struct thread *self) void thread__delete(struct thread *thread)
{ {
map_groups__exit(&self->mg); map_groups__exit(&thread->mg);
free(self->comm); free(thread->comm);
free(self); free(thread);
} }
int thread__set_comm(struct thread *self, const char *comm) int thread__set_comm(struct thread *thread, const char *comm)
{ {
int err; int err;
if (self->comm) if (thread->comm)
free(self->comm); free(thread->comm);
self->comm = strdup(comm); thread->comm = strdup(comm);
err = self->comm == NULL ? -ENOMEM : 0; err = thread->comm == NULL ? -ENOMEM : 0;
if (!err) { if (!err) {
self->comm_set = true; thread->comm_set = true;
} }
return err; return err;
} }
int thread__comm_len(struct thread *self) int thread__comm_len(struct thread *thread)
{ {
if (!self->comm_len) { if (!thread->comm_len) {
if (!self->comm) if (!thread->comm)
return 0; return 0;
self->comm_len = strlen(self->comm); thread->comm_len = strlen(thread->comm);
} }
return self->comm_len; return thread->comm_len;
} }
size_t thread__fprintf(struct thread *thread, FILE *fp) size_t thread__fprintf(struct thread *thread, FILE *fp)
...@@ -62,30 +62,30 @@ size_t thread__fprintf(struct thread *thread, FILE *fp) ...@@ -62,30 +62,30 @@ size_t thread__fprintf(struct thread *thread, FILE *fp)
map_groups__fprintf(&thread->mg, verbose, fp); map_groups__fprintf(&thread->mg, verbose, fp);
} }
void thread__insert_map(struct thread *self, struct map *map) void thread__insert_map(struct thread *thread, struct map *map)
{ {
map_groups__fixup_overlappings(&self->mg, map, verbose, stderr); map_groups__fixup_overlappings(&thread->mg, map, verbose, stderr);
map_groups__insert(&self->mg, map); map_groups__insert(&thread->mg, map);
} }
int thread__fork(struct thread *self, struct thread *parent) int thread__fork(struct thread *thread, struct thread *parent)
{ {
int i; int i;
if (parent->comm_set) { if (parent->comm_set) {
if (self->comm) if (thread->comm)
free(self->comm); free(thread->comm);
self->comm = strdup(parent->comm); thread->comm = strdup(parent->comm);
if (!self->comm) if (!thread->comm)
return -ENOMEM; return -ENOMEM;
self->comm_set = true; thread->comm_set = true;
} }
for (i = 0; i < MAP__NR_TYPES; ++i) for (i = 0; i < MAP__NR_TYPES; ++i)
if (map_groups__clone(&self->mg, &parent->mg, i) < 0) if (map_groups__clone(&thread->mg, &parent->mg, i) < 0)
return -ENOMEM; return -ENOMEM;
self->ppid = parent->tid; thread->ppid = parent->tid;
return 0; return 0;
} }
...@@ -386,6 +386,8 @@ unsigned long parse_tag_value(const char *str, struct parse_tag *tags) ...@@ -386,6 +386,8 @@ unsigned long parse_tag_value(const char *str, struct parse_tag *tags)
if (s != endptr) if (s != endptr)
break; break;
if (value > ULONG_MAX / i->mult)
break;
value *= i->mult; value *= i->mult;
return value; return value;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment