perf report/top with callchain fixes improvements
Arnaldo Carvalho de Melo
maintainerHi,
These patches try to address inconsistencies in the navigation
in the 'perf report' and 'perf top' when callchains are present.
Linus reported that when pressing ENTER with callchains enabled
it no longer shows the popup menu, instead it toggles the callchains, which is surprising and rather annoying.
So this patchset makes it consistent by presenting the popup
menu when ENTER is pressed and callchains are present, and then an extra menu entry, associated with the new '+' toggle is added and appears proeminently in the popup menu, together with suggestions about using 'e' to toogle all the callchains for the top level entry,
Other changes in this patchkit allows for using those suggested
hotkeys directly from the popup menu and add a new 'k' hotkey to zoom straight into the main kernel map. Pressing it again works just like using the popup menu via ENTER + "Zoom out of the kernel" or using ESC to Zoom out from the last filtering operation.
While working on this I noticed some other oddities like in
the default --children mode where the Annotation popup option appeared even for entries where no samples were taken, i.e. something that appeared just on some callchain, suppressing the Annotation popup entry for those cases. If the user insists in using the 'a' hotkey on such an entry, a popup warning is showed.
Also a fix for kernel maps for ranges that seldom appear in
samples, like "[kernel.vmlinux].init.text", that didn't a pointer back to the kernel maps data structure and thus was causing an assertion falure were found and fix, please test, available at:
Available at:
git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux.git perf/hists_browser
Best regards,
- Arnaldo
Arnaldo Carvalho de Melo (12):
perf hists browser: Restore ESC as "Zoom out" of DSO/thread/etc
perf report/top: Make ENTER consistently bring up menu
perf report/top: Add menu entry for toggling callchain expansion
perf report/top: Improve toggle callchain menu option
perf hists browser: Generalize the do_zoom_dso() function
perf report/top: Add 'k' hotkey to zoom directly into the kernel map perf hists browser: Allow passing an initial hotkey
tools ui popup: Allow returning hotkeys
perf report/top: Allow pressing hotkeys in the options popup menu perf report/top: Do not offer annotation for symbols without samples perf report/top: Make 'e' visible in the help and make it toggle showing callchains perf maps: Set maps pointer in the kmap area for kernel maps
tools/perf/builtin-c2c.c | 4 +- tools/perf/tests/maps.c | 8 +- tools/perf/ui/browsers/hists.c | 141 ++++++++++++++++++++++++---- tools/perf/ui/browsers/hists.h | 2 +- tools/perf/ui/browsers/res_sample.c | 2 +- tools/perf/ui/browsers/scripts.c | 2 +- tools/perf/ui/tui/util.c | 12 ++- tools/perf/ui/util.h | 2 +- tools/perf/util/auxtrace.c | 2 +- tools/perf/util/dso.c | 4 +- tools/perf/util/dso.h | 4 +- tools/perf/util/machine.c | 10 +- tools/perf/util/map.c | 15 ++- tools/perf/util/map.h | 2 +- tools/perf/util/probe-event.c | 10 +- tools/perf/util/sort.c | 3 +- tools/perf/util/sort.h | 2 + tools/perf/util/symbol-elf.c | 2 +- tools/perf/util/symbol.c | 6 +- 19 files changed, 178 insertions(+), 55 deletions(-)
Signature · 1 line
2.21.0
Arnaldo Carvalho de Melo
maintainerPATCH 1/12 perf hists browser: Restore ESC as "Zoom out" of DSO/thread/etc
From: Arnaldo Carvalho de Melo <[email protected]>
We need to set actions->ms.map since 599a2f38a989 ("perf hists browser:
Check sort keys before hot key actions"), as in that patch we bail out if map is NULL.
--- tools/perf/ui/browsers/hists.c | 1 + 1 file changed, 1 insertion(+)
tools/perf/ui/browsers/hists.c +1 -0
@@ -3062,6 +3062,7 @@ static int perf_evsel__hists_browse(struct evsel *evsel, int nr_events,continue ; } + actions->ms.map = map; top =pstack__peek (browser->pstack);if (top == &browser->hists->dso_filter) {/*
Signature · 1 line
2.21.0
Arnaldo Carvalho de Melo
maintainerPATCH 2/12 perf report/top: Make ENTER consistently bring up menu
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
When callchains are present the ENTER key switches from bringing up the menu that offers Annotation, Zoom by DSO, etc to expanding/collapsing one callchain level, causing confusion, fix it by making it consistently bring up the menu and use '+' to expand/collapse one callchain level.
Next patch will also add an entry to the menu to allow expanding/collapsing, so that people used to ENTER expanding one callchain level can quickly find it and use it instead.
--- tools/perf/ui/browsers/hists.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
tools/perf/ui/browsers/hists.c +2 -1
@@ -706,7 +706,7 @@ int hist_browser__run(struct hist_browser *browser, const char *help, browser->show_headers = !browser->show_headers;hist_browser__update_rows (browser);break ; -case K_ENTER : +case '+' :if (hist_browser__toggle_fold (browser))break ;/* fall thru */
@@ -2858,6 +2858,7 @@ static int perf_evsel__hists_browse(struct evsel *evsel, int nr_events,"For symbolic views (--sort has sym):\n\n" \"ENTER Zoom into DSO/Threads & Annotate current symbol\n" \"ESC Zoom out\n" \ +"+ Expand/Collapse one callchain level\n" \"a Annotate current symbol\n" \"C Collapse all callchains\n" \"d Zoom into current DSO\n" \
Signature · 1 line
2.21.0
Arnaldo Carvalho de Melo
maintainerPATCH 3/12 perf report/top: Add menu entry for toggling callchain expansion
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
Since previously pressing ENTER toggled expansion/collapse of callchain entries and now brings up the same menu used when callchains are not present, add an entry so that users can quickly figure out the change in behaviour.
Its worth mentioning that we also always had 'e'/'c' to expand/collapse all entries in a hist entry and 'E'/'C' for all hist entries.
--- tools/perf/ui/browsers/hists.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+)
tools/perf/ui/browsers/hists.c +21 -0
@@ -2527,6 +2527,26 @@ add_dso_opt(struct hist_browser *browser, struct popup_action *act,return 1 ; } +static int do_toggle_callchain (struct hist_browser *browser,struct popup_action *act__maybe_unused ) +{ +hist_browser__toggle_fold (browser); +return 0 ; +} + +static int add_callchain_toggle_opt (struct hist_browser *browser,struct popup_action *act,char **optstr) +{ +struct hist_entry *he = browser->he_selection; + +if (!he->has_children) +return 0 ; + +if (asprintf (optstr,"Expand/Collapse callchain" ) <0 ) +return 0 ; + + act->fn = do_toggle_callchain; +return 1 ; +} +static int do_browse_map (struct hist_browser *browser__maybe_unused ,struct popup_action *act)
@@ -3137,6 +3157,7 @@ static int perf_evsel__hists_browse(struct evsel *evsel, int nr_events, &options[nr_options], thread); nr_options +=add_dso_opt (browser, &actions[nr_options], &options[nr_options], map); + nr_options +=add_callchain_toggle_opt (browser, &actions[nr_options], &options[nr_options]); nr_options += add_map_opt(browser, &actions[nr_options], &options[nr_options], browser->selection ?
Signature · 1 line
2.21.0
Arnaldo Carvalho de Melo
maintainerPATCH 4/12 perf report/top: Improve toggle callchain menu option
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
Taking into account the current status of the callchain, i.e. if folded, show "Expand", otherwise "Collapse", also show the name of the entry that will be affected and mention the hotkeys for expanding/collapsing all callchains below the main entry, the one that appears with/without callchains.
--- tools/perf/ui/browsers/hists.c | 54 ++++++++++++++++++++++++++++++++-- tools/perf/util/sort.c | 3 +- tools/perf/util/sort.h | 2 ++ 3 files changed, 54 insertions(+), 5 deletions(-)
tools/perf/ui/browsers/hists.c +51 -3
@@ -391,6 +391,52 @@ static void hist_entry__init_have_children(struct hist_entry *he) he->init_have_children = true; } +static bool hist_browser__selection_has_children (struct hist_browser *browser) +{ +struct hist_entry *he = browser->he_selection; +struct map_symbol *ms = browser->selection; + +if (!he || !ms) +return false; + +if (ms == &he->ms) +return he->has_children; + + return container_of(ms, struct callchain_list, ms)->has_children; +} + +static bool hist_browser__selection_unfolded (struct hist_browser *browser) +{ +struct hist_entry *he = browser->he_selection; +struct map_symbol *ms = browser->selection; + +if (!he || !ms) +return false; + +if (ms == &he->ms) +return he->unfolded; + + return container_of(ms, struct callchain_list, ms)->unfolded; +} + +static char *hist_browser__selection_sym_name (struct hist_browser *browser,char *bf,size_t size) +{ +struct hist_entry *he = browser->he_selection; +struct map_symbol *ms = browser->selection; +struct callchain_list *callchain_entry; + +if (!he || !ms) +return NULL ; + +if (ms == &he->ms) { +hist_entry__sym_snprintf (he, bf, size,0 ); +return bf +4 ;// skip the level, e.g. '[k] ' + } + + callchain_entry = container_of(ms, struct callchain_list, ms); +return callchain_list__sym_name (callchain_entry, bf, size, browser->show_dso); +} +static bool hist_browser__toggle_fold (struct hist_browser *browser) {struct hist_entry *he = browser->he_selection;
@@ -2535,12 +2581,14 @@ static int do_toggle_callchain(struct hist_browser *browser, struct popup_actionstatic int add_callchain_toggle_opt (struct hist_browser *browser,struct popup_action *act,char **optstr) { -struct hist_entry *he = browser->he_selection; +char sym_name[512 ]; -if (!he->has_children) +if (!hist_browser__selection_has_children (browser))return 0 ; -if (asprintf (optstr,"Expand/Collapse callchain" ) <0 ) +if (asprintf (optstr,"%s [%s] callchain (one level, same as '+' hotkey, use 'e'/'c' for the whole main level entry)" , +hist_browser__selection_unfolded (browser) ?"Collapse" :"Expand" , +hist_browser__selection_sym_name (browser, sym_name,sizeof (sym_name))) <0 )return 0 ; act->fn = do_toggle_callchain;
tools/perf/util/sort.c +1 -2
@@ -324,8 +324,7 @@ static int _hist_entry__sym_snprintf(struct map_symbol *ms,return ret; } -static int hist_entry__sym_snprintf (struct hist_entry *he,char *bf, -size_t size,unsigned int width) +int hist_entry__sym_snprintf (struct hist_entry *he,char *bf,size_t size,unsigned int width) {return _hist_entry__sym_snprintf (&he->ms, he->ip, he->level, bf, size, width);
tools/perf/util/sort.h +2 -0
@@ -164,6 +164,8 @@ static __pure inline bool hist_entry__has_callchains(struct hist_entry *he)return he->callchain_size !=0 ; } +int hist_entry__sym_snprintf (struct hist_entry *he,char *bf,size_t size,unsigned int width); +static inline bool hist_entry__has_pairs (struct hist_entry *he) {return !list_empty (&he->pairs.node);
Signature · 1 line
2.21.0
Arnaldo Carvalho de Melo
maintainerPATCH 5/12 perf hists browser: Generalize the do_zoom_dso() function
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
We'll use it to provide a top level hotkey to zoom into the kernel dso directly.
--- tools/perf/ui/browsers/hists.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
tools/perf/ui/browsers/hists.c +7 -4
@@ -2530,11 +2530,8 @@ add_thread_opt(struct hist_browser *browser, struct popup_action *act,return 1 ; } -static int -do_zoom_dso (struct hist_browser *browser,struct popup_action *act) +static int hists_browser__zoom_map (struct hist_browser *browser,struct map *map) { -struct map *map = act->ms.map; -if (!hists__has (browser->hists, dso) || map ==NULL )return 0 ;
@@ -2556,6 +2553,12 @@ do_zoom_dso(struct hist_browser *browser, struct popup_action *act)return 0 ; } +static int +do_zoom_dso (struct hist_browser *browser,struct popup_action *act) +{ +return hists_browser__zoom_map (browser, act->ms.map); +} +static int add_dso_opt (struct hist_browser *browser,struct popup_action *act,char **optstr,struct map *map)
Signature · 1 line
2.21.0
Arnaldo Carvalho de Melo
maintainerPATCH 6/12 perf report/top: Add 'k' hotkey to zoom directly into the kernel map
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
As a convenience, equivalent to pressing Enter in a line with a kernel symbol and then selecting "Zoom" into the kernel DSO.
--- tools/perf/ui/browsers/hists.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
tools/perf/ui/browsers/hists.c +8 -1
@@ -18,7 +18,9 @@#include "../../util/evlist.h" #include "../../util/header.h" #include "../../util/hist.h" +#include "../../util/machine.h" #include "../../util/map.h" +#include "../../util/maps.h" #include "../../util/symbol.h" #include "../../util/map_symbol.h" #include "../../util/branch.h"
@@ -2566,7 +2568,7 @@ add_dso_opt(struct hist_browser *browser, struct popup_action *act,if (!hists__has (browser->hists, dso) || map ==NULL )return 0 ; -if (asprintf (optstr,"Zoom %s %s DSO" , +if (asprintf (optstr,"Zoom %s %s DSO (use the 'k' hotkey to zoom directly into the kernel)" , browser->hists->dso_filter ?"out of" :"into" ,__map__is_kernel (map) ?"the Kernel" : map->dso->short_name) <0 )return 0 ;
@@ -2936,6 +2938,7 @@ static int perf_evsel__hists_browse(struct evsel *evsel, int nr_events,"E Expand all callchains\n" \"F Toggle percentage of filtered entries\n" \"H Display column headers\n" \ +"k Zoom into the kernel map\n" \"L Change percent limit\n" \"m Display context menu\n" \"S Zoom into current Processor Socket\n" \
@@ -3033,6 +3036,10 @@ static int perf_evsel__hists_browse(struct evsel *evsel, int nr_events, actions->ms.map = map;do_zoom_dso (browser, actions);continue ; +case 'k' : +if (browser->selection !=NULL ) +hists_browser__zoom_map (browser, browser->selection->maps->machine->vmlinux_map); +continue ;case 'V' : verbose = (verbose +1 ) %4 ; browser->show_dso = verbose >0 ;
Signature · 1 line
2.21.0
Namhyung Kim
maintainerRe: [PATCH 06/12] perf report/top: Add 'k' hotkey to zoom directly into the kernel map
Hi Arnaldo,
Quoted 5 lines · Arnaldo Carvalho de Melo
From: Arnaldo Carvalho de Melo <[email protected]>
As a convenience, equivalent to pressing Enter in a line with a kernel symbol and then selecting "Zoom" into the kernel DSO.
We already have 'd' key for 'zoom into current dso'. Do you really want 'k' for kernel specially?
Quoted 29 lines
Cc Adrian Hunter <[email protected]>Cc Andi Kleen <[email protected]>Cc Jin Yao <[email protected]>Cc Jiri Olsa <[email protected]>Cc Kan Liang <[email protected]>Cc Linus Torvalds <[email protected]>Cc Namhyung Kim <[email protected]>Signed-off-by Arnaldo Carvalho de Melo <[email protected]>--- tools/perf/ui/browsers/hists.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)tools/perf/ui/browsers/hists.c +2
-0@@ -18,7 +18,9 @@#include "../../util/evlist.h" #include "../../util/header.h" #include "../../util/hist.h" +#include "../../util/machine.h" #include "../../util/map.h" +#include "../../util/maps.h" #include "../../util/symbol.h" #include "../../util/map_symbol.h" #include "../../util/branch.h"
tools/perf/ui/browsers/hists.c add_dso_opt(struct hist_browser *browser, struct popup_action *act, · line 2571
Quoted 5 lines
tools/perf/ui/browsers/hists.c +1
-1@@ -2566,7 +2568,7 @@ add_dso_opt(struct hist_browser *browser, struct popup_action *act,if (!hists__has (browser->hists, dso) || map ==NULL )return 0 ; - if (asprintf(optstr, "Zoom %s %s DSO", + if (asprintf(optstr, "Zoom %s %s DSO (use the 'k' hotkey to zoom directly into the kernel)",
Wouldn't it be better suggesting 'd' key instead?
Thanks
Namhyung
Quoted 25 lines
tools/perf/ui/browsers/hists.c +5
-1browser->hists->dso_filter ?"out of" :"into" , __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0) return 0;@@ -2936,6 +2938,7 @@ static int perf_evsel__hists_browse(struct evsel *evsel, int nr_events,"E Expand all callchains\n" \"F Toggle percentage of filtered entries\n" \"H Display column headers\n" \ +"k Zoom into the kernel map\n" \"L Change percent limit\n" \"m Display context menu\n" \"S Zoom into current Processor Socket\n" \@@ -3033,6 +3036,10 @@ static int perf_evsel__hists_browse(struct evsel *evsel, int nr_events, actions->ms.map = map;do_zoom_dso (browser, actions);continue ; +case 'k' : +if (browser->selection !=NULL ) +hists_browser__zoom_map (browser, browser->selection->maps->machine->vmlinux_map); +continue ;case 'V' : verbose = (verbose +1 ) %4 ; browser->show_dso = verbose >0 ; --2.21.0
Re: [PATCH 06/12] perf report/top: Add 'k' hotkey to zoom directly into the kernel map
Em Fri, Dec 20, 2019 at 03:48:23PM +0900, Namhyung Kim escreveu:
Quoted 6 lines · Arnaldo Carvalho de Melo
Quoted 3 lines
From: Arnaldo Carvalho de Melo <[email protected]>
As a convenience, equivalent to pressing Enter in a line with a kernel symbol and then selecting "Zoom" into the kernel DSO.We already have 'd' key for 'zoom into current dso'.
Right, current DSO, 'k' is equivalent to:
1. Navigate to a kernel map entry
2. Press 'd'
And also to:
1. Navigate to a kernel map entry
2. Press ENTER
3. Navigate to "Zoom into Kernel DSO"
4. Press ENTER
One key versus 2 or four.
Quoted 1 line
Do you really want 'k' for kernel specially?
I thought kernel hackers would like the convenience, doing:
perf top + k
To get the main kernel samples looks faster than:
perf top -e cycles:k
And those are not even equivalent, as cycles:k will show everything in ring 0, while 'perf top + k' will show just what is in the kernel _and_ in the main kernel map.
- Arnaldo
Namhyung Kim
maintainerRe: [PATCH 06/12] perf report/top: Add 'k' hotkey to zoom directly into the kernel map
Quoted 29 lines · Arnaldo Carvalho de Melo
Em Fri, Dec 20, 2019 at 03:48:23PM +0900, Namhyung Kim escreveu:
Quoted 6 lines · Arnaldo Carvalho de Melo
Quoted 3 lines
From: Arnaldo Carvalho de Melo <[email protected]>
As a convenience, equivalent to pressing Enter in a line with a kernel symbol and then selecting "Zoom" into the kernel DSO.We already have 'd' key for 'zoom into current dso'.
Right, current DSO, 'k' is equivalent to:
1. Navigate to a kernel map entry
2. Press 'd'And also to:
1. Navigate to a kernel map entry
2. Press ENTER
3. Navigate to "Zoom into Kernel DSO"
4. Press ENTEROne key versus 2 or four.
Quoted 1 line
Do you really want 'k' for kernel specially?
I thought kernel hackers would like the convenience, doing:
perf top + k
Quoted 7 lines
To get the main kernel samples looks faster than:
perf top -e cycles:k
And those are not even equivalent, as cycles:k will show everything in ring 0, while 'perf top + k' will show just what is in the kernel _and_ in the main kernel map.
I'm fine with adding 'k' key itself, but I thought a bit strange when it suggests kernel even with user DSOs.
Thanks
Namhyung
Arnaldo Carvalho de Melo
maintainerPATCH 7/12 perf hists browser: Allow passing an initial hotkey
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
Sometimes we're in an outer code, like the main hists browser popup menu and the user follows a suggestion about using some hotkey, and that hotkey is really handled by hists_browser__run(), so allow for calling it with that hotkey, making it handle it instead of waiting for the user to press one.
--- tools/perf/builtin-c2c.c | 4 ++-- tools/perf/ui/browsers/hists.c | 13 +++++++------ tools/perf/ui/browsers/hists.h | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-)
tools/perf/builtin-c2c.c +2 -2
@@ -2384,7 +2384,7 @@ static int perf_c2c__browse_cacheline(struct hist_entry *he)c2c_browser__update_nr_entries (browser);while (1 ) { - key =hist_browser__run (browser,"? - help" , true); + key =hist_browser__run (browser,"? - help" , true,0 );switch (key) {case 's' :
@@ -2453,7 +2453,7 @@ static int perf_c2c__hists_browse(struct hists *hists)c2c_browser__update_nr_entries (browser);while (1 ) { - key =hist_browser__run (browser,"? - help" , true); + key =hist_browser__run (browser,"? - help" , true,0 );switch (key) {case 'q' :
tools/perf/ui/browsers/hists.c +7 -6
@@ -673,9 +673,8 @@ static int hist_browser__title(struct hist_browser *browser, char *bf, size_t si }int hist_browser__run (struct hist_browser *browser,const char *help, -bool warn_lost_event) +bool warn_lost_event,int key) { -int key;char title[160 ];struct hist_browser_timer *hbt = browser->hbt;int delay_secs = hbt ? hbt->refresh :0 ;
@@ -688,9 +687,12 @@ int hist_browser__run(struct hist_browser *browser, const char *help,if (ui_browser__show (&browser->b, title,"%s" , help) <0 )return -1 ; +if (key) + goto do_hotkey; +while (1 ) { key =ui_browser__run (&browser->b, delay_secs); - +do_hotkey:switch (key) {case K_TIMER : {u64 nr_entries;
@@ -2994,8 +2996,7 @@ static int perf_evsel__hists_browse(struct evsel *evsel, int nr_events, nr_options =0 ; - key =hist_browser__run (browser, helpline, - warn_lost_event); + key =hist_browser__run (browser, helpline, warn_lost_event,0 );if (browser->he_selection !=NULL ) { thread =hist_browser__selected_thread (browser);
@@ -3573,7 +3574,7 @@ int block_hists_tui_browse(struct block_hist *bh, struct evsel *evsel,memset (&action,0 ,sizeof (action));while (1 ) { - key =hist_browser__run (browser,"? - help" , true); + key =hist_browser__run (browser,"? - help" , true,0 );switch (key) {case 'q' :
tools/perf/ui/browsers/hists.h +1 -1
@@ -34,7 +34,7 @@ struct hist_browser {struct hist_browser *hist_browser__new (struct hists *hists);void hist_browser__delete (struct hist_browser *browser);int hist_browser__run (struct hist_browser *browser,const char *help, -bool warn_lost_event); +bool warn_lost_event,int key);void hist_browser__init (struct hist_browser *browser,struct hists *hists);#endif /* _PERF_UI_BROWSER_HISTS_H_ */
Signature · 1 line
2.21.0
Re: [PATCH 07/12] perf hists browser: Allow passing an initial hotkey
On Tue, Dec 17, 2019 at 11:48:23AM -0300, Arnaldo Carvalho de Melo wrote:
SNIP
Quoted 16 lines
tools/perf/ui/browsers/hists.c +1
-2@@ -673,9 +673,8 @@ static int hist_browser__title(struct hist_browser *browser, char *bf, size_t si }int hist_browser__run (struct hist_browser *browser,const char *help, -bool warn_lost_event) +bool warn_lost_event,int key) { -int key;char title[160 ];struct hist_browser_timer *hbt = browser->hbt;int delay_secs = hbt ? hbt->refresh :0 ;
tools/perf/ui/browsers/hists.c int hist_browser__run(struct hist_browser *browser, const char *help, · line 695
Quoted 10 lines
tools/perf/ui/browsers/hists.c +4
-1@@ -688,9 +687,12 @@ int hist_browser__run(struct hist_browser *browser, const char *help,if (ui_browser__show (&browser->b, title,"%s" , help) <0 )return -1 ; +if (key) + goto do_hotkey; +while (1 ) { key =ui_browser__run (&browser->b, delay_secs); - +do_hotkey:
or we could switch the 'swtich' and ui_browser__run, and get rid of the goto, like:
while (1) {
switch (key) {
...
}
key = ui_browser__run(&browser->b, delay_secs);
}jirka
Quoted 38 lines
tools/perf/ui/browsers/hists.c +2
-3switch (key) {case K_TIMER : {u64 nr_entries;@@ -2994,8 +2996,7 @@ static int perf_evsel__hists_browse(struct evsel *evsel, int nr_events, nr_options =0 ; - key =hist_browser__run (browser, helpline, - warn_lost_event); + key =hist_browser__run (browser, helpline, warn_lost_event,0 );if (browser->he_selection !=NULL ) { thread =hist_browser__selected_thread (browser);@@ -3573,7 +3574,7 @@ int block_hists_tui_browse(struct block_hist *bh, struct evsel *evsel,memset (&action,0 ,sizeof (action));while (1 ) { - key =hist_browser__run (browser,"? - help" , true); + key =hist_browser__run (browser,"? - help" , true,0 );switch (key) {case 'q' :tools/perf/ui/browsers/hists.h +1
-1@@ -34,7 +34,7 @@ struct hist_browser {struct hist_browser *hist_browser__new (struct hists *hists);void hist_browser__delete (struct hist_browser *browser);int hist_browser__run (struct hist_browser *browser,const char *help, -bool warn_lost_event); +bool warn_lost_event,int key);void hist_browser__init (struct hist_browser *browser,struct hists *hists);#endif /* _PERF_UI_BROWSER_HISTS_H_ */ Signature · 1 line
2.21.0
Re: [PATCH 07/12] perf hists browser: Allow passing an initial hotkey
Em Wed, Dec 18, 2019 at 09:08:18AM +0100, Jiri Olsa escreveu:
Quoted 33 lines · Arnaldo Carvalho de Melo
SNIP
Quoted 16 lines
tools/perf/ui/browsers/hists.c +1
-2@@ -673,9 +673,8 @@ static int hist_browser__title(struct hist_browser *browser, char *bf, size_t si }int hist_browser__run (struct hist_browser *browser,const char *help, -bool warn_lost_event) +bool warn_lost_event,int key) { -int key;char title[160 ];struct hist_browser_timer *hbt = browser->hbt;int delay_secs = hbt ? hbt->refresh :0 ;tools/perf/ui/browsers/hists.c int hist_browser__run(struct hist_browser *browser, const char *help, · line 695
Quoted 10 lines
tools/perf/ui/browsers/hists.c +4
-1@@ -688,9 +687,12 @@ int hist_browser__run(struct hist_browser *browser, const char *help,if (ui_browser__show (&browser->b, title,"%s" , help) <0 )return -1 ; +if (key) + goto do_hotkey; +while (1 ) { key =ui_browser__run (&browser->b, delay_secs); - +do_hotkey:or we could switch the 'swtich' and
ui_browser__run, and get rid of the goto, like:
Quoted 7 lines
while (1) {
switch (key) {
...
}
key = ui_browser__run(&browser->b, delay_secs);
}I think those are equivalent and having the test like I did is more clear, i.e. "has this key been provided" instead of going to the switch just to hit the default case for the zero in key and call ui_browser__run().
- Arnaldo
Quoted 40 lines
jirka
Quoted 38 lines
tools/perf/ui/browsers/hists.c +2
-3switch (key) {case K_TIMER : {u64 nr_entries;@@ -2994,8 +2996,7 @@ static int perf_evsel__hists_browse(struct evsel *evsel, int nr_events, nr_options =0 ; - key =hist_browser__run (browser, helpline, - warn_lost_event); + key =hist_browser__run (browser, helpline, warn_lost_event,0 );if (browser->he_selection !=NULL ) { thread =hist_browser__selected_thread (browser);@@ -3573,7 +3574,7 @@ int block_hists_tui_browse(struct block_hist *bh, struct evsel *evsel,memset (&action,0 ,sizeof (action));while (1 ) { - key =hist_browser__run (browser,"? - help" , true); + key =hist_browser__run (browser,"? - help" , true,0 );switch (key) {case 'q' :tools/perf/ui/browsers/hists.h +1
-1@@ -34,7 +34,7 @@ struct hist_browser {struct hist_browser *hist_browser__new (struct hists *hists);void hist_browser__delete (struct hist_browser *browser);int hist_browser__run (struct hist_browser *browser,const char *help, -bool warn_lost_event); +bool warn_lost_event,int key);void hist_browser__init (struct hist_browser *browser,struct hists *hists);#endif /* _PERF_UI_BROWSER_HISTS_H_ */ Signature · 1 line
2.21.0
Signature · 1 line
- Arnaldo
Re: [PATCH 07/12] perf hists browser: Allow passing an initial hotkey
Quoted 39 lines · Arnaldo Carvalho de Melo
Em Wed, Dec 18, 2019 at 09:08:18AM +0100, Jiri Olsa escreveu:
Quoted 38 lines · Arnaldo Carvalho de Melo
SNIP
Quoted 16 lines
tools/perf/ui/browsers/hists.c +1
-2@@ -673,9 +673,8 @@ static int hist_browser__title(struct hist_browser *browser, char *bf, size_t si }int hist_browser__run (struct hist_browser *browser,const char *help, -bool warn_lost_event) +bool warn_lost_event,int key) { -int key;char title[160 ];struct hist_browser_timer *hbt = browser->hbt;int delay_secs = hbt ? hbt->refresh :0 ;tools/perf/ui/browsers/hists.c int hist_browser__run(struct hist_browser *browser, const char *help, · line 695
Quoted 10 lines
tools/perf/ui/browsers/hists.c +4
-1@@ -688,9 +687,12 @@ int hist_browser__run(struct hist_browser *browser, const char *help,if (ui_browser__show (&browser->b, title,"%s" , help) <0 )return -1 ; +if (key) + goto do_hotkey; +while (1 ) { key =ui_browser__run (&browser->b, delay_secs); - +do_hotkey:or we could switch the 'swtich' and
ui_browser__run, and get rid of the goto, like:while (1) { switch (key) { ... }
Quoted 7 lines
Quoted 2 lines
key = ui_browser__run(&browser->b, delay_secs); }I think those are equivalent and having the test like I did is more clear, i.e. "has this key been provided" instead of going to the switch just to hit the default case for the zero in key and call
ui_browser__run().
sure, I just don't like goto other than for error handling, looks too hacky to me ;-) but of course it's your call
jirka
Re: [PATCH 07/12] perf hists browser: Allow passing an initial hotkey
Em Wed, Dec 18, 2019 at 03:23:21PM +0100, Jiri Olsa escreveu:
Quoted 21 lines · Arnaldo Carvalho de Melo
Quoted 19 lines
Em Wed, Dec 18, 2019 at 09:08:18AM +0100, Jiri Olsa escreveu:
Quoted 18 lines · Arnaldo Carvalho de Melo
Review
Quoted 7 lines
(quoted diff) +4
-1+ if (key) + goto do_hotkey; + while (1) { key = ui_browser__run(&browser->b, delay_secs); - +do_hotkey:or we could switch the 'swtich' and
ui_browser__run, and get rid of the goto, like:while (1) { switch (key) { ... } key = ui_browser__run(&browser->b, delay_secs); }
Quoted 7 lines
Quoted 4 lines
I think those are equivalent and having the test like I did is more clear, i.e. "has this key been provided" instead of going to the switch just to hit the default case for the zero in key and call
ui_browser__run().sure, I just don't like goto other than for error handling, looks too hacky to me ;-) but of course it's your call
How about the one below?
- Arnaldo
commit 9290297c911ad6c315c5f46f35afa3ce517a4c9f
Author: Arnaldo Carvalho de Melo <[email protected]> Date: Thu Dec 12 15:31:40 2019 -0300
perf hists browser: Allow passing an initial hotkey
Sometimes we're in an outer code, like the main hists browser popup menu and the user follows a suggestion about using some hotkey, and that hotkey is really handled by hists_browser__run(), so allow for calling it with that hotkey, making it handle it instead of waiting for the user to press one.
tools/perf/builtin-c2c.c +2 -2
@@ -2384,7 +2384,7 @@ static int perf_c2c__browse_cacheline(struct hist_entry *he)c2c_browser__update_nr_entries (browser);while (1 ) { - key =hist_browser__run (browser,"? - help" , true); + key =hist_browser__run (browser,"? - help" , true,0 );switch (key) {case 's' :
@@ -2453,7 +2453,7 @@ static int perf_c2c__hists_browse(struct hists *hists)c2c_browser__update_nr_entries (browser);while (1 ) { - key =hist_browser__run (browser,"? - help" , true); + key =hist_browser__run (browser,"? - help" , true,0 );switch (key) {case 'q' :
tools/perf/ui/browsers/hists.c +79 -74
183 lines not on this page · raw message
tools/perf/ui/browsers/hists.h +1 -1
@@ -34,7 +34,7 @@ struct hist_browser {struct hist_browser *hist_browser__new (struct hists *hists);void hist_browser__delete (struct hist_browser *browser);int hist_browser__run (struct hist_browser *browser,const char *help, -bool warn_lost_event); +bool warn_lost_event,int key);void hist_browser__init (struct hist_browser *browser,struct hists *hists);#endif /* _PERF_UI_BROWSER_HISTS_H_ */
Re: [PATCH 07/12] perf hists browser: Allow passing an initial hotkey
Quoted 27 lines · Arnaldo Carvalho de Melo
Em Wed, Dec 18, 2019 at 03:23:21PM +0100, Jiri Olsa escreveu:
Quoted 25 lines · Arnaldo Carvalho de Melo
Quoted 24 lines
Em Wed, Dec 18, 2019 at 09:08:18AM +0100, Jiri Olsa escreveu:
Quoted 11 lines · Arnaldo Carvalho de Melo
tools/perf/ui/browsers/hists.c int hist_browser__run(struct hist_browser *browser, const char *help,
Quoted 7 lines
tools/perf/ui/browsers/hists.c +4
-1+if (key) + goto do_hotkey; +while (1 ) { key =ui_browser__run (&browser->b, delay_secs); - +do_hotkey:or we could switch the 'swtich' and
ui_browser__run, and get rid of the goto, like:Quoted 7 lines
while (1) { switch (key) { ... } key = ui_browser__run(&browser->b, delay_secs); }I think those are equivalent and having the test like I did is more clear, i.e. "has this key been provided" instead of going to the switch just to hit the default case for the zero in key and call
ui_browser__run().
Quoted 4 lines
Quoted 2 lines
sure, I just don't like goto other than for error handling, looks too hacky to me ;-) but of course it's your call
How about the one below?
looks good, thanks
jirka
Arnaldo Carvalho de Melo
maintainerPATCH 8/12 tools ui popup: Allow returning hotkeys
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
With this patch if an optional pointer is passed to ui__popup_menu() then when any key that is not being handled (ENTER, ESC, etc) is typed, it'll record that key in the pointer and return, allowing for hotkey processing on the caller.
If NULL is passed, no change in logic, unhandled keys continue to be ignored.
--- tools/perf/ui/browsers/hists.c | 4 ++-- tools/perf/ui/browsers/res_sample.c | 2 +- tools/perf/ui/browsers/scripts.c | 2 +- tools/perf/ui/tui/util.c | 12 ++++++++---- tools/perf/ui/util.h | 2 +- 5 files changed, 13 insertions(+), 9 deletions(-)
tools/perf/ui/browsers/hists.c +2 -2
@@ -2389,7 +2389,7 @@ static int switch_data_file(void)closedir (pwd_dir);if (nr_options) { - choice =ui__popup_menu (nr_options, options); + choice =ui__popup_menu (nr_options, options,NULL );if (choice < nr_options && choice >=0 ) { tmp =strdup (abs_path[choice]);if (tmp) {
@@ -3275,7 +3275,7 @@ static int perf_evsel__hists_browse(struct evsel *evsel, int nr_events, do { struct popup_action *act; - choice = ui__popup_menu(nr_options, options); + choice = ui__popup_menu(nr_options, options, NULL); if (choice == -1 || choice >= nr_options) break;
tools/perf/ui/browsers/res_sample.c +1 -1
@@ -56,7 +56,7 @@ int res_sample_browse(struct res_sample *res_samples, int num_res,return -1 ; } } - choice =ui__popup_menu (num_res, names); + choice =ui__popup_menu (num_res, names,NULL );for (i =0 ; i < num_res; i++)zfree (&names[i]);free (names);
tools/perf/ui/browsers/scripts.c +1 -1
@@ -126,7 +126,7 @@ static int list_scripts(char *script_name, bool *custom, SCRIPT_FULLPATH_LEN);if (num <0 ) num =0 ; - choice =ui__popup_menu (num + max_std, (char *const *)names); + choice =ui__popup_menu (num + max_std, (char *const *)names,NULL );if (choice <0 ) { ret =-1 ; goto out;
tools/perf/ui/tui/util.c +8 -4
@@ -23,7 +23,7 @@ static void ui_browser__argv_write(struct ui_browser *browser,ui_browser__write_nstring (browser, *arg, browser->width); } -static int popup_menu__run (struct ui_browser *menu) +static int popup_menu__run (struct ui_browser *menu,int *keyp) {int key;
@@ -45,6 +45,11 @@ static int popup_menu__run(struct ui_browser *menu) key =-1 ;break ;default : +if (keyp) { + *keyp = key; + key = menu->nr_entries; +break ; + }continue ; }
@@ -55,7 +60,7 @@ static int popup_menu__run(struct ui_browser *menu)return key; } -int ui__popup_menu (int argc,char *const argv[]) +int ui__popup_menu (int argc,char *const argv[],int *keyp) {struct ui_browser menu = { .entries = (void *)argv,
@@ -64,8 +69,7 @@ int ui__popup_menu(int argc, char * const argv[]) .write = ui_browser__argv_write, .nr_entries = argc, }; - -return popup_menu__run (&menu); +return popup_menu__run (&menu, keyp); } int ui_browser__input_window(const char *title, const char *text, char *input,
tools/perf/ui/util.h +1 -1
@@ -5,7 +5,7 @@#include <stdarg.h> int ui__getch (int delay_secs); -int ui__popup_menu (int argc,char *const argv[]); +int ui__popup_menu (int argc,char *const argv[],int *keyp);int ui__help_window (const char *text);int ui__dialog_yesno (const char *msg);void __ui__info_window (const char *title,const char *text,const char *exit_msg);
Signature · 1 line
2.21.0
Arnaldo Carvalho de Melo
maintainerPATCH 9/12 perf report/top: Allow pressing hotkeys in the options popup menu
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
When the users presses ENTER in the main 'perf report/top' screen a popup menu is presented, in it some hotkeys are suggested as alternatives to using the menu, or for additional features.
At that point the user may try those hotkeys, so allow for that by recording the key used and exiting, the caller then can check for that possibility and process the hotkey.
I.e. try pressing ENTER, and then 'k' to exit and zoom into the kernel map, using ESC then zooms out, etc.
--- tools/perf/ui/browsers/hists.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-)
tools/perf/ui/browsers/hists.c +10 -6
@@ -2991,12 +2991,13 @@ static int perf_evsel__hists_browse(struct evsel *evsel, int nr_events,while (1 ) {struct thread *thread =NULL ;struct map *map =NULL ; -int choice =0 ; +int choice;int socked_id =-1 ; - nr_options =0 ; - - key =hist_browser__run (browser, helpline, warn_lost_event,0 ); + key =0 ;// reset key +do_hotkey:// key came straight from options ui__popup_menu() + choice = nr_options =0 ; + key =hist_browser__run (browser, helpline, warn_lost_event, key);if (browser->he_selection !=NULL ) { thread =hist_browser__selected_thread (browser);
@@ -3275,10 +3276,13 @@ static int perf_evsel__hists_browse(struct evsel *evsel, int nr_events,do {struct popup_action *act; - choice =ui__popup_menu (nr_options, options,NULL ); -if (choice ==-1 || choice >= nr_options) + choice =ui__popup_menu (nr_options, options, &key); +if (choice ==-1 )break ; +if (choice == nr_options) + goto do_hotkey; + act = &actions[choice]; key = act->fn (browser, act); }while (key ==1 );
Signature · 1 line
2.21.0
Arnaldo Carvalho de Melo
maintainerPATCH 10/12 perf report/top: Do not offer annotation for symbols without samples
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
This can happen in the --children mode, i.e. the default mode when callchains are present, where one of the main entries may be a callchain entry with no samples.
So far we were not providing any information about why an annotation couldn't be provided even offering the Annotation option in the popup menu.
Work is needed to allow for no-samples "annotation', i.e. to show the disassembly anyway and allow for navigation, etc.
--- tools/perf/ui/browsers/hists.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
tools/perf/ui/browsers/hists.c +10 -1
@@ -2461,7 +2461,8 @@ add_annotate_opt(struct hist_browser *browser __maybe_unused, struct popup_action *act, char **optstr, struct map_symbol *ms) { - if (ms->sym == NULL || ms->map->dso->annotate_warned) + if (ms->sym == NULL || ms->map->dso->annotate_warned || + symbol__annotation(ms->sym)->src == NULL) return 0; if (asprintf(optstr, "Annotate %s", ms->sym->name) < 0)
@@ -3027,6 +3028,14 @@ static int perf_evsel__hists_browse(struct evsel *evsel, int nr_events, browser->selection->map->dso->annotate_warned) continue; +if (symbol__annotation (browser->selection->sym)->src ==NULL ) { +ui_browser__warning (&browser->b, delay_secs *2 , +"No samples for the \"%s\" symbol.\n\n" +"Probably appeared just in a callchain" , + browser->selection->sym->name); +continue ; + } + actions->ms.map = browser->selection->map; actions->ms.sym = browser->selection->sym;do_annotate (browser, actions);
Signature · 1 line
2.21.0
Arnaldo Carvalho de Melo
maintainerPATCH 11/12 perf report/top: Make 'e' visible in the help and make it toggle showing callchains
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
The 'e' and 'c' hotkeys were present for a long time, but not documented in the help window, change 'e' to be a toggle so that it gets consistent with other toggles like '+' and document it in the help window.
Keep 'c' as is for people used to it but don't document, as it is easier to just use 'e' to show/hide all the callchains for a top level histogram entry.
--- tools/perf/ui/browsers/hists.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
tools/perf/ui/browsers/hists.c +7 -1
@@ -407,6 +407,11 @@ static bool hist_browser__selection_has_children(struct hist_browser *browser) return container_of(ms, struct callchain_list, ms)->has_children; } +static bool hist_browser__he_selection_unfolded (struct hist_browser *browser) +{ +return browser->he_selection ? browser->he_selection->unfolded : false; +} +static bool hist_browser__selection_unfolded (struct hist_browser *browser) {struct hist_entry *he = browser->he_selection;
@@ -750,7 +755,7 @@ int hist_browser__run(struct hist_browser *browser, const char *help,break ;case 'e' :/* Expand the selected entry. */ -hist_browser__set_folding_selected (browser, true); +hist_browser__set_folding_selected (browser, !hist_browser__he_selection_unfolded (browser));break ;case 'H' : browser->show_headers = !browser->show_headers;
@@ -2938,6 +2943,7 @@ static int perf_evsel__hists_browse(struct evsel *evsel, int nr_events,"a Annotate current symbol\n" \"C Collapse all callchains\n" \"d Zoom into current DSO\n" \ +"e Expand/Collapse main entry callchains\n" \"E Expand all callchains\n" \"F Toggle percentage of filtered entries\n" \"H Display column headers\n" \
Signature · 1 line
2.21.0
Arnaldo Carvalho de Melo
maintainerPATCH 12/12 perf maps: Set maps pointer in the kmap area for kernel maps
In reply to Arnaldo Carvalho de MeloFrom: Arnaldo Carvalho de Melo <[email protected]>
When kernel maps are created with map__new2() we allocate an extra area to store a pointer to the 'struct maps' for the kernel maps, and this ends up being used in places like __map__is_kernel() to figure out if a map is the main kernel one.
We were setting this up only in __machine__create_kernel_maps() and machine__create_extra_kernel_map(), but not when splitting kallsyms, kcore address ranges in new kernel maps such as "[kernel.vmlinux].init.text", leading to assertion failures in __map__is_kernel().
So make map__new2() receive the kernel 'struct maps' pointer so that all kernel maps point back to it in its 'struct kmap' area.
--- tools/perf/tests/maps.c | 8 ++++---- tools/perf/util/auxtrace.c | 2 +- tools/perf/util/dso.c | 4 ++-- tools/perf/util/dso.h | 4 +++- tools/perf/util/machine.c | 10 ++++------ tools/perf/util/map.c | 15 ++++++++++++++- tools/perf/util/map.h | 2 +- tools/perf/util/probe-event.c | 10 ++++++---- tools/perf/util/symbol-elf.c | 2 +- tools/perf/util/symbol.c | 6 ++++-- 10 files changed, 40 insertions(+), 23 deletions(-)
tools/perf/tests/maps.c +4 -4
@@ -69,7 +69,7 @@ int test__maps__merge_in(struct test *t __maybe_unused, int subtest __maybe_unusfor (i =0 ; i <ARRAY_SIZE (bpf_progs); i++) {struct map *map; - map =dso__new_map (bpf_progs[i].name); + map =dso__new_map (bpf_progs[i].name, &maps);TEST_ASSERT_VAL ("failed to create map" , map); map->start = bpf_progs[i].start;
@@ -78,13 +78,13 @@ int test__maps__merge_in(struct test *t __maybe_unused, int subtest __maybe_unusmap__put (map); } - map_kcore1 =dso__new_map ("kcore1" ); + map_kcore1 =dso__new_map ("kcore1" , &maps);TEST_ASSERT_VAL ("failed to create map" , map_kcore1); - map_kcore2 =dso__new_map ("kcore2" ); + map_kcore2 =dso__new_map ("kcore2" , &maps);TEST_ASSERT_VAL ("failed to create map" , map_kcore2); - map_kcore3 =dso__new_map ("kcore3" ); + map_kcore3 =dso__new_map ("kcore3" , &maps);TEST_ASSERT_VAL ("failed to create map" , map_kcore3);/* kcore1 map overlaps over all bpf maps */
tools/perf/util/auxtrace.c +1 -1
@@ -2250,7 +2250,7 @@ static struct dso *load_dso(const char *name)struct map *map;struct dso *dso; - map =dso__new_map (name); + map =dso__new_map (name,NULL );if (!map)return NULL ;
tools/perf/util/dso.c +2 -2
@@ -1118,13 +1118,13 @@ ssize_t dso__data_write_cache_addr(struct dso *dso, struct map *map,return dso__data_write_cache_offs (dso, machine, offset, data, size); } -struct map *dso__new_map (const char *name) +struct map *dso__new_map (const char *name,struct maps *kmaps) {struct map *map =NULL ;struct dso *dso =dso__new (name);if (dso) - map =map__new2 (0 , dso); + map =map__new2 (0 , dso, kmaps);return map; }
tools/perf/util/dso.h +3 -1
@@ -353,7 +353,9 @@ ssize_t dso__data_write_cache_addr(struct dso *dso, struct map *map, struct machine *machine, u64 addr, const u8 *data, ssize_t size); -struct map *dso__new_map (const char *name); +struct maps ; + +struct map *dso__new_map (const char *name,struct maps *kmaps);struct dso *machine__findnew_kernel (struct machine *machine,const char *name,const char *short_name,int dso_type);
tools/perf/util/machine.c +4 -6
@@ -726,7 +726,7 @@ static int machine__process_ksymbol_register(struct machine *machine,struct map *map =maps__find (&machine->kmaps, event->ksymbol.addr);if (!map) { - map =dso__new_map (event->ksymbol.name); + map =dso__new_map (event->ksymbol.name, &machine->kmaps);if (!map)return -ENOMEM ;
@@ -784,7 +784,7 @@ static struct map *machine__addnew_module_map(struct machine *machine, u64 startif (dso ==NULL ) goto out; - map =map__new2 (start, dso); + map =map__new2 (start, dso, &machine->kmaps);if (map ==NULL ) goto out;
@@ -963,7 +963,7 @@ int machine__create_extra_kernel_map(struct machine *machine,struct kmap *kmap;struct map *map; - map =map__new2 (xm->start, kernel); + map =map__new2 (xm->start, kernel, &machine->kmaps);if (!map)return -1 ;
@@ -972,7 +972,6 @@ int machine__create_extra_kernel_map(struct machine *machine, kmap =map__kmap (map); - kmap->kmaps = &machine->kmaps;strlcpy (kmap->name, xm->name,KMAP_NAME_LEN );maps__insert (&machine->kmaps, map);
@@ -1088,7 +1087,7 @@ __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)/* In case of renewal the kernel map, destroy previous one */ machine__destroy_kernel_maps (machine); - machine->vmlinux_map =map__new2 (0 , kernel); + machine->vmlinux_map =map__new2 (0 , kernel, &machine->kmaps);if (machine->vmlinux_map ==NULL )return -1 ;
@@ -1098,7 +1097,6 @@ __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)if (!kmap)return -1 ; - kmap->kmaps = &machine->kmaps;maps__insert (&machine->kmaps, map);return 0 ;
tools/perf/util/map.c +14 -1
@@ -223,7 +223,7 @@ struct map *map__new(struct machine *machine, u64 start, u64 len,* they are loaded) and for vmlinux, where only after we load all the * symbols we'll know where it starts and ends. */ -struct map *map__new2 (u64 start,struct dso *dso) +struct map *map__new2 (u64 start,struct dso *dso,struct maps *kmaps) {struct map *map =calloc (1 , (sizeof (*map) + (dso->kernel ?sizeof (struct kmap ) :0 )));
@@ -232,6 +232,19 @@ struct map *map__new2(u64 start, struct dso *dso)* ->end will be filled after we load all the symbols */ map__init (map, start,0 ,0 , dso); +if (dso->kernel) { +/* +* __map__is_kernel() Needs this for in-kernel map ranges +* such as: +* (gdb) print map->dso->name +* $8 = 0x1232d6c "[kernel.vmlinux].init.text" +* (gdb) print map->dso->kernel +* $9 = DSO_TYPE_KERNEL +* (gdb) +*/ +struct kmap *kmap =map__kmap (map); + kmap->kmaps = kmaps; + } }return map;
tools/perf/util/map.h +1 -1
@@ -108,7 +108,7 @@ struct dso_id;struct map *map__new (struct machine *machine,u64 start,u64 len,u64 pgoff,struct dso_id *id,u32 prot,u32 flags,char *filename,struct thread *thread); -struct map *map__new2 (u64 start,struct dso *dso); +struct map *map__new2 (u64 start,struct dso *dso,struct maps *kmaps);void map__delete (struct map *map);struct map *map__clone (struct map *map);
tools/perf/util/probe-event.c +6 -4
@@ -146,7 +146,7 @@ static struct map *kernel_get_module_map(const char *module)/* A file path -- this is an offline module */ if (module &&strchr (module,'/' )) -return dso__new_map (module); +return dso__new_map (module, maps);if (!module) { pos =machine__kernel_map (host_machine);
@@ -170,7 +170,7 @@ struct map *get_target_map(const char *target, struct nsinfo *nsi, bool user)if (user) {struct map *map; - map =dso__new_map (target); + map =dso__new_map (target,NULL );if (map && map->dso) map->dso->nsinfo =nsinfo__get (nsi);return map;
@@ -651,12 +651,13 @@ static int post_process_offline_probe_trace_events(struct probe_trace_event *tevs, int ntevs, const char *pathname) { + struct maps *maps = machine__kernel_maps(host_machine);struct map *map;unsigned long stext =0 ;int i, ret =0 ;/* Prepare a map for offline binary */ - map =dso__new_map (pathname); + map =dso__new_map (pathname, maps);if (!map ||get_text_start_address (pathname, &stext,NULL ) <0 ) {pr_warning ("Failed to get ELF symbols for %s\n" , pathname);return -EINVAL ;
@@ -2111,7 +2112,8 @@ static int find_perf_probe_point_from_map(struct probe_trace_point *tp,int ret = -ENOENT ;if (!is_kprobe) { - map =dso__new_map (tp->module); +struct maps *maps =machine__kernel_maps (host_machine); + map =dso__new_map (tp->module, maps);if (!map) goto out; sym =map__find_symbol (map, addr);
tools/perf/util/symbol-elf.c +1 -1
@@ -915,7 +915,7 @@ static int dso__process_kernel_symbol(struct dso *dso, struct map *map, curr_dso->kernel = dso->kernel; curr_dso->long_name = dso->long_name; curr_dso->long_name_len = dso->long_name_len; - curr_map =map__new2 (start, curr_dso); + curr_map =map__new2 (start, curr_dso, kmaps);dso__put (curr_dso);if (curr_map ==NULL )return -1 ;
tools/perf/util/symbol.c +4 -2
@@ -856,7 +856,7 @@ static int maps__split_kallsyms(struct maps *kmaps, struct dso *dso, u64 delta, ndso->kernel = dso->kernel; - curr_map =map__new2 (pos->start, ndso); + curr_map =map__new2 (pos->start, ndso, kmaps);if (curr_map ==NULL ) {dso__put (ndso);return -1 ;
@@ -1144,6 +1144,7 @@ static int validate_kcore_addresses(const char *kallsyms_filename,struct kcore_mapfn_data {struct dso *dso; +struct maps *kmaps;struct list_head maps; };
@@ -1152,7 +1153,7 @@ static int kcore_mapfn(u64 start, u64 len, u64 pgoff, void *data)struct kcore_mapfn_data *md = data;struct map *map; - map =map__new2 (start, md->dso); + map =map__new2 (start, md->dso, md->kmaps);if (map ==NULL )return -ENOMEM ;
@@ -1271,6 +1272,7 @@ static int dso__load_kcore(struct dso *dso, struct map *map,return -EINVAL ; md.dso = dso; + md.kmaps = kmaps;INIT_LIST_HEAD (&md.maps); fd =open (kcore_filename,O_RDONLY );
Signature · 1 line
2.21.0
Re: [PATCH 12/12] perf maps: Set maps pointer in the kmap area for kernel maps
On Tue, Dec 17, 2019 at 11:48:28AM -0300, Arnaldo Carvalho de Melo wrote:
SNIP
Quoted 26 lines
tools/perf/util/machine.c +1
-1+ machine->vmlinux_map =map__new2 (0 , kernel, &machine->kmaps);if (machine->vmlinux_map ==NULL )return -1 ;@@ -1098,7 +1097,6 @@ __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)if (!kmap)return -1 ; - kmap->kmaps = &machine->kmaps;maps__insert (&machine->kmaps, map);return 0 ;tools/perf/util/map.c +1
-1@@ -223,7 +223,7 @@ struct map *map__new(struct machine *machine, u64 start, u64 len,* they are loaded) and for vmlinux, where only after we load all the * symbols we'll know where it starts and ends. */ -struct map *map__new2 (u64 start,struct dso *dso) +struct map *map__new2 (u64 start,struct dso *dso,struct maps *kmaps) {struct map *map =calloc (1 , (sizeof (*map) + (dso->kernel ?sizeof (struct kmap ) :0 )));
tools/perf/util/map.c struct map *map__new2(u64 start, struct dso *dso) · line 234
Quoted 3 lines
tools/perf/util/map.c +0
-0@@ -232,6 +232,19 @@ struct map *map__new2(u64 start, struct dso *dso)* ->end will be filled after we load all the symbols */ map__init (map, start,0 ,0 , dso);
we are passing NULL for kmaps in some cases,
should we check it in here and warn?
if (!WARN_ON_ONCE(!kmaps, "too bad..") && dso->kernel)
jirka
Re: [PATCH 12/12] perf maps: Set maps pointer in the kmap area for kernel maps
Em Wed, Dec 18, 2019 at 10:05:04AM +0100, Jiri Olsa escreveu:
Quoted 37 lines · Arnaldo Carvalho de Melo
SNIP
Quoted 26 lines
tools/perf/util/machine.c +1
-1+ machine->vmlinux_map =map__new2 (0 , kernel, &machine->kmaps);if (machine->vmlinux_map ==NULL )return -1 ;@@ -1098,7 +1097,6 @@ __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)if (!kmap)return -1 ; - kmap->kmaps = &machine->kmaps;maps__insert (&machine->kmaps, map);return 0 ;tools/perf/util/map.c +1
-1@@ -223,7 +223,7 @@ struct map *map__new(struct machine *machine, u64 start, u64 len,* they are loaded) and for vmlinux, where only after we load all the * symbols we'll know where it starts and ends. */ -struct map *map__new2 (u64 start,struct dso *dso) +struct map *map__new2 (u64 start,struct dso *dso,struct maps *kmaps) {struct map *map =calloc (1 , (sizeof (*map) + (dso->kernel ?sizeof (struct kmap ) :0 )));tools/perf/util/map.c struct map *map__new2(u64 start, struct dso *dso) · line 234
Quoted 3 lines
tools/perf/util/map.c +0
-0@@ -232,6 +232,19 @@ struct map *map__new2(u64 start, struct dso *dso)* ->end will be filled after we load all the symbols */ map__init (map, start,0 ,0 , dso);we are passing NULL for kmaps in some cases,
should we check it in here and warn?
Quoted 1 line
if (!WARN_ON_ONCE(!kmaps, "too bad..") && dso->kernel)
I'll add that, yeah
- Arnaldo
Re: [PATCH 12/12] perf maps: Set maps pointer in the kmap area for kernel maps
In reply to Jiri OlsaEm Wed, Dec 18, 2019 at 10:05:04AM +0100, Jiri Olsa escreveu:
Quoted 37 lines · Arnaldo Carvalho de Melo
SNIP
Quoted 26 lines
(quoted diff) +1
-1+ machine->vmlinux_map = map__new2(0, kernel, &machine->kmaps); if (machine->vmlinux_map == NULL) return -1;@@ -1098,7 +1097,6 @@ __machine__create_kernel_maps(struct machine *machine, struct dso *kernel) if (!kmap) return -1; - kmap->kmaps = &machine->kmaps; maps__insert(&machine->kmaps, map); return 0;tools/perf/util/map.c +1
-1@@ -223,7 +223,7 @@ struct map *map__new(struct machine *machine, u64 start, u64 len,* they are loaded) and for vmlinux, where only after we load all the * symbols we'll know where it starts and ends. */ -struct map *map__new2 (u64 start,struct dso *dso) +struct map *map__new2 (u64 start,struct dso *dso,struct maps *kmaps) {struct map *map =calloc (1 , (sizeof (*map) + (dso->kernel ?sizeof (struct kmap ) :0 )));tools/perf/util/map.c struct map *map__new2(u64 start, struct dso *dso) · line 234
Quoted 3 lines
tools/perf/util/map.c +0
-0@@ -232,6 +232,19 @@ struct map *map__new2(u64 start, struct dso *dso)* ->end will be filled after we load all the symbols */ map__init (map, start,0 ,0 , dso);we are passing NULL for kmaps in some cases,
should we check it in here and warn?
Quoted 1 line
if (!WARN_ON_ONCE(!kmaps, "too bad..") && dso->kernel)
After looking at this some more, I retract this patch and instead the two-liner at the end of this message seems enough.
I forgot the dso->kernel is just set for the main kernel map, and what dso__process_kernel_symbol is doing is to split that map into chunks for the ELF sections for the main kernel map, as an extra tidbit of information, i.e. that symbol is in a specific main kernel section, so its dso->kernel continues being set and thus it expects the kmap area to be in place.
There is space for simplification in this old code, but for now the safest is just the patch below, agreed?
- Arnaldo
tools/perf/util/symbol-elf.c +3 -0
@@ -920,6 +920,9 @@ static int dso__process_kernel_symbol(struct dso *dso, struct map *map,if (curr_map ==NULL )return -1 ; +if (curr_dso->kernel) +map__kmap (curr_map)->kmaps = kmaps; +if (adjust_kernel_syms) { curr_map->start = shdr->sh_addr +ref_reloc (kmap); curr_map->end = curr_map->start + shdr->sh_size;
Re: [PATCH 12/12] perf maps: Set maps pointer in the kmap area for kernel maps
Em Wed, Dec 18, 2019 at 03:22:54PM -0300, Arnaldo Carvalho de Melo escreveu:
Quoted 3 lines
Em Wed, Dec 18, 2019 at 10:05:04AM +0100, Jiri Olsa escreveu:
After looking at this some more, I retract this patch and instead the two-liner at the end of this message seems enough.
So here is the full cset, I have not made changes to the other patches,
- Arnaldo
commit 178427a192bcbe3ad93dd0637c3dceaa3ccef31e
Author: Arnaldo Carvalho de Melo <[email protected]> Date: Wed Dec 18 15:23:14 2019 -0300
perf map: Set kmap->kmaps backpointer for main kernel map chunks
When a map is create to represent the main kernel area (vmlinux) with map__new2() we allocate an extra area to store a pointer to the 'struct maps' for the kernel maps, so that we can access that struct when loading ELF files or kallsyms, as we will need to split it in multiple maps, one per kernel module or ELF section (such as ".init.text").
So when map->dso->kernel is non-zero, it is expected that map__kmap(map)->kmaps to be set to the tree of kernel maps (modules, chunks of the main kernel, bpf progs put in place via PERF_RECORD_KSYMBOL, the main kernel).
This was not the case when we were splitting the main kernel into chunks for its ELF sections, which ended up making 'perf report --children' processing a perf.data file with callchains to trip on __map__is_kernel(), when we press ENTER to see the popup menu for main histogram entries that starts at a symbol in the ".init.text" ELF section, e.g.:
- 8.83% 0.00% swapper [kernel.vmlinux].init.text [k] start_kernel
start_kernel
cpu_startup_entry
do_idle
cpuidle_enter
cpuidle_enter_state
intel_idle
Fix it.
tools/perf/util/symbol-elf.c +3 -0
@@ -920,6 +920,9 @@ static int dso__process_kernel_symbol(struct dso *dso, struct map *map,if (curr_map ==NULL )return -1 ; +if (curr_dso->kernel) +map__kmap (curr_map)->kmaps = kmaps; +if (adjust_kernel_syms) { curr_map->start = shdr->sh_addr +ref_reloc (kmap); curr_map->end = curr_map->start + shdr->sh_size;
Re: [PATCH 12/12] perf maps: Set maps pointer in the kmap area for kernel maps
Quoted 55 lines · Arnaldo Carvalho de Melo
Em Wed, Dec 18, 2019 at 03:22:54PM -0300, Arnaldo Carvalho de Melo escreveu:
Quoted 3 lines
Em Wed, Dec 18, 2019 at 10:05:04AM +0100, Jiri Olsa escreveu:
After looking at this some more, I retract this patch and instead the two-liner at the end of this message seems enough.So here is the full cset, I have not made changes to the other patches,
- Arnaldo
commit
178427a192bcbe3ad93dd0637c3dceaa3ccef31eAuthor: Arnaldo Carvalho de Melo <[email protected]> Date: Wed Dec 18 15:23:14 2019 -0300perf map: Set
kmap->kmapsbackpointer for main kernel map chunksWhen a map is create to represent the main kernel area (vmlinux) with
map__new2()we allocate an extra area to store a pointer to the 'struct maps' for the kernel maps, so that we can access that struct when loading ELF files or kallsyms, as we will need to split it in multiple maps, one per kernel module or ELF section (such as ".init.text").So when
map->dso->kernelis non-zero, it is expected that map__kmap(map)->kmaps to be set to the tree of kernel maps (modules, chunks of the main kernel, bpf progs put in place viaPERF_RECORD_KSYMBOL, the main kernel).This was not the case when we were splitting the main kernel into chunks for its ELF sections, which ended up making 'perf report --children' processing a perf.data file with callchains to trip on
__map__is_kernel(), when we press ENTER to see the popup menu for main histogram entries that starts at a symbol in the ".init.text" ELF section, e.g.:- 8.83% 0.00% swapper [kernel.vmlinux].init.text [k]
start_kernel
start_kernel
cpu_startup_entry
do_idle
cpuidle_enter
cpuidle_enter_state
intel_idleFix it.
Cc Adrian Hunter <[email protected]>Cc Jiri Olsa <[email protected]>Cc Namhyung Kim <[email protected]>Signed-off-by Arnaldo Carvalho de Melo <[email protected]>tools/perf/util/symbol-elf.c +0
-0
tools/perf/util/symbol-elf.c static int dso__process_kernel_symbol(struct dso *dso, struct map *map, · line 928
Quoted 9 lines
tools/perf/util/symbol-elf.c +3
-0@@ -920,6 +920,9 @@ static int dso__process_kernel_symbol(struct dso *dso, struct map *map,if (curr_map ==NULL )return -1 ; +if (curr_dso->kernel) +map__kmap (curr_map)->kmaps = kmaps; +if (adjust_kernel_syms) { curr_map->start = shdr->sh_addr +ref_reloc (kmap); curr_map->end = curr_map->start + shdr->sh_size;
looks good ;-)
jirka
Re: [PATCH 12/12] perf maps: Set maps pointer in the kmap area for kernel maps
In reply to Arnaldo Carvalho de MeloOn Tue, Dec 17, 2019 at 11:48:28AM -0300, Arnaldo Carvalho de Melo wrote:
SNIP
Quoted 14 lines
tools/perf/util/machine.c +0
-1@@ -1098,7 +1097,6 @@ __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)if (!kmap)return -1 ; - kmap->kmaps = &machine->kmaps;maps__insert (&machine->kmaps, map);return 0 ;tools/perf/util/map.c +0
-0
tools/perf/util/map.c struct map *map__new(struct machine *machine, u64 start, u64 len, · line 226
Quoted 5 lines
tools/perf/util/map.c +1
-1@@ -223,7 +223,7 @@ struct map *map__new(struct machine *machine, u64 start, u64 len,* they are loaded) and for vmlinux, where only after we load all the * symbols we'll know where it starts and ends. */ -struct map *map__new2 (u64 start,struct dso *dso) +struct map *map__new2 (u64 start,struct dso *dso,struct maps *kmaps)
hum, how about map__new? kernel maps could go throught that as well, right?
jirka
Re: [PATCH 12/12] perf maps: Set maps pointer in the kmap area for kernel maps
Em Wed, Dec 18, 2019 at 10:07:07AM +0100, Jiri Olsa escreveu:
Quoted 12 lines · Arnaldo Carvalho de Melo
SNIP
Quoted 8 lines
tools/perf/util/machine.c +0
-1@@ -1098,7 +1097,6 @@ __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)if (!kmap)return -1 ; - kmap->kmaps = &machine->kmaps;maps__insert (&machine->kmaps, map);
Quoted 13 lines
tools/perf/util/map.c struct map *map__new(struct machine *machine, u64 start, u64 len, · line 226
Quoted 11 lines
tools/perf/util/machine.c +0
-0return 0 ;tools/perf/util/map.c +1
-1@@ -223,7 +223,7 @@ struct map *map__new(struct machine *machine, u64 start, u64 len,* they are loaded) and for vmlinux, where only after we load all the * symbols we'll know where it starts and ends. */ -struct map *map__new2 (u64 start,struct dso *dso) +struct map *map__new2 (u64 start,struct dso *dso,struct maps *kmaps)hum, how about
map__new? kernel maps could go throught that as well, right?
Nope, I even thought about renaming map__new2() to map__new_kmap() as only it is used to create kernel/modules maps, as is stated above in the comment just before map__new2().
map__new() is only called from machine__process_mmap_event() and machine__process_mmap2_event() and only after checking if it is not a kernel "mmap":
if (sample->cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
sample->cpumode == PERF_RECORD_MISC_KERNEL) {
ret = machine__process_kernel_mmap_event(machine, event);
if (ret < 0)
goto out_problem;
return 0;
...
map = map__new(...);- Arnaldo