Commit c1776a18 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull perf updates from Ingo Molnar:
 "This tree includes an x86 PMU scheduling fix, but most changes are
  late breaking tooling fixes and updates:

  User visible fixes:

   - Create config.detected into OUTPUT directory, fixing parallel
     builds sharing the same source directory (Aaro Kiskinen)

   - Allow to specify custom linker command, fixing some MIPS64 builds.
     (Aaro Kiskinen)

   - Fix to show proper convergence stats in 'perf bench numa' (Srikar
     Dronamraju)

  User visible changes:

   - Validate syscall list passed via -e argument to 'perf trace'.
     (Arnaldo Carvalho de Melo)

   - Introduce 'perf stat --per-thread' (Jiri Olsa)

   - Check access permission for --kallsyms and --vmlinux (Li Zhang)

   - Move toggling event logic from 'perf top' and into hists browser,
     allowing freeze/unfreeze with event lists with more than one entry
     (Namhyung Kim)

   - Add missing newlines when dumping PERF_RECORD_FINISHED_ROUND and
     showing the Aggregated stats in 'perf report -D' (Adrian Hunter)

  Infrastructure fixes:

   - Add missing break for PERF_RECORD_ITRACE_START, which caused those
     events samples to be parsed as well as PERF_RECORD_LOST_SAMPLES.
     ITRACE_START only appears when Intel PT or BTS are present, so..
     (Jiri Olsa)

   - Call the perf_session destructor when bailing out in the inject,
     kmem, report, kvm and mem tools (Taeung Song)

  Infrastructure changes:

   - Move stuff out of 'perf stat' and into the lib for further use
     (Jiri Olsa)

   - Reference count the cpu_map and thread_map classes (Jiri Olsa)

   - Set evsel->{cpus,threads} from the evlist, if not set, allowing the
     generalization of some 'perf stat' functions that previously were
     accessing private static evlist variable (Jiri Olsa)

   - Delete an unnecessary check before the calling free_event_desc()
     (Markus Elfring)

   - Allow auxtrace data alignment (Adrian Hunter)

   - Allow events with dot (Andi Kleen)

   - Fix failure to 'perf probe' events on arm (He Kuang)

   - Add testing for Makefile.perf (Jiri Olsa)

   - Add test for make install with prefix (Jiri Olsa)

   - Fix single target build dependency check (Jiri Olsa)

   - Access thread_map entries via accessors, prep patch to hold more
     info per entry, for ongoing 'perf stat --per-thread' work (Jiri
     Olsa)

   - Use __weak definition from compiler.h (Sukadev Bhattiprolu)

   - Split perf_pmu__new_alias() (Sukadev Bhattiprolu)"

* 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (54 commits)
  perf tools: Allow to specify custom linker command
  perf tools: Create config.detected into OUTPUT directory
  perf mem: Fill in the missing session freeing after an error occurs
  perf kvm: Fill in the missing session freeing after an error occurs
  perf report: Fill in the missing session freeing after an error occurs
  perf kmem: Fill in the missing session freeing after an error occurs
  perf inject: Fill in the missing session freeing after an error occurs
  perf tools: Add missing break for PERF_RECORD_ITRACE_START
  perf/x86: Fix 'active_events' imbalance
  perf symbols: Check access permission when reading symbol files
  perf stat: Introduce --per-thread option
  perf stat: Introduce print_counters function
  perf stat: Using init_stats instead of memset
  perf stat: Rename print_interval to process_interval
  perf stat: Remove perf_evsel__read_cb function
  perf stat: Move perf_stat initialization counter process code
  perf stat: Move zero_per_pkg into counter process code
  perf stat: Separate counters reading and processing
  perf stat: Introduce read_counters function
  perf stat: Introduce perf_evsel__read function
  ...
parents 91cca0f0 b9df84fd
...@@ -357,34 +357,24 @@ void x86_release_hardware(void) ...@@ -357,34 +357,24 @@ void x86_release_hardware(void)
*/ */
int x86_add_exclusive(unsigned int what) int x86_add_exclusive(unsigned int what)
{ {
int ret = -EBUSY, i; int i;
if (atomic_inc_not_zero(&x86_pmu.lbr_exclusive[what]))
return 0;
mutex_lock(&pmc_reserve_mutex); if (!atomic_inc_not_zero(&x86_pmu.lbr_exclusive[what])) {
for (i = 0; i < ARRAY_SIZE(x86_pmu.lbr_exclusive); i++) { mutex_lock(&pmc_reserve_mutex);
if (i != what && atomic_read(&x86_pmu.lbr_exclusive[i])) for (i = 0; i < ARRAY_SIZE(x86_pmu.lbr_exclusive); i++) {
goto out; if (i != what && atomic_read(&x86_pmu.lbr_exclusive[i]))
goto fail_unlock;
}
atomic_inc(&x86_pmu.lbr_exclusive[what]);
mutex_unlock(&pmc_reserve_mutex);
} }
atomic_inc(&x86_pmu.lbr_exclusive[what]); atomic_inc(&active_events);
ret = 0; return 0;
out: fail_unlock:
mutex_unlock(&pmc_reserve_mutex); mutex_unlock(&pmc_reserve_mutex);
return -EBUSY;
/*
* Assuming that all exclusive events will share the PMI handler
* (which checks active_events for whether there is work to do),
* we can bump active_events counter right here, except for
* x86_lbr_exclusive_lbr events that go through x86_pmu_event_init()
* path, which already bumps active_events for them.
*/
if (!ret && what != x86_lbr_exclusive_lbr)
atomic_inc(&active_events);
return ret;
} }
void x86_del_exclusive(unsigned int what) void x86_del_exclusive(unsigned int what)
......
...@@ -25,7 +25,7 @@ build-dir := $(srctree)/tools/build ...@@ -25,7 +25,7 @@ build-dir := $(srctree)/tools/build
include $(build-dir)/Build.include include $(build-dir)/Build.include
# do not force detected configuration # do not force detected configuration
-include .config-detected -include $(OUTPUT).config-detected
# Init all relevant variables used in build files so # Init all relevant variables used in build files so
# 1) they have correct type # 1) they have correct type
......
...@@ -144,6 +144,10 @@ is a useful mode to detect imbalance between physical cores. To enable this mod ...@@ -144,6 +144,10 @@ is a useful mode to detect imbalance between physical cores. To enable this mod
use --per-core in addition to -a. (system-wide). The output includes the use --per-core in addition to -a. (system-wide). The output includes the
core number and the number of online logical processors on that physical processor. core number and the number of online logical processors on that physical processor.
--per-thread::
Aggregate counts per monitored threads, when monitoring threads (-t option)
or processes (-p option).
-D msecs:: -D msecs::
--delay msecs:: --delay msecs::
After starting the program, wait msecs before measuring. This is useful to After starting the program, wait msecs before measuring. This is useful to
......
...@@ -83,8 +83,8 @@ build-test: ...@@ -83,8 +83,8 @@ build-test:
# #
# All other targets get passed through: # All other targets get passed through:
# #
%: %: FORCE
$(print_msg) $(print_msg)
$(make) $(make)
.PHONY: tags TAGS .PHONY: tags TAGS FORCE Makefile
...@@ -110,7 +110,7 @@ $(OUTPUT)PERF-VERSION-FILE: ../../.git/HEAD ...@@ -110,7 +110,7 @@ $(OUTPUT)PERF-VERSION-FILE: ../../.git/HEAD
$(Q)touch $(OUTPUT)PERF-VERSION-FILE $(Q)touch $(OUTPUT)PERF-VERSION-FILE
CC = $(CROSS_COMPILE)gcc CC = $(CROSS_COMPILE)gcc
LD = $(CROSS_COMPILE)ld LD ?= $(CROSS_COMPILE)ld
AR = $(CROSS_COMPILE)ar AR = $(CROSS_COMPILE)ar
PKG_CONFIG = $(CROSS_COMPILE)pkg-config PKG_CONFIG = $(CROSS_COMPILE)pkg-config
...@@ -545,7 +545,7 @@ config-clean: ...@@ -545,7 +545,7 @@ config-clean:
clean: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean config-clean clean: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean config-clean
$(call QUIET_CLEAN, core-objs) $(RM) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(LANG_BINDINGS) $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(LANG_BINDINGS)
$(Q)find . -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete $(Q)find . -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete
$(Q)$(RM) .config-detected $(Q)$(RM) $(OUTPUT).config-detected
$(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32 $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32
$(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)FEATURE-DUMP $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex* $(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)FEATURE-DUMP $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex*
$(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
......
...@@ -630,12 +630,13 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -630,12 +630,13 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
if (inject.session == NULL) if (inject.session == NULL)
return -1; return -1;
if (symbol__init(&inject.session->header.env) < 0) ret = symbol__init(&inject.session->header.env);
return -1; if (ret < 0)
goto out_delete;
ret = __cmd_inject(&inject); ret = __cmd_inject(&inject);
out_delete:
perf_session__delete(inject.session); perf_session__delete(inject.session);
return ret; return ret;
} }
...@@ -1916,7 +1916,7 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -1916,7 +1916,7 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
if (!perf_evlist__find_tracepoint_by_name(session->evlist, if (!perf_evlist__find_tracepoint_by_name(session->evlist,
"kmem:kmalloc")) { "kmem:kmalloc")) {
pr_err(errmsg, "slab", "slab"); pr_err(errmsg, "slab", "slab");
return -1; goto out_delete;
} }
} }
...@@ -1927,7 +1927,7 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -1927,7 +1927,7 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
"kmem:mm_page_alloc"); "kmem:mm_page_alloc");
if (evsel == NULL) { if (evsel == NULL) {
pr_err(errmsg, "page", "page"); pr_err(errmsg, "page", "page");
return -1; goto out_delete;
} }
kmem_page_size = pevent_get_page_size(evsel->tp_format->pevent); kmem_page_size = pevent_get_page_size(evsel->tp_format->pevent);
......
...@@ -1061,8 +1061,10 @@ static int read_events(struct perf_kvm_stat *kvm) ...@@ -1061,8 +1061,10 @@ static int read_events(struct perf_kvm_stat *kvm)
symbol__init(&kvm->session->header.env); symbol__init(&kvm->session->header.env);
if (!perf_session__has_traces(kvm->session, "kvm record")) if (!perf_session__has_traces(kvm->session, "kvm record")) {
return -EINVAL; ret = -EINVAL;
goto out_delete;
}
/* /*
* Do not use 'isa' recorded in kvm_exit tracepoint since it is not * Do not use 'isa' recorded in kvm_exit tracepoint since it is not
...@@ -1070,9 +1072,13 @@ static int read_events(struct perf_kvm_stat *kvm) ...@@ -1070,9 +1072,13 @@ static int read_events(struct perf_kvm_stat *kvm)
*/ */
ret = cpu_isa_config(kvm); ret = cpu_isa_config(kvm);
if (ret < 0) if (ret < 0)
return ret; goto out_delete;
return perf_session__process_events(kvm->session); ret = perf_session__process_events(kvm->session);
out_delete:
perf_session__delete(kvm->session);
return ret;
} }
static int parse_target_str(struct perf_kvm_stat *kvm) static int parse_target_str(struct perf_kvm_stat *kvm)
......
...@@ -124,7 +124,6 @@ static int report_raw_events(struct perf_mem *mem) ...@@ -124,7 +124,6 @@ static int report_raw_events(struct perf_mem *mem)
.mode = PERF_DATA_MODE_READ, .mode = PERF_DATA_MODE_READ,
.force = mem->force, .force = mem->force,
}; };
int err = -EINVAL;
int ret; int ret;
struct perf_session *session = perf_session__new(&file, false, struct perf_session *session = perf_session__new(&file, false,
&mem->tool); &mem->tool);
...@@ -135,24 +134,21 @@ static int report_raw_events(struct perf_mem *mem) ...@@ -135,24 +134,21 @@ static int report_raw_events(struct perf_mem *mem)
if (mem->cpu_list) { if (mem->cpu_list) {
ret = perf_session__cpu_bitmap(session, mem->cpu_list, ret = perf_session__cpu_bitmap(session, mem->cpu_list,
mem->cpu_bitmap); mem->cpu_bitmap);
if (ret) if (ret < 0)
goto out_delete; goto out_delete;
} }
if (symbol__init(&session->header.env) < 0) ret = symbol__init(&session->header.env);
return -1; if (ret < 0)
goto out_delete;
printf("# PID, TID, IP, ADDR, LOCAL WEIGHT, DSRC, SYMBOL\n"); printf("# PID, TID, IP, ADDR, LOCAL WEIGHT, DSRC, SYMBOL\n");
err = perf_session__process_events(session); ret = perf_session__process_events(session);
if (err)
return err;
return 0;
out_delete: out_delete:
perf_session__delete(session); perf_session__delete(session);
return err; return ret;
} }
static int report_events(int argc, const char **argv, struct perf_mem *mem) static int report_events(int argc, const char **argv, struct perf_mem *mem)
......
...@@ -742,6 +742,17 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -742,6 +742,17 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
argc = parse_options(argc, argv, options, report_usage, 0); argc = parse_options(argc, argv, options, report_usage, 0);
if (symbol_conf.vmlinux_name &&
access(symbol_conf.vmlinux_name, R_OK)) {
pr_err("Invalid file: %s\n", symbol_conf.vmlinux_name);
return -EINVAL;
}
if (symbol_conf.kallsyms_name &&
access(symbol_conf.kallsyms_name, R_OK)) {
pr_err("Invalid file: %s\n", symbol_conf.kallsyms_name);
return -EINVAL;
}
if (report.use_stdio) if (report.use_stdio)
use_browser = 0; use_browser = 0;
else if (report.use_tui) else if (report.use_tui)
...@@ -828,8 +839,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -828,8 +839,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
if (report.header || report.header_only) { if (report.header || report.header_only) {
perf_session__fprintf_info(session, stdout, perf_session__fprintf_info(session, stdout,
report.show_full_info); report.show_full_info);
if (report.header_only) if (report.header_only) {
return 0; ret = 0;
goto error;
}
} else if (use_browser == 0) { } else if (use_browser == 0) {
fputs("# To display the perf.data header info, please use --header/--header-only options.\n#\n", fputs("# To display the perf.data header info, please use --header/--header-only options.\n#\n",
stdout); stdout);
......
This diff is collapsed.
...@@ -586,27 +586,9 @@ static void *display_thread_tui(void *arg) ...@@ -586,27 +586,9 @@ static void *display_thread_tui(void *arg)
hists->uid_filter_str = top->record_opts.target.uid_str; hists->uid_filter_str = top->record_opts.target.uid_str;
} }
while (true) { perf_evlist__tui_browse_hists(top->evlist, help, &hbt,
int key = perf_evlist__tui_browse_hists(top->evlist, help, &hbt, top->min_percent,
top->min_percent, &top->session->header.env);
&top->session->header.env);
if (key != 'f')
break;
perf_evlist__toggle_enable(top->evlist);
/*
* No need to refresh, resort/decay histogram entries
* if we are not collecting samples:
*/
if (top->evlist->enabled) {
hbt.refresh = top->delay_secs;
help = "Press 'f' to disable the events or 'h' to see other hotkeys";
} else {
help = "Press 'f' again to re-enable the events";
hbt.refresh = 0;
}
}
done = 1; done = 1;
return NULL; return NULL;
......
...@@ -1617,6 +1617,34 @@ static int trace__read_syscall_info(struct trace *trace, int id) ...@@ -1617,6 +1617,34 @@ static int trace__read_syscall_info(struct trace *trace, int id)
return syscall__set_arg_fmts(sc); return syscall__set_arg_fmts(sc);
} }
static int trace__validate_ev_qualifier(struct trace *trace)
{
int err = 0;
struct str_node *pos;
strlist__for_each(pos, trace->ev_qualifier) {
const char *sc = pos->s;
if (audit_name_to_syscall(sc, trace->audit.machine) < 0) {
if (err == 0) {
fputs("Error:\tInvalid syscall ", trace->output);
err = -EINVAL;
} else {
fputs(", ", trace->output);
}
fputs(sc, trace->output);
}
}
if (err < 0) {
fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
"\nHint:\tand: 'man syscalls'\n", trace->output);
}
return err;
}
/* /*
* args is to be interpreted as a series of longs but we need to handle * args is to be interpreted as a series of longs but we need to handle
* 8-byte unaligned accesses. args points to raw_data within the event * 8-byte unaligned accesses. args points to raw_data within the event
...@@ -2325,7 +2353,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv) ...@@ -2325,7 +2353,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
*/ */
if (trace->filter_pids.nr > 0) if (trace->filter_pids.nr > 0)
err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries); err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
else if (evlist->threads->map[0] == -1) else if (thread_map__pid(evlist->threads, 0) == -1)
err = perf_evlist__set_filter_pid(evlist, getpid()); err = perf_evlist__set_filter_pid(evlist, getpid());
if (err < 0) { if (err < 0) {
...@@ -2343,7 +2371,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv) ...@@ -2343,7 +2371,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
if (forks) if (forks)
perf_evlist__start_workload(evlist); perf_evlist__start_workload(evlist);
trace->multiple_threads = evlist->threads->map[0] == -1 || trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
evlist->threads->nr > 1 || evlist->threads->nr > 1 ||
perf_evlist__first(evlist)->attr.inherit; perf_evlist__first(evlist)->attr.inherit;
again: again:
...@@ -2862,6 +2890,10 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -2862,6 +2890,10 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
err = -ENOMEM; err = -ENOMEM;
goto out_close; goto out_close;
} }
err = trace__validate_ev_qualifier(&trace);
if (err)
goto out_close;
} }
err = target__validate(&trace.opts.target); err = target__validate(&trace.opts.target);
......
...@@ -11,9 +11,9 @@ ifneq ($(obj-perf),) ...@@ -11,9 +11,9 @@ ifneq ($(obj-perf),)
obj-perf := $(abspath $(obj-perf))/ obj-perf := $(abspath $(obj-perf))/
endif endif
$(shell echo -n > .config-detected) $(shell echo -n > $(OUTPUT).config-detected)
detected = $(shell echo "$(1)=y" >> .config-detected) detected = $(shell echo "$(1)=y" >> $(OUTPUT).config-detected)
detected_var = $(shell echo "$(1)=$($(1))" >> .config-detected) detected_var = $(shell echo "$(1)=$($(1))" >> $(OUTPUT).config-detected)
CFLAGS := $(EXTRA_CFLAGS) $(EXTRA_WARNINGS) CFLAGS := $(EXTRA_CFLAGS) $(EXTRA_WARNINGS)
......
...@@ -31,6 +31,7 @@ perf-y += code-reading.o ...@@ -31,6 +31,7 @@ perf-y += code-reading.o
perf-y += sample-parsing.o perf-y += sample-parsing.o
perf-y += parse-no-sample-id-all.o perf-y += parse-no-sample-id-all.o
perf-y += kmod-path.o perf-y += kmod-path.o
perf-y += thread-map.o
perf-$(CONFIG_X86) += perf-time-to-tsc.o perf-$(CONFIG_X86) += perf-time-to-tsc.o
......
...@@ -170,6 +170,10 @@ static struct test { ...@@ -170,6 +170,10 @@ static struct test {
.desc = "Test kmod_path__parse function", .desc = "Test kmod_path__parse function",
.func = test__kmod_path__parse, .func = test__kmod_path__parse,
}, },
{
.desc = "Test thread map",
.func = test__thread_map,
},
{ {
.func = NULL, .func = NULL,
}, },
......
...@@ -545,8 +545,8 @@ static int do_test_code_reading(bool try_kcore) ...@@ -545,8 +545,8 @@ static int do_test_code_reading(bool try_kcore)
if (evlist) { if (evlist) {
perf_evlist__delete(evlist); perf_evlist__delete(evlist);
} else { } else {
cpu_map__delete(cpus); cpu_map__put(cpus);
thread_map__delete(threads); thread_map__put(threads);
} }
machines__destroy_kernel_maps(&machines); machines__destroy_kernel_maps(&machines);
machine__delete_threads(machine); machine__delete_threads(machine);
......
...@@ -144,8 +144,8 @@ int test__keep_tracking(void) ...@@ -144,8 +144,8 @@ int test__keep_tracking(void)
perf_evlist__disable(evlist); perf_evlist__disable(evlist);
perf_evlist__delete(evlist); perf_evlist__delete(evlist);
} else { } else {
cpu_map__delete(cpus); cpu_map__put(cpus);
thread_map__delete(threads); thread_map__put(threads);
} }
return err; return err;
......
ifndef MK
ifeq ($(MAKECMDGOALS),)
# no target specified, trigger the whole suite
all:
@echo "Testing Makefile"; $(MAKE) -sf tests/make MK=Makefile
@echo "Testing Makefile.perf"; $(MAKE) -sf tests/make MK=Makefile.perf
else
# run only specific test over 'Makefile'
%:
@echo "Testing Makefile"; $(MAKE) -sf tests/make MK=Makefile $@
endif
else
PERF := . PERF := .
MK := Makefile
include config/Makefile.arch include config/Makefile.arch
...@@ -47,6 +58,7 @@ make_install_man := install-man ...@@ -47,6 +58,7 @@ make_install_man := install-man
make_install_html := install-html make_install_html := install-html
make_install_info := install-info make_install_info := install-info
make_install_pdf := install-pdf make_install_pdf := install-pdf
make_install_prefix := install prefix=/tmp/krava
make_static := LDFLAGS=-static make_static := LDFLAGS=-static
# all the NO_* variable combined # all the NO_* variable combined
...@@ -57,7 +69,12 @@ make_minimal += NO_LIBDW_DWARF_UNWIND=1 NO_AUXTRACE=1 ...@@ -57,7 +69,12 @@ make_minimal += NO_LIBDW_DWARF_UNWIND=1 NO_AUXTRACE=1
# $(run) contains all available tests # $(run) contains all available tests
run := make_pure run := make_pure
# Targets 'clean all' can be run together only through top level
# Makefile because we detect clean target in Makefile.perf and
# disable features detection
ifeq ($(MK),Makefile)
run += make_clean_all run += make_clean_all
endif
run += make_python_perf_so run += make_python_perf_so
run += make_debug run += make_debug
run += make_no_libperl run += make_no_libperl
...@@ -83,6 +100,7 @@ run += make_util_map_o ...@@ -83,6 +100,7 @@ run += make_util_map_o
run += make_util_pmu_bison_o run += make_util_pmu_bison_o
run += make_install run += make_install
run += make_install_bin run += make_install_bin
run += make_install_prefix
# FIXME 'install-*' commented out till they're fixed # FIXME 'install-*' commented out till they're fixed
# run += make_install_doc # run += make_install_doc
# run += make_install_man # run += make_install_man
...@@ -157,6 +175,12 @@ test_make_install_O := $(call test_dest_files,$(installed_files_all)) ...@@ -157,6 +175,12 @@ test_make_install_O := $(call test_dest_files,$(installed_files_all))
test_make_install_bin := $(call test_dest_files,$(installed_files_bin)) test_make_install_bin := $(call test_dest_files,$(installed_files_bin))
test_make_install_bin_O := $(call test_dest_files,$(installed_files_bin)) test_make_install_bin_O := $(call test_dest_files,$(installed_files_bin))
# We prefix all installed files for make_install_prefix
# with '/tmp/krava' to match installed/prefix-ed files.
installed_files_all_prefix := $(addprefix /tmp/krava/,$(installed_files_all))
test_make_install_prefix := $(call test_dest_files,$(installed_files_all_prefix))
test_make_install_prefix_O := $(call test_dest_files,$(installed_files_all_prefix))
# FIXME nothing gets installed # FIXME nothing gets installed
test_make_install_man := test -f $$TMP_DEST/share/man/man1/perf.1 test_make_install_man := test -f $$TMP_DEST/share/man/man1/perf.1
test_make_install_man_O := $(test_make_install_man) test_make_install_man_O := $(test_make_install_man)
...@@ -226,13 +250,13 @@ tarpkg: ...@@ -226,13 +250,13 @@ tarpkg:
( eval $$cmd ) >> $@ 2>&1 ( eval $$cmd ) >> $@ 2>&1
make_kernelsrc: make_kernelsrc:
@echo " - make -C <kernelsrc> tools/perf" @echo "- make -C <kernelsrc> tools/perf"
$(call clean); \ $(call clean); \
(make -C ../.. tools/perf) > $@ 2>&1 && \ (make -C ../.. tools/perf) > $@ 2>&1 && \
test -x perf && rm -f $@ || (cat $@ ; false) test -x perf && rm -f $@ || (cat $@ ; false)
make_kernelsrc_tools: make_kernelsrc_tools:
@echo " - make -C <kernelsrc>/tools perf" @echo "- make -C <kernelsrc>/tools perf"
$(call clean); \ $(call clean); \
(make -C ../../tools perf) > $@ 2>&1 && \ (make -C ../../tools perf) > $@ 2>&1 && \
test -x perf && rm -f $@ || (cat $@ ; false) test -x perf && rm -f $@ || (cat $@ ; false)
...@@ -244,3 +268,4 @@ out: $(run_O) ...@@ -244,3 +268,4 @@ out: $(run_O)
@echo OK @echo OK
.PHONY: all $(run) $(run_O) tarpkg clean .PHONY: all $(run) $(run_O) tarpkg clean
endif # ifndef MK
...@@ -140,8 +140,8 @@ int test__basic_mmap(void) ...@@ -140,8 +140,8 @@ int test__basic_mmap(void)
cpus = NULL; cpus = NULL;
threads = NULL; threads = NULL;
out_free_cpus: out_free_cpus:
cpu_map__delete(cpus); cpu_map__put(cpus);
out_free_threads: out_free_threads:
thread_map__delete(threads); thread_map__put(threads);
return err; return err;
} }
...@@ -143,7 +143,7 @@ static int synth_process(struct machine *machine) ...@@ -143,7 +143,7 @@ static int synth_process(struct machine *machine)
perf_event__process, perf_event__process,
machine, 0, 500); machine, 0, 500);
thread_map__delete(map); thread_map__put(map);
return err; return err;
} }
......
...@@ -78,7 +78,7 @@ int test__openat_syscall_event_on_all_cpus(void) ...@@ -78,7 +78,7 @@ int test__openat_syscall_event_on_all_cpus(void)
* we use the auto allocation it will allocate just for 1 cpu, * we use the auto allocation it will allocate just for 1 cpu,
* as we start by cpu 0. * as we start by cpu 0.
*/ */
if (perf_evsel__alloc_counts(evsel, cpus->nr) < 0) { if (perf_evsel__alloc_counts(evsel, cpus->nr, 1) < 0) {
pr_debug("perf_evsel__alloc_counts(ncpus=%d)\n", cpus->nr); pr_debug("perf_evsel__alloc_counts(ncpus=%d)\n", cpus->nr);
goto out_close_fd; goto out_close_fd;
} }
...@@ -98,9 +98,9 @@ int test__openat_syscall_event_on_all_cpus(void) ...@@ -98,9 +98,9 @@ int test__openat_syscall_event_on_all_cpus(void)
} }
expected = nr_openat_calls + cpu; expected = nr_openat_calls + cpu;
if (evsel->counts->cpu[cpu].val != expected) { if (perf_counts(evsel->counts, cpu, 0)->val != expected) {
pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls on cpu %d, got %" PRIu64 "\n", pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls on cpu %d, got %" PRIu64 "\n",
expected, cpus->map[cpu], evsel->counts->cpu[cpu].val); expected, cpus->map[cpu], perf_counts(evsel->counts, cpu, 0)->val);
err = -1; err = -1;
} }
} }
...@@ -111,6 +111,6 @@ int test__openat_syscall_event_on_all_cpus(void) ...@@ -111,6 +111,6 @@ int test__openat_syscall_event_on_all_cpus(void)
out_evsel_delete: out_evsel_delete:
perf_evsel__delete(evsel); perf_evsel__delete(evsel);
out_thread_map_delete: out_thread_map_delete:
thread_map__delete(threads); thread_map__put(threads);
return err; return err;
} }
...@@ -45,7 +45,7 @@ int test__syscall_openat_tp_fields(void) ...@@ -45,7 +45,7 @@ int test__syscall_openat_tp_fields(void)
perf_evsel__config(evsel, &opts); perf_evsel__config(evsel, &opts);
evlist->threads->map[0] = getpid(); thread_map__set_pid(evlist->threads, 0, getpid());
err = perf_evlist__open(evlist); err = perf_evlist__open(evlist);
if (err < 0) { if (err < 0) {
......
...@@ -44,9 +44,9 @@ int test__openat_syscall_event(void) ...@@ -44,9 +44,9 @@ int test__openat_syscall_event(void)
goto out_close_fd; goto out_close_fd;
} }
if (evsel->counts->cpu[0].val != nr_openat_calls) { if (perf_counts(evsel->counts, 0, 0)->val != nr_openat_calls) {
pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls, got %" PRIu64 "\n", pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls, got %" PRIu64 "\n",
nr_openat_calls, evsel->counts->cpu[0].val); nr_openat_calls, perf_counts(evsel->counts, 0, 0)->val);
goto out_close_fd; goto out_close_fd;
} }
...@@ -56,6 +56,6 @@ int test__openat_syscall_event(void) ...@@ -56,6 +56,6 @@ int test__openat_syscall_event(void)
out_evsel_delete: out_evsel_delete:
perf_evsel__delete(evsel); perf_evsel__delete(evsel);
out_thread_map_delete: out_thread_map_delete:
thread_map__delete(threads); thread_map__put(threads);
return err; return err;
} }
...@@ -560,8 +560,8 @@ int test__switch_tracking(void) ...@@ -560,8 +560,8 @@ int test__switch_tracking(void)
perf_evlist__disable(evlist); perf_evlist__disable(evlist);
perf_evlist__delete(evlist); perf_evlist__delete(evlist);
} else { } else {
cpu_map__delete(cpus); cpu_map__put(cpus);
thread_map__delete(threads); thread_map__put(threads);
} }
return err; return err;
......
...@@ -61,6 +61,7 @@ int test__switch_tracking(void); ...@@ -61,6 +61,7 @@ int test__switch_tracking(void);
int test__fdarray__filter(void); int test__fdarray__filter(void);
int test__fdarray__add(void); int test__fdarray__add(void);
int test__kmod_path__parse(void); int test__kmod_path__parse(void);
int test__thread_map(void);
#if defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__) #if defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__)
#ifdef HAVE_DWARF_UNWIND_SUPPORT #ifdef HAVE_DWARF_UNWIND_SUPPORT
......
#include <sys/types.h>
#include <unistd.h>
#include "tests.h"
#include "thread_map.h"
#include "debug.h"
int test__thread_map(void)
{
struct thread_map *map;
/* test map on current pid */
map = thread_map__new_by_pid(getpid());
TEST_ASSERT_VAL("failed to alloc map", map);
thread_map__read_comms(map);
TEST_ASSERT_VAL("wrong nr", map->nr == 1);
TEST_ASSERT_VAL("wrong pid",
thread_map__pid(map, 0) == getpid());
TEST_ASSERT_VAL("wrong comm",
thread_map__comm(map, 0) &&
!strcmp(thread_map__comm(map, 0), "perf"));
thread_map__put(map);
/* test dummy pid */
map = thread_map__new_dummy();
TEST_ASSERT_VAL("failed to alloc map", map);
thread_map__read_comms(map);
TEST_ASSERT_VAL("wrong nr", map->nr == 1);
TEST_ASSERT_VAL("wrong pid", thread_map__pid(map, 0) == -1);
TEST_ASSERT_VAL("wrong comm",
thread_map__comm(map, 0) &&
!strcmp(thread_map__comm(map, 0), "dummy"));
thread_map__put(map);
return 0;
}
...@@ -1902,8 +1902,23 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, ...@@ -1902,8 +1902,23 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
case CTRL('c'): case CTRL('c'):
goto out_free_stack; goto out_free_stack;
case 'f': case 'f':
if (!is_report_browser(hbt)) if (!is_report_browser(hbt)) {
goto out_free_stack; struct perf_top *top = hbt->arg;
perf_evlist__toggle_enable(top->evlist);
/*
* No need to refresh, resort/decay histogram
* entries if we are not collecting samples:
*/
if (top->evlist->enabled) {
helpline = "Press 'f' to disable the events or 'h' to see other hotkeys";
hbt->refresh = delay_secs;
} else {
helpline = "Press 'f' again to re-enable the events";
hbt->refresh = 0;
}
continue;
}
/* Fall thru */ /* Fall thru */
default: default:
helpline = "Press '?' for help on key bindings"; helpline = "Press '?' for help on key bindings";
......
...@@ -119,12 +119,12 @@ void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp, ...@@ -119,12 +119,12 @@ void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp,
if (per_cpu) { if (per_cpu) {
mp->cpu = evlist->cpus->map[idx]; mp->cpu = evlist->cpus->map[idx];
if (evlist->threads) if (evlist->threads)
mp->tid = evlist->threads->map[0]; mp->tid = thread_map__pid(evlist->threads, 0);
else else
mp->tid = -1; mp->tid = -1;
} else { } else {
mp->cpu = -1; mp->cpu = -1;
mp->tid = evlist->threads->map[idx]; mp->tid = thread_map__pid(evlist->threads, idx);
} }
} }
...@@ -1182,6 +1182,13 @@ static int __auxtrace_mmap__read(struct auxtrace_mmap *mm, ...@@ -1182,6 +1182,13 @@ static int __auxtrace_mmap__read(struct auxtrace_mmap *mm,
data2 = NULL; data2 = NULL;
} }
if (itr->alignment) {
unsigned int unwanted = len1 % itr->alignment;
len1 -= unwanted;
size -= unwanted;
}
/* padding must be written by fn() e.g. record__process_auxtrace() */ /* padding must be written by fn() e.g. record__process_auxtrace() */
padding = size & 7; padding = size & 7;
if (padding) if (padding)
......
...@@ -303,6 +303,7 @@ struct auxtrace_record { ...@@ -303,6 +303,7 @@ struct auxtrace_record {
const char *str); const char *str);
u64 (*reference)(struct auxtrace_record *itr); u64 (*reference)(struct auxtrace_record *itr);
int (*read_finish)(struct auxtrace_record *itr, int idx); int (*read_finish)(struct auxtrace_record *itr, int idx);
unsigned int alignment;
}; };
#ifdef HAVE_AUXTRACE_SUPPORT #ifdef HAVE_AUXTRACE_SUPPORT
......
...@@ -7,11 +7,15 @@ ...@@ -7,11 +7,15 @@
static unsigned long flag = PERF_FLAG_FD_CLOEXEC; static unsigned long flag = PERF_FLAG_FD_CLOEXEC;
#ifdef __GLIBC_PREREQ
#if !__GLIBC_PREREQ(2, 6)
int __weak sched_getcpu(void) int __weak sched_getcpu(void)
{ {
errno = ENOSYS; errno = ENOSYS;
return -1; return -1;
} }
#endif
#endif
static int perf_flag_probe(void) static int perf_flag_probe(void)
{ {
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include <assert.h> #include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include "asm/bug.h"
static struct cpu_map *cpu_map__default_new(void) static struct cpu_map *cpu_map__default_new(void)
{ {
...@@ -22,6 +23,7 @@ static struct cpu_map *cpu_map__default_new(void) ...@@ -22,6 +23,7 @@ static struct cpu_map *cpu_map__default_new(void)
cpus->map[i] = i; cpus->map[i] = i;
cpus->nr = nr_cpus; cpus->nr = nr_cpus;
atomic_set(&cpus->refcnt, 1);
} }
return cpus; return cpus;
...@@ -35,6 +37,7 @@ static struct cpu_map *cpu_map__trim_new(int nr_cpus, int *tmp_cpus) ...@@ -35,6 +37,7 @@ static struct cpu_map *cpu_map__trim_new(int nr_cpus, int *tmp_cpus)
if (cpus != NULL) { if (cpus != NULL) {
cpus->nr = nr_cpus; cpus->nr = nr_cpus;
memcpy(cpus->map, tmp_cpus, payload_size); memcpy(cpus->map, tmp_cpus, payload_size);
atomic_set(&cpus->refcnt, 1);
} }
return cpus; return cpus;
...@@ -194,14 +197,32 @@ struct cpu_map *cpu_map__dummy_new(void) ...@@ -194,14 +197,32 @@ struct cpu_map *cpu_map__dummy_new(void)
if (cpus != NULL) { if (cpus != NULL) {
cpus->nr = 1; cpus->nr = 1;
cpus->map[0] = -1; cpus->map[0] = -1;
atomic_set(&cpus->refcnt, 1);
} }
return cpus; return cpus;
} }
void cpu_map__delete(struct cpu_map *map) static void cpu_map__delete(struct cpu_map *map)
{ {
free(map); if (map) {
WARN_ONCE(atomic_read(&map->refcnt) != 0,
"cpu_map refcnt unbalanced\n");
free(map);
}
}
struct cpu_map *cpu_map__get(struct cpu_map *map)
{
if (map)
atomic_inc(&map->refcnt);
return map;
}
void cpu_map__put(struct cpu_map *map)
{
if (map && atomic_dec_and_test(&map->refcnt))
cpu_map__delete(map);
} }
int cpu_map__get_socket(struct cpu_map *map, int idx) int cpu_map__get_socket(struct cpu_map *map, int idx)
...@@ -263,6 +284,7 @@ static int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res, ...@@ -263,6 +284,7 @@ static int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res,
/* ensure we process id in increasing order */ /* ensure we process id in increasing order */
qsort(c->map, c->nr, sizeof(int), cmp_ids); qsort(c->map, c->nr, sizeof(int), cmp_ids);
atomic_set(&cpus->refcnt, 1);
*res = c; *res = c;
return 0; return 0;
} }
......
...@@ -3,18 +3,19 @@ ...@@ -3,18 +3,19 @@
#include <stdio.h> #include <stdio.h>
#include <stdbool.h> #include <stdbool.h>
#include <linux/atomic.h>
#include "perf.h" #include "perf.h"
#include "util/debug.h" #include "util/debug.h"
struct cpu_map { struct cpu_map {
atomic_t refcnt;
int nr; int nr;
int map[]; int map[];
}; };
struct cpu_map *cpu_map__new(const char *cpu_list); struct cpu_map *cpu_map__new(const char *cpu_list);
struct cpu_map *cpu_map__dummy_new(void); struct cpu_map *cpu_map__dummy_new(void);
void cpu_map__delete(struct cpu_map *map);
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__get_socket(struct cpu_map *map, int idx);
...@@ -22,6 +23,9 @@ int cpu_map__get_core(struct cpu_map *map, int idx); ...@@ -22,6 +23,9 @@ int cpu_map__get_core(struct cpu_map *map, int idx);
int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp); int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp);
int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep); int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep);
struct cpu_map *cpu_map__get(struct cpu_map *map);
void cpu_map__put(struct cpu_map *map);
static inline int cpu_map__socket(struct cpu_map *sock, int s) static inline int cpu_map__socket(struct cpu_map *sock, int s)
{ {
if (!sock || s > sock->nr || s < 0) if (!sock || s > sock->nr || s < 0)
......
...@@ -504,7 +504,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool, ...@@ -504,7 +504,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
for (thread = 0; thread < threads->nr; ++thread) { for (thread = 0; thread < threads->nr; ++thread) {
if (__event__synthesize_thread(comm_event, mmap_event, if (__event__synthesize_thread(comm_event, mmap_event,
fork_event, fork_event,
threads->map[thread], 0, thread_map__pid(threads, thread), 0,
process, tool, machine, process, tool, machine,
mmap_data, proc_map_timeout)) { mmap_data, proc_map_timeout)) {
err = -1; err = -1;
...@@ -515,12 +515,12 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool, ...@@ -515,12 +515,12 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
* comm.pid is set to thread group id by * comm.pid is set to thread group id by
* perf_event__synthesize_comm * perf_event__synthesize_comm
*/ */
if ((int) comm_event->comm.pid != threads->map[thread]) { if ((int) comm_event->comm.pid != thread_map__pid(threads, thread)) {
bool need_leader = true; bool need_leader = true;
/* is thread group leader in thread_map? */ /* is thread group leader in thread_map? */
for (j = 0; j < threads->nr; ++j) { for (j = 0; j < threads->nr; ++j) {
if ((int) comm_event->comm.pid == threads->map[j]) { if ((int) comm_event->comm.pid == thread_map__pid(threads, j)) {
need_leader = false; need_leader = false;
break; break;
} }
......
...@@ -114,8 +114,8 @@ void perf_evlist__delete(struct perf_evlist *evlist) ...@@ -114,8 +114,8 @@ void perf_evlist__delete(struct perf_evlist *evlist)
{ {
perf_evlist__munmap(evlist); perf_evlist__munmap(evlist);
perf_evlist__close(evlist); perf_evlist__close(evlist);
cpu_map__delete(evlist->cpus); cpu_map__put(evlist->cpus);
thread_map__delete(evlist->threads); thread_map__put(evlist->threads);
evlist->cpus = NULL; evlist->cpus = NULL;
evlist->threads = NULL; evlist->threads = NULL;
perf_evlist__purge(evlist); perf_evlist__purge(evlist);
...@@ -548,7 +548,7 @@ static void perf_evlist__set_sid_idx(struct perf_evlist *evlist, ...@@ -548,7 +548,7 @@ static void perf_evlist__set_sid_idx(struct perf_evlist *evlist,
else else
sid->cpu = -1; sid->cpu = -1;
if (!evsel->system_wide && evlist->threads && thread >= 0) if (!evsel->system_wide && evlist->threads && thread >= 0)
sid->tid = evlist->threads->map[thread]; sid->tid = thread_map__pid(evlist->threads, thread);
else else
sid->tid = -1; sid->tid = -1;
} }
...@@ -1101,6 +1101,31 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, ...@@ -1101,6 +1101,31 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
return perf_evlist__mmap_ex(evlist, pages, overwrite, 0, false); return perf_evlist__mmap_ex(evlist, pages, overwrite, 0, false);
} }
static int perf_evlist__propagate_maps(struct perf_evlist *evlist,
struct target *target)
{
struct perf_evsel *evsel;
evlist__for_each(evlist, evsel) {
/*
* We already have cpus for evsel (via PMU sysfs) so
* keep it, if there's no target cpu list defined.
*/
if (evsel->cpus && target->cpu_list)
cpu_map__put(evsel->cpus);
if (!evsel->cpus || target->cpu_list)
evsel->cpus = cpu_map__get(evlist->cpus);
evsel->threads = thread_map__get(evlist->threads);
if (!evsel->cpus || !evsel->threads)
return -ENOMEM;
}
return 0;
}
int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target) int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target)
{ {
evlist->threads = thread_map__new_str(target->pid, target->tid, evlist->threads = thread_map__new_str(target->pid, target->tid,
...@@ -1117,10 +1142,10 @@ int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target) ...@@ -1117,10 +1142,10 @@ int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target)
if (evlist->cpus == NULL) if (evlist->cpus == NULL)
goto out_delete_threads; goto out_delete_threads;
return 0; return perf_evlist__propagate_maps(evlist, target);
out_delete_threads: out_delete_threads:
thread_map__delete(evlist->threads); thread_map__put(evlist->threads);
evlist->threads = NULL; evlist->threads = NULL;
return -1; return -1;
} }
...@@ -1353,7 +1378,7 @@ static int perf_evlist__create_syswide_maps(struct perf_evlist *evlist) ...@@ -1353,7 +1378,7 @@ static int perf_evlist__create_syswide_maps(struct perf_evlist *evlist)
out: out:
return err; return err;
out_free_cpus: out_free_cpus:
cpu_map__delete(evlist->cpus); cpu_map__put(evlist->cpus);
evlist->cpus = NULL; evlist->cpus = NULL;
goto out; goto out;
} }
...@@ -1475,7 +1500,7 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *tar ...@@ -1475,7 +1500,7 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *tar
__func__, __LINE__); __func__, __LINE__);
goto out_close_pipes; goto out_close_pipes;
} }
evlist->threads->map[0] = evlist->workload.pid; thread_map__set_pid(evlist->threads, 0, evlist->workload.pid);
} }
close(child_ready_pipe[1]); close(child_ready_pipe[1]);
......
...@@ -289,5 +289,4 @@ void perf_evlist__to_front(struct perf_evlist *evlist, ...@@ -289,5 +289,4 @@ void perf_evlist__to_front(struct perf_evlist *evlist,
void perf_evlist__set_tracking_event(struct perf_evlist *evlist, void perf_evlist__set_tracking_event(struct perf_evlist *evlist,
struct perf_evsel *tracking_evsel); struct perf_evsel *tracking_evsel);
#endif /* __PERF_EVLIST_H */ #endif /* __PERF_EVLIST_H */
...@@ -885,6 +885,8 @@ void perf_evsel__exit(struct perf_evsel *evsel) ...@@ -885,6 +885,8 @@ void perf_evsel__exit(struct perf_evsel *evsel)
perf_evsel__free_fd(evsel); perf_evsel__free_fd(evsel);
perf_evsel__free_id(evsel); perf_evsel__free_id(evsel);
close_cgroup(evsel->cgrp); close_cgroup(evsel->cgrp);
cpu_map__put(evsel->cpus);
thread_map__put(evsel->threads);
zfree(&evsel->group_name); zfree(&evsel->group_name);
zfree(&evsel->name); zfree(&evsel->name);
perf_evsel__object.fini(evsel); perf_evsel__object.fini(evsel);
...@@ -896,7 +898,7 @@ void perf_evsel__delete(struct perf_evsel *evsel) ...@@ -896,7 +898,7 @@ void perf_evsel__delete(struct perf_evsel *evsel)
free(evsel); free(evsel);
} }
void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu, void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu, int thread,
struct perf_counts_values *count) struct perf_counts_values *count)
{ {
struct perf_counts_values tmp; struct perf_counts_values tmp;
...@@ -908,8 +910,8 @@ void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu, ...@@ -908,8 +910,8 @@ void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu,
tmp = evsel->prev_raw_counts->aggr; tmp = evsel->prev_raw_counts->aggr;
evsel->prev_raw_counts->aggr = *count; evsel->prev_raw_counts->aggr = *count;
} else { } else {
tmp = evsel->prev_raw_counts->cpu[cpu]; tmp = *perf_counts(evsel->prev_raw_counts, cpu, thread);
evsel->prev_raw_counts->cpu[cpu] = *count; *perf_counts(evsel->prev_raw_counts, cpu, thread) = *count;
} }
count->val = count->val - tmp.val; count->val = count->val - tmp.val;
...@@ -937,20 +939,18 @@ void perf_counts_values__scale(struct perf_counts_values *count, ...@@ -937,20 +939,18 @@ void perf_counts_values__scale(struct perf_counts_values *count,
*pscaled = scaled; *pscaled = scaled;
} }
int perf_evsel__read_cb(struct perf_evsel *evsel, int cpu, int thread, int perf_evsel__read(struct perf_evsel *evsel, int cpu, int thread,
perf_evsel__read_cb_t cb) struct perf_counts_values *count)
{ {
struct perf_counts_values count; memset(count, 0, sizeof(*count));
memset(&count, 0, sizeof(count));
if (FD(evsel, cpu, thread) < 0) if (FD(evsel, cpu, thread) < 0)
return -EINVAL; return -EINVAL;
if (readn(FD(evsel, cpu, thread), &count, sizeof(count)) < 0) if (readn(FD(evsel, cpu, thread), count, sizeof(*count)) < 0)
return -errno; return -errno;
return cb(evsel, cpu, thread, &count); return 0;
} }
int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
...@@ -962,15 +962,15 @@ int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, ...@@ -962,15 +962,15 @@ int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
if (FD(evsel, cpu, thread) < 0) if (FD(evsel, cpu, thread) < 0)
return -EINVAL; return -EINVAL;
if (evsel->counts == NULL && perf_evsel__alloc_counts(evsel, cpu + 1) < 0) if (evsel->counts == NULL && perf_evsel__alloc_counts(evsel, cpu + 1, thread + 1) < 0)
return -ENOMEM; return -ENOMEM;
if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0) if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0)
return -errno; return -errno;
perf_evsel__compute_deltas(evsel, cpu, &count); perf_evsel__compute_deltas(evsel, cpu, thread, &count);
perf_counts_values__scale(&count, scale, NULL); perf_counts_values__scale(&count, scale, NULL);
evsel->counts->cpu[cpu] = count; *perf_counts(evsel->counts, cpu, thread) = count;
return 0; return 0;
} }
...@@ -1167,7 +1167,7 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, ...@@ -1167,7 +1167,7 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
int group_fd; int group_fd;
if (!evsel->cgrp && !evsel->system_wide) if (!evsel->cgrp && !evsel->system_wide)
pid = threads->map[thread]; pid = thread_map__pid(threads, thread);
group_fd = get_group_fd(evsel, cpu, thread); group_fd = get_group_fd(evsel, cpu, thread);
retry_open: retry_open:
......
...@@ -8,23 +8,8 @@ ...@@ -8,23 +8,8 @@
#include <linux/types.h> #include <linux/types.h>
#include "xyarray.h" #include "xyarray.h"
#include "symbol.h" #include "symbol.h"
#include "cpumap.h"
struct perf_counts_values { #include "stat.h"
union {
struct {
u64 val;
u64 ena;
u64 run;
};
u64 values[3];
};
};
struct perf_counts {
s8 scaled;
struct perf_counts_values aggr;
struct perf_counts_values cpu[];
};
struct perf_evsel; struct perf_evsel;
...@@ -82,6 +67,7 @@ struct perf_evsel { ...@@ -82,6 +67,7 @@ struct perf_evsel {
struct cgroup_sel *cgrp; struct cgroup_sel *cgrp;
void *handler; void *handler;
struct cpu_map *cpus; struct cpu_map *cpus;
struct thread_map *threads;
unsigned int sample_size; unsigned int sample_size;
int id_pos; int id_pos;
int is_pos; int is_pos;
...@@ -113,10 +99,20 @@ struct thread_map; ...@@ -113,10 +99,20 @@ struct thread_map;
struct perf_evlist; struct perf_evlist;
struct record_opts; struct record_opts;
static inline struct cpu_map *perf_evsel__cpus(struct perf_evsel *evsel)
{
return evsel->cpus;
}
static inline int perf_evsel__nr_cpus(struct perf_evsel *evsel)
{
return perf_evsel__cpus(evsel)->nr;
}
void perf_counts_values__scale(struct perf_counts_values *count, void perf_counts_values__scale(struct perf_counts_values *count,
bool scale, s8 *pscaled); bool scale, s8 *pscaled);
void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu, void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu, int thread,
struct perf_counts_values *count); struct perf_counts_values *count);
int perf_evsel__object_config(size_t object_size, int perf_evsel__object_config(size_t object_size,
...@@ -233,12 +229,8 @@ static inline bool perf_evsel__match2(struct perf_evsel *e1, ...@@ -233,12 +229,8 @@ static inline bool perf_evsel__match2(struct perf_evsel *e1,
(a)->attr.type == (b)->attr.type && \ (a)->attr.type == (b)->attr.type && \
(a)->attr.config == (b)->attr.config) (a)->attr.config == (b)->attr.config)
typedef int (perf_evsel__read_cb_t)(struct perf_evsel *evsel, int perf_evsel__read(struct perf_evsel *evsel, int cpu, int thread,
int cpu, int thread, struct perf_counts_values *count);
struct perf_counts_values *count);
int perf_evsel__read_cb(struct perf_evsel *evsel, int cpu, int thread,
perf_evsel__read_cb_t cb);
int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
int cpu, int thread, bool scale); int cpu, int thread, bool scale);
......
...@@ -1063,8 +1063,7 @@ read_event_desc(struct perf_header *ph, int fd) ...@@ -1063,8 +1063,7 @@ read_event_desc(struct perf_header *ph, int fd)
free(buf); free(buf);
return events; return events;
error: error:
if (events) free_event_desc(events);
free_event_desc(events);
events = NULL; events = NULL;
goto out; goto out;
} }
......
...@@ -1448,10 +1448,9 @@ int machine__process_event(struct machine *machine, union perf_event *event, ...@@ -1448,10 +1448,9 @@ int machine__process_event(struct machine *machine, union perf_event *event,
case PERF_RECORD_AUX: case PERF_RECORD_AUX:
ret = machine__process_aux_event(machine, event); break; ret = machine__process_aux_event(machine, event); break;
case PERF_RECORD_ITRACE_START: case PERF_RECORD_ITRACE_START:
ret = machine__process_itrace_start_event(machine, event); ret = machine__process_itrace_start_event(machine, event); break;
case PERF_RECORD_LOST_SAMPLES: case PERF_RECORD_LOST_SAMPLES:
ret = machine__process_lost_samples_event(machine, event, sample); break; ret = machine__process_lost_samples_event(machine, event, sample); break;
break;
default: default:
ret = -1; ret = -1;
break; break;
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "parse-events-flex.h" #include "parse-events-flex.h"
#include "pmu.h" #include "pmu.h"
#include "thread_map.h" #include "thread_map.h"
#include "cpumap.h"
#include "asm/bug.h" #include "asm/bug.h"
#define MAX_NAME_LEN 100 #define MAX_NAME_LEN 100
...@@ -285,7 +286,9 @@ __add_event(struct list_head *list, int *idx, ...@@ -285,7 +286,9 @@ __add_event(struct list_head *list, int *idx,
if (!evsel) if (!evsel)
return NULL; return NULL;
evsel->cpus = cpus; if (cpus)
evsel->cpus = cpu_map__get(cpus);
if (name) if (name)
evsel->name = strdup(name); evsel->name = strdup(name);
list_add_tail(&evsel->node, list); list_add_tail(&evsel->node, list);
......
...@@ -119,8 +119,8 @@ event [^,{}/]+ ...@@ -119,8 +119,8 @@ event [^,{}/]+
num_dec [0-9]+ num_dec [0-9]+
num_hex 0x[a-fA-F0-9]+ num_hex 0x[a-fA-F0-9]+
num_raw_hex [a-fA-F0-9]+ num_raw_hex [a-fA-F0-9]+
name [a-zA-Z_*?][a-zA-Z0-9_*?]* name [a-zA-Z_*?][a-zA-Z0-9_*?.]*
name_minus [a-zA-Z_*?][a-zA-Z0-9\-_*?]* name_minus [a-zA-Z_*?][a-zA-Z0-9\-_*?.]*
/* If you add a modifier you need to update check_modifier() */ /* If you add a modifier you need to update check_modifier() */
modifier_event [ukhpGHSDI]+ modifier_event [ukhpGHSDI]+
modifier_bp [rwx]{1,3} modifier_bp [rwx]{1,3}
...@@ -165,7 +165,6 @@ modifier_bp [rwx]{1,3} ...@@ -165,7 +165,6 @@ modifier_bp [rwx]{1,3}
return PE_EVENT_NAME; return PE_EVENT_NAME;
} }
. |
<<EOF>> { <<EOF>> {
BEGIN(INITIAL); BEGIN(INITIAL);
REWIND(0); REWIND(0);
......
#include <linux/list.h> #include <linux/list.h>
#include <linux/compiler.h>
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include <stdio.h> #include <stdio.h>
...@@ -205,17 +206,12 @@ static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias, ...@@ -205,17 +206,12 @@ static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias,
return 0; return 0;
} }
static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file) static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
char *desc __maybe_unused, char *val)
{ {
struct perf_pmu_alias *alias; struct perf_pmu_alias *alias;
char buf[256];
int ret; int ret;
ret = fread(buf, 1, sizeof(buf), file);
if (ret == 0)
return -EINVAL;
buf[ret] = 0;
alias = malloc(sizeof(*alias)); alias = malloc(sizeof(*alias));
if (!alias) if (!alias)
return -ENOMEM; return -ENOMEM;
...@@ -225,26 +221,43 @@ static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FI ...@@ -225,26 +221,43 @@ static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FI
alias->unit[0] = '\0'; alias->unit[0] = '\0';
alias->per_pkg = false; alias->per_pkg = false;
ret = parse_events_terms(&alias->terms, buf); ret = parse_events_terms(&alias->terms, val);
if (ret) { if (ret) {
pr_err("Cannot parse alias %s: %d\n", val, ret);
free(alias); free(alias);
return ret; return ret;
} }
alias->name = strdup(name); alias->name = strdup(name);
/* if (dir) {
* load unit name and scale if available /*
*/ * load unit name and scale if available
perf_pmu__parse_unit(alias, dir, name); */
perf_pmu__parse_scale(alias, dir, name); perf_pmu__parse_unit(alias, dir, name);
perf_pmu__parse_per_pkg(alias, dir, name); perf_pmu__parse_scale(alias, dir, name);
perf_pmu__parse_snapshot(alias, dir, name); perf_pmu__parse_per_pkg(alias, dir, name);
perf_pmu__parse_snapshot(alias, dir, name);
}
list_add_tail(&alias->list, list); list_add_tail(&alias->list, list);
return 0; return 0;
} }
static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file)
{
char buf[256];
int ret;
ret = fread(buf, 1, sizeof(buf), file);
if (ret == 0)
return -EINVAL;
buf[ret] = 0;
return __perf_pmu__new_alias(list, dir, name, NULL, buf);
}
static inline bool pmu_alias_info_file(char *name) static inline bool pmu_alias_info_file(char *name)
{ {
size_t len; size_t len;
...@@ -436,7 +449,7 @@ static struct cpu_map *pmu_cpumask(const char *name) ...@@ -436,7 +449,7 @@ static struct cpu_map *pmu_cpumask(const char *name)
return cpus; return cpus;
} }
struct perf_event_attr *__attribute__((weak)) struct perf_event_attr * __weak
perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused)
{ {
return NULL; return NULL;
......
...@@ -249,8 +249,12 @@ static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs) ...@@ -249,8 +249,12 @@ static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
static bool kprobe_blacklist__listed(unsigned long address); static bool kprobe_blacklist__listed(unsigned long address);
static bool kprobe_warn_out_range(const char *symbol, unsigned long address) static bool kprobe_warn_out_range(const char *symbol, unsigned long address)
{ {
u64 etext_addr;
/* Get the address of _etext for checking non-probable text symbol */ /* Get the address of _etext for checking non-probable text symbol */
if (kernel_get_symbol_address_by_name("_etext", false) < address) etext_addr = kernel_get_symbol_address_by_name("_etext", false);
if (etext_addr != 0 && etext_addr < address)
pr_warning("%s is out of .text, skip it.\n", symbol); pr_warning("%s is out of .text, skip it.\n", symbol);
else if (kprobe_blacklist__listed(address)) else if (kprobe_blacklist__listed(address))
pr_warning("%s is blacklisted function, skip it.\n", symbol); pr_warning("%s is blacklisted function, skip it.\n", symbol);
......
...@@ -20,3 +20,4 @@ util/stat.c ...@@ -20,3 +20,4 @@ util/stat.c
util/strlist.c util/strlist.c
util/trace-event.c util/trace-event.c
../../lib/rbtree.c ../../lib/rbtree.c
util/string.c
...@@ -384,7 +384,7 @@ static int pyrf_cpu_map__init(struct pyrf_cpu_map *pcpus, ...@@ -384,7 +384,7 @@ static int pyrf_cpu_map__init(struct pyrf_cpu_map *pcpus,
static void pyrf_cpu_map__delete(struct pyrf_cpu_map *pcpus) static void pyrf_cpu_map__delete(struct pyrf_cpu_map *pcpus)
{ {
cpu_map__delete(pcpus->cpus); cpu_map__put(pcpus->cpus);
pcpus->ob_type->tp_free((PyObject*)pcpus); pcpus->ob_type->tp_free((PyObject*)pcpus);
} }
...@@ -453,7 +453,7 @@ static int pyrf_thread_map__init(struct pyrf_thread_map *pthreads, ...@@ -453,7 +453,7 @@ static int pyrf_thread_map__init(struct pyrf_thread_map *pthreads,
static void pyrf_thread_map__delete(struct pyrf_thread_map *pthreads) static void pyrf_thread_map__delete(struct pyrf_thread_map *pthreads)
{ {
thread_map__delete(pthreads->threads); thread_map__put(pthreads->threads);
pthreads->ob_type->tp_free((PyObject*)pthreads); pthreads->ob_type->tp_free((PyObject*)pthreads);
} }
......
...@@ -64,7 +64,7 @@ static bool perf_probe_api(setup_probe_fn_t fn) ...@@ -64,7 +64,7 @@ static bool perf_probe_api(setup_probe_fn_t fn)
if (!cpus) if (!cpus)
return false; return false;
cpu = cpus->map[0]; cpu = cpus->map[0];
cpu_map__delete(cpus); cpu_map__put(cpus);
do { do {
ret = perf_do_probe_api(fn, cpu, try[i++]); ret = perf_do_probe_api(fn, cpu, try[i++]);
...@@ -226,7 +226,7 @@ bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str) ...@@ -226,7 +226,7 @@ bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str)
struct cpu_map *cpus = cpu_map__new(NULL); struct cpu_map *cpus = cpu_map__new(NULL);
cpu = cpus ? cpus->map[0] : 0; cpu = cpus ? cpus->map[0] : 0;
cpu_map__delete(cpus); cpu_map__put(cpus);
} else { } else {
cpu = evlist->cpus->map[0]; cpu = evlist->cpus->map[0];
} }
......
...@@ -686,6 +686,8 @@ static int process_finished_round(struct perf_tool *tool __maybe_unused, ...@@ -686,6 +686,8 @@ static int process_finished_round(struct perf_tool *tool __maybe_unused,
union perf_event *event __maybe_unused, union perf_event *event __maybe_unused,
struct ordered_events *oe) struct ordered_events *oe)
{ {
if (dump_trace)
fprintf(stdout, "\n");
return ordered_events__flush(oe, OE_FLUSH__ROUND); return ordered_events__flush(oe, OE_FLUSH__ROUND);
} }
...@@ -1726,7 +1728,7 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) ...@@ -1726,7 +1728,7 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
if (perf_header__has_feat(&session->header, HEADER_AUXTRACE)) if (perf_header__has_feat(&session->header, HEADER_AUXTRACE))
msg = " (excludes AUX area (e.g. instruction trace) decoded / synthesized events)"; msg = " (excludes AUX area (e.g. instruction trace) decoded / synthesized events)";
ret = fprintf(fp, "Aggregated stats:%s\n", msg); ret = fprintf(fp, "\nAggregated stats:%s\n", msg);
ret += events_stats__fprintf(&session->evlist->stats, fp); ret += events_stats__fprintf(&session->evlist->stats, fp);
return ret; return ret;
...@@ -1893,7 +1895,7 @@ int perf_session__cpu_bitmap(struct perf_session *session, ...@@ -1893,7 +1895,7 @@ int perf_session__cpu_bitmap(struct perf_session *session,
err = 0; err = 0;
out_delete_map: out_delete_map:
cpu_map__delete(map); cpu_map__put(map);
return err; return err;
} }
......
#include <math.h> #include <math.h>
#include "stat.h" #include "stat.h"
#include "evlist.h"
#include "evsel.h" #include "evsel.h"
#include "thread_map.h"
void update_stats(struct stats *stats, u64 val) void update_stats(struct stats *stats, u64 val)
{ {
...@@ -95,33 +97,46 @@ void perf_stat_evsel_id_init(struct perf_evsel *evsel) ...@@ -95,33 +97,46 @@ void perf_stat_evsel_id_init(struct perf_evsel *evsel)
} }
} }
struct perf_counts *perf_counts__new(int ncpus) struct perf_counts *perf_counts__new(int ncpus, int nthreads)
{ {
int size = sizeof(struct perf_counts) + struct perf_counts *counts = zalloc(sizeof(*counts));
ncpus * sizeof(struct perf_counts_values);
return zalloc(size); if (counts) {
struct xyarray *values;
values = xyarray__new(ncpus, nthreads, sizeof(struct perf_counts_values));
if (!values) {
free(counts);
return NULL;
}
counts->values = values;
}
return counts;
} }
void perf_counts__delete(struct perf_counts *counts) void perf_counts__delete(struct perf_counts *counts)
{ {
free(counts); if (counts) {
xyarray__delete(counts->values);
free(counts);
}
} }
static void perf_counts__reset(struct perf_counts *counts, int ncpus) static void perf_counts__reset(struct perf_counts *counts)
{ {
memset(counts, 0, (sizeof(*counts) + xyarray__reset(counts->values);
(ncpus * sizeof(struct perf_counts_values))));
} }
void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus) void perf_evsel__reset_counts(struct perf_evsel *evsel)
{ {
perf_counts__reset(evsel->counts, ncpus); perf_counts__reset(evsel->counts);
} }
int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus) int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus, int nthreads)
{ {
evsel->counts = perf_counts__new(ncpus); evsel->counts = perf_counts__new(ncpus, nthreads);
return evsel->counts != NULL ? 0 : -ENOMEM; return evsel->counts != NULL ? 0 : -ENOMEM;
} }
...@@ -130,3 +145,96 @@ void perf_evsel__free_counts(struct perf_evsel *evsel) ...@@ -130,3 +145,96 @@ void perf_evsel__free_counts(struct perf_evsel *evsel)
perf_counts__delete(evsel->counts); perf_counts__delete(evsel->counts);
evsel->counts = NULL; evsel->counts = NULL;
} }
void perf_evsel__reset_stat_priv(struct perf_evsel *evsel)
{
int i;
struct perf_stat *ps = evsel->priv;
for (i = 0; i < 3; i++)
init_stats(&ps->res_stats[i]);
perf_stat_evsel_id_init(evsel);
}
int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel)
{
evsel->priv = zalloc(sizeof(struct perf_stat));
if (evsel->priv == NULL)
return -ENOMEM;
perf_evsel__reset_stat_priv(evsel);
return 0;
}
void perf_evsel__free_stat_priv(struct perf_evsel *evsel)
{
zfree(&evsel->priv);
}
int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel,
int ncpus, int nthreads)
{
struct perf_counts *counts;
counts = perf_counts__new(ncpus, nthreads);
if (counts)
evsel->prev_raw_counts = counts;
return counts ? 0 : -ENOMEM;
}
void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel)
{
perf_counts__delete(evsel->prev_raw_counts);
evsel->prev_raw_counts = NULL;
}
int perf_evsel__alloc_stats(struct perf_evsel *evsel, bool alloc_raw)
{
int ncpus = perf_evsel__nr_cpus(evsel);
int nthreads = thread_map__nr(evsel->threads);
if (perf_evsel__alloc_stat_priv(evsel) < 0 ||
perf_evsel__alloc_counts(evsel, ncpus, nthreads) < 0 ||
(alloc_raw && perf_evsel__alloc_prev_raw_counts(evsel, ncpus, nthreads) < 0))
return -ENOMEM;
return 0;
}
int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw)
{
struct perf_evsel *evsel;
evlist__for_each(evlist, evsel) {
if (perf_evsel__alloc_stats(evsel, alloc_raw))
goto out_free;
}
return 0;
out_free:
perf_evlist__free_stats(evlist);
return -1;
}
void perf_evlist__free_stats(struct perf_evlist *evlist)
{
struct perf_evsel *evsel;
evlist__for_each(evlist, evsel) {
perf_evsel__free_stat_priv(evsel);
perf_evsel__free_counts(evsel);
perf_evsel__free_prev_raw_counts(evsel);
}
}
void perf_evlist__reset_stats(struct perf_evlist *evlist)
{
struct perf_evsel *evsel;
evlist__for_each(evlist, evsel) {
perf_evsel__reset_stat_priv(evsel);
perf_evsel__reset_counts(evsel);
}
}
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <stdio.h> #include <stdio.h>
#include "xyarray.h"
struct stats struct stats
{ {
...@@ -29,8 +30,32 @@ enum aggr_mode { ...@@ -29,8 +30,32 @@ enum aggr_mode {
AGGR_GLOBAL, AGGR_GLOBAL,
AGGR_SOCKET, AGGR_SOCKET,
AGGR_CORE, AGGR_CORE,
AGGR_THREAD,
}; };
struct perf_counts_values {
union {
struct {
u64 val;
u64 ena;
u64 run;
};
u64 values[3];
};
};
struct perf_counts {
s8 scaled;
struct perf_counts_values aggr;
struct xyarray *values;
};
static inline struct perf_counts_values*
perf_counts(struct perf_counts *counts, int cpu, int thread)
{
return xyarray__entry(counts->values, cpu, thread);
}
void update_stats(struct stats *stats, u64 val); void update_stats(struct stats *stats, u64 val);
double avg_stats(struct stats *stats); double avg_stats(struct stats *stats);
double stddev_stats(struct stats *stats); double stddev_stats(struct stats *stats);
...@@ -46,6 +71,8 @@ static inline void init_stats(struct stats *stats) ...@@ -46,6 +71,8 @@ static inline void init_stats(struct stats *stats)
} }
struct perf_evsel; struct perf_evsel;
struct perf_evlist;
bool __perf_evsel_stat__is(struct perf_evsel *evsel, bool __perf_evsel_stat__is(struct perf_evsel *evsel,
enum perf_stat_evsel_id id); enum perf_stat_evsel_id id);
...@@ -62,10 +89,24 @@ void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 *count, ...@@ -62,10 +89,24 @@ void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 *count,
void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel, void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel,
double avg, int cpu, enum aggr_mode aggr); double avg, int cpu, enum aggr_mode aggr);
struct perf_counts *perf_counts__new(int ncpus); struct perf_counts *perf_counts__new(int ncpus, int nthreads);
void perf_counts__delete(struct perf_counts *counts); void perf_counts__delete(struct perf_counts *counts);
void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus); void perf_evsel__reset_counts(struct perf_evsel *evsel);
int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus); int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus, int nthreads);
void perf_evsel__free_counts(struct perf_evsel *evsel); void perf_evsel__free_counts(struct perf_evsel *evsel);
void perf_evsel__reset_stat_priv(struct perf_evsel *evsel);
int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel);
void perf_evsel__free_stat_priv(struct perf_evsel *evsel);
int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel,
int ncpus, int nthreads);
void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel);
int perf_evsel__alloc_stats(struct perf_evsel *evsel, bool alloc_raw);
int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw);
void perf_evlist__free_stats(struct perf_evlist *evlist);
void perf_evlist__reset_stats(struct perf_evlist *evlist);
#endif #endif
...@@ -748,7 +748,7 @@ static int str_to_bitmap(char *s, cpumask_t *b) ...@@ -748,7 +748,7 @@ static int str_to_bitmap(char *s, cpumask_t *b)
set_bit(c, cpumask_bits(b)); set_bit(c, cpumask_bits(b));
} }
cpu_map__delete(m); cpu_map__put(m);
return ret; return ret;
} }
......
...@@ -1132,8 +1132,11 @@ static int dso__load_kcore(struct dso *dso, struct map *map, ...@@ -1132,8 +1132,11 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
INIT_LIST_HEAD(&md.maps); INIT_LIST_HEAD(&md.maps);
fd = open(kcore_filename, O_RDONLY); fd = open(kcore_filename, O_RDONLY);
if (fd < 0) if (fd < 0) {
pr_err("%s requires CAP_SYS_RAWIO capability to access.\n",
kcore_filename);
return -EINVAL; return -EINVAL;
}
/* Read new maps into temporary lists */ /* Read new maps into temporary lists */
err = file__read_maps(fd, md.type == MAP__FUNCTION, kcore_mapfn, &md, err = file__read_maps(fd, md.type == MAP__FUNCTION, kcore_mapfn, &md,
......
...@@ -8,8 +8,11 @@ ...@@ -8,8 +8,11 @@
#include <unistd.h> #include <unistd.h>
#include "strlist.h" #include "strlist.h"
#include <string.h> #include <string.h>
#include <api/fs/fs.h>
#include "asm/bug.h"
#include "thread_map.h" #include "thread_map.h"
#include "util.h" #include "util.h"
#include "debug.h"
/* Skip "." and ".." directories */ /* Skip "." and ".." directories */
static int filter(const struct dirent *dir) static int filter(const struct dirent *dir)
...@@ -20,11 +23,26 @@ static int filter(const struct dirent *dir) ...@@ -20,11 +23,26 @@ static int filter(const struct dirent *dir)
return 1; return 1;
} }
static void thread_map__reset(struct thread_map *map, int start, int nr)
{
size_t size = (nr - start) * sizeof(map->map[0]);
memset(&map->map[start], 0, size);
}
static struct thread_map *thread_map__realloc(struct thread_map *map, int nr) static struct thread_map *thread_map__realloc(struct thread_map *map, int nr)
{ {
size_t size = sizeof(*map) + sizeof(pid_t) * nr; size_t size = sizeof(*map) + sizeof(map->map[0]) * nr;
int start = map ? map->nr : 0;
map = realloc(map, size);
/*
* We only realloc to add more items, let's reset new items.
*/
if (map)
thread_map__reset(map, start, nr);
return realloc(map, size); return map;
} }
#define thread_map__alloc(__nr) thread_map__realloc(NULL, __nr) #define thread_map__alloc(__nr) thread_map__realloc(NULL, __nr)
...@@ -45,8 +63,9 @@ struct thread_map *thread_map__new_by_pid(pid_t pid) ...@@ -45,8 +63,9 @@ struct thread_map *thread_map__new_by_pid(pid_t pid)
threads = thread_map__alloc(items); threads = thread_map__alloc(items);
if (threads != NULL) { if (threads != NULL) {
for (i = 0; i < items; i++) for (i = 0; i < items; i++)
threads->map[i] = atoi(namelist[i]->d_name); thread_map__set_pid(threads, i, atoi(namelist[i]->d_name));
threads->nr = items; threads->nr = items;
atomic_set(&threads->refcnt, 1);
} }
for (i=0; i<items; i++) for (i=0; i<items; i++)
...@@ -61,8 +80,9 @@ struct thread_map *thread_map__new_by_tid(pid_t tid) ...@@ -61,8 +80,9 @@ struct thread_map *thread_map__new_by_tid(pid_t tid)
struct thread_map *threads = thread_map__alloc(1); struct thread_map *threads = thread_map__alloc(1);
if (threads != NULL) { if (threads != NULL) {
threads->map[0] = tid; thread_map__set_pid(threads, 0, tid);
threads->nr = 1; threads->nr = 1;
atomic_set(&threads->refcnt, 1);
} }
return threads; return threads;
...@@ -84,6 +104,7 @@ struct thread_map *thread_map__new_by_uid(uid_t uid) ...@@ -84,6 +104,7 @@ struct thread_map *thread_map__new_by_uid(uid_t uid)
goto out_free_threads; goto out_free_threads;
threads->nr = 0; threads->nr = 0;
atomic_set(&threads->refcnt, 1);
while (!readdir_r(proc, &dirent, &next) && next) { while (!readdir_r(proc, &dirent, &next) && next) {
char *end; char *end;
...@@ -123,8 +144,10 @@ struct thread_map *thread_map__new_by_uid(uid_t uid) ...@@ -123,8 +144,10 @@ struct thread_map *thread_map__new_by_uid(uid_t uid)
threads = tmp; threads = tmp;
} }
for (i = 0; i < items; i++) for (i = 0; i < items; i++) {
threads->map[threads->nr + i] = atoi(namelist[i]->d_name); thread_map__set_pid(threads, threads->nr + i,
atoi(namelist[i]->d_name));
}
for (i = 0; i < items; i++) for (i = 0; i < items; i++)
zfree(&namelist[i]); zfree(&namelist[i]);
...@@ -201,7 +224,7 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str) ...@@ -201,7 +224,7 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str)
threads = nt; threads = nt;
for (i = 0; i < items; i++) { for (i = 0; i < items; i++) {
threads->map[j++] = atoi(namelist[i]->d_name); thread_map__set_pid(threads, j++, atoi(namelist[i]->d_name));
zfree(&namelist[i]); zfree(&namelist[i]);
} }
threads->nr = total_tasks; threads->nr = total_tasks;
...@@ -210,6 +233,8 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str) ...@@ -210,6 +233,8 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str)
out: out:
strlist__delete(slist); strlist__delete(slist);
if (threads)
atomic_set(&threads->refcnt, 1);
return threads; return threads;
out_free_namelist: out_free_namelist:
...@@ -227,8 +252,9 @@ struct thread_map *thread_map__new_dummy(void) ...@@ -227,8 +252,9 @@ struct thread_map *thread_map__new_dummy(void)
struct thread_map *threads = thread_map__alloc(1); struct thread_map *threads = thread_map__alloc(1);
if (threads != NULL) { if (threads != NULL) {
threads->map[0] = -1; thread_map__set_pid(threads, 0, -1);
threads->nr = 1; threads->nr = 1;
atomic_set(&threads->refcnt, 1);
} }
return threads; return threads;
} }
...@@ -267,10 +293,12 @@ static struct thread_map *thread_map__new_by_tid_str(const char *tid_str) ...@@ -267,10 +293,12 @@ static struct thread_map *thread_map__new_by_tid_str(const char *tid_str)
goto out_free_threads; goto out_free_threads;
threads = nt; threads = nt;
threads->map[ntasks - 1] = tid; thread_map__set_pid(threads, ntasks - 1, tid);
threads->nr = ntasks; threads->nr = ntasks;
} }
out: out:
if (threads)
atomic_set(&threads->refcnt, 1);
return threads; return threads;
out_free_threads: out_free_threads:
...@@ -290,9 +318,30 @@ struct thread_map *thread_map__new_str(const char *pid, const char *tid, ...@@ -290,9 +318,30 @@ struct thread_map *thread_map__new_str(const char *pid, const char *tid,
return thread_map__new_by_tid_str(tid); return thread_map__new_by_tid_str(tid);
} }
void thread_map__delete(struct thread_map *threads) static void thread_map__delete(struct thread_map *threads)
{ {
free(threads); if (threads) {
int i;
WARN_ONCE(atomic_read(&threads->refcnt) != 0,
"thread map refcnt unbalanced\n");
for (i = 0; i < threads->nr; i++)
free(thread_map__comm(threads, i));
free(threads);
}
}
struct thread_map *thread_map__get(struct thread_map *map)
{
if (map)
atomic_inc(&map->refcnt);
return map;
}
void thread_map__put(struct thread_map *map)
{
if (map && atomic_dec_and_test(&map->refcnt))
thread_map__delete(map);
} }
size_t thread_map__fprintf(struct thread_map *threads, FILE *fp) size_t thread_map__fprintf(struct thread_map *threads, FILE *fp)
...@@ -301,7 +350,60 @@ size_t thread_map__fprintf(struct thread_map *threads, FILE *fp) ...@@ -301,7 +350,60 @@ size_t thread_map__fprintf(struct thread_map *threads, FILE *fp)
size_t printed = fprintf(fp, "%d thread%s: ", size_t printed = fprintf(fp, "%d thread%s: ",
threads->nr, threads->nr > 1 ? "s" : ""); threads->nr, threads->nr > 1 ? "s" : "");
for (i = 0; i < threads->nr; ++i) for (i = 0; i < threads->nr; ++i)
printed += fprintf(fp, "%s%d", i ? ", " : "", threads->map[i]); printed += fprintf(fp, "%s%d", i ? ", " : "", thread_map__pid(threads, i));
return printed + fprintf(fp, "\n"); return printed + fprintf(fp, "\n");
} }
static int get_comm(char **comm, pid_t pid)
{
char *path;
size_t size;
int err;
if (asprintf(&path, "%s/%d/comm", procfs__mountpoint(), pid) == -1)
return -ENOMEM;
err = filename__read_str(path, comm, &size);
if (!err) {
/*
* We're reading 16 bytes, while filename__read_str
* allocates data per BUFSIZ bytes, so we can safely
* mark the end of the string.
*/
(*comm)[size] = 0;
rtrim(*comm);
}
free(path);
return err;
}
static void comm_init(struct thread_map *map, int i)
{
pid_t pid = thread_map__pid(map, i);
char *comm = NULL;
/* dummy pid comm initialization */
if (pid == -1) {
map->map[i].comm = strdup("dummy");
return;
}
/*
* The comm name is like extra bonus ;-),
* so just warn if we fail for any reason.
*/
if (get_comm(&comm, pid))
pr_warning("Couldn't resolve comm name for pid %d\n", pid);
map->map[i].comm = comm;
}
void thread_map__read_comms(struct thread_map *threads)
{
int i;
for (i = 0; i < threads->nr; ++i)
comm_init(threads, i);
}
...@@ -3,10 +3,17 @@ ...@@ -3,10 +3,17 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdio.h> #include <stdio.h>
#include <linux/atomic.h>
struct thread_map_data {
pid_t pid;
char *comm;
};
struct thread_map { struct thread_map {
atomic_t refcnt;
int nr; int nr;
pid_t map[]; struct thread_map_data map[];
}; };
struct thread_map *thread_map__new_dummy(void); struct thread_map *thread_map__new_dummy(void);
...@@ -15,11 +22,12 @@ struct thread_map *thread_map__new_by_tid(pid_t tid); ...@@ -15,11 +22,12 @@ struct thread_map *thread_map__new_by_tid(pid_t tid);
struct thread_map *thread_map__new_by_uid(uid_t uid); struct thread_map *thread_map__new_by_uid(uid_t uid);
struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid); struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid);
struct thread_map *thread_map__get(struct thread_map *map);
void thread_map__put(struct thread_map *map);
struct thread_map *thread_map__new_str(const char *pid, struct thread_map *thread_map__new_str(const char *pid,
const char *tid, uid_t uid); const char *tid, uid_t uid);
void thread_map__delete(struct thread_map *threads);
size_t thread_map__fprintf(struct thread_map *threads, FILE *fp); size_t thread_map__fprintf(struct thread_map *threads, FILE *fp);
static inline int thread_map__nr(struct thread_map *threads) static inline int thread_map__nr(struct thread_map *threads)
...@@ -27,4 +35,21 @@ static inline int thread_map__nr(struct thread_map *threads) ...@@ -27,4 +35,21 @@ static inline int thread_map__nr(struct thread_map *threads)
return threads ? threads->nr : 1; return threads ? threads->nr : 1;
} }
static inline pid_t thread_map__pid(struct thread_map *map, int thread)
{
return map->map[thread].pid;
}
static inline void
thread_map__set_pid(struct thread_map *map, int thread, pid_t pid)
{
map->map[thread].pid = pid;
}
static inline char *thread_map__comm(struct thread_map *map, int thread)
{
return map->map[thread].comm;
}
void thread_map__read_comms(struct thread_map *threads);
#endif /* __PERF_THREAD_MAP_H */ #endif /* __PERF_THREAD_MAP_H */
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