Commit 661e5915 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:

. Check for flex and bison before continuing building, from Borislav Petkov.

. Make event_copy local to mmaps, fixing buffer wrap around problems, from
  David Ahern.

. Add option for runtime switching perf data file in perf report, just press
  's' and a menu with the valid files found in the current directory will be
  presented, from Feng Tang.

. Add support to display whole group data for raw columns, from Jiri Olsa.

. Fix SIGALRM and pipe read race for the rwtop perl script. from Jiri Olsa.

. Fix perf_evsel::exclude_GH handling and add a test to catch regressions, from
  Jiri Olsa.

. Error checking fixes, from Namhyung Kim.

. Fix calloc argument ordering, from Paul Gortmaker.

. Fix set event list leader, from Stephane Eranian.

. Add per processor socket count aggregation in perf stat, from Stephane Eranian.

. Fix perf python binding breakage.
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents 0fbdad07 88fd2b6a
...@@ -116,9 +116,16 @@ perf stat --repeat 10 --null --sync --pre 'make -s O=defconfig-build/clean' -- m ...@@ -116,9 +116,16 @@ perf stat --repeat 10 --null --sync --pre 'make -s O=defconfig-build/clean' -- m
-I msecs:: -I msecs::
--interval-print msecs:: --interval-print msecs::
print count deltas every N milliseconds (minimum: 100ms) Print count deltas every N milliseconds (minimum: 100ms)
example: perf stat -I 1000 -e cycles -a sleep 5 example: perf stat -I 1000 -e cycles -a sleep 5
--aggr-socket::
Aggregate counts per processor socket for system-wide mode measurements. This
is a useful mode to detect imbalance between sockets. To enable this mode,
use --aggr-socket in addition to -a. (system-wide). The output includes the
socket number and the number of online processors on that socket. This is
useful to gauge the amount of aggregation.
EXAMPLES EXAMPLES
-------- --------
......
...@@ -149,6 +149,8 @@ RM = rm -f ...@@ -149,6 +149,8 @@ RM = rm -f
MKDIR = mkdir MKDIR = mkdir
FIND = find FIND = find
INSTALL = install INSTALL = install
FLEX = flex
BISON= bison
# sparse is architecture-neutral, which means that we need to tell it # sparse is architecture-neutral, which means that we need to tell it
# explicitly what architecture to check for. Fix this up for yours.. # explicitly what architecture to check for. Fix this up for yours..
...@@ -158,6 +160,14 @@ ifneq ($(MAKECMDGOALS),clean) ...@@ -158,6 +160,14 @@ ifneq ($(MAKECMDGOALS),clean)
ifneq ($(MAKECMDGOALS),tags) ifneq ($(MAKECMDGOALS),tags)
-include config/feature-tests.mak -include config/feature-tests.mak
ifeq ($(call get-executable,$(FLEX)),)
dummy := $(error Error: $(FLEX) is missing on this system, please install it)
endif
ifeq ($(call get-executable,$(BISON)),)
dummy := $(error Error: $(BISON) is missing on this system, please install it)
endif
ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -fstack-protector-all,-fstack-protector-all),y) ifeq ($(call try-cc,$(SOURCE_HELLO),$(CFLAGS) -Werror -fstack-protector-all,-fstack-protector-all),y)
CFLAGS := $(CFLAGS) -fstack-protector-all CFLAGS := $(CFLAGS) -fstack-protector-all
endif endif
...@@ -282,9 +292,6 @@ endif ...@@ -282,9 +292,6 @@ endif
export PERL_PATH export PERL_PATH
FLEX = flex
BISON= bison
$(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c $(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c
$(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h $(PARSER_DEBUG_FLEX) -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c $(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h $(PARSER_DEBUG_FLEX) -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c
......
...@@ -309,7 +309,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -309,7 +309,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
if (symbol__init() < 0) if (symbol__init() < 0)
return -1; return -1;
setup_sorting(annotate_usage, options); if (setup_sorting() < 0)
usage_with_options(annotate_usage, options);
if (argc) { if (argc) {
/* /*
......
...@@ -605,7 +605,9 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -605,7 +605,9 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
ui_init(); ui_init();
setup_sorting(diff_usage, options); if (setup_sorting() < 0)
usage_with_options(diff_usage, options);
setup_pager(); setup_pager();
sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", NULL); sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", NULL);
......
...@@ -39,7 +39,7 @@ int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -39,7 +39,7 @@ int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused)
OPT_BOOLEAN('F', "freq", &details.freq, "Show the sample frequency"), OPT_BOOLEAN('F', "freq", &details.freq, "Show the sample frequency"),
OPT_BOOLEAN('v', "verbose", &details.verbose, OPT_BOOLEAN('v', "verbose", &details.verbose,
"Show all event attr details"), "Show all event attr details"),
OPT_BOOLEAN('g', "group", &symbol_conf.event_group, OPT_BOOLEAN('g', "group", &details.event_group,
"Show event group information"), "Show event group information"),
OPT_END() OPT_END()
}; };
...@@ -52,7 +52,7 @@ int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -52,7 +52,7 @@ int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused)
if (argc) if (argc)
usage_with_options(evlist_usage, options); usage_with_options(evlist_usage, options);
if (symbol_conf.event_group && (details.verbose || details.freq)) { if (details.event_group && (details.verbose || details.freq)) {
pr_err("--group option is not compatible with other options\n"); pr_err("--group option is not compatible with other options\n");
usage_with_options(evlist_usage, options); usage_with_options(evlist_usage, options);
} }
......
...@@ -468,9 +468,17 @@ static int __cmd_report(struct perf_report *rep) ...@@ -468,9 +468,17 @@ static int __cmd_report(struct perf_report *rep)
if (use_browser > 0) { if (use_browser > 0) {
if (use_browser == 1) { if (use_browser == 1) {
perf_evlist__tui_browse_hists(session->evlist, help, ret = perf_evlist__tui_browse_hists(session->evlist,
NULL, help,
&session->header.env); NULL,
&session->header.env);
/*
* Usually "ret" is the last pressed key, and we only
* care if the key notifies us to switch data file.
*/
if (ret != K_SWITCH_INPUT_DATA)
ret = 0;
} else if (use_browser == 2) { } else if (use_browser == 2) {
perf_evlist__gtk_browse_hists(session->evlist, help, perf_evlist__gtk_browse_hists(session->evlist, help,
NULL); NULL);
...@@ -708,6 +716,16 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -708,6 +716,16 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
else else
input_name = "perf.data"; input_name = "perf.data";
} }
if (strcmp(input_name, "-") != 0)
setup_browser(true);
else {
use_browser = 0;
perf_hpp__column_enable(PERF_HPP__OVERHEAD);
perf_hpp__init();
}
repeat:
session = perf_session__new(input_name, O_RDONLY, session = perf_session__new(input_name, O_RDONLY,
report.force, false, &report.tool); report.force, false, &report.tool);
if (session == NULL) if (session == NULL)
...@@ -733,15 +751,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -733,15 +751,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
} }
if (strcmp(input_name, "-") != 0) if (setup_sorting() < 0)
setup_browser(true); usage_with_options(report_usage, options);
else {
use_browser = 0;
perf_hpp__column_enable(PERF_HPP__OVERHEAD);
perf_hpp__init();
}
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,
...@@ -809,6 +820,12 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -809,6 +820,12 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
} }
ret = __cmd_report(&report); ret = __cmd_report(&report);
if (ret == K_SWITCH_INPUT_DATA) {
perf_session__delete(session);
goto repeat;
} else
ret = 0;
error: error:
perf_session__delete(session); perf_session__delete(session);
return ret; return ret;
......
...@@ -68,6 +68,7 @@ ...@@ -68,6 +68,7 @@
static void print_stat(int argc, const char **argv); static void print_stat(int argc, const char **argv);
static void print_counter_aggr(struct perf_evsel *counter, char *prefix); static void print_counter_aggr(struct perf_evsel *counter, char *prefix);
static void print_counter(struct perf_evsel *counter, char *prefix); static void print_counter(struct perf_evsel *counter, char *prefix);
static void print_aggr_socket(char *prefix);
static struct perf_evlist *evsel_list; static struct perf_evlist *evsel_list;
...@@ -79,6 +80,7 @@ static int run_count = 1; ...@@ -79,6 +80,7 @@ static int run_count = 1;
static bool no_inherit = false; static bool no_inherit = false;
static bool scale = true; static bool scale = true;
static bool no_aggr = false; static bool no_aggr = false;
static bool aggr_socket = false;
static pid_t child_pid = -1; static pid_t child_pid = -1;
static bool null_run = false; static bool null_run = false;
static int detailed_run = 0; static int detailed_run = 0;
...@@ -93,6 +95,7 @@ static const char *post_cmd = NULL; ...@@ -93,6 +95,7 @@ static const char *post_cmd = NULL;
static bool sync_run = false; static bool sync_run = false;
static unsigned int interval = 0; static unsigned int interval = 0;
static struct timespec ref_time; static struct timespec ref_time;
static struct cpu_map *sock_map;
static volatile int done = 0; static volatile int done = 0;
...@@ -312,7 +315,9 @@ static void print_interval(void) ...@@ -312,7 +315,9 @@ static void print_interval(void)
sprintf(prefix, "%6lu.%09lu%s", rs.tv_sec, rs.tv_nsec, csv_sep); sprintf(prefix, "%6lu.%09lu%s", rs.tv_sec, rs.tv_nsec, csv_sep);
if (num_print_interval == 0 && !csv_output) { if (num_print_interval == 0 && !csv_output) {
if (no_aggr) if (aggr_socket)
fprintf(output, "# time socket cpus counts events\n");
else if (no_aggr)
fprintf(output, "# time CPU counts events\n"); fprintf(output, "# time CPU counts events\n");
else else
fprintf(output, "# time counts events\n"); fprintf(output, "# time counts events\n");
...@@ -321,7 +326,9 @@ static void print_interval(void) ...@@ -321,7 +326,9 @@ static void print_interval(void)
if (++num_print_interval == 25) if (++num_print_interval == 25)
num_print_interval = 0; num_print_interval = 0;
if (no_aggr) { if (aggr_socket)
print_aggr_socket(prefix);
else if (no_aggr) {
list_for_each_entry(counter, &evsel_list->entries, node) list_for_each_entry(counter, &evsel_list->entries, node)
print_counter(counter, prefix); print_counter(counter, prefix);
} else { } else {
...@@ -349,6 +356,12 @@ static int __run_perf_stat(int argc __maybe_unused, const char **argv) ...@@ -349,6 +356,12 @@ static int __run_perf_stat(int argc __maybe_unused, const char **argv)
ts.tv_nsec = 0; ts.tv_nsec = 0;
} }
if (aggr_socket
&& cpu_map__build_socket_map(evsel_list->cpus, &sock_map)) {
perror("cannot build socket map");
return -1;
}
if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) { if (forks && (pipe(child_ready_pipe) < 0 || pipe(go_pipe) < 0)) {
perror("failed to create pipes"); perror("failed to create pipes");
return -1; return -1;
...@@ -529,13 +542,21 @@ static void print_noise(struct perf_evsel *evsel, double avg) ...@@ -529,13 +542,21 @@ static void print_noise(struct perf_evsel *evsel, double avg)
print_noise_pct(stddev_stats(&ps->res_stats[0]), avg); print_noise_pct(stddev_stats(&ps->res_stats[0]), avg);
} }
static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg) static void nsec_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
{ {
double msecs = avg / 1e6; double msecs = avg / 1e6;
char cpustr[16] = { '\0', }; char cpustr[16] = { '\0', };
const char *fmt = csv_output ? "%s%.6f%s%s" : "%s%18.6f%s%-25s"; const char *fmt = csv_output ? "%s%.6f%s%s" : "%s%18.6f%s%-25s";
if (no_aggr) if (aggr_socket)
sprintf(cpustr, "S%*d%s%*d%s",
csv_output ? 0 : -5,
cpu,
csv_sep,
csv_output ? 0 : 4,
nr,
csv_sep);
else if (no_aggr)
sprintf(cpustr, "CPU%*d%s", sprintf(cpustr, "CPU%*d%s",
csv_output ? 0 : -4, csv_output ? 0 : -4,
perf_evsel__cpus(evsel)->map[cpu], csv_sep); perf_evsel__cpus(evsel)->map[cpu], csv_sep);
...@@ -734,7 +755,7 @@ static void print_ll_cache_misses(int cpu, ...@@ -734,7 +755,7 @@ static void print_ll_cache_misses(int cpu,
fprintf(output, " of all LL-cache hits "); fprintf(output, " of all LL-cache hits ");
} }
static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) static void abs_printout(int cpu, int nr, struct perf_evsel *evsel, double avg)
{ {
double total, ratio = 0.0; double total, ratio = 0.0;
char cpustr[16] = { '\0', }; char cpustr[16] = { '\0', };
...@@ -747,7 +768,15 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) ...@@ -747,7 +768,15 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
else else
fmt = "%s%18.0f%s%-25s"; fmt = "%s%18.0f%s%-25s";
if (no_aggr) if (aggr_socket)
sprintf(cpustr, "S%*d%s%*d%s",
csv_output ? 0 : -5,
cpu,
csv_sep,
csv_output ? 0 : 4,
nr,
csv_sep);
else if (no_aggr)
sprintf(cpustr, "CPU%*d%s", sprintf(cpustr, "CPU%*d%s",
csv_output ? 0 : -4, csv_output ? 0 : -4,
perf_evsel__cpus(evsel)->map[cpu], csv_sep); perf_evsel__cpus(evsel)->map[cpu], csv_sep);
...@@ -853,6 +882,70 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg) ...@@ -853,6 +882,70 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
} }
} }
static void print_aggr_socket(char *prefix)
{
struct perf_evsel *counter;
u64 ena, run, val;
int cpu, s, s2, sock, nr;
if (!sock_map)
return;
for (s = 0; s < sock_map->nr; s++) {
sock = cpu_map__socket(sock_map, s);
list_for_each_entry(counter, &evsel_list->entries, node) {
val = ena = run = 0;
nr = 0;
for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
s2 = cpu_map__get_socket(evsel_list->cpus, cpu);
if (s2 != sock)
continue;
val += counter->counts->cpu[cpu].val;
ena += counter->counts->cpu[cpu].ena;
run += counter->counts->cpu[cpu].run;
nr++;
}
if (prefix)
fprintf(output, "%s", prefix);
if (run == 0 || ena == 0) {
fprintf(output, "S%*d%s%*d%s%*s%s%*s",
csv_output ? 0 : -5,
s,
csv_sep,
csv_output ? 0 : 4,
nr,
csv_sep,
csv_output ? 0 : 18,
counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
csv_sep,
csv_output ? 0 : -24,
perf_evsel__name(counter));
if (counter->cgrp)
fprintf(output, "%s%s",
csv_sep, counter->cgrp->name);
fputc('\n', output);
continue;
}
if (nsec_counter(counter))
nsec_printout(sock, nr, counter, val);
else
abs_printout(sock, nr, counter, val);
if (!csv_output) {
print_noise(counter, 1.0);
if (run != ena)
fprintf(output, " (%.2f%%)",
100.0 * run / ena);
}
fputc('\n', output);
}
}
}
/* /*
* Print out the results of a single counter: * Print out the results of a single counter:
* aggregated counts in system-wide mode * aggregated counts in system-wide mode
...@@ -882,9 +975,9 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix) ...@@ -882,9 +975,9 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
} }
if (nsec_counter(counter)) if (nsec_counter(counter))
nsec_printout(-1, counter, avg); nsec_printout(-1, 0, counter, avg);
else else
abs_printout(-1, counter, avg); abs_printout(-1, 0, counter, avg);
print_noise(counter, avg); print_noise(counter, avg);
...@@ -940,9 +1033,9 @@ static void print_counter(struct perf_evsel *counter, char *prefix) ...@@ -940,9 +1033,9 @@ static void print_counter(struct perf_evsel *counter, char *prefix)
} }
if (nsec_counter(counter)) if (nsec_counter(counter))
nsec_printout(cpu, counter, val); nsec_printout(cpu, 0, counter, val);
else else
abs_printout(cpu, counter, val); abs_printout(cpu, 0, counter, val);
if (!csv_output) { if (!csv_output) {
print_noise(counter, 1.0); print_noise(counter, 1.0);
...@@ -980,7 +1073,9 @@ static void print_stat(int argc, const char **argv) ...@@ -980,7 +1073,9 @@ static void print_stat(int argc, const char **argv)
fprintf(output, ":\n\n"); fprintf(output, ":\n\n");
} }
if (no_aggr) { if (aggr_socket)
print_aggr_socket(NULL);
else if (no_aggr) {
list_for_each_entry(counter, &evsel_list->entries, node) list_for_each_entry(counter, &evsel_list->entries, node)
print_counter(counter, NULL); print_counter(counter, NULL);
} else { } else {
...@@ -1228,6 +1323,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -1228,6 +1323,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
"command to run after to the measured command"), "command to run after to the measured command"),
OPT_UINTEGER('I', "interval-print", &interval, OPT_UINTEGER('I', "interval-print", &interval,
"print counts at regular interval in ms (>= 100)"), "print counts at regular interval in ms (>= 100)"),
OPT_BOOLEAN(0, "aggr-socket", &aggr_socket, "aggregate counts per processor socket"),
OPT_END() OPT_END()
}; };
const char * const stat_usage[] = { const char * const stat_usage[] = {
...@@ -1314,6 +1410,14 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -1314,6 +1410,14 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
usage_with_options(stat_usage, options); usage_with_options(stat_usage, options);
} }
if (aggr_socket) {
if (!perf_target__has_cpu(&target)) {
fprintf(stderr, "--aggr-socket only available in system-wide mode (-a)\n");
usage_with_options(stat_usage, options);
}
no_aggr = true;
}
if (add_default_attributes()) if (add_default_attributes())
goto out; goto out;
......
...@@ -1129,7 +1129,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -1129,7 +1129,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
if (sort_order == default_sort_order) if (sort_order == default_sort_order)
sort_order = "dso,symbol"; sort_order = "dso,symbol";
setup_sorting(top_usage, options); if (setup_sorting() < 0)
usage_with_options(top_usage, options);
if (top.use_stdio) if (top.use_stdio)
use_browser = 0; use_browser = 0;
......
...@@ -103,32 +103,6 @@ ...@@ -103,32 +103,6 @@
#include "util/types.h" #include "util/types.h"
#include <stdbool.h> #include <stdbool.h>
struct perf_mmap {
void *base;
int mask;
unsigned int prev;
};
static inline unsigned int perf_mmap__read_head(struct perf_mmap *mm)
{
struct perf_event_mmap_page *pc = mm->base;
int head = pc->data_head;
rmb();
return head;
}
static inline void perf_mmap__write_tail(struct perf_mmap *md,
unsigned long tail)
{
struct perf_event_mmap_page *pc = md->base;
/*
* ensure all reads are done before we write the tail out.
*/
/* mb(); */
pc->data_tail = tail;
}
/* /*
* prctl(PR_TASK_PERF_EVENTS_DISABLE) will (cheaply) disable all * prctl(PR_TASK_PERF_EVENTS_DISABLE) will (cheaply) disable all
* counters in the current task. * counters in the current task.
......
...@@ -17,6 +17,7 @@ use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib"; ...@@ -17,6 +17,7 @@ use lib "$ENV{'PERF_EXEC_PATH'}/scripts/perl/Perf-Trace-Util/lib";
use lib "./Perf-Trace-Util/lib"; use lib "./Perf-Trace-Util/lib";
use Perf::Trace::Core; use Perf::Trace::Core;
use Perf::Trace::Util; use Perf::Trace::Util;
use POSIX qw/SIGALRM SA_RESTART/;
my $default_interval = 3; my $default_interval = 3;
my $nlines = 20; my $nlines = 20;
...@@ -90,7 +91,10 @@ sub syscalls::sys_enter_write ...@@ -90,7 +91,10 @@ sub syscalls::sys_enter_write
sub trace_begin sub trace_begin
{ {
$SIG{ALRM} = \&set_print_pending; my $sa = POSIX::SigAction->new(\&set_print_pending);
$sa->flags(SA_RESTART);
$sa->safe(1);
POSIX::sigaction(SIGALRM, $sa) or die "Can't set SIGALRM handler: $!\n";
alarm 1; alarm 1;
} }
......
...@@ -449,7 +449,8 @@ int test__hists_link(void) ...@@ -449,7 +449,8 @@ int test__hists_link(void)
goto out; goto out;
/* default sort order (comm,dso,sym) will be used */ /* default sort order (comm,dso,sym) will be used */
setup_sorting(NULL, NULL); if (setup_sorting() < 0)
goto out;
machines__init(&machines); machines__init(&machines);
......
...@@ -577,7 +577,7 @@ static int test__group2(struct perf_evlist *evlist) ...@@ -577,7 +577,7 @@ static int test__group2(struct perf_evlist *evlist)
TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
TEST_ASSERT_VAL("wrong leader", evsel->leader == leader); TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
...@@ -811,6 +811,166 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused) ...@@ -811,6 +811,166 @@ static int test__group5(struct perf_evlist *evlist __maybe_unused)
return 0; return 0;
} }
static int test__group_gh1(struct perf_evlist *evlist)
{
struct perf_evsel *evsel, *leader;
TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups);
/* cycles + :H group modifier */
evsel = leader = perf_evlist__first(evlist);
TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
TEST_ASSERT_VAL("wrong config",
PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
/* cache-misses:G + :H group modifier */
evsel = perf_evsel__next(evsel);
TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
TEST_ASSERT_VAL("wrong config",
PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config);
TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
return 0;
}
static int test__group_gh2(struct perf_evlist *evlist)
{
struct perf_evsel *evsel, *leader;
TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups);
/* cycles + :G group modifier */
evsel = leader = perf_evlist__first(evlist);
TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
TEST_ASSERT_VAL("wrong config",
PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
/* cache-misses:H + :G group modifier */
evsel = perf_evsel__next(evsel);
TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
TEST_ASSERT_VAL("wrong config",
PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config);
TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv);
TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
return 0;
}
static int test__group_gh3(struct perf_evlist *evlist)
{
struct perf_evsel *evsel, *leader;
TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups);
/* cycles:G + :u group modifier */
evsel = leader = perf_evlist__first(evlist);
TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
TEST_ASSERT_VAL("wrong config",
PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
/* cache-misses:H + :u group modifier */
evsel = perf_evsel__next(evsel);
TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
TEST_ASSERT_VAL("wrong config",
PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config);
TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest);
TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
return 0;
}
static int test__group_gh4(struct perf_evlist *evlist)
{
struct perf_evsel *evsel, *leader;
TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
TEST_ASSERT_VAL("wrong number of groups", 1 == evlist->nr_groups);
/* cycles:G + :uG group modifier */
evsel = leader = perf_evlist__first(evlist);
TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
TEST_ASSERT_VAL("wrong config",
PERF_COUNT_HW_CPU_CYCLES == evsel->attr.config);
TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host);
TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
TEST_ASSERT_VAL("wrong group name", !evsel->group_name);
TEST_ASSERT_VAL("wrong leader", perf_evsel__is_group_leader(evsel));
TEST_ASSERT_VAL("wrong nr_members", evsel->nr_members == 2);
TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 0);
/* cache-misses:H + :uG group modifier */
evsel = perf_evsel__next(evsel);
TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->attr.type);
TEST_ASSERT_VAL("wrong config",
PERF_COUNT_HW_CACHE_MISSES == evsel->attr.config);
TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user);
TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel);
TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv);
TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest);
TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host);
TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip);
TEST_ASSERT_VAL("wrong leader", evsel->leader == leader);
TEST_ASSERT_VAL("wrong group_idx", perf_evsel__group_idx(evsel) == 1);
return 0;
}
static int count_tracepoints(void) static int count_tracepoints(void)
{ {
char events_path[PATH_MAX]; char events_path[PATH_MAX];
...@@ -1011,6 +1171,22 @@ static struct evlist_test test__events[] = { ...@@ -1011,6 +1171,22 @@ static struct evlist_test test__events[] = {
.name = "*:*", .name = "*:*",
.check = test__all_tracepoints, .check = test__all_tracepoints,
}, },
[34] = {
.name = "{cycles,cache-misses:G}:H",
.check = test__group_gh1,
},
[35] = {
.name = "{cycles,cache-misses:H}:G",
.check = test__group_gh2,
},
[36] = {
.name = "{cycles:G,cache-misses:H}:u",
.check = test__group_gh3,
},
[37] = {
.name = "{cycles:G,cache-misses:H}:uG",
.check = test__group_gh4,
},
}; };
static struct evlist_test test__events_pmu[] = { static struct evlist_test test__events_pmu[] = {
......
...@@ -1241,6 +1241,96 @@ static inline bool is_report_browser(void *timer) ...@@ -1241,6 +1241,96 @@ static inline bool is_report_browser(void *timer)
return timer == NULL; return timer == NULL;
} }
/*
* Only runtime switching of perf data file will make "input_name" point
* to a malloced buffer. So add "is_input_name_malloced" flag to decide
* whether we need to call free() for current "input_name" during the switch.
*/
static bool is_input_name_malloced = false;
static int switch_data_file(void)
{
char *pwd, *options[32], *abs_path[32], *tmp;
DIR *pwd_dir;
int nr_options = 0, choice = -1, ret = -1;
struct dirent *dent;
pwd = getenv("PWD");
if (!pwd)
return ret;
pwd_dir = opendir(pwd);
if (!pwd_dir)
return ret;
memset(options, 0, sizeof(options));
memset(options, 0, sizeof(abs_path));
while ((dent = readdir(pwd_dir))) {
char path[PATH_MAX];
u64 magic;
char *name = dent->d_name;
FILE *file;
if (!(dent->d_type == DT_REG))
continue;
snprintf(path, sizeof(path), "%s/%s", pwd, name);
file = fopen(path, "r");
if (!file)
continue;
if (fread(&magic, 1, 8, file) < 8)
goto close_file_and_continue;
if (is_perf_magic(magic)) {
options[nr_options] = strdup(name);
if (!options[nr_options])
goto close_file_and_continue;
abs_path[nr_options] = strdup(path);
if (!abs_path[nr_options]) {
free(options[nr_options]);
ui__warning("Can't search all data files due to memory shortage.\n");
fclose(file);
break;
}
nr_options++;
}
close_file_and_continue:
fclose(file);
if (nr_options >= 32) {
ui__warning("Too many perf data files in PWD!\n"
"Only the first 32 files will be listed.\n");
break;
}
}
closedir(pwd_dir);
if (nr_options) {
choice = ui__popup_menu(nr_options, options);
if (choice < nr_options && choice >= 0) {
tmp = strdup(abs_path[choice]);
if (tmp) {
if (is_input_name_malloced)
free((void *)input_name);
input_name = tmp;
is_input_name_malloced = true;
ret = 0;
} else
ui__warning("Data switch failed due to memory shortage!\n");
}
}
free_popup_options(options, nr_options);
free_popup_options(abs_path, nr_options);
return ret;
}
static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
const char *helpline, const char *ev_name, const char *helpline, const char *ev_name,
bool left_exits, bool left_exits,
...@@ -1275,7 +1365,8 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, ...@@ -1275,7 +1365,8 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
int choice = 0, int choice = 0,
annotate = -2, zoom_dso = -2, zoom_thread = -2, annotate = -2, zoom_dso = -2, zoom_thread = -2,
annotate_f = -2, annotate_t = -2, browse_map = -2; annotate_f = -2, annotate_t = -2, browse_map = -2;
int scripts_comm = -2, scripts_symbol = -2, scripts_all = -2; int scripts_comm = -2, scripts_symbol = -2,
scripts_all = -2, switch_data = -2;
nr_options = 0; nr_options = 0;
...@@ -1332,6 +1423,10 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, ...@@ -1332,6 +1423,10 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
if (is_report_browser(hbt)) if (is_report_browser(hbt))
goto do_scripts; goto do_scripts;
continue; continue;
case 's':
if (is_report_browser(hbt))
goto do_data_switch;
continue;
case K_F1: case K_F1:
case 'h': case 'h':
case '?': case '?':
...@@ -1351,6 +1446,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, ...@@ -1351,6 +1446,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
"d Zoom into current DSO\n" "d Zoom into current DSO\n"
"t Zoom into current Thread\n" "t Zoom into current Thread\n"
"r Run available scripts('perf report' only)\n" "r Run available scripts('perf report' only)\n"
"s Switch to another data file in PWD ('perf report' only)\n"
"P Print histograms to perf.hist.N\n" "P Print histograms to perf.hist.N\n"
"V Verbose (DSO names in callchains, etc)\n" "V Verbose (DSO names in callchains, etc)\n"
"/ Filter symbol by name"); "/ Filter symbol by name");
...@@ -1458,6 +1554,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, ...@@ -1458,6 +1554,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
if (asprintf(&options[nr_options], "Run scripts for all samples") > 0) if (asprintf(&options[nr_options], "Run scripts for all samples") > 0)
scripts_all = nr_options++; scripts_all = nr_options++;
if (is_report_browser(hbt) && asprintf(&options[nr_options],
"Switch to another data file in PWD") > 0)
switch_data = nr_options++;
add_exit_option: add_exit_option:
options[nr_options++] = (char *)"Exit"; options[nr_options++] = (char *)"Exit";
retry_popup_menu: retry_popup_menu:
...@@ -1568,6 +1667,16 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, ...@@ -1568,6 +1667,16 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
script_browse(script_opt); script_browse(script_opt);
} }
/* Switch to another data file */
else if (choice == switch_data) {
do_data_switch:
if (!switch_data_file()) {
key = K_SWITCH_INPUT_DATA;
break;
} else
ui__warning("Won't switch the data files due to\n"
"no valid data file get selected!\n");
}
} }
out_free_stack: out_free_stack:
pstack__delete(fstack); pstack__delete(fstack);
...@@ -1694,6 +1803,7 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu, ...@@ -1694,6 +1803,7 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
"Do you really want to exit?")) "Do you really want to exit?"))
continue; continue;
/* Fall thru */ /* Fall thru */
case K_SWITCH_INPUT_DATA:
case 'q': case 'q':
case CTRL('c'): case CTRL('c'):
goto out; goto out;
......
...@@ -9,18 +9,24 @@ ...@@ -9,18 +9,24 @@
typedef int (*hpp_snprint_fn)(char *buf, size_t size, const char *fmt, ...); typedef int (*hpp_snprint_fn)(char *buf, size_t size, const char *fmt, ...);
static int __hpp__percent_fmt(struct perf_hpp *hpp, struct hist_entry *he, static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
u64 (*get_field)(struct hist_entry *), u64 (*get_field)(struct hist_entry *),
const char *fmt, hpp_snprint_fn print_fn) const char *fmt, hpp_snprint_fn print_fn,
bool fmt_percent)
{ {
int ret; int ret;
double percent = 0.0;
struct hists *hists = he->hists; struct hists *hists = he->hists;
if (hists->stats.total_period) if (fmt_percent) {
percent = 100.0 * get_field(he) / hists->stats.total_period; double percent = 0.0;
if (hists->stats.total_period)
percent = 100.0 * get_field(he) /
hists->stats.total_period;
ret = print_fn(hpp->buf, hpp->size, fmt, percent); ret = print_fn(hpp->buf, hpp->size, fmt, percent);
} else
ret = print_fn(hpp->buf, hpp->size, fmt, get_field(he));
if (symbol_conf.event_group) { if (symbol_conf.event_group) {
int prev_idx, idx_delta; int prev_idx, idx_delta;
...@@ -49,11 +55,15 @@ static int __hpp__percent_fmt(struct perf_hpp *hpp, struct hist_entry *he, ...@@ -49,11 +55,15 @@ static int __hpp__percent_fmt(struct perf_hpp *hpp, struct hist_entry *he,
* have no sample * have no sample
*/ */
ret += print_fn(hpp->buf + ret, hpp->size - ret, ret += print_fn(hpp->buf + ret, hpp->size - ret,
fmt, 0.0); fmt, 0);
} }
ret += print_fn(hpp->buf + ret, hpp->size - ret, if (fmt_percent)
fmt, 100.0 * period / total); ret += print_fn(hpp->buf + ret, hpp->size - ret,
fmt, 100.0 * period / total);
else
ret += print_fn(hpp->buf + ret, hpp->size - ret,
fmt, period);
prev_idx = perf_evsel__group_idx(evsel); prev_idx = perf_evsel__group_idx(evsel);
} }
...@@ -65,23 +75,12 @@ static int __hpp__percent_fmt(struct perf_hpp *hpp, struct hist_entry *he, ...@@ -65,23 +75,12 @@ static int __hpp__percent_fmt(struct perf_hpp *hpp, struct hist_entry *he,
* zero-fill group members at last which have no sample * zero-fill group members at last which have no sample
*/ */
ret += print_fn(hpp->buf + ret, hpp->size - ret, ret += print_fn(hpp->buf + ret, hpp->size - ret,
fmt, 0.0); fmt, 0);
} }
} }
return ret; return ret;
} }
static int __hpp__raw_fmt(struct perf_hpp *hpp, struct hist_entry *he,
u64 (*get_field)(struct hist_entry *),
const char *fmt, hpp_snprint_fn print_fn)
{
int ret;
ret = print_fn(hpp->buf, hpp->size, fmt, get_field(he));
return ret;
}
#define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ #define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
static int hpp__header_##_type(struct perf_hpp *hpp) \ static int hpp__header_##_type(struct perf_hpp *hpp) \
{ \ { \
...@@ -116,16 +115,16 @@ static u64 he_get_##_field(struct hist_entry *he) \ ...@@ -116,16 +115,16 @@ static u64 he_get_##_field(struct hist_entry *he) \
\ \
static int hpp__color_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ static int hpp__color_##_type(struct perf_hpp *hpp, struct hist_entry *he) \
{ \ { \
return __hpp__percent_fmt(hpp, he, he_get_##_field, " %6.2f%%", \ return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%", \
(hpp_snprint_fn)percent_color_snprintf); \ (hpp_snprint_fn)percent_color_snprintf, true); \
} }
#define __HPP_ENTRY_PERCENT_FN(_type, _field) \ #define __HPP_ENTRY_PERCENT_FN(_type, _field) \
static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \
{ \ { \
const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \ const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \
return __hpp__percent_fmt(hpp, he, he_get_##_field, fmt, \ return __hpp__fmt(hpp, he, he_get_##_field, fmt, \
scnprintf); \ scnprintf, true); \
} }
#define __HPP_ENTRY_RAW_FN(_type, _field) \ #define __HPP_ENTRY_RAW_FN(_type, _field) \
...@@ -137,7 +136,7 @@ static u64 he_get_raw_##_field(struct hist_entry *he) \ ...@@ -137,7 +136,7 @@ static u64 he_get_raw_##_field(struct hist_entry *he) \
static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \
{ \ { \
const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64; \ const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64; \
return __hpp__raw_fmt(hpp, he, he_get_raw_##_field, fmt, scnprintf); \ return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt, scnprintf, false); \
} }
#define HPP_PERCENT_FNS(_type, _str, _field, _min_width, _unit_width) \ #define HPP_PERCENT_FNS(_type, _str, _field, _min_width, _unit_width) \
......
...@@ -23,5 +23,6 @@ ...@@ -23,5 +23,6 @@
#define K_TIMER -1 #define K_TIMER -1
#define K_ERROR -2 #define K_ERROR -2
#define K_RESIZE -3 #define K_RESIZE -3
#define K_SWITCH_INPUT_DATA -4
#endif /* _PERF_KEYSYMS_H_ */ #endif /* _PERF_KEYSYMS_H_ */
...@@ -444,7 +444,7 @@ int callchain_cursor_append(struct callchain_cursor *cursor, ...@@ -444,7 +444,7 @@ int callchain_cursor_append(struct callchain_cursor *cursor,
struct callchain_cursor_node *node = *cursor->last; struct callchain_cursor_node *node = *cursor->last;
if (!node) { if (!node) {
node = calloc(sizeof(*node), 1); node = calloc(1, sizeof(*node));
if (!node) if (!node)
return -ENOMEM; return -ENOMEM;
......
#include "util.h" #include "util.h"
#include "sysfs.h"
#include "../perf.h" #include "../perf.h"
#include "cpumap.h" #include "cpumap.h"
#include <assert.h> #include <assert.h>
...@@ -201,3 +202,56 @@ void cpu_map__delete(struct cpu_map *map) ...@@ -201,3 +202,56 @@ void cpu_map__delete(struct cpu_map *map)
{ {
free(map); free(map);
} }
int cpu_map__get_socket(struct cpu_map *map, int idx)
{
FILE *fp;
const char *mnt;
char path[PATH_MAX];
int cpu, ret;
if (idx > map->nr)
return -1;
cpu = map->map[idx];
mnt = sysfs_find_mountpoint();
if (!mnt)
return -1;
sprintf(path,
"%s/devices/system/cpu/cpu%d/topology/physical_package_id",
mnt, cpu);
fp = fopen(path, "r");
if (!fp)
return -1;
ret = fscanf(fp, "%d", &cpu);
fclose(fp);
return ret == 1 ? cpu : -1;
}
int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp)
{
struct cpu_map *sock;
int nr = cpus->nr;
int cpu, s1, s2;
sock = calloc(1, sizeof(*sock) + nr * sizeof(int));
if (!sock)
return -1;
for (cpu = 0; cpu < nr; cpu++) {
s1 = cpu_map__get_socket(cpus, cpu);
for (s2 = 0; s2 < sock->nr; s2++) {
if (s1 == sock->map[s2])
break;
}
if (s2 == sock->nr) {
sock->map[sock->nr] = s1;
sock->nr++;
}
}
*sockp = sock;
return 0;
}
...@@ -14,6 +14,15 @@ struct cpu_map *cpu_map__dummy_new(void); ...@@ -14,6 +14,15 @@ 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); 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);
int cpu_map__get_socket(struct cpu_map *map, int idx);
int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp);
static inline int cpu_map__socket(struct cpu_map *sock, int s)
{
if (!sock || s > sock->nr || s < 0)
return 0;
return sock->map[s];
}
static inline int cpu_map__nr(const struct cpu_map *map) static inline int cpu_map__nr(const struct cpu_map *map)
{ {
......
...@@ -122,8 +122,7 @@ void __perf_evlist__set_leader(struct list_head *list) ...@@ -122,8 +122,7 @@ void __perf_evlist__set_leader(struct list_head *list)
leader->nr_members = evsel->idx - leader->idx + 1; leader->nr_members = evsel->idx - leader->idx + 1;
list_for_each_entry(evsel, list, node) { list_for_each_entry(evsel, list, node) {
if (evsel != leader) evsel->leader = leader;
evsel->leader = leader;
} }
} }
...@@ -376,7 +375,7 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) ...@@ -376,7 +375,7 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
if ((old & md->mask) + size != ((old + size) & md->mask)) { if ((old & md->mask) + size != ((old + size) & md->mask)) {
unsigned int offset = old; unsigned int offset = old;
unsigned int len = min(sizeof(*event), size), cpy; unsigned int len = min(sizeof(*event), size), cpy;
void *dst = &evlist->event_copy; void *dst = &md->event_copy;
do { do {
cpy = min(md->mask + 1 - (offset & md->mask), len); cpy = min(md->mask + 1 - (offset & md->mask), len);
...@@ -386,7 +385,7 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) ...@@ -386,7 +385,7 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
len -= cpy; len -= cpy;
} while (len); } while (len);
event = &evlist->event_copy; event = &md->event_copy;
} }
old += size; old += size;
......
...@@ -17,6 +17,13 @@ struct perf_record_opts; ...@@ -17,6 +17,13 @@ struct perf_record_opts;
#define PERF_EVLIST__HLIST_BITS 8 #define PERF_EVLIST__HLIST_BITS 8
#define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS) #define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS)
struct perf_mmap {
void *base;
int mask;
unsigned int prev;
union perf_event event_copy;
};
struct perf_evlist { struct perf_evlist {
struct list_head entries; struct list_head entries;
struct hlist_head heads[PERF_EVLIST__HLIST_SIZE]; struct hlist_head heads[PERF_EVLIST__HLIST_SIZE];
...@@ -30,7 +37,6 @@ struct perf_evlist { ...@@ -30,7 +37,6 @@ struct perf_evlist {
pid_t pid; pid_t pid;
} workload; } workload;
bool overwrite; bool overwrite;
union perf_event event_copy;
struct perf_mmap *mmap; struct perf_mmap *mmap;
struct pollfd *pollfd; struct pollfd *pollfd;
struct thread_map *threads; struct thread_map *threads;
...@@ -136,4 +142,25 @@ static inline struct perf_evsel *perf_evlist__last(struct perf_evlist *evlist) ...@@ -136,4 +142,25 @@ static inline struct perf_evsel *perf_evlist__last(struct perf_evlist *evlist)
} }
size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp); size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp);
static inline unsigned int perf_mmap__read_head(struct perf_mmap *mm)
{
struct perf_event_mmap_page *pc = mm->base;
int head = pc->data_head;
rmb();
return head;
}
static inline void perf_mmap__write_tail(struct perf_mmap *md,
unsigned long tail)
{
struct perf_event_mmap_page *pc = md->base;
/*
* ensure all reads are done before we write the tail out.
*/
/* mb(); */
pc->data_tail = tail;
}
#endif /* __PERF_EVLIST_H */ #endif /* __PERF_EVLIST_H */
...@@ -1391,7 +1391,7 @@ int perf_evsel__fprintf(struct perf_evsel *evsel, ...@@ -1391,7 +1391,7 @@ int perf_evsel__fprintf(struct perf_evsel *evsel,
bool first = true; bool first = true;
int printed = 0; int printed = 0;
if (symbol_conf.event_group) { if (details->event_group) {
struct perf_evsel *pos; struct perf_evsel *pos;
if (!perf_evsel__is_group_leader(evsel)) if (!perf_evsel__is_group_leader(evsel))
......
...@@ -254,6 +254,7 @@ static inline bool perf_evsel__is_group_leader(const struct perf_evsel *evsel) ...@@ -254,6 +254,7 @@ static inline bool perf_evsel__is_group_leader(const struct perf_evsel *evsel)
struct perf_attr_details { struct perf_attr_details {
bool freq; bool freq;
bool verbose; bool verbose;
bool event_group;
}; };
int perf_evsel__fprintf(struct perf_evsel *evsel, int perf_evsel__fprintf(struct perf_evsel *evsel,
......
...@@ -2253,7 +2253,7 @@ static int perf_header__adds_write(struct perf_header *header, ...@@ -2253,7 +2253,7 @@ static int perf_header__adds_write(struct perf_header *header,
if (!nr_sections) if (!nr_sections)
return 0; return 0;
feat_sec = p = calloc(sizeof(*feat_sec), nr_sections); feat_sec = p = calloc(nr_sections, sizeof(*feat_sec));
if (feat_sec == NULL) if (feat_sec == NULL)
return -ENOMEM; return -ENOMEM;
...@@ -2425,7 +2425,7 @@ int perf_header__process_sections(struct perf_header *header, int fd, ...@@ -2425,7 +2425,7 @@ int perf_header__process_sections(struct perf_header *header, int fd,
if (!nr_sections) if (!nr_sections)
return 0; return 0;
feat_sec = sec = calloc(sizeof(*feat_sec), nr_sections); feat_sec = sec = calloc(nr_sections, sizeof(*feat_sec));
if (!feat_sec) if (!feat_sec)
return -1; return -1;
......
...@@ -699,14 +699,6 @@ static int get_event_modifier(struct event_modifier *mod, char *str, ...@@ -699,14 +699,6 @@ static int get_event_modifier(struct event_modifier *mod, char *str,
int exclude = eu | ek | eh; int exclude = eu | ek | eh;
int exclude_GH = evsel ? evsel->exclude_GH : 0; int exclude_GH = evsel ? evsel->exclude_GH : 0;
/*
* We are here for group and 'GH' was not set as event
* modifier and whatever event/group modifier override
* default 'GH' setup.
*/
if (evsel && !exclude_GH)
eH = eG = 0;
memset(mod, 0, sizeof(*mod)); memset(mod, 0, sizeof(*mod));
while (*str) { while (*str) {
......
...@@ -18,4 +18,5 @@ util/cgroup.c ...@@ -18,4 +18,5 @@ util/cgroup.c
util/debugfs.c util/debugfs.c
util/rblist.c util/rblist.c
util/strlist.c util/strlist.c
util/sysfs.c
../../lib/rbtree.c ../../lib/rbtree.c
...@@ -160,9 +160,10 @@ struct sort_entry sort_dso = { ...@@ -160,9 +160,10 @@ struct sort_entry sort_dso = {
/* --sort symbol */ /* --sort symbol */
static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r, static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
u64 ip_l, u64 ip_r)
{ {
u64 ip_l, ip_r;
if (!sym_l || !sym_r) if (!sym_l || !sym_r)
return cmp_null(sym_l, sym_r); return cmp_null(sym_l, sym_r);
...@@ -178,21 +179,10 @@ static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r, ...@@ -178,21 +179,10 @@ static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r,
static int64_t static int64_t
sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
{ {
u64 ip_l, ip_r;
if (!left->ms.sym && !right->ms.sym) if (!left->ms.sym && !right->ms.sym)
return right->level - left->level; return right->level - left->level;
if (!left->ms.sym || !right->ms.sym) return _sort__sym_cmp(left->ms.sym, right->ms.sym);
return cmp_null(left->ms.sym, right->ms.sym);
if (left->ms.sym == right->ms.sym)
return 0;
ip_l = left->ms.sym->start;
ip_r = right->ms.sym->start;
return _sort__sym_cmp(left->ms.sym, right->ms.sym, ip_l, ip_r);
} }
static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym, static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
...@@ -383,8 +373,7 @@ sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right) ...@@ -383,8 +373,7 @@ sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
if (!from_l->sym && !from_r->sym) if (!from_l->sym && !from_r->sym)
return right->level - left->level; return right->level - left->level;
return _sort__sym_cmp(from_l->sym, from_r->sym, from_l->addr, return _sort__sym_cmp(from_l->sym, from_r->sym);
from_r->addr);
} }
static int64_t static int64_t
...@@ -396,7 +385,7 @@ sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right) ...@@ -396,7 +385,7 @@ sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
if (!to_l->sym && !to_r->sym) if (!to_l->sym && !to_r->sym)
return right->level - left->level; return right->level - left->level;
return _sort__sym_cmp(to_l->sym, to_r->sym, to_l->addr, to_r->addr); 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 *self, char *bf,
...@@ -576,23 +565,30 @@ int sort_dimension__add(const char *tok) ...@@ -576,23 +565,30 @@ int sort_dimension__add(const char *tok)
return -ESRCH; return -ESRCH;
} }
void setup_sorting(const char * const usagestr[], const struct option *opts) int setup_sorting(void)
{ {
char *tmp, *tok, *str = strdup(sort_order); char *tmp, *tok, *str = strdup(sort_order);
int ret = 0;
if (str == NULL) {
error("Not enough memory to setup sort keys");
return -ENOMEM;
}
for (tok = strtok_r(str, ", ", &tmp); for (tok = strtok_r(str, ", ", &tmp);
tok; tok = strtok_r(NULL, ", ", &tmp)) { tok; tok = strtok_r(NULL, ", ", &tmp)) {
int ret = sort_dimension__add(tok); ret = sort_dimension__add(tok);
if (ret == -EINVAL) { if (ret == -EINVAL) {
error("Invalid --sort key: `%s'", tok); error("Invalid --sort key: `%s'", tok);
usage_with_options(usagestr, opts); break;
} else if (ret == -ESRCH) { } else if (ret == -ESRCH) {
error("Unknown --sort key: `%s'", tok); error("Unknown --sort key: `%s'", tok);
usage_with_options(usagestr, opts); break;
} }
} }
free(str); free(str);
return ret;
} }
void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
......
...@@ -160,7 +160,7 @@ struct sort_entry { ...@@ -160,7 +160,7 @@ struct sort_entry {
extern struct sort_entry sort_thread; extern struct sort_entry sort_thread;
extern struct list_head hist_entry__sort_list; extern struct list_head hist_entry__sort_list;
void setup_sorting(const char * const usagestr[], const struct option *opts); int setup_sorting(void);
extern int sort_dimension__add(const char *); extern int sort_dimension__add(const char *);
void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
const char *list_name, FILE *fp); const char *list_name, FILE *fp);
......
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