forked from ~ljy/RK356X_SDK_RELEASE

hc
2023-12-11 6778948f9de86c3cfaf36725a7c87dcff9ba247f
kernel/tools/perf/ui/browsers/hists.c
....@@ -6,17 +6,31 @@
66 #include <stdlib.h>
77 #include <string.h>
88 #include <linux/rbtree.h>
9
+#include <linux/string.h>
910 #include <sys/ttydefaults.h>
11
+#include <linux/time64.h>
12
+#include <linux/zalloc.h>
1013
14
+#include "../../util/debug.h"
15
+#include "../../util/dso.h"
16
+#include "../../util/callchain.h"
1117 #include "../../util/evsel.h"
1218 #include "../../util/evlist.h"
19
+#include "../../util/header.h"
1320 #include "../../util/hist.h"
21
+#include "../../util/machine.h"
22
+#include "../../util/map.h"
23
+#include "../../util/maps.h"
24
+#include "../../util/symbol.h"
25
+#include "../../util/map_symbol.h"
26
+#include "../../util/branch.h"
1427 #include "../../util/pstack.h"
1528 #include "../../util/sort.h"
16
-#include "../../util/util.h"
1729 #include "../../util/top.h"
1830 #include "../../util/thread.h"
31
+#include "../../util/block-info.h"
1932 #include "../../arch/common.h"
33
+#include "../../perf.h"
2034
2135 #include "../browsers/hists.h"
2236 #include "../helpline.h"
....@@ -27,8 +41,9 @@
2741 #include "srcline.h"
2842 #include "string2.h"
2943 #include "units.h"
44
+#include "time-utils.h"
3045
31
-#include "sane_ctype.h"
46
+#include <linux/ctype.h>
3247
3348 extern void hist_browser__init_hpp(void);
3449
....@@ -49,7 +64,7 @@
4964 struct hists *hists = browser->hists;
5065 int unfolded_rows = 0;
5166
52
- for (nd = rb_first(&hists->entries);
67
+ for (nd = rb_first_cached(&hists->entries);
5368 (nd = hists__filter_entries(nd, browser->min_pcnt)) != NULL;
5469 nd = rb_hierarchy_next(nd)) {
5570 struct hist_entry *he =
....@@ -267,7 +282,7 @@
267282 if (he->has_no_entry)
268283 return 1;
269284
270
- node = rb_first(&he->hroot_out);
285
+ node = rb_first_cached(&he->hroot_out);
271286 while (node) {
272287 float percent;
273288
....@@ -372,10 +387,61 @@
372387 he->has_children = !RB_EMPTY_ROOT(&he->sorted_chain);
373388 callchain__init_have_children(&he->sorted_chain);
374389 } else {
375
- he->has_children = !RB_EMPTY_ROOT(&he->hroot_out);
390
+ he->has_children = !RB_EMPTY_ROOT(&he->hroot_out.rb_root);
376391 }
377392
378393 he->init_have_children = true;
394
+}
395
+
396
+static bool hist_browser__selection_has_children(struct hist_browser *browser)
397
+{
398
+ struct hist_entry *he = browser->he_selection;
399
+ struct map_symbol *ms = browser->selection;
400
+
401
+ if (!he || !ms)
402
+ return false;
403
+
404
+ if (ms == &he->ms)
405
+ return he->has_children;
406
+
407
+ return container_of(ms, struct callchain_list, ms)->has_children;
408
+}
409
+
410
+static bool hist_browser__he_selection_unfolded(struct hist_browser *browser)
411
+{
412
+ return browser->he_selection ? browser->he_selection->unfolded : false;
413
+}
414
+
415
+static bool hist_browser__selection_unfolded(struct hist_browser *browser)
416
+{
417
+ struct hist_entry *he = browser->he_selection;
418
+ struct map_symbol *ms = browser->selection;
419
+
420
+ if (!he || !ms)
421
+ return false;
422
+
423
+ if (ms == &he->ms)
424
+ return he->unfolded;
425
+
426
+ return container_of(ms, struct callchain_list, ms)->unfolded;
427
+}
428
+
429
+static char *hist_browser__selection_sym_name(struct hist_browser *browser, char *bf, size_t size)
430
+{
431
+ struct hist_entry *he = browser->he_selection;
432
+ struct map_symbol *ms = browser->selection;
433
+ struct callchain_list *callchain_entry;
434
+
435
+ if (!he || !ms)
436
+ return NULL;
437
+
438
+ if (ms == &he->ms) {
439
+ hist_entry__sym_snprintf(he, bf, size, 0);
440
+ return bf + 4; // skip the level, e.g. '[k] '
441
+ }
442
+
443
+ callchain_entry = container_of(ms, struct callchain_list, ms);
444
+ return callchain_list__sym_name(callchain_entry, bf, size, browser->show_dso);
379445 }
380446
381447 static bool hist_browser__toggle_fold(struct hist_browser *browser)
....@@ -508,7 +574,7 @@
508574 struct hist_entry *child;
509575 int n = 0;
510576
511
- for (nd = rb_first(&he->hroot_out); nd; nd = rb_next(nd)) {
577
+ for (nd = rb_first_cached(&he->hroot_out); nd; nd = rb_next(nd)) {
512578 child = rb_entry(nd, struct hist_entry, rb_node);
513579 percent = hist_entry__get_percent_limit(child);
514580 if (!child->filtered && percent >= hb->min_pcnt)
....@@ -566,7 +632,7 @@
566632 struct rb_node *nd;
567633 struct hist_entry *he;
568634
569
- nd = rb_first(&browser->hists->entries);
635
+ nd = rb_first_cached(&browser->hists->entries);
570636 while (nd) {
571637 he = rb_entry(nd, struct hist_entry, rb_node);
572638
....@@ -611,10 +677,81 @@
611677 return browser->title ? browser->title(browser, bf, size) : 0;
612678 }
613679
614
-int hist_browser__run(struct hist_browser *browser, const char *help,
615
- bool warn_lost_event)
680
+static int hist_browser__handle_hotkey(struct hist_browser *browser, bool warn_lost_event, char *title, size_t size, int key)
616681 {
617
- int key;
682
+ switch (key) {
683
+ case K_TIMER: {
684
+ struct hist_browser_timer *hbt = browser->hbt;
685
+ u64 nr_entries;
686
+
687
+ WARN_ON_ONCE(!hbt);
688
+
689
+ if (hbt)
690
+ hbt->timer(hbt->arg);
691
+
692
+ if (hist_browser__has_filter(browser) || symbol_conf.report_hierarchy)
693
+ hist_browser__update_nr_entries(browser);
694
+
695
+ nr_entries = hist_browser__nr_entries(browser);
696
+ ui_browser__update_nr_entries(&browser->b, nr_entries);
697
+
698
+ if (warn_lost_event &&
699
+ (browser->hists->stats.nr_lost_warned !=
700
+ browser->hists->stats.nr_events[PERF_RECORD_LOST])) {
701
+ browser->hists->stats.nr_lost_warned =
702
+ browser->hists->stats.nr_events[PERF_RECORD_LOST];
703
+ ui_browser__warn_lost_events(&browser->b);
704
+ }
705
+
706
+ hist_browser__title(browser, title, size);
707
+ ui_browser__show_title(&browser->b, title);
708
+ break;
709
+ }
710
+ case 'D': { /* Debug */
711
+ struct hist_entry *h = rb_entry(browser->b.top, struct hist_entry, rb_node);
712
+ static int seq;
713
+
714
+ ui_helpline__pop();
715
+ ui_helpline__fpush("%d: nr_ent=(%d,%d), etl: %d, rows=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d",
716
+ seq++, browser->b.nr_entries, browser->hists->nr_entries,
717
+ browser->b.extra_title_lines, browser->b.rows,
718
+ browser->b.index, browser->b.top_idx, h->row_offset, h->nr_rows);
719
+ }
720
+ break;
721
+ case 'C':
722
+ /* Collapse the whole world. */
723
+ hist_browser__set_folding(browser, false);
724
+ break;
725
+ case 'c':
726
+ /* Collapse the selected entry. */
727
+ hist_browser__set_folding_selected(browser, false);
728
+ break;
729
+ case 'E':
730
+ /* Expand the whole world. */
731
+ hist_browser__set_folding(browser, true);
732
+ break;
733
+ case 'e':
734
+ /* Expand the selected entry. */
735
+ hist_browser__set_folding_selected(browser, !hist_browser__he_selection_unfolded(browser));
736
+ break;
737
+ case 'H':
738
+ browser->show_headers = !browser->show_headers;
739
+ hist_browser__update_rows(browser);
740
+ break;
741
+ case '+':
742
+ if (hist_browser__toggle_fold(browser))
743
+ break;
744
+ /* fall thru */
745
+ default:
746
+ return -1;
747
+ }
748
+
749
+ return 0;
750
+}
751
+
752
+int hist_browser__run(struct hist_browser *browser, const char *help,
753
+ bool warn_lost_event, int key)
754
+{
618755 char title[160];
619756 struct hist_browser_timer *hbt = browser->hbt;
620757 int delay_secs = hbt ? hbt->refresh : 0;
....@@ -627,79 +764,14 @@
627764 if (ui_browser__show(&browser->b, title, "%s", help) < 0)
628765 return -1;
629766
767
+ if (key && hist_browser__handle_hotkey(browser, warn_lost_event, title, sizeof(title), key))
768
+ goto out;
769
+
630770 while (1) {
631771 key = ui_browser__run(&browser->b, delay_secs);
632772
633
- switch (key) {
634
- case K_TIMER: {
635
- u64 nr_entries;
636
-
637
- WARN_ON_ONCE(!hbt);
638
-
639
- if (hbt)
640
- hbt->timer(hbt->arg);
641
-
642
- if (hist_browser__has_filter(browser) ||
643
- symbol_conf.report_hierarchy)
644
- hist_browser__update_nr_entries(browser);
645
-
646
- nr_entries = hist_browser__nr_entries(browser);
647
- ui_browser__update_nr_entries(&browser->b, nr_entries);
648
-
649
- if (warn_lost_event &&
650
- (browser->hists->stats.nr_lost_warned !=
651
- browser->hists->stats.nr_events[PERF_RECORD_LOST])) {
652
- browser->hists->stats.nr_lost_warned =
653
- browser->hists->stats.nr_events[PERF_RECORD_LOST];
654
- ui_browser__warn_lost_events(&browser->b);
655
- }
656
-
657
- hist_browser__title(browser, title, sizeof(title));
658
- ui_browser__show_title(&browser->b, title);
659
- continue;
660
- }
661
- case 'D': { /* Debug */
662
- static int seq;
663
- struct hist_entry *h = rb_entry(browser->b.top,
664
- struct hist_entry, rb_node);
665
- ui_helpline__pop();
666
- ui_helpline__fpush("%d: nr_ent=(%d,%d), etl: %d, rows=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d",
667
- seq++, browser->b.nr_entries,
668
- browser->hists->nr_entries,
669
- browser->b.extra_title_lines,
670
- browser->b.rows,
671
- browser->b.index,
672
- browser->b.top_idx,
673
- h->row_offset, h->nr_rows);
674
- }
773
+ if (hist_browser__handle_hotkey(browser, warn_lost_event, title, sizeof(title), key))
675774 break;
676
- case 'C':
677
- /* Collapse the whole world. */
678
- hist_browser__set_folding(browser, false);
679
- break;
680
- case 'c':
681
- /* Collapse the selected entry. */
682
- hist_browser__set_folding_selected(browser, false);
683
- break;
684
- case 'E':
685
- /* Expand the whole world. */
686
- hist_browser__set_folding(browser, true);
687
- break;
688
- case 'e':
689
- /* Expand the selected entry. */
690
- hist_browser__set_folding_selected(browser, true);
691
- break;
692
- case 'H':
693
- browser->show_headers = !browser->show_headers;
694
- hist_browser__update_rows(browser);
695
- break;
696
- case K_ENTER:
697
- if (hist_browser__toggle_fold(browser))
698
- break;
699
- /* fall thru */
700
- default:
701
- goto out;
702
- }
703775 }
704776 out:
705777 ui_browser__hide(&browser->b);
....@@ -1225,6 +1297,8 @@
12251297 hist_browser__hpp_color_overhead_guest_us;
12261298 perf_hpp__format[PERF_HPP__OVERHEAD_ACC].color =
12271299 hist_browser__hpp_color_overhead_acc;
1300
+
1301
+ res_sample_init();
12281302 }
12291303
12301304 static int hist_browser__show_entry(struct hist_browser *browser,
....@@ -1467,7 +1541,7 @@
14671541 int i = 0;
14681542
14691543 width -= fmt->entry(fmt, &hpp, entry);
1470
- ui_browser__printf(&browser->b, "%s", ltrim(s));
1544
+ ui_browser__printf(&browser->b, "%s", skip_spaces(s));
14711545
14721546 while (isspace(s[i++]))
14731547 width++;
....@@ -1683,7 +1757,7 @@
16831757 ret = fmt->header(fmt, &dummy_hpp, hists, 0, NULL);
16841758 dummy_hpp.buf[ret] = '\0';
16851759
1686
- start = trim(dummy_hpp.buf);
1760
+ start = strim(dummy_hpp.buf);
16871761 ret = strlen(start);
16881762
16891763 if (start != dummy_hpp.buf)
....@@ -1742,7 +1816,7 @@
17421816 struct hist_browser *hb;
17431817
17441818 hb = container_of(browser, struct hist_browser, b);
1745
- browser->top = rb_first(&hb->hists->entries);
1819
+ browser->top = rb_first_cached(&hb->hists->entries);
17461820 }
17471821 }
17481822
....@@ -1769,7 +1843,11 @@
17691843 continue;
17701844 }
17711845
1772
- percent = hist_entry__get_percent_limit(h);
1846
+ if (symbol_conf.report_individual_block)
1847
+ percent = block_info__total_cycles_percent(h);
1848
+ else
1849
+ percent = hist_entry__get_percent_limit(h);
1850
+
17731851 if (percent < hb->min_pcnt)
17741852 continue;
17751853
....@@ -2067,7 +2145,8 @@
20672145 advance_hpp(&hpp, ret);
20682146 }
20692147
2070
- printed += fprintf(fp, "%s\n", rtrim(s));
2148
+ strim(s);
2149
+ printed += fprintf(fp, "%s\n", s);
20712150
20722151 if (he->leaf && folded_sign == '-') {
20732152 printed += hist_browser__fprintf_callchain(browser, he, fp,
....@@ -2178,7 +2257,7 @@
21782257 }
21792258
21802259 static struct hist_browser *
2181
-perf_evsel_browser__new(struct perf_evsel *evsel,
2260
+perf_evsel_browser__new(struct evsel *evsel,
21822261 struct hist_browser_timer *hbt,
21832262 struct perf_env *env,
21842263 struct annotation_options *annotation_opts)
....@@ -2209,6 +2288,11 @@
22092288 return browser->he_selection->thread;
22102289 }
22112290
2291
+static struct res_sample *hist_browser__selected_res_sample(struct hist_browser *browser)
2292
+{
2293
+ return browser->he_selection ? browser->he_selection->res_samples : NULL;
2294
+}
2295
+
22122296 /* Check whether the browser is for 'top' or 'report' */
22132297 static inline bool is_report_browser(void *timer)
22142298 {
....@@ -2223,9 +2307,20 @@
22232307 if (!is_report_browser(hbt)) {
22242308 struct perf_top *top = hbt->arg;
22252309
2310
+ printed += scnprintf(bf + printed, size - printed,
2311
+ " lost: %" PRIu64 "/%" PRIu64,
2312
+ top->lost, top->lost_total);
2313
+
2314
+ printed += scnprintf(bf + printed, size - printed,
2315
+ " drop: %" PRIu64 "/%" PRIu64,
2316
+ top->drop, top->drop_total);
2317
+
22262318 if (top->zero)
22272319 printed += scnprintf(bf + printed, size - printed, " [z]");
2320
+
2321
+ perf_top__reset_sample_counters(top);
22282322 }
2323
+
22292324
22302325 return printed;
22312326 }
....@@ -2308,7 +2403,7 @@
23082403 closedir(pwd_dir);
23092404
23102405 if (nr_options) {
2311
- choice = ui__popup_menu(nr_options, options);
2406
+ choice = ui__popup_menu(nr_options, options, NULL);
23122407 if (choice < nr_options && choice >= 0) {
23132408 tmp = strdup(abs_path[choice]);
23142409 if (tmp) {
....@@ -2328,9 +2423,12 @@
23282423 }
23292424
23302425 struct popup_action {
2426
+ unsigned long time;
23312427 struct thread *thread;
23322428 struct map_symbol ms;
23332429 int socket;
2430
+ struct evsel *evsel;
2431
+ enum rstype rstype;
23342432
23352433 int (*fn)(struct hist_browser *browser, struct popup_action *act);
23362434 };
....@@ -2338,7 +2436,7 @@
23382436 static int
23392437 do_annotate(struct hist_browser *browser, struct popup_action *act)
23402438 {
2341
- struct perf_evsel *evsel;
2439
+ struct evsel *evsel;
23422440 struct annotation *notes;
23432441 struct hist_entry *he;
23442442 int err;
....@@ -2351,7 +2449,11 @@
23512449 if (!notes->src)
23522450 return 0;
23532451
2354
- evsel = hists_to_evsel(browser->hists);
2452
+ if (browser->block_evsel)
2453
+ evsel = browser->block_evsel;
2454
+ else
2455
+ evsel = hists_to_evsel(browser->hists);
2456
+
23552457 err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt,
23562458 browser->annotation_opts);
23572459 he = hist_browser__selected_entry(browser);
....@@ -2368,19 +2470,47 @@
23682470 return 0;
23692471 }
23702472
2473
+static struct symbol *symbol__new_unresolved(u64 addr, struct map *map)
2474
+{
2475
+ struct annotated_source *src;
2476
+ struct symbol *sym;
2477
+ char name[64];
2478
+
2479
+ snprintf(name, sizeof(name), "%.*" PRIx64, BITS_PER_LONG / 4, addr);
2480
+
2481
+ sym = symbol__new(addr, ANNOTATION_DUMMY_LEN, 0, 0, name);
2482
+ if (sym) {
2483
+ src = symbol__hists(sym, 1);
2484
+ if (!src) {
2485
+ symbol__delete(sym);
2486
+ return NULL;
2487
+ }
2488
+
2489
+ dso__insert_symbol(map->dso, sym);
2490
+ }
2491
+
2492
+ return sym;
2493
+}
2494
+
23712495 static int
23722496 add_annotate_opt(struct hist_browser *browser __maybe_unused,
23732497 struct popup_action *act, char **optstr,
2374
- struct map *map, struct symbol *sym)
2498
+ struct map_symbol *ms,
2499
+ u64 addr)
23752500 {
2376
- if (sym == NULL || map->dso->annotate_warned)
2501
+ if (!ms->map || !ms->map->dso || ms->map->dso->annotate_warned)
23772502 return 0;
23782503
2379
- if (asprintf(optstr, "Annotate %s", sym->name) < 0)
2504
+ if (!ms->sym)
2505
+ ms->sym = symbol__new_unresolved(addr, ms->map);
2506
+
2507
+ if (ms->sym == NULL || symbol__annotation(ms->sym)->src == NULL)
23802508 return 0;
23812509
2382
- act->ms.map = map;
2383
- act->ms.sym = sym;
2510
+ if (asprintf(optstr, "Annotate %s", ms->sym->name) < 0)
2511
+ return 0;
2512
+
2513
+ act->ms = *ms;
23842514 act->fn = do_annotate;
23852515 return 1;
23862516 }
....@@ -2447,11 +2577,8 @@
24472577 return 1;
24482578 }
24492579
2450
-static int
2451
-do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
2580
+static int hists_browser__zoom_map(struct hist_browser *browser, struct map *map)
24522581 {
2453
- struct map *map = act->ms.map;
2454
-
24552582 if (!hists__has(browser->hists, dso) || map == NULL)
24562583 return 0;
24572584
....@@ -2474,19 +2601,47 @@
24742601 }
24752602
24762603 static int
2604
+do_zoom_dso(struct hist_browser *browser, struct popup_action *act)
2605
+{
2606
+ return hists_browser__zoom_map(browser, act->ms.map);
2607
+}
2608
+
2609
+static int
24772610 add_dso_opt(struct hist_browser *browser, struct popup_action *act,
24782611 char **optstr, struct map *map)
24792612 {
24802613 if (!hists__has(browser->hists, dso) || map == NULL)
24812614 return 0;
24822615
2483
- if (asprintf(optstr, "Zoom %s %s DSO",
2616
+ if (asprintf(optstr, "Zoom %s %s DSO (use the 'k' hotkey to zoom directly into the kernel)",
24842617 browser->hists->dso_filter ? "out of" : "into",
24852618 __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0)
24862619 return 0;
24872620
24882621 act->ms.map = map;
24892622 act->fn = do_zoom_dso;
2623
+ return 1;
2624
+}
2625
+
2626
+static int do_toggle_callchain(struct hist_browser *browser, struct popup_action *act __maybe_unused)
2627
+{
2628
+ hist_browser__toggle_fold(browser);
2629
+ return 0;
2630
+}
2631
+
2632
+static int add_callchain_toggle_opt(struct hist_browser *browser, struct popup_action *act, char **optstr)
2633
+{
2634
+ char sym_name[512];
2635
+
2636
+ if (!hist_browser__selection_has_children(browser))
2637
+ return 0;
2638
+
2639
+ if (asprintf(optstr, "%s [%s] callchain (one level, same as '+' hotkey, use 'e'/'c' for the whole main level entry)",
2640
+ hist_browser__selection_unfolded(browser) ? "Collapse" : "Expand",
2641
+ hist_browser__selection_sym_name(browser, sym_name, sizeof(sym_name))) < 0)
2642
+ return 0;
2643
+
2644
+ act->fn = do_toggle_callchain;
24902645 return 1;
24912646 }
24922647
....@@ -2517,42 +2672,133 @@
25172672 do_run_script(struct hist_browser *browser __maybe_unused,
25182673 struct popup_action *act)
25192674 {
2520
- char script_opt[64];
2521
- memset(script_opt, 0, sizeof(script_opt));
2675
+ char *script_opt;
2676
+ int len;
2677
+ int n = 0;
25222678
2679
+ len = 100;
2680
+ if (act->thread)
2681
+ len += strlen(thread__comm_str(act->thread));
2682
+ else if (act->ms.sym)
2683
+ len += strlen(act->ms.sym->name);
2684
+ script_opt = malloc(len);
2685
+ if (!script_opt)
2686
+ return -1;
2687
+
2688
+ script_opt[0] = 0;
25232689 if (act->thread) {
2524
- scnprintf(script_opt, sizeof(script_opt), " -c %s ",
2690
+ n = scnprintf(script_opt, len, " -c %s ",
25252691 thread__comm_str(act->thread));
25262692 } else if (act->ms.sym) {
2527
- scnprintf(script_opt, sizeof(script_opt), " -S %s ",
2693
+ n = scnprintf(script_opt, len, " -S %s ",
25282694 act->ms.sym->name);
25292695 }
25302696
2531
- script_browse(script_opt);
2697
+ if (act->time) {
2698
+ char start[32], end[32];
2699
+ unsigned long starttime = act->time;
2700
+ unsigned long endtime = act->time + symbol_conf.time_quantum;
2701
+
2702
+ if (starttime == endtime) { /* Display 1ms as fallback */
2703
+ starttime -= 1*NSEC_PER_MSEC;
2704
+ endtime += 1*NSEC_PER_MSEC;
2705
+ }
2706
+ timestamp__scnprintf_usec(starttime, start, sizeof start);
2707
+ timestamp__scnprintf_usec(endtime, end, sizeof end);
2708
+ n += snprintf(script_opt + n, len - n, " --time %s,%s", start, end);
2709
+ }
2710
+
2711
+ script_browse(script_opt, act->evsel);
2712
+ free(script_opt);
25322713 return 0;
25332714 }
25342715
25352716 static int
2536
-add_script_opt(struct hist_browser *browser __maybe_unused,
2537
- struct popup_action *act, char **optstr,
2538
- struct thread *thread, struct symbol *sym)
2717
+do_res_sample_script(struct hist_browser *browser __maybe_unused,
2718
+ struct popup_action *act)
25392719 {
2720
+ struct hist_entry *he;
2721
+
2722
+ he = hist_browser__selected_entry(browser);
2723
+ res_sample_browse(he->res_samples, he->num_res, act->evsel, act->rstype);
2724
+ return 0;
2725
+}
2726
+
2727
+static int
2728
+add_script_opt_2(struct hist_browser *browser __maybe_unused,
2729
+ struct popup_action *act, char **optstr,
2730
+ struct thread *thread, struct symbol *sym,
2731
+ struct evsel *evsel, const char *tstr)
2732
+{
2733
+
25402734 if (thread) {
2541
- if (asprintf(optstr, "Run scripts for samples of thread [%s]",
2542
- thread__comm_str(thread)) < 0)
2735
+ if (asprintf(optstr, "Run scripts for samples of thread [%s]%s",
2736
+ thread__comm_str(thread), tstr) < 0)
25432737 return 0;
25442738 } else if (sym) {
2545
- if (asprintf(optstr, "Run scripts for samples of symbol [%s]",
2546
- sym->name) < 0)
2739
+ if (asprintf(optstr, "Run scripts for samples of symbol [%s]%s",
2740
+ sym->name, tstr) < 0)
25472741 return 0;
25482742 } else {
2549
- if (asprintf(optstr, "Run scripts for all samples") < 0)
2743
+ if (asprintf(optstr, "Run scripts for all samples%s", tstr) < 0)
25502744 return 0;
25512745 }
25522746
25532747 act->thread = thread;
25542748 act->ms.sym = sym;
2749
+ act->evsel = evsel;
25552750 act->fn = do_run_script;
2751
+ return 1;
2752
+}
2753
+
2754
+static int
2755
+add_script_opt(struct hist_browser *browser,
2756
+ struct popup_action *act, char **optstr,
2757
+ struct thread *thread, struct symbol *sym,
2758
+ struct evsel *evsel)
2759
+{
2760
+ int n, j;
2761
+ struct hist_entry *he;
2762
+
2763
+ n = add_script_opt_2(browser, act, optstr, thread, sym, evsel, "");
2764
+
2765
+ he = hist_browser__selected_entry(browser);
2766
+ if (sort_order && strstr(sort_order, "time")) {
2767
+ char tstr[128];
2768
+
2769
+ optstr++;
2770
+ act++;
2771
+ j = sprintf(tstr, " in ");
2772
+ j += timestamp__scnprintf_usec(he->time, tstr + j,
2773
+ sizeof tstr - j);
2774
+ j += sprintf(tstr + j, "-");
2775
+ timestamp__scnprintf_usec(he->time + symbol_conf.time_quantum,
2776
+ tstr + j, sizeof tstr - j);
2777
+ n += add_script_opt_2(browser, act, optstr, thread, sym,
2778
+ evsel, tstr);
2779
+ act->time = he->time;
2780
+ }
2781
+ return n;
2782
+}
2783
+
2784
+static int
2785
+add_res_sample_opt(struct hist_browser *browser __maybe_unused,
2786
+ struct popup_action *act, char **optstr,
2787
+ struct res_sample *res_sample,
2788
+ struct evsel *evsel,
2789
+ enum rstype type)
2790
+{
2791
+ if (!res_sample)
2792
+ return 0;
2793
+
2794
+ if (asprintf(optstr, "Show context for individual samples %s",
2795
+ type == A_ASM ? "with assembler" :
2796
+ type == A_SOURCE ? "with source" : "") < 0)
2797
+ return 0;
2798
+
2799
+ act->fn = do_res_sample_script;
2800
+ act->evsel = evsel;
2801
+ act->rstype = type;
25562802 return 1;
25572803 }
25582804
....@@ -2642,7 +2888,7 @@
26422888 static void hist_browser__update_nr_entries(struct hist_browser *hb)
26432889 {
26442890 u64 nr_entries = 0;
2645
- struct rb_node *nd = rb_first(&hb->hists->entries);
2891
+ struct rb_node *nd = rb_first_cached(&hb->hists->entries);
26462892
26472893 if (hb->min_pcnt == 0 && !symbol_conf.report_hierarchy) {
26482894 hb->nr_non_filtered_entries = hb->hists->nr_non_filtered_entries;
....@@ -2662,7 +2908,7 @@
26622908 double percent)
26632909 {
26642910 struct hist_entry *he;
2665
- struct rb_node *nd = rb_first(&hb->hists->entries);
2911
+ struct rb_node *nd = rb_first_cached(&hb->hists->entries);
26662912 u64 total = hists__total_period(hb->hists);
26672913 u64 min_callchain_hits = total * (percent / 100);
26682914
....@@ -2700,7 +2946,7 @@
27002946 }
27012947 }
27022948
2703
-static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
2949
+static int perf_evsel__hists_browse(struct evsel *evsel, int nr_events,
27042950 const char *helpline,
27052951 bool left_exits,
27062952 struct hist_browser_timer *hbt,
....@@ -2717,7 +2963,7 @@
27172963 struct popup_action actions[MAX_OPTIONS];
27182964 int nr_options = 0;
27192965 int key = -1;
2720
- char buf[64];
2966
+ char buf[128];
27212967 int delay_secs = hbt ? hbt->refresh : 0;
27222968
27232969 #define HIST_BROWSER_HELP_COMMON \
....@@ -2730,26 +2976,30 @@
27302976 "For symbolic views (--sort has sym):\n\n" \
27312977 "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \
27322978 "ESC Zoom out\n" \
2979
+ "+ Expand/Collapse one callchain level\n" \
27332980 "a Annotate current symbol\n" \
27342981 "C Collapse all callchains\n" \
27352982 "d Zoom into current DSO\n" \
2983
+ "e Expand/Collapse main entry callchains\n" \
27362984 "E Expand all callchains\n" \
27372985 "F Toggle percentage of filtered entries\n" \
27382986 "H Display column headers\n" \
2987
+ "k Zoom into the kernel map\n" \
27392988 "L Change percent limit\n" \
27402989 "m Display context menu\n" \
27412990 "S Zoom into current Processor Socket\n" \
27422991
27432992 /* help messages are sorted by lexical order of the hotkey */
2744
- const char report_help[] = HIST_BROWSER_HELP_COMMON
2993
+ static const char report_help[] = HIST_BROWSER_HELP_COMMON
27452994 "i Show header information\n"
27462995 "P Print histograms to perf.hist.N\n"
27472996 "r Run available scripts\n"
27482997 "s Switch to another data file in PWD\n"
27492998 "t Zoom into current Thread\n"
27502999 "V Verbose (DSO names in callchains, etc)\n"
2751
- "/ Filter symbol by name";
2752
- const char top_help[] = HIST_BROWSER_HELP_COMMON
3000
+ "/ Filter symbol by name\n"
3001
+ "0-9 Sort by event n in group";
3002
+ static const char top_help[] = HIST_BROWSER_HELP_COMMON
27533003 "P Print histograms to perf.hist.N\n"
27543004 "t Zoom into current Thread\n"
27553005 "V Verbose (DSO names in callchains, etc)\n"
....@@ -2780,16 +3030,19 @@
27803030 if (symbol_conf.col_width_list_str)
27813031 perf_hpp__set_user_width(symbol_conf.col_width_list_str);
27823032
3033
+ if (!is_report_browser(hbt))
3034
+ browser->b.no_samples_msg = "Collecting samples...";
3035
+
27833036 while (1) {
27843037 struct thread *thread = NULL;
27853038 struct map *map = NULL;
2786
- int choice = 0;
3039
+ int choice;
27873040 int socked_id = -1;
27883041
2789
- nr_options = 0;
2790
-
2791
- key = hist_browser__run(browser, helpline,
2792
- warn_lost_event);
3042
+ key = 0; // reset key
3043
+do_hotkey: // key came straight from options ui__popup_menu()
3044
+ choice = nr_options = 0;
3045
+ key = hist_browser__run(browser, helpline, warn_lost_event, key);
27933046
27943047 if (browser->he_selection != NULL) {
27953048 thread = hist_browser__selected_thread(browser);
....@@ -2806,6 +3059,31 @@
28063059 * go to the next or previous
28073060 */
28083061 goto out_free_stack;
3062
+ case '0' ... '9':
3063
+ if (!symbol_conf.event_group ||
3064
+ evsel->core.nr_members < 2) {
3065
+ snprintf(buf, sizeof(buf),
3066
+ "Sort by index only available with group events!");
3067
+ helpline = buf;
3068
+ continue;
3069
+ }
3070
+
3071
+ if (key - '0' == symbol_conf.group_sort_idx)
3072
+ continue;
3073
+
3074
+ symbol_conf.group_sort_idx = key - '0';
3075
+
3076
+ if (symbol_conf.group_sort_idx >= evsel->core.nr_members) {
3077
+ snprintf(buf, sizeof(buf),
3078
+ "Max event group index to sort is %d (index from 0 to %d)",
3079
+ evsel->core.nr_members - 1,
3080
+ evsel->core.nr_members - 1);
3081
+ helpline = buf;
3082
+ continue;
3083
+ }
3084
+
3085
+ key = K_RELOAD;
3086
+ goto out_free_stack;
28093087 case 'a':
28103088 if (!hists__has(hists, sym)) {
28113089 ui_browser__warning(&browser->b, delay_secs * 2,
....@@ -2814,13 +3092,45 @@
28143092 continue;
28153093 }
28163094
2817
- if (browser->selection == NULL ||
2818
- browser->selection->sym == NULL ||
2819
- browser->selection->map->dso->annotate_warned)
3095
+ if (!browser->selection ||
3096
+ !browser->selection->map ||
3097
+ !browser->selection->map->dso ||
3098
+ browser->selection->map->dso->annotate_warned) {
28203099 continue;
3100
+ }
28213101
2822
- actions->ms.map = browser->selection->map;
2823
- actions->ms.sym = browser->selection->sym;
3102
+ if (!browser->selection->sym) {
3103
+ if (!browser->he_selection)
3104
+ continue;
3105
+
3106
+ if (sort__mode == SORT_MODE__BRANCH) {
3107
+ bi = browser->he_selection->branch_info;
3108
+ if (!bi || !bi->to.ms.map)
3109
+ continue;
3110
+
3111
+ actions->ms.sym = symbol__new_unresolved(bi->to.al_addr, bi->to.ms.map);
3112
+ actions->ms.map = bi->to.ms.map;
3113
+ } else {
3114
+ actions->ms.sym = symbol__new_unresolved(browser->he_selection->ip,
3115
+ browser->selection->map);
3116
+ actions->ms.map = browser->selection->map;
3117
+ }
3118
+
3119
+ if (!actions->ms.sym)
3120
+ continue;
3121
+ } else {
3122
+ if (symbol__annotation(browser->selection->sym)->src == NULL) {
3123
+ ui_browser__warning(&browser->b, delay_secs * 2,
3124
+ "No samples for the \"%s\" symbol.\n\n"
3125
+ "Probably appeared just in a callchain",
3126
+ browser->selection->sym->name);
3127
+ continue;
3128
+ }
3129
+
3130
+ actions->ms.map = browser->selection->map;
3131
+ actions->ms.sym = browser->selection->sym;
3132
+ }
3133
+
28243134 do_annotate(browser, actions);
28253135 continue;
28263136 case 'P':
....@@ -2829,6 +3139,10 @@
28293139 case 'd':
28303140 actions->ms.map = map;
28313141 do_zoom_dso(browser, actions);
3142
+ continue;
3143
+ case 'k':
3144
+ if (browser->selection != NULL)
3145
+ hists_browser__zoom_map(browser, browser->selection->maps->machine->vmlinux_map);
28323146 continue;
28333147 case 'V':
28343148 verbose = (verbose + 1) % 4;
....@@ -2988,26 +3302,27 @@
29883302 nr_options += add_annotate_opt(browser,
29893303 &actions[nr_options],
29903304 &options[nr_options],
2991
- bi->from.map,
2992
- bi->from.sym);
2993
- if (bi->to.sym != bi->from.sym)
3305
+ &bi->from.ms,
3306
+ bi->from.al_addr);
3307
+ if (bi->to.ms.sym != bi->from.ms.sym)
29943308 nr_options += add_annotate_opt(browser,
29953309 &actions[nr_options],
29963310 &options[nr_options],
2997
- bi->to.map,
2998
- bi->to.sym);
3311
+ &bi->to.ms,
3312
+ bi->to.al_addr);
29993313 } else {
30003314 nr_options += add_annotate_opt(browser,
30013315 &actions[nr_options],
30023316 &options[nr_options],
3003
- browser->selection->map,
3004
- browser->selection->sym);
3317
+ browser->selection,
3318
+ browser->he_selection->ip);
30053319 }
30063320 skip_annotation:
30073321 nr_options += add_thread_opt(browser, &actions[nr_options],
30083322 &options[nr_options], thread);
30093323 nr_options += add_dso_opt(browser, &actions[nr_options],
30103324 &options[nr_options], map);
3325
+ nr_options += add_callchain_toggle_opt(browser, &actions[nr_options], &options[nr_options]);
30113326 nr_options += add_map_opt(browser, &actions[nr_options],
30123327 &options[nr_options],
30133328 browser->selection ?
....@@ -3024,7 +3339,7 @@
30243339 nr_options += add_script_opt(browser,
30253340 &actions[nr_options],
30263341 &options[nr_options],
3027
- thread, NULL);
3342
+ thread, NULL, evsel);
30283343 }
30293344 /*
30303345 * Note that browser->selection != NULL
....@@ -3039,11 +3354,24 @@
30393354 nr_options += add_script_opt(browser,
30403355 &actions[nr_options],
30413356 &options[nr_options],
3042
- NULL, browser->selection->sym);
3357
+ NULL, browser->selection->sym,
3358
+ evsel);
30433359 }
30443360 }
30453361 nr_options += add_script_opt(browser, &actions[nr_options],
3046
- &options[nr_options], NULL, NULL);
3362
+ &options[nr_options], NULL, NULL, evsel);
3363
+ nr_options += add_res_sample_opt(browser, &actions[nr_options],
3364
+ &options[nr_options],
3365
+ hist_browser__selected_res_sample(browser),
3366
+ evsel, A_NORMAL);
3367
+ nr_options += add_res_sample_opt(browser, &actions[nr_options],
3368
+ &options[nr_options],
3369
+ hist_browser__selected_res_sample(browser),
3370
+ evsel, A_ASM);
3371
+ nr_options += add_res_sample_opt(browser, &actions[nr_options],
3372
+ &options[nr_options],
3373
+ hist_browser__selected_res_sample(browser),
3374
+ evsel, A_SOURCE);
30473375 nr_options += add_switch_opt(browser, &actions[nr_options],
30483376 &options[nr_options]);
30493377 skip_scripting:
....@@ -3053,9 +3381,12 @@
30533381 do {
30543382 struct popup_action *act;
30553383
3056
- choice = ui__popup_menu(nr_options, options);
3057
- if (choice == -1 || choice >= nr_options)
3384
+ choice = ui__popup_menu(nr_options, options, &key);
3385
+ if (choice == -1)
30583386 break;
3387
+
3388
+ if (choice == nr_options)
3389
+ goto do_hotkey;
30593390
30603391 act = &actions[choice];
30613392 key = act->fn(browser, act);
....@@ -3072,9 +3403,9 @@
30723403 return key;
30733404 }
30743405
3075
-struct perf_evsel_menu {
3406
+struct evsel_menu {
30763407 struct ui_browser b;
3077
- struct perf_evsel *selection;
3408
+ struct evsel *selection;
30783409 struct annotation_options *annotation_opts;
30793410 bool lost_events, lost_events_warned;
30803411 float min_pcnt;
....@@ -3084,13 +3415,13 @@
30843415 static void perf_evsel_menu__write(struct ui_browser *browser,
30853416 void *entry, int row)
30863417 {
3087
- struct perf_evsel_menu *menu = container_of(browser,
3088
- struct perf_evsel_menu, b);
3089
- struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
3418
+ struct evsel_menu *menu = container_of(browser,
3419
+ struct evsel_menu, b);
3420
+ struct evsel *evsel = list_entry(entry, struct evsel, core.node);
30903421 struct hists *hists = evsel__hists(evsel);
30913422 bool current_entry = ui_browser__is_current_entry(browser, row);
30923423 unsigned long nr_events = hists->stats.nr_events[PERF_RECORD_SAMPLE];
3093
- const char *ev_name = perf_evsel__name(evsel);
3424
+ const char *ev_name = evsel__name(evsel);
30943425 char bf[256], unit;
30953426 const char *warn = " ";
30963427 size_t printed;
....@@ -3098,10 +3429,10 @@
30983429 ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
30993430 HE_COLORSET_NORMAL);
31003431
3101
- if (perf_evsel__is_group_event(evsel)) {
3102
- struct perf_evsel *pos;
3432
+ if (evsel__is_group_event(evsel)) {
3433
+ struct evsel *pos;
31033434
3104
- ev_name = perf_evsel__group_name(evsel);
3435
+ ev_name = evsel__group_name(evsel);
31053436
31063437 for_each_group_member(pos, evsel) {
31073438 struct hists *pos_hists = evsel__hists(pos);
....@@ -3131,13 +3462,13 @@
31313462 menu->selection = evsel;
31323463 }
31333464
3134
-static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
3465
+static int perf_evsel_menu__run(struct evsel_menu *menu,
31353466 int nr_events, const char *help,
31363467 struct hist_browser_timer *hbt,
31373468 bool warn_lost_event)
31383469 {
3139
- struct perf_evlist *evlist = menu->b.priv;
3140
- struct perf_evsel *pos;
3470
+ struct evlist *evlist = menu->b.priv;
3471
+ struct evsel *pos;
31413472 const char *title = "Available samples";
31423473 int delay_secs = hbt ? hbt->refresh : 0;
31433474 int key;
....@@ -3183,18 +3514,19 @@
31833514 ui_browser__show_title(&menu->b, title);
31843515 switch (key) {
31853516 case K_TAB:
3186
- if (pos->node.next == &evlist->entries)
3187
- pos = perf_evlist__first(evlist);
3517
+ if (pos->core.node.next == &evlist->core.entries)
3518
+ pos = evlist__first(evlist);
31883519 else
3189
- pos = perf_evsel__next(pos);
3520
+ pos = evsel__next(pos);
31903521 goto browse_hists;
31913522 case K_UNTAB:
3192
- if (pos->node.prev == &evlist->entries)
3193
- pos = perf_evlist__last(evlist);
3523
+ if (pos->core.node.prev == &evlist->core.entries)
3524
+ pos = evlist__last(evlist);
31943525 else
3195
- pos = perf_evsel__prev(pos);
3526
+ pos = evsel__prev(pos);
31963527 goto browse_hists;
31973528 case K_SWITCH_INPUT_DATA:
3529
+ case K_RELOAD:
31983530 case 'q':
31993531 case CTRL('c'):
32003532 goto out;
....@@ -3225,15 +3557,15 @@
32253557 static bool filter_group_entries(struct ui_browser *browser __maybe_unused,
32263558 void *entry)
32273559 {
3228
- struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
3560
+ struct evsel *evsel = list_entry(entry, struct evsel, core.node);
32293561
3230
- if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel))
3562
+ if (symbol_conf.event_group && !evsel__is_group_leader(evsel))
32313563 return true;
32323564
32333565 return false;
32343566 }
32353567
3236
-static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
3568
+static int __perf_evlist__tui_browse_hists(struct evlist *evlist,
32373569 int nr_entries, const char *help,
32383570 struct hist_browser_timer *hbt,
32393571 float min_pcnt,
....@@ -3241,10 +3573,10 @@
32413573 bool warn_lost_event,
32423574 struct annotation_options *annotation_opts)
32433575 {
3244
- struct perf_evsel *pos;
3245
- struct perf_evsel_menu menu = {
3576
+ struct evsel *pos;
3577
+ struct evsel_menu menu = {
32463578 .b = {
3247
- .entries = &evlist->entries,
3579
+ .entries = &evlist->core.entries,
32483580 .refresh = ui_browser__list_head_refresh,
32493581 .seek = ui_browser__list_head_seek,
32503582 .write = perf_evsel_menu__write,
....@@ -3260,7 +3592,7 @@
32603592 ui_helpline__push("Press ESC to exit");
32613593
32623594 evlist__for_each_entry(evlist, pos) {
3263
- const char *ev_name = perf_evsel__name(pos);
3595
+ const char *ev_name = evsel__name(pos);
32643596 size_t line_len = strlen(ev_name) + 7;
32653597
32663598 if (menu.b.width < line_len)
....@@ -3271,31 +3603,49 @@
32713603 hbt, warn_lost_event);
32723604 }
32733605
3274
-int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
3606
+static bool perf_evlist__single_entry(struct evlist *evlist)
3607
+{
3608
+ int nr_entries = evlist->core.nr_entries;
3609
+
3610
+ if (nr_entries == 1)
3611
+ return true;
3612
+
3613
+ if (nr_entries == 2) {
3614
+ struct evsel *last = evlist__last(evlist);
3615
+
3616
+ if (evsel__is_dummy_event(last))
3617
+ return true;
3618
+ }
3619
+
3620
+ return false;
3621
+}
3622
+
3623
+int perf_evlist__tui_browse_hists(struct evlist *evlist, const char *help,
32753624 struct hist_browser_timer *hbt,
32763625 float min_pcnt,
32773626 struct perf_env *env,
32783627 bool warn_lost_event,
32793628 struct annotation_options *annotation_opts)
32803629 {
3281
- int nr_entries = evlist->nr_entries;
3630
+ int nr_entries = evlist->core.nr_entries;
32823631
3283
-single_entry:
3284
- if (nr_entries == 1) {
3285
- struct perf_evsel *first = perf_evlist__first(evlist);
3632
+ if (perf_evlist__single_entry(evlist)) {
3633
+single_entry: {
3634
+ struct evsel *first = evlist__first(evlist);
32863635
32873636 return perf_evsel__hists_browse(first, nr_entries, help,
32883637 false, hbt, min_pcnt,
32893638 env, warn_lost_event,
32903639 annotation_opts);
32913640 }
3641
+ }
32923642
32933643 if (symbol_conf.event_group) {
3294
- struct perf_evsel *pos;
3644
+ struct evsel *pos;
32953645
32963646 nr_entries = 0;
32973647 evlist__for_each_entry(evlist, pos) {
3298
- if (perf_evsel__is_group_leader(pos))
3648
+ if (evsel__is_group_leader(pos))
32993649 nr_entries++;
33003650 }
33013651
....@@ -3308,3 +3658,75 @@
33083658 warn_lost_event,
33093659 annotation_opts);
33103660 }
3661
+
3662
+static int block_hists_browser__title(struct hist_browser *browser, char *bf,
3663
+ size_t size)
3664
+{
3665
+ struct hists *hists = evsel__hists(browser->block_evsel);
3666
+ const char *evname = evsel__name(browser->block_evsel);
3667
+ unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
3668
+ int ret;
3669
+
3670
+ ret = scnprintf(bf, size, "# Samples: %lu", nr_samples);
3671
+ if (evname)
3672
+ scnprintf(bf + ret, size - ret, " of event '%s'", evname);
3673
+
3674
+ return 0;
3675
+}
3676
+
3677
+int block_hists_tui_browse(struct block_hist *bh, struct evsel *evsel,
3678
+ float min_percent, struct perf_env *env,
3679
+ struct annotation_options *annotation_opts)
3680
+{
3681
+ struct hists *hists = &bh->block_hists;
3682
+ struct hist_browser *browser;
3683
+ int key = -1;
3684
+ struct popup_action action;
3685
+ static const char help[] =
3686
+ " q Quit \n";
3687
+
3688
+ browser = hist_browser__new(hists);
3689
+ if (!browser)
3690
+ return -1;
3691
+
3692
+ browser->block_evsel = evsel;
3693
+ browser->title = block_hists_browser__title;
3694
+ browser->min_pcnt = min_percent;
3695
+ browser->env = env;
3696
+ browser->annotation_opts = annotation_opts;
3697
+
3698
+ /* reset abort key so that it can get Ctrl-C as a key */
3699
+ SLang_reset_tty();
3700
+ SLang_init_tty(0, 0, 0);
3701
+
3702
+ memset(&action, 0, sizeof(action));
3703
+
3704
+ while (1) {
3705
+ key = hist_browser__run(browser, "? - help", true, 0);
3706
+
3707
+ switch (key) {
3708
+ case 'q':
3709
+ goto out;
3710
+ case '?':
3711
+ ui_browser__help_window(&browser->b, help);
3712
+ break;
3713
+ case 'a':
3714
+ case K_ENTER:
3715
+ if (!browser->selection ||
3716
+ !browser->selection->sym) {
3717
+ continue;
3718
+ }
3719
+
3720
+ action.ms.map = browser->selection->map;
3721
+ action.ms.sym = browser->selection->sym;
3722
+ do_annotate(browser, &action);
3723
+ continue;
3724
+ default:
3725
+ break;
3726
+ }
3727
+ }
3728
+
3729
+out:
3730
+ hist_browser__delete(browser);
3731
+ return 0;
3732
+}