diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-08-22 08:47:50 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-08-22 08:47:50 -0700 |
| commit | 473f6c8f437b049f8ec015d57cd59bb983b1d85c (patch) | |
| tree | b06f7045dbd0fabfe6b26c523a1ffe30d5697a8c /tools/perf/ui | |
| parent | 47f05f71ad988c3180bdba807151e6e86ed75aa3 (diff) | |
| parent | 9453bc6a69ef43755f1c28d5688cacdd69fa16bd (diff) | |
Merge tag 'perf-tools-for-v7.3-2026-08-21' of git://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools
Pull perf tools updates from Namhyung Kim:
"perf c2c:
- Add 'function view' in perf c2c report TUI (switched by pressing
'TAB' in the cacheline view) to organize samples around functions
rather than cachelines in 3-level hierarchy:
Level 1: Read-side function (sorted by estimated Cycles %)
Level 2: Contending writer functions (sorted by Store count)
Level 3: Shared cacheline addresses
Users can navigate the entries and fold/unfold using 'e' key. An
example output would look like below:
Shared Data Functions Table (19 entries, sorted on Cycles %)
Cycles Store
% count Function / Contending function / Cacheline
----------------------------------------------------------------------
+ 35.67% 876 + [k] cpupri_set
+ 24.31% 424 + [k] pull_rt_task
- 16.53% 555 - [k] dequeue_pushable_task
145 - [k] pull_rt_task
145 0xff2d0082809da080
139 - [k] enqueue_pushable_task
70 0xff2d00a2071f9640
69 0xff2d0082809da000
python module support:
- Extend "perf" python module so that it can be fully functional. The
goal is to run scripts directly, not by 'perf script' command. This
would give better performance as well as more control to build
standalone programs with UI.
- Add LiveSession helper (perf_live.py) to enable live event
collection directly from Python using perf.evlist and
perf.parse_events.
perf stat:
- Add --hide-zero-events option to suppress zero-count events
- Reject conflicting --field-separator and --json-output options
- Fix duplicate event output with --for-each-cgroup
perf sched latency:
- Add -H/--histogram and --hist-mode (log|linear) options to show
scheduler wait latency histograms
- Add --time option to filter analysis by time span in 'perf sched
latency'
ARM CoreSight:
- Synthesize callchains for instruction samples from CoreSight trace
using thread stack ('--itrace=g...')
- Support call indentation ('perf script -F +callindent') to display
call depth hierarchy on branch samples
- Decode ETE (Embedded Trace Extension) exception packets
Build system:
- Add 'make install-build-deps' target to install required packages
- Parallelize JSON and metric pre-computation in jevents.py for
faster builds
Vendor event/metric updates:
- Add Intel Nova Lake events and update tables for existing models
- Update AMD Zen 5 and Zen 6 core events
- Update Arm64 Tegra410 metrics and PowerPC hcalls
Internal changes and fixes:
- Harden trace-event and synthetic event parsing against corrupted
data
- Fix unwinding of multi-threaded processes in libdw unwinder
- Fix memory leaks in various commands and python bindings
- Speed up 'perf test' shell tests"
* tag 'perf-tools-for-v7.3-2026-08-21' of git://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools: (232 commits)
perf vendor events arm64: Fix Tegra410 Olympus event 0x0197
perf vendor events arm64: fix swapped MetricGroup for Tegra410 L1 prefetcher metrics
perf evlist: Warn when 'sleep' workload is used without system-wide (-a) option
perf c2c: document function view in perf-c2c man page
perf c2c: add function view browser UI and cacheline detail
perf c2c: build and finalize the function view hierarchy
perf c2c: add function view hierarchy entry creation
perf c2c: add function view stats merge and memory management
perf c2c: add HPP list parsing for function view columns
perf c2c: add column rendering for function view
perf c2c: add function view model skeleton
perf c2c: extract shared data structures into util/c2c.h
perf test sample-parsing: Validate PERF_FORMAT_GROUP values without LOST
perf dso: Replace assert with runtime check in dso__read_symbol()
perf dso: Guard against cache underflow on short reads in dso_cache__memcpy()
perf dso: Use stored fd error instead of stale errno in file_read() and file_size()
perf dso: Guard close() against invalid fd in dso__decompress_kmodule_path()
perf dso: Guard against errno==0 when dso__get_filename() returns NULL
perf build: install-build-deps: add RHEL family devel package mapping
perf build: Remove leftover feature tests for removed cxx and clang support
...
Diffstat (limited to 'tools/perf/ui')
| -rw-r--r-- | tools/perf/ui/browsers/Build | 1 | ||||
| -rw-r--r-- | tools/perf/ui/browsers/annotate.c | 4 | ||||
| -rw-r--r-- | tools/perf/ui/browsers/c2c-function.c | 209 | ||||
| -rw-r--r-- | tools/perf/ui/browsers/hists.c | 201 |
4 files changed, 342 insertions, 73 deletions
diff --git a/tools/perf/ui/browsers/Build b/tools/perf/ui/browsers/Build index a07489e44765..ae67a2161f7d 100644 --- a/tools/perf/ui/browsers/Build +++ b/tools/perf/ui/browsers/Build @@ -5,3 +5,4 @@ perf-ui-y += map.o perf-ui-y += scripts.o perf-ui-y += header.o perf-ui-y += res_sample.o +perf-ui-y += c2c-function.o diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 97ae4c86bebb..e47a46775089 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -597,7 +597,7 @@ static bool annotate_browser__callq(struct annotate_browser *browser, notes = symbol__annotation(dl->ops.target.sym); annotation__lock(notes); - if (!symbol__hists(dl->ops.target.sym, evsel->evlist->core.nr_entries)) { + if (!symbol__hists(dl->ops.target.sym, evlist__nr_entries(evsel->evlist))) { annotation__unlock(notes); ui__warning("Not enough memory for annotating '%s' symbol!\n", dl->ops.target.sym->name); @@ -1201,7 +1201,7 @@ int __hist_entry__tui_annotate(struct hist_entry *he, struct map_symbol *ms, ui__warning("Annotation has no source code."); } } else { - err = thread__get_arch(ms->thread, &browser.arch); + err = map_symbol__get_arch(ms, &browser.arch); if (err) { annotate_browser__symbol_annotate_error(&browser, err); return -1; diff --git a/tools/perf/ui/browsers/c2c-function.c b/tools/perf/ui/browsers/c2c-function.c new file mode 100644 index 000000000000..3d23e9d84981 --- /dev/null +++ b/tools/perf/ui/browsers/c2c-function.c @@ -0,0 +1,209 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * C2C function browser - TUI front end for function-level sharing analysis + */ + +#include <errno.h> +#include <inttypes.h> +#include <stdlib.h> +#include <sys/ttydefaults.h> +#include <linux/rbtree.h> +#include <linux/zalloc.h> + +#include "../browser.h" +#include "../keysyms.h" +#include "../libslang.h" +#include "../ui.h" +#include "../../util/c2c.h" +#include "../../util/debug.h" +#include "../../util/hist.h" +#include "../../util/symbol.h" +#include "hists.h" + +struct c2c_function_browser { + struct hist_browser hb; + unsigned int (*orig_refresh)(struct ui_browser *browser); + int (*browse_cacheline)(struct hist_entry *he); +}; + +/* + * Count visible entries in @root, descending only through visible, unfolded + * parents. Match hists__filter_entries(), which drives generic browser + * navigation, so the count cannot include rows the browser skips. + */ +static u64 +c2c_function__nr_visible_rows(struct rb_root_cached *root, float min_pcnt) +{ + struct rb_node *nd; + u64 rows = 0; + + for (nd = rb_first_cached(root); nd; nd = rb_next(nd)) { + struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); + + /* + * The generic refresh folds filtered parents and therefore hides + * their subtree. A percentage-rejected parent is merely skipped; + * if it is unfolded, qualifying descendants are still rendered. + */ + if (he->filtered) + continue; + + if (hist_entry__get_percent_limit(he) >= min_pcnt) + rows++; + if (he->has_children && he->unfolded) + rows += c2c_function__nr_visible_rows(&he->hroot_out, + min_pcnt); + } + return rows; +} + +static void +c2c_function_browser__update_nr_entries(struct c2c_function_browser *browser) +{ + u64 nr_entries; + + nr_entries = c2c_function__nr_visible_rows(&browser->hb.hists->entries, + browser->hb.min_pcnt); + browser->hb.nr_non_filtered_entries = nr_entries; + browser->hb.b.nr_entries = nr_entries; +} + +static unsigned int c2c_function_browser__refresh(struct ui_browser *ui_browser) +{ + struct hist_browser *hist_browser = container_of(ui_browser, struct hist_browser, b); + struct c2c_function_browser *browser; + + browser = container_of(hist_browser, struct c2c_function_browser, hb); + c2c_function_browser__update_nr_entries(browser); + return browser->orig_refresh(ui_browser); +} + +static int c2c_function_browser__title(struct hist_browser *browser, + char *bf, size_t size) +{ + scnprintf(bf, size, + "Shared Data Functions Table (%" PRIu64 " entries, sorted on Cycles %%)", + browser->hists->nr_non_filtered_entries); + return 0; +} + +static struct c2c_function_browser * +c2c_function_browser__new(struct hists *hists, + int (*browse_cacheline)(struct hist_entry *he)) +{ + struct c2c_function_browser *browser; + + if (!hists) + return NULL; + + browser = zalloc(sizeof(*browser)); + if (!browser) + return NULL; + + hist_browser__init(&browser->hb, hists); + browser->orig_refresh = browser->hb.b.refresh; + browser->hb.b.refresh = c2c_function_browser__refresh; + browser->browse_cacheline = browse_cacheline; + + browser->hb.title = c2c_function_browser__title; + browser->hb.c2c_filter = true; + browser->hb.show_headers = true; + /* Keep title line count consistent with forcing headers on. */ + browser->hb.b.extra_title_lines = hists->hpp_list->nr_header_lines; + browser->hb.min_pcnt = 0.0; + + return browser; +} + +static void c2c_function_browser__delete(struct c2c_function_browser *browser) +{ + free(browser); +} + +static int +c2c_browser__browse_cacheline(struct c2c_function_browser *browser, + struct hist_entry *he_selection) +{ + struct hist_entry *he = c2c_function__find_cacheline(he_selection); + + return he ? browser->browse_cacheline(he) : -1; +} + +int perf_c2c__browse_function_view(struct c2c_function_view_args *args) +{ + struct c2c_function_browser *browser; + struct hists *hists; + bool saved_use_callchain = symbol_conf.use_callchain; + int key, ret; + static const char help[] = + " d Display details for the selected level-3 cacheline\n" + " e/+ Expand/collapse the selected entry\n" + " TAB/ESC/q/^C Return to the cacheline view\n"; + + if (!args || !args->cl_hists || !args->browse_cacheline) + return -EINVAL; + + /* + * Function view does not display callchains; cacheline detail temporarily + * restores them. + */ + symbol_conf.use_callchain = false; + + ret = c2c_function__build(args->cl_hists, args->cl_sort, + args->symbol_full, &hists); + if (ret) { + if (ret == -EOPNOTSUPP) + ui__warning("The function view requires iaddr in --coalesce.\n"); + else + ui__error("Failed to build function view hierarchy (ret=%d)\n", ret); + goto out; + } + + browser = c2c_function_browser__new(hists, args->browse_cacheline); + if (!browser) { + ret = -ENOMEM; + goto out_reset; + } + + /* Reset abort key so we can receive Ctrl-C as a key. */ + SLang_reset_tty(); + SLang_init_tty(0, 0, 0); + SLtty_set_suspend_state(true); + + while (1) { + c2c_function_browser__update_nr_entries(browser); + key = hist_browser__run(&browser->hb, "? - help", true, 0); + + switch (key) { + case 'q': + case K_TAB: + case K_ESC: + case CTRL('c'): + goto browser_done; + case 'd': + /* Cacheline detail honors the user's callchain setting. */ + symbol_conf.use_callchain = saved_use_callchain; + c2c_browser__browse_cacheline(browser, browser->hb.he_selection); + /* + * Preserve any toggle made in the detail view, then + * re-disable callchain for the function view. + */ + saved_use_callchain = symbol_conf.use_callchain; + symbol_conf.use_callchain = false; + break; + case '?': + ui_browser__help_window(&browser->hb.b, help); + break; + default: + break; + } + } + +browser_done: + c2c_function_browser__delete(browser); +out_reset: + c2c_function__reset(); +out: + symbol_conf.use_callchain = saved_use_callchain; + return ret; +} diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index cfa6386e6e1d..c15874a491b4 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -2,6 +2,7 @@ #include <dirent.h> #include <errno.h> #include <inttypes.h> +#include <limits.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -688,10 +689,10 @@ static int hist_browser__handle_hotkey(struct hist_browser *browser, bool warn_l ui_browser__update_nr_entries(&browser->b, nr_entries); if (warn_lost_event && - (evsel->evlist->stats.nr_lost_warned != - evsel->evlist->stats.nr_events[PERF_RECORD_LOST])) { - evsel->evlist->stats.nr_lost_warned = - evsel->evlist->stats.nr_events[PERF_RECORD_LOST]; + (evlist__stats(evsel->evlist)->nr_lost_warned != + evlist__stats(evsel->evlist)->nr_events[PERF_RECORD_LOST])) { + evlist__stats(evsel->evlist)->nr_lost_warned = + evlist__stats(evsel->evlist)->nr_events[PERF_RECORD_LOST]; ui_browser__warn_lost_events(&browser->b); } @@ -2356,6 +2357,15 @@ static int hists_browser__scnprintf_title(struct hist_browser *browser, char *bf return printed; } +struct popup_action { + unsigned long time; + int (*fn)(struct hist_browser *browser, struct popup_action *act); + struct map_symbol ms; + int socket; + enum rstype rstype; + +}; + static inline void free_popup_options(char **options, int n) { int i; @@ -2364,6 +2374,16 @@ static inline void free_popup_options(char **options, int n) zfree(&options[i]); } +static inline void free_popup_actions(struct popup_action *actions, int n) +{ + int i; + + for (i = 0; i < n; ++i) { + map_symbol__exit(&actions[i].ms); + memset(&actions[i], 0, sizeof(struct popup_action)); + } +} + /* * Only runtime switching of perf data file will make "input_name" point * to a malloced buffer. So add "is_input_name_malloced" flag to decide @@ -2453,16 +2473,6 @@ close_file_and_continue: return ret; } -struct popup_action { - unsigned long time; - struct thread *thread; - int (*fn)(struct hist_browser *browser, struct popup_action *act); - struct map_symbol ms; - int socket; - enum rstype rstype; - -}; - static int do_annotate(struct hist_browser *browser, struct popup_action *act) { @@ -2540,7 +2550,7 @@ add_annotate_opt(struct popup_action *act, char **optstr, if (asprintf(optstr, "Annotate %s", ms->sym->name) < 0) return 0; - act->ms = *ms; + map_symbol__copy(&act->ms, ms); act->fn = do_annotate; return 1; } @@ -2572,7 +2582,7 @@ add_annotate_type_opt(struct popup_action *act, char **optstr, static int do_zoom_thread(struct hist_browser *browser, struct popup_action *act) { - struct thread *thread = act->thread; + struct thread *thread = act->ms.thread; if ((!hists__has(browser->hists, thread) && !hists__has(browser->hists, comm)) || thread == NULL) @@ -2627,7 +2637,7 @@ add_thread_opt(struct hist_browser *browser, struct popup_action *act, if (ret < 0) return 0; - act->thread = thread; + act->ms.thread = thread__get(thread); act->fn = do_zoom_thread; return 1; } @@ -2640,13 +2650,14 @@ static int hists_browser__zoom_map(struct hist_browser *browser, struct map *map if (browser->hists->dso_filter) { pstack__remove(browser->pstack, &browser->hists->dso_filter); perf_hpp__set_elide(HISTC_DSO, false); + dso__put((struct dso *)browser->hists->dso_filter); browser->hists->dso_filter = NULL; ui_helpline__pop(); } else { struct dso *dso = map__dso(map); ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"", __map__is_kernel(map) ? "the Kernel" : dso__short_name(dso)); - browser->hists->dso_filter = dso; + browser->hists->dso_filter = dso__get(dso); perf_hpp__set_elide(HISTC_DSO, true); pstack__push(browser->pstack, &browser->hists->dso_filter); } @@ -2674,7 +2685,7 @@ add_dso_opt(struct hist_browser *browser, struct popup_action *act, __map__is_kernel(map) ? "the Kernel" : dso__short_name(map__dso(map))) < 0) return 0; - act->ms.map = map; + act->ms.map = map__get(map); act->fn = do_zoom_dso; return 1; } @@ -2719,7 +2730,7 @@ add_map_opt(struct hist_browser *browser, if (asprintf(optstr, "Browse map details") < 0) return 0; - act->ms.map = map; + act->ms.map = map__get(map); act->fn = do_browse_map; return 1; } @@ -2733,8 +2744,8 @@ do_run_script(struct hist_browser *browser, int n = 0; len = 100; - if (act->thread) - len += strlen(thread__comm_str(act->thread)); + if (act->ms.thread) + len += strlen(thread__comm_str(act->ms.thread)); else if (act->ms.sym) len += strlen(act->ms.sym->name); script_opt = malloc(len); @@ -2742,9 +2753,9 @@ do_run_script(struct hist_browser *browser, return -1; script_opt[0] = 0; - if (act->thread) { + if (act->ms.thread) { n = scnprintf(script_opt, len, " -c %s ", - thread__comm_str(act->thread)); + thread__comm_str(act->ms.thread)); } else if (act->ms.sym) { n = scnprintf(script_opt, len, " -S %s ", act->ms.sym->name); @@ -2799,7 +2810,7 @@ add_script_opt_2(struct popup_action *act, char **optstr, return 0; } - act->thread = thread; + act->ms.thread = thread__get(thread); act->ms.sym = sym; act->fn = do_run_script; return 1; @@ -2810,7 +2821,7 @@ add_script_opt(struct hist_browser *browser, struct popup_action *act, char **optstr, struct thread *thread, struct symbol *sym) { - int n, j; + int n, j, ret; struct hist_entry *he; n = add_script_opt_2(act, optstr, thread, sym, ""); @@ -2818,17 +2829,26 @@ add_script_opt(struct hist_browser *browser, he = hist_browser__selected_entry(browser); if (sort_order && strstr(sort_order, "time")) { char tstr[128]; + struct popup_action *time_act = act; + char **time_optstr = optstr; - optstr++; - act++; + if (n > 0) { + time_optstr++; + time_act++; + } + if (he == NULL) + return n; j = sprintf(tstr, " in "); j += timestamp__scnprintf_usec(he->time, tstr + j, sizeof tstr - j); j += sprintf(tstr + j, "-"); timestamp__scnprintf_usec(he->time + symbol_conf.time_quantum, tstr + j, sizeof tstr - j); - n += add_script_opt_2(act, optstr, thread, sym, tstr); - act->time = he->time; + ret = add_script_opt_2(time_act, time_optstr, thread, sym, tstr); + if (ret > 0) { + time_act->time = he->time; + n += ret; + } } return n; } @@ -3003,9 +3023,9 @@ static int evsel__hists_browse(struct evsel *evsel, int nr_events, const char *h struct hists *hists = evsel__hists(evsel); struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env); struct branch_info *bi = NULL; -#define MAX_OPTIONS 16 +#define MAX_OPTIONS 32 char *options[MAX_OPTIONS]; - struct popup_action actions[MAX_OPTIONS]; + struct popup_action actions[MAX_OPTIONS], hotkey_act; int nr_options = 0; int key = -1; char buf[128]; @@ -3064,15 +3084,15 @@ static int evsel__hists_browse(struct evsel *evsel, int nr_events, const char *h browser->min_pcnt = min_pcnt; hist_browser__update_nr_entries(browser); + memset(options, 0, sizeof(options)); + memset(actions, 0, sizeof(actions)); + browser->pstack = pstack__new(3); if (browser->pstack == NULL) goto out; ui_helpline__push(helpline); - memset(options, 0, sizeof(options)); - memset(actions, 0, sizeof(actions)); - if (symbol_conf.col_width_list_str) perf_hpp__set_user_width(symbol_conf.col_width_list_str); @@ -3087,6 +3107,8 @@ static int evsel__hists_browse(struct evsel *evsel, int nr_events, const char *h key = 0; // reset key do_hotkey: // key came straight from options ui__popup_menu() + free_popup_options(options, MAX_OPTIONS); + free_popup_actions(actions, MAX_OPTIONS); choice = nr_options = 0; key = hist_browser__run(browser, helpline, warn_lost_event, key); @@ -3146,24 +3168,40 @@ do_hotkey: // key came straight from options ui__popup_menu() } if (!browser->selection->sym) { + struct map_symbol source_ms; + if (!browser->he_selection) continue; + memset(&source_ms, 0, sizeof(source_ms)); + if (sort__mode == SORT_MODE__BRANCH) { bi = browser->he_selection->branch_info; if (!bi || !bi->to.ms.map) continue; - actions->ms.sym = symbol__new_unresolved(bi->to.al_addr, bi->to.ms.map); - actions->ms.map = bi->to.ms.map; + source_ms.sym = + symbol__new_unresolved( + bi->to.al_addr, + bi->to.ms.map); + source_ms.thread = bi->to.ms.thread; + source_ms.map = bi->to.ms.map; } else { - actions->ms.sym = symbol__new_unresolved(browser->he_selection->ip, - browser->selection->map); - actions->ms.map = browser->selection->map; + source_ms.sym = + symbol__new_unresolved( + browser->he_selection->ip, + browser->selection->map); + source_ms.thread = browser->selection->thread; + source_ms.map = browser->selection->map; } - if (!actions->ms.sym) + if (!source_ms.sym) continue; + + memset(&hotkey_act, 0, sizeof(hotkey_act)); + map_symbol__copy(&hotkey_act.ms, &source_ms); + do_annotate(browser, &hotkey_act); + map_symbol__exit(&hotkey_act.ms); } else { if (symbol__annotation(browser->selection->sym)->src == NULL) { ui_browser__warning(&browser->b, delay_secs * 2, @@ -3173,18 +3211,20 @@ do_hotkey: // key came straight from options ui__popup_menu() continue; } - actions->ms.map = browser->selection->map; - actions->ms.sym = browser->selection->sym; + memset(&hotkey_act, 0, sizeof(hotkey_act)); + map_symbol__copy(&hotkey_act.ms, browser->selection); + do_annotate(browser, &hotkey_act); + map_symbol__exit(&hotkey_act.ms); } - - do_annotate(browser, actions); continue; case 'P': hist_browser__dump(browser); continue; case 'd': - actions->ms.map = map; - do_zoom_dso(browser, actions); + memset(&hotkey_act, 0, sizeof(hotkey_act)); + hotkey_act.ms.map = map__get(map); + do_zoom_dso(browser, &hotkey_act); + map_symbol__exit(&hotkey_act.ms); continue; case 'k': if (browser->selection != NULL) @@ -3199,12 +3239,16 @@ do_hotkey: // key came straight from options ui__popup_menu() verbose); continue; case 't': - actions->thread = thread; - do_zoom_thread(browser, actions); + memset(&hotkey_act, 0, sizeof(hotkey_act)); + hotkey_act.ms.thread = thread__get(thread); + do_zoom_thread(browser, &hotkey_act); + map_symbol__exit(&hotkey_act.ms); continue; case 'S': - actions->socket = socked_id; - do_zoom_socket(browser, actions); + memset(&hotkey_act, 0, sizeof(hotkey_act)); + hotkey_act.socket = socked_id; + do_zoom_socket(browser, &hotkey_act); + map_symbol__exit(&hotkey_act.ms); continue; case '/': if (ui_browser__input_window("Symbol to show", @@ -3212,16 +3256,21 @@ do_hotkey: // key came straight from options ui__popup_menu() "To remove the filter later, press / + ENTER.", buf, "ENTER: OK, ESC: Cancel", delay_secs * 2) == K_ENTER) { - hists->symbol_filter_str = *buf ? buf : NULL; + char *new_filter = *buf ? strdup(buf) : NULL; + + zfree(&hists->symbol_filter_str); + hists->symbol_filter_str = new_filter; hists__filter_by_symbol(hists); hist_browser__reset(browser); } continue; case 'r': if (is_report_browser(hbt)) { - actions->thread = NULL; - actions->ms.sym = NULL; - do_run_script(browser, actions); + memset(&hotkey_act, 0, sizeof(hotkey_act)); + hotkey_act.ms.thread = NULL; + hotkey_act.ms.sym = NULL; + do_run_script(browser, &hotkey_act); + map_symbol__exit(&hotkey_act.ms); } continue; case 's': @@ -3293,20 +3342,19 @@ do_hotkey: // key came straight from options ui__popup_menu() continue; } - actions->ms.map = map; + memset(&hotkey_act, 0, sizeof(hotkey_act)); top = pstack__peek(browser->pstack); if (top == &browser->hists->dso_filter) { - /* - * No need to set actions->dso here since - * it's just to remove the current filter. - */ - do_zoom_dso(browser, actions); + hotkey_act.ms.map = map__get(map); + do_zoom_dso(browser, &hotkey_act); } else if (top == &browser->hists->thread_filter) { - actions->thread = thread; - do_zoom_thread(browser, actions); + hotkey_act.ms.thread = thread__get(thread); + do_zoom_thread(browser, &hotkey_act); } else if (top == &browser->hists->socket_filter) { - do_zoom_socket(browser, actions); + hotkey_act.socket = socked_id; + do_zoom_socket(browser, &hotkey_act); } + map_symbol__exit(&hotkey_act.ms); continue; } case 'q': @@ -3321,7 +3369,7 @@ do_hotkey: // key came straight from options ui__popup_menu() * No need to refresh, resort/decay histogram * entries if we are not collecting samples: */ - if (top->evlist->enabled) { + if (evlist__enabled(top->evlist)) { helpline = "Press 'f' to disable the events or 'h' to see other hotkeys"; hbt->refresh = delay_secs; } else { @@ -3443,9 +3491,20 @@ skip_scripting: if (key == K_SWITCH_INPUT_DATA) break; + + free_popup_options(options, MAX_OPTIONS); + free_popup_actions(actions, MAX_OPTIONS); } out_free_stack: pstack__delete(browser->pstack); + free_popup_actions(actions, MAX_OPTIONS); + thread__zput(hists->thread_filter); + dso__put((struct dso *)hists->dso_filter); + hists->dso_filter = NULL; + perf_hpp__set_elide(HISTC_DSO, false); + perf_hpp__set_elide(HISTC_THREAD, false); + hists__filter_by_dso(hists); + hists__filter_by_thread(hists); out: hist_browser__delete(browser); free_popup_options(options, MAX_OPTIONS); @@ -3493,7 +3552,7 @@ static void perf_evsel_menu__write(struct ui_browser *browser, unit, unit == ' ' ? "" : " ", ev_name); ui_browser__printf(browser, "%s", bf); - nr_events = evsel->evlist->stats.nr_events[PERF_RECORD_LOST]; + nr_events = evlist__stats(evsel->evlist)->nr_events[PERF_RECORD_LOST]; if (nr_events != 0) { menu->lost_events = true; if (!current_entry) @@ -3559,13 +3618,13 @@ browse_hists: ui_browser__show_title(&menu->b, title); switch (key) { case K_TAB: - if (pos->core.node.next == &evlist->core.entries) + if (pos->core.node.next == &evlist__core(evlist)->entries) pos = evlist__first(evlist); else pos = evsel__next(pos); goto browse_hists; case K_UNTAB: - if (pos->core.node.prev == &evlist->core.entries) + if (pos->core.node.prev == &evlist__core(evlist)->entries) pos = evlist__last(evlist); else pos = evsel__prev(pos); @@ -3618,7 +3677,7 @@ static int __evlist__tui_browse_hists(struct evlist *evlist, int nr_entries, con struct evsel *pos; struct evsel_menu menu = { .b = { - .entries = &evlist->core.entries, + .entries = &evlist__core(evlist)->entries, .refresh = ui_browser__list_head_refresh, .seek = ui_browser__list_head_seek, .write = perf_evsel_menu__write, @@ -3646,7 +3705,7 @@ static int __evlist__tui_browse_hists(struct evlist *evlist, int nr_entries, con static bool evlist__single_entry(struct evlist *evlist) { - int nr_entries = evlist->core.nr_entries; + int nr_entries = evlist__nr_entries(evlist); if (nr_entries == 1) return true; @@ -3664,7 +3723,7 @@ static bool evlist__single_entry(struct evlist *evlist) int evlist__tui_browse_hists(struct evlist *evlist, const char *help, struct hist_browser_timer *hbt, float min_pcnt, struct perf_env *env, bool warn_lost_event) { - int nr_entries = evlist->core.nr_entries; + int nr_entries = evlist__nr_entries(evlist); if (evlist__single_entry(evlist)) { single_entry: { |
