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)
*/
int x86_add_exclusive(unsigned int what)
{
int ret = -EBUSY, i;
if (atomic_inc_not_zero(&x86_pmu.lbr_exclusive[what]))
return 0;
int i;
mutex_lock(&pmc_reserve_mutex);
for (i = 0; i < ARRAY_SIZE(x86_pmu.lbr_exclusive); i++) {
if (i != what && atomic_read(&x86_pmu.lbr_exclusive[i]))
goto out;
if (!atomic_inc_not_zero(&x86_pmu.lbr_exclusive[what])) {
mutex_lock(&pmc_reserve_mutex);
for (i = 0; i < ARRAY_SIZE(x86_pmu.lbr_exclusive); i++) {
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]);
ret = 0;
atomic_inc(&active_events);
return 0;
out:
fail_unlock:
mutex_unlock(&pmc_reserve_mutex);
/*
* 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;
return -EBUSY;
}
void x86_del_exclusive(unsigned int what)
......
......@@ -25,7 +25,7 @@ build-dir := $(srctree)/tools/build
include $(build-dir)/Build.include
# do not force detected configuration
-include .config-detected
-include $(OUTPUT).config-detected
# Init all relevant variables used in build files so
# 1) they have correct type
......
......@@ -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
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::
--delay msecs::
After starting the program, wait msecs before measuring. This is useful to
......
......@@ -83,8 +83,8 @@ build-test:
#
# All other targets get passed through:
#
%:
%: FORCE
$(print_msg)
$(make)
.PHONY: tags TAGS
.PHONY: tags TAGS FORCE Makefile
......@@ -110,7 +110,7 @@ $(OUTPUT)PERF-VERSION-FILE: ../../.git/HEAD
$(Q)touch $(OUTPUT)PERF-VERSION-FILE
CC = $(CROSS_COMPILE)gcc
LD = $(CROSS_COMPILE)ld
LD ?= $(CROSS_COMPILE)ld
AR = $(CROSS_COMPILE)ar
PKG_CONFIG = $(CROSS_COMPILE)pkg-config
......@@ -545,7 +545,7 @@ 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)
$(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-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
......
......@@ -630,12 +630,13 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
if (inject.session == NULL)
return -1;
if (symbol__init(&inject.session->header.env) < 0)
return -1;
ret = symbol__init(&inject.session->header.env);
if (ret < 0)
goto out_delete;
ret = __cmd_inject(&inject);
out_delete:
perf_session__delete(inject.session);
return ret;
}
......@@ -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,
"kmem:kmalloc")) {
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)
"kmem:mm_page_alloc");
if (evsel == NULL) {
pr_err(errmsg, "page", "page");
return -1;
goto out_delete;
}
kmem_page_size = pevent_get_page_size(evsel->tp_format->pevent);
......
......@@ -1061,8 +1061,10 @@ static int read_events(struct perf_kvm_stat *kvm)
symbol__init(&kvm->session->header.env);
if (!perf_session__has_traces(kvm->session, "kvm record"))
return -EINVAL;
if (!perf_session__has_traces(kvm->session, "kvm record")) {
ret = -EINVAL;
goto out_delete;
}
/*
* 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)
*/
ret = cpu_isa_config(kvm);
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)
......
......@@ -124,7 +124,6 @@ static int report_raw_events(struct perf_mem *mem)
.mode = PERF_DATA_MODE_READ,
.force = mem->force,
};
int err = -EINVAL;
int ret;
struct perf_session *session = perf_session__new(&file, false,
&mem->tool);
......@@ -135,24 +134,21 @@ static int report_raw_events(struct perf_mem *mem)
if (mem->cpu_list) {
ret = perf_session__cpu_bitmap(session, mem->cpu_list,
mem->cpu_bitmap);
if (ret)
if (ret < 0)
goto out_delete;
}
if (symbol__init(&session->header.env) < 0)
return -1;
ret = symbol__init(&session->header.env);
if (ret < 0)
goto out_delete;
printf("# PID, TID, IP, ADDR, LOCAL WEIGHT, DSRC, SYMBOL\n");
err = perf_session__process_events(session);
if (err)
return err;
return 0;
ret = perf_session__process_events(session);
out_delete:
perf_session__delete(session);
return err;
return ret;
}
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)
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)
use_browser = 0;
else if (report.use_tui)
......@@ -828,8 +839,10 @@ repeat:
if (report.header || report.header_only) {
perf_session__fprintf_info(session, stdout,
report.show_full_info);
if (report.header_only)
return 0;
if (report.header_only) {
ret = 0;
goto error;
}
} else if (use_browser == 0) {
fputs("# To display the perf.data header info, please use --header/--header-only options.\n#\n",
stdout);
......
This diff is collapsed.
......@@ -586,27 +586,9 @@ static void *display_thread_tui(void *arg)
hists->uid_filter_str = top->record_opts.target.uid_str;
}
while (true) {
int key = perf_evlist__tui_browse_hists(top->evlist, help, &hbt,
top->min_percent,
&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;
}
}
perf_evlist__tui_browse_hists(top->evlist, help, &hbt,
top->min_percent,
&top->session->header.env);
done = 1;
return NULL;
......
......@@ -1617,6 +1617,34 @@ static int trace__read_syscall_info(struct trace *trace, int id)
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
* 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)
*/
if (trace->filter_pids.nr > 0)
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());
if (err < 0) {
......@@ -2343,7 +2371,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
if (forks)
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 ||
perf_evlist__first(evlist)->attr.inherit;
again:
......@@ -2862,6 +2890,10 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
err = -ENOMEM;
goto out_close;
}
err = trace__validate_ev_qualifier(&trace);
if (err)
goto out_close;
}
err = target__validate(&trace.opts.target);
......
......@@ -11,9 +11,9 @@ ifneq ($(obj-perf),)
obj-perf := $(abspath $(obj-perf))/
endif
$(shell echo -n > .config-detected)
detected = $(shell echo "$(1)=y" >> .config-detected)
detected_var = $(shell echo "$(1)=$($(1))" >> .config-detected)
$(shell echo -n > $(OUTPUT).config-detected)
detected = $(shell echo "$(1)=y" >> $(OUTPUT).config-detected)
detected_var = $(shell echo "$(1)=$($(1))" >> $(OUTPUT).config-detected)
CFLAGS := $(EXTRA_CFLAGS) $(EXTRA_WARNINGS)
......
......@@ -31,6 +31,7 @@ perf-y += code-reading.o
perf-y += sample-parsing.o
perf-y += parse-no-sample-id-all.o
perf-y += kmod-path.o
perf-y += thread-map.o
perf-$(CONFIG_X86) += perf-time-to-tsc.o
......
......@@ -170,6 +170,10 @@ static struct test {
.desc = "Test kmod_path__parse function",
.func = test__kmod_path__parse,
},
{
.desc = "Test thread map",
.func = test__thread_map,
},
{
.func = NULL,
},
......
......@@ -545,8 +545,8 @@ out_err:
if (evlist) {
perf_evlist__delete(evlist);
} else {
cpu_map__delete(cpus);
thread_map__delete(threads);
cpu_map__put(cpus);
thread_map__put(threads);
}
machines__destroy_kernel_maps(&machines);
machine__delete_threads(machine);
......
......@@ -144,8 +144,8 @@ out_err:
perf_evlist__disable(evlist);
perf_evlist__delete(evlist);
} else {
cpu_map__delete(cpus);
thread_map__delete(threads);
cpu_map__put(cpus);
thread_map__put(threads);
}
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 := .
MK := Makefile
include config/Makefile.arch
......@@ -47,6 +58,7 @@ make_install_man := install-man
make_install_html := install-html
make_install_info := install-info
make_install_pdf := install-pdf
make_install_prefix := install prefix=/tmp/krava
make_static := LDFLAGS=-static
# all the NO_* variable combined
......@@ -57,7 +69,12 @@ make_minimal += NO_LIBDW_DWARF_UNWIND=1 NO_AUXTRACE=1
# $(run) contains all available tests
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
endif
run += make_python_perf_so
run += make_debug
run += make_no_libperl
......@@ -83,6 +100,7 @@ run += make_util_map_o
run += make_util_pmu_bison_o
run += make_install
run += make_install_bin
run += make_install_prefix
# FIXME 'install-*' commented out till they're fixed
# run += make_install_doc
# run += make_install_man
......@@ -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_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
test_make_install_man := test -f $$TMP_DEST/share/man/man1/perf.1
test_make_install_man_O := $(test_make_install_man)
......@@ -226,13 +250,13 @@ tarpkg:
( eval $$cmd ) >> $@ 2>&1
make_kernelsrc:
@echo " - make -C <kernelsrc> tools/perf"
@echo "- make -C <kernelsrc> tools/perf"
$(call clean); \
(make -C ../.. tools/perf) > $@ 2>&1 && \
test -x perf && rm -f $@ || (cat $@ ; false)
make_kernelsrc_tools:
@echo " - make -C <kernelsrc>/tools perf"
@echo "- make -C <kernelsrc>/tools perf"
$(call clean); \
(make -C ../../tools perf) > $@ 2>&1 && \
test -x perf && rm -f $@ || (cat $@ ; false)
......@@ -244,3 +268,4 @@ out: $(run_O)
@echo OK
.PHONY: all $(run) $(run_O) tarpkg clean
endif # ifndef MK
......@@ -140,8 +140,8 @@ out_delete_evlist:
cpus = NULL;
threads = NULL;
out_free_cpus:
cpu_map__delete(cpus);
cpu_map__put(cpus);
out_free_threads:
thread_map__delete(threads);
thread_map__put(threads);
return err;
}
......@@ -143,7 +143,7 @@ static int synth_process(struct machine *machine)
perf_event__process,
machine, 0, 500);
thread_map__delete(map);
thread_map__put(map);
return err;
}
......
......@@ -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,
* 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);
goto out_close_fd;
}
......@@ -98,9 +98,9 @@ int test__openat_syscall_event_on_all_cpus(void)
}
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",
expected, cpus->map[cpu], evsel->counts->cpu[cpu].val);
expected, cpus->map[cpu], perf_counts(evsel->counts, cpu, 0)->val);
err = -1;
}
}
......@@ -111,6 +111,6 @@ out_close_fd:
out_evsel_delete:
perf_evsel__delete(evsel);
out_thread_map_delete:
thread_map__delete(threads);
thread_map__put(threads);
return err;
}
......@@ -45,7 +45,7 @@ int test__syscall_openat_tp_fields(void)
perf_evsel__config(evsel, &opts);
evlist->threads->map[0] = getpid();
thread_map__set_pid(evlist->threads, 0, getpid());
err = perf_evlist__open(evlist);
if (err < 0) {
......
......@@ -44,9 +44,9 @@ int test__openat_syscall_event(void)
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",
nr_openat_calls, evsel->counts->cpu[0].val);
nr_openat_calls, perf_counts(evsel->counts, 0, 0)->val);
goto out_close_fd;
}
......@@ -56,6 +56,6 @@ out_close_fd:
out_evsel_delete:
perf_evsel__delete(evsel);
out_thread_map_delete:
thread_map__delete(threads);
thread_map__put(threads);
return err;
}
......@@ -560,8 +560,8 @@ out:
perf_evlist__disable(evlist);
perf_evlist__delete(evlist);
} else {
cpu_map__delete(cpus);
thread_map__delete(threads);
cpu_map__put(cpus);
thread_map__put(threads);
}
return err;
......
......@@ -61,6 +61,7 @@ int test__switch_tracking(void);
int test__fdarray__filter(void);
int test__fdarray__add(void);
int test__kmod_path__parse(void);
int test__thread_map(void);
#if defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__)
#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,
case CTRL('c'):
goto out_free_stack;
case 'f':
if (!is_report_browser(hbt))
goto out_free_stack;
if (!is_report_browser(hbt)) {
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 */