mirror of
https://github.com/torvalds/linux.git
synced 2026-05-22 06:01:53 +02:00
perf annotate-data: Implement folding in TUI browser
Like 'perf report', use 'e' or 'E' key to toggle folding the current entry so that it can control displaying child entries. Note I didn't add the 'c' and 'C' key to collapse the entry because it's also handled with the 'e'/'E' since it toggles the state. Committer testing: Do some 'perf mem record' for some workload of the whole system, using the target options, as usual (--pid/-p, -C/--cpu, -a for the system wide profiling, etc) and then: # perf annotate --skip-empty --data-type=pthread_mutex_t That, by default, will start as --tui, then press 'E' to see the whole struct unfolded, etc. Signed-off-by: Namhyung Kim <namhyung@kernel.org> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Ian Rogers <irogers@google.com> Cc: Ingo Molnar <mingo@kernel.org> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Kan Liang <kan.liang@linux.intel.com> Cc: Peter Zijlstra <peterz@infradead.org> Link: https://lore.kernel.org/r/20240812194447.2049187-3-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
05fc5b7de3
commit
af73856e9a
|
|
@ -18,12 +18,6 @@
|
|||
#define UNFOLD_SIGN '-'
|
||||
#define NOCHLD_SIGN ' '
|
||||
|
||||
struct annotated_data_browser {
|
||||
struct ui_browser b;
|
||||
struct list_head entries;
|
||||
int nr_events;
|
||||
};
|
||||
|
||||
struct browser_entry {
|
||||
struct list_head node;
|
||||
struct annotated_member *data;
|
||||
|
|
@ -35,6 +29,13 @@ struct browser_entry {
|
|||
bool folded; /* only can be false when it has children */
|
||||
};
|
||||
|
||||
struct annotated_data_browser {
|
||||
struct ui_browser b;
|
||||
struct list_head entries;
|
||||
struct browser_entry *curr;
|
||||
int nr_events;
|
||||
};
|
||||
|
||||
static struct annotated_data_browser *get_browser(struct ui_browser *uib)
|
||||
{
|
||||
return container_of(uib, struct annotated_data_browser, b);
|
||||
|
|
@ -302,6 +303,7 @@ static void browser__seek(struct ui_browser *uib, off_t offset, int whence)
|
|||
|
||||
static unsigned int browser__refresh(struct ui_browser *uib)
|
||||
{
|
||||
struct annotated_data_browser *browser = get_browser(uib);
|
||||
struct browser_entry *entry, *next;
|
||||
int row = 0;
|
||||
|
||||
|
|
@ -314,6 +316,8 @@ static unsigned int browser__refresh(struct ui_browser *uib)
|
|||
if (!uib->filter || !uib->filter(uib, &entry->node)) {
|
||||
ui_browser__gotorc(uib, row, 0);
|
||||
uib->write(uib, entry, row);
|
||||
if (uib->top_idx + row == uib->index)
|
||||
browser->curr = entry;
|
||||
if (++row == uib->rows)
|
||||
break;
|
||||
}
|
||||
|
|
@ -438,6 +442,78 @@ static void browser__write(struct ui_browser *uib, void *entry, int row)
|
|||
ui_browser__write_nstring(uib, "", uib->width);
|
||||
}
|
||||
|
||||
static void annotated_data_browser__fold(struct annotated_data_browser *browser,
|
||||
struct browser_entry *entry,
|
||||
bool recursive)
|
||||
{
|
||||
struct browser_entry *child;
|
||||
|
||||
if (list_empty(&entry->children))
|
||||
return;
|
||||
if (entry->folded && !recursive)
|
||||
return;
|
||||
|
||||
if (recursive) {
|
||||
list_for_each_entry(child, &entry->children, node)
|
||||
annotated_data_browser__fold(browser, child, true);
|
||||
}
|
||||
|
||||
entry->nr_entries = 1;
|
||||
entry->folded = true;
|
||||
}
|
||||
|
||||
static void annotated_data_browser__unfold(struct annotated_data_browser *browser,
|
||||
struct browser_entry *entry,
|
||||
bool recursive)
|
||||
{
|
||||
struct browser_entry *child;
|
||||
int nr_entries;
|
||||
|
||||
if (list_empty(&entry->children))
|
||||
return;
|
||||
if (!entry->folded && !recursive)
|
||||
return;
|
||||
|
||||
nr_entries = 1; /* for self */
|
||||
list_for_each_entry(child, &entry->children, node) {
|
||||
if (recursive)
|
||||
annotated_data_browser__unfold(browser, child, true);
|
||||
|
||||
nr_entries += child->nr_entries;
|
||||
}
|
||||
|
||||
entry->nr_entries = nr_entries;
|
||||
entry->folded = false;
|
||||
}
|
||||
|
||||
static void annotated_data_browser__toggle_fold(struct annotated_data_browser *browser,
|
||||
bool recursive)
|
||||
{
|
||||
struct browser_entry *curr = browser->curr;
|
||||
struct browser_entry *parent;
|
||||
|
||||
parent = curr->parent;
|
||||
while (parent) {
|
||||
parent->nr_entries -= curr->nr_entries;
|
||||
parent = parent->parent;
|
||||
}
|
||||
browser->b.nr_entries -= curr->nr_entries;
|
||||
|
||||
if (curr->folded)
|
||||
annotated_data_browser__unfold(browser, curr, recursive);
|
||||
else
|
||||
annotated_data_browser__fold(browser, curr, recursive);
|
||||
|
||||
parent = curr->parent;
|
||||
while (parent) {
|
||||
parent->nr_entries += curr->nr_entries;
|
||||
parent = parent->parent;
|
||||
}
|
||||
browser->b.nr_entries += curr->nr_entries;
|
||||
|
||||
assert(browser->b.nr_entries == count_visible_entries(browser));
|
||||
}
|
||||
|
||||
static int annotated_data_browser__run(struct annotated_data_browser *browser,
|
||||
struct evsel *evsel __maybe_unused,
|
||||
struct hist_browser_timer *hbt)
|
||||
|
|
@ -462,8 +538,18 @@ static int annotated_data_browser__run(struct annotated_data_browser *browser,
|
|||
"UP/DOWN/PGUP\n"
|
||||
"PGDN/SPACE Navigate\n"
|
||||
"</> Move to prev/next symbol\n"
|
||||
"e Expand/Collapse current entry\n"
|
||||
"E Expand/Collapse all children of the current\n"
|
||||
"q/ESC/CTRL+C Exit\n\n");
|
||||
continue;
|
||||
case 'e':
|
||||
annotated_data_browser__toggle_fold(browser,
|
||||
/*recursive=*/false);
|
||||
break;
|
||||
case 'E':
|
||||
annotated_data_browser__toggle_fold(browser,
|
||||
/*recursive=*/true);
|
||||
break;
|
||||
case K_LEFT:
|
||||
case '<':
|
||||
case '>':
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user