Merge tag 'v3.4-rc4' into perf/core
authorIngo Molnar <mingo@kernel.org>
Wed, 25 Apr 2012 06:59:16 +0000 (08:59 +0200)
committerIngo Molnar <mingo@kernel.org>
Wed, 25 Apr 2012 06:59:16 +0000 (08:59 +0200)
Merge v3.4-rc4 - we were on -rc2 before.

Signed-off-by: Ingo Molnar <mingo@kernel.org>
48 files changed:
Makefile
tools/Makefile [new file with mode: 0644]
tools/perf/Documentation/perfconfig.example
tools/perf/Makefile
tools/perf/builtin-record.c
tools/perf/builtin-report.c
tools/perf/builtin-stat.c
tools/perf/ui/browser.c [new file with mode: 0644]
tools/perf/ui/browser.h [new file with mode: 0644]
tools/perf/ui/browsers/annotate.c [new file with mode: 0644]
tools/perf/ui/browsers/hists.c [new file with mode: 0644]
tools/perf/ui/browsers/map.c [new file with mode: 0644]
tools/perf/ui/browsers/map.h [new file with mode: 0644]
tools/perf/ui/gtk/browser.c [new file with mode: 0644]
tools/perf/ui/gtk/gtk.h [new file with mode: 0644]
tools/perf/ui/helpline.c [new file with mode: 0644]
tools/perf/ui/helpline.h [new file with mode: 0644]
tools/perf/ui/keysyms.h [new file with mode: 0644]
tools/perf/ui/libslang.h [new file with mode: 0644]
tools/perf/ui/progress.c [new file with mode: 0644]
tools/perf/ui/progress.h [new file with mode: 0644]
tools/perf/ui/setup.c [new file with mode: 0644]
tools/perf/ui/ui.h [new file with mode: 0644]
tools/perf/ui/util.c [new file with mode: 0644]
tools/perf/ui/util.h [new file with mode: 0644]
tools/perf/util/annotate.c
tools/perf/util/debug.h
tools/perf/util/gtk/browser.c [deleted file]
tools/perf/util/gtk/gtk.h [deleted file]
tools/perf/util/hist.h
tools/perf/util/thread_map.h
tools/perf/util/ui/browser.c [deleted file]
tools/perf/util/ui/browser.h [deleted file]
tools/perf/util/ui/browsers/annotate.c [deleted file]
tools/perf/util/ui/browsers/hists.c [deleted file]
tools/perf/util/ui/browsers/map.c [deleted file]
tools/perf/util/ui/browsers/map.h [deleted file]
tools/perf/util/ui/helpline.c [deleted file]
tools/perf/util/ui/helpline.h [deleted file]
tools/perf/util/ui/keysyms.h [deleted file]
tools/perf/util/ui/libslang.h [deleted file]
tools/perf/util/ui/progress.c [deleted file]
tools/perf/util/ui/progress.h [deleted file]
tools/perf/util/ui/setup.c [deleted file]
tools/perf/util/ui/ui.h [deleted file]
tools/perf/util/ui/util.c [deleted file]
tools/perf/util/ui/util.h [deleted file]
tools/scripts/Makefile.include [new file with mode: 0644]

index afc868e6c75dd26dbbf28c3511cbcf29c0471573..2280dff31b62fab631d1ca9e6407a1b5137e0be8 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1468,6 +1468,13 @@ kernelrelease:
 kernelversion:
        @echo $(KERNELVERSION)
 
+# Clear a bunch of variables before executing the submake
+tools/: FORCE
+       $(Q)$(MAKE) LDFLAGS= MAKEFLAGS= -C $(src)/tools/
+
+tools/%: FORCE
+       $(Q)$(MAKE) LDFLAGS= MAKEFLAGS= -C $(src)/tools/ $*
+
 # Single targets
 # ---------------------------------------------------------------------------
 # Single targets are compatible with:
diff --git a/tools/Makefile b/tools/Makefile
new file mode 100644 (file)
index 0000000..3ae4394
--- /dev/null
@@ -0,0 +1,77 @@
+include scripts/Makefile.include
+
+help:
+       @echo 'Possible targets:'
+       @echo ''
+       @echo '  cpupower   - a tool for all things x86 CPU power'
+       @echo '  firewire   - the userspace part of nosy, an IEEE-1394 traffic sniffer'
+       @echo '  lguest     - a minimal 32-bit x86 hypervisor'
+       @echo '  perf       - Linux performance measurement and analysis tool'
+       @echo '  selftests  - various kernel selftests'
+       @echo '  turbostat  - Intel CPU idle stats and freq reporting tool'
+       @echo '  usb        - USB testing tools'
+       @echo '  virtio     - vhost test module'
+       @echo '  vm         - misc vm tools'
+       @echo '  x86_energy_perf_policy - Intel energy policy tool'
+       @echo ''
+       @echo 'You can do:'
+       @echo ' $$ make -C tools/<tool>_install'
+       @echo ''
+       @echo '  from the kernel command line to build and install one of'
+       @echo '  the tools above'
+       @echo ''
+       @echo '  $$ make tools/install'
+       @echo ''
+       @echo '  installs all tools.'
+       @echo ''
+       @echo 'Cleaning targets:'
+       @echo ''
+       @echo '  all of the above with the "_clean" string appended cleans'
+       @echo '    the respective build directory.'
+       @echo '  clean: a summary clean target to clean _all_ folders'
+
+cpupower: FORCE
+       $(QUIET_SUBDIR0)power/$@/ $(QUIET_SUBDIR1)
+
+firewire lguest perf usb virtio vm: FORCE
+       $(QUIET_SUBDIR0)$@/ $(QUIET_SUBDIR1)
+
+selftests: FORCE
+       $(QUIET_SUBDIR0)testing/$@/ $(QUIET_SUBDIR1)
+
+turbostat x86_energy_perf_policy: FORCE
+       $(QUIET_SUBDIR0)power/x86/$@/ $(QUIET_SUBDIR1)
+
+cpupower_install:
+       $(QUIET_SUBDIR0)power/$(@:_install=)/ $(QUIET_SUBDIR1) install
+
+firewire_install lguest_install perf_install usb_install virtio_install vm_install:
+       $(QUIET_SUBDIR0)$(@:_install=)/ $(QUIET_SUBDIR1) install
+
+selftests_install:
+       $(QUIET_SUBDIR0)testing/$(@:_clean=)/ $(QUIET_SUBDIR1) install
+
+turbostat_install x86_energy_perf_policy_install:
+       $(QUIET_SUBDIR0)power/x86/$(@:_install=)/ $(QUIET_SUBDIR1) install
+
+install: cpupower_install firewire_install lguest_install perf_install \
+               selftests_install turbostat_install usb_install virtio_install \
+               vm_install x86_energy_perf_policy_install
+
+cpupower_clean:
+       $(QUIET_SUBDIR0)power/cpupower/ $(QUIET_SUBDIR1) clean
+
+firewire_clean lguest_clean perf_clean usb_clean virtio_clean vm_clean:
+       $(QUIET_SUBDIR0)$(@:_clean=)/ $(QUIET_SUBDIR1) clean
+
+selftests_clean:
+       $(QUIET_SUBDIR0)testing/$(@:_clean=)/ $(QUIET_SUBDIR1) clean
+
+turbostat_clean x86_energy_perf_policy_clean:
+       $(QUIET_SUBDIR0)power/x86/$(@:_clean=)/ $(QUIET_SUBDIR1) clean
+
+clean: cpupower_clean firewire_clean lguest_clean perf_clean selftests_clean \
+               turbostat_clean usb_clean virtio_clean vm_clean \
+               x86_energy_perf_policy_clean
+
+.PHONY: FORCE
index d1448668f4d4f03e8a9abc30afa156f07d6965a8..42c6fd2ae85d19ac31fa5f0c191dfcf776ca60e9 100644 (file)
@@ -6,6 +6,7 @@
        normal = black, lightgray
        selected = lightgray, magenta
        code = blue, lightgray
+       addr = magenta, lightgray
 
 [tui]
 
index 03059e75665a267b39baa45b5f7e107557b96542..e98e14c88532af549ce39c315b767a7f9676ccc4 100644 (file)
@@ -1,18 +1,10 @@
-ifeq ("$(origin O)", "command line")
-       OUTPUT := $(O)/
-endif
+include ../scripts/Makefile.include
 
 # The default target of this Makefile is...
 all:
 
 include config/utilities.mak
 
-ifneq ($(OUTPUT),)
-# check that the output directory actually exists
-OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd)
-$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist))
-endif
-
 # Define V to have a more verbose compile.
 #
 # Define O to save output files in a separate directory.
@@ -84,31 +76,6 @@ ifneq ($(WERROR),0)
        CFLAGS_WERROR := -Werror
 endif
 
-#
-# Include saner warnings here, which can catch bugs:
-#
-
-EXTRA_WARNINGS := -Wformat
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat-security
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wformat-y2k
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wshadow
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Winit-self
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wpacked
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wredundant-decls
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-aliasing=3
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-default
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wswitch-enum
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wno-system-headers
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wundef
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wwrite-strings
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wbad-function-cast
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wmissing-declarations
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wmissing-prototypes
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wnested-externs
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wold-style-definition
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-prototypes
-EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wdeclaration-after-statement
-
 ifeq ("$(origin DEBUG)", "command line")
   PERF_DEBUG = $(DEBUG)
 endif
@@ -506,22 +473,22 @@ else
                # Fedora has /usr/include/slang/slang.h, but ubuntu /usr/include/slang.h
                BASIC_CFLAGS += -I/usr/include/slang
                EXTLIBS += -lnewt -lslang
-               LIB_OBJS += $(OUTPUT)util/ui/setup.o
-               LIB_OBJS += $(OUTPUT)util/ui/browser.o
-               LIB_OBJS += $(OUTPUT)util/ui/browsers/annotate.o
-               LIB_OBJS += $(OUTPUT)util/ui/browsers/hists.o
-               LIB_OBJS += $(OUTPUT)util/ui/browsers/map.o
-               LIB_OBJS += $(OUTPUT)util/ui/helpline.o
-               LIB_OBJS += $(OUTPUT)util/ui/progress.o
-               LIB_OBJS += $(OUTPUT)util/ui/util.o
-               LIB_H += util/ui/browser.h
-               LIB_H += util/ui/browsers/map.h
-               LIB_H += util/ui/helpline.h
-               LIB_H += util/ui/keysyms.h
-               LIB_H += util/ui/libslang.h
-               LIB_H += util/ui/progress.h
-               LIB_H += util/ui/util.h
-               LIB_H += util/ui/ui.h
+               LIB_OBJS += $(OUTPUT)ui/setup.o
+               LIB_OBJS += $(OUTPUT)ui/browser.o
+               LIB_OBJS += $(OUTPUT)ui/browsers/annotate.o
+               LIB_OBJS += $(OUTPUT)ui/browsers/hists.o
+               LIB_OBJS += $(OUTPUT)ui/browsers/map.o
+               LIB_OBJS += $(OUTPUT)ui/helpline.o
+               LIB_OBJS += $(OUTPUT)ui/progress.o
+               LIB_OBJS += $(OUTPUT)ui/util.o
+               LIB_H += ui/browser.h
+               LIB_H += ui/browsers/map.h
+               LIB_H += ui/helpline.h
+               LIB_H += ui/keysyms.h
+               LIB_H += ui/libslang.h
+               LIB_H += ui/progress.h
+               LIB_H += ui/util.h
+               LIB_H += ui/ui.h
        endif
 endif
 
@@ -535,7 +502,7 @@ else
        else
                BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0)
                EXTLIBS += $(shell pkg-config --libs gtk+-2.0)
-               LIB_OBJS += $(OUTPUT)util/gtk/browser.o
+               LIB_OBJS += $(OUTPUT)ui/gtk/browser.o
        endif
 endif
 
@@ -678,18 +645,6 @@ else
        endif
 endif
 
-ifneq ($(findstring $(MAKEFLAGS),s),s)
-ifndef V
-       QUIET_CC       = @echo '   ' CC $@;
-       QUIET_AR       = @echo '   ' AR $@;
-       QUIET_LINK     = @echo '   ' LINK $@;
-       QUIET_MKDIR    = @echo '   ' MKDIR $@;
-       QUIET_GEN      = @echo '   ' GEN $@;
-       QUIET_FLEX     = @echo '   ' FLEX $@;
-       QUIET_BISON    = @echo '   ' BISON $@;
-endif
-endif
-
 ifdef ASCIIDOC8
        export ASCIIDOC8
 endif
@@ -800,16 +755,16 @@ $(OUTPUT)util/exec_cmd.o: util/exec_cmd.c $(OUTPUT)PERF-CFLAGS
 $(OUTPUT)util/config.o: util/config.c $(OUTPUT)PERF-CFLAGS
        $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $<
 
-$(OUTPUT)util/ui/browser.o: util/ui/browser.c $(OUTPUT)PERF-CFLAGS
+$(OUTPUT)ui/browser.o: ui/browser.c $(OUTPUT)PERF-CFLAGS
        $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
 
-$(OUTPUT)util/ui/browsers/annotate.o: util/ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS
+$(OUTPUT)ui/browsers/annotate.o: ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS
        $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
 
-$(OUTPUT)util/ui/browsers/hists.o: util/ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS
+$(OUTPUT)ui/browsers/hists.o: ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS
        $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
 
-$(OUTPUT)util/ui/browsers/map.o: util/ui/browsers/map.c $(OUTPUT)PERF-CFLAGS
+$(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS
        $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $<
 
 $(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS
index be4e1eee782e658f00ab06cfa679414341952086..10b1f1f25ed7c6d61db3b9ed6a356b9ecb9789f8 100644 (file)
@@ -245,7 +245,7 @@ try_again:
                         * based cpu-clock-tick sw counter, which
                         * is always available even if no PMU support:
                         */
-                       if (attr->type == PERF_TYPE_HARDWARE
+                       if (err == ENOENT && attr->type == PERF_TYPE_HARDWARE
                                        && attr->config == PERF_COUNT_HW_CPU_CYCLES) {
 
                                if (verbose)
index 2e317438980b4767bbca4fdc3512cbd55d4ad1d2..cec2b8cee80cada5db9957d7355e708324cf83a2 100644 (file)
@@ -296,12 +296,15 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self,
 {
        size_t ret;
        char unit;
-       unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE];
+       unsigned long nr_samples = self->stats.nr_events[PERF_RECORD_SAMPLE];
+       u64 nr_events = self->stats.total_period;
 
-       nr_events = convert_unit(nr_events, &unit);
-       ret = fprintf(fp, "# Events: %lu%c", nr_events, unit);
+       nr_samples = convert_unit(nr_samples, &unit);
+       ret = fprintf(fp, "# Samples: %lu%c", nr_samples, unit);
        if (evname != NULL)
-               ret += fprintf(fp, " %s", evname);
+               ret += fprintf(fp, " of event '%s'", evname);
+
+       ret += fprintf(fp, "\n# Event count (approx.): %lu", nr_events);
        return ret + fprintf(fp, "\n#\n");
 }
 
index c941bb640f4990f8590f8fb410dfaa0247bcc3b8..dde9e17c018b859d19b02052ef4e0aa5a90b07a4 100644 (file)
@@ -173,7 +173,7 @@ static struct perf_event_attr very_very_detailed_attrs[] = {
 
 
 
-struct perf_evlist             *evsel_list;
+static struct perf_evlist      *evsel_list;
 
 static bool                    system_wide                     =  false;
 static int                     run_idx                         =  0;
@@ -265,18 +265,18 @@ static double stddev_stats(struct stats *stats)
        return sqrt(variance_mean);
 }
 
-struct stats                   runtime_nsecs_stats[MAX_NR_CPUS];
-struct stats                   runtime_cycles_stats[MAX_NR_CPUS];
-struct stats                   runtime_stalled_cycles_front_stats[MAX_NR_CPUS];
-struct stats                   runtime_stalled_cycles_back_stats[MAX_NR_CPUS];
-struct stats                   runtime_branches_stats[MAX_NR_CPUS];
-struct stats                   runtime_cacherefs_stats[MAX_NR_CPUS];
-struct stats                   runtime_l1_dcache_stats[MAX_NR_CPUS];
-struct stats                   runtime_l1_icache_stats[MAX_NR_CPUS];
-struct stats                   runtime_ll_cache_stats[MAX_NR_CPUS];
-struct stats                   runtime_itlb_cache_stats[MAX_NR_CPUS];
-struct stats                   runtime_dtlb_cache_stats[MAX_NR_CPUS];
-struct stats                   walltime_nsecs_stats;
+static struct stats runtime_nsecs_stats[MAX_NR_CPUS];
+static struct stats runtime_cycles_stats[MAX_NR_CPUS];
+static struct stats runtime_stalled_cycles_front_stats[MAX_NR_CPUS];
+static struct stats runtime_stalled_cycles_back_stats[MAX_NR_CPUS];
+static struct stats runtime_branches_stats[MAX_NR_CPUS];
+static struct stats runtime_cacherefs_stats[MAX_NR_CPUS];
+static struct stats runtime_l1_dcache_stats[MAX_NR_CPUS];
+static struct stats runtime_l1_icache_stats[MAX_NR_CPUS];
+static struct stats runtime_ll_cache_stats[MAX_NR_CPUS];
+static struct stats runtime_itlb_cache_stats[MAX_NR_CPUS];
+static struct stats runtime_dtlb_cache_stats[MAX_NR_CPUS];
+static struct stats walltime_nsecs_stats;
 
 static int create_perf_stat_counter(struct perf_evsel *evsel,
                                    struct perf_evsel *first)
diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c
new file mode 100644 (file)
index 0000000..a1b140c
--- /dev/null
@@ -0,0 +1,606 @@
+#include "../util.h"
+#include "../cache.h"
+#include "../../perf.h"
+#include "libslang.h"
+#include <newt.h>
+#include "ui.h"
+#include "util.h"
+#include <linux/compiler.h>
+#include <linux/list.h>
+#include <linux/rbtree.h>
+#include <stdlib.h>
+#include <sys/ttydefaults.h>
+#include "browser.h"
+#include "helpline.h"
+#include "keysyms.h"
+#include "../color.h"
+
+static int ui_browser__percent_color(struct ui_browser *browser,
+                                    double percent, bool current)
+{
+       if (current && (!browser->use_navkeypressed || browser->navkeypressed))
+               return HE_COLORSET_SELECTED;
+       if (percent >= MIN_RED)
+               return HE_COLORSET_TOP;
+       if (percent >= MIN_GREEN)
+               return HE_COLORSET_MEDIUM;
+       return HE_COLORSET_NORMAL;
+}
+
+int ui_browser__set_color(struct ui_browser *browser, int color)
+{
+       int ret = browser->current_color;
+       browser->current_color = color;
+       SLsmg_set_color(color);
+       return ret;
+}
+
+void ui_browser__set_percent_color(struct ui_browser *self,
+                                  double percent, bool current)
+{
+        int color = ui_browser__percent_color(self, percent, current);
+        ui_browser__set_color(self, color);
+}
+
+void ui_browser__gotorc(struct ui_browser *self, int y, int x)
+{
+       SLsmg_gotorc(self->y + y, self->x + x);
+}
+
+static struct list_head *
+ui_browser__list_head_filter_entries(struct ui_browser *browser,
+                                    struct list_head *pos)
+{
+       do {
+               if (!browser->filter || !browser->filter(browser, pos))
+                       return pos;
+               pos = pos->next;
+       } while (pos != browser->entries);
+
+       return NULL;
+}
+
+static struct list_head *
+ui_browser__list_head_filter_prev_entries(struct ui_browser *browser,
+                                         struct list_head *pos)
+{
+       do {
+               if (!browser->filter || !browser->filter(browser, pos))
+                       return pos;
+               pos = pos->prev;
+       } while (pos != browser->entries);
+
+       return NULL;
+}
+
+void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence)
+{
+       struct list_head *head = self->entries;
+       struct list_head *pos;
+
+       if (self->nr_entries == 0)
+               return;
+
+       switch (whence) {
+       case SEEK_SET:
+               pos = ui_browser__list_head_filter_entries(self, head->next);
+               break;
+       case SEEK_CUR:
+               pos = self->top;
+               break;
+       case SEEK_END:
+               pos = ui_browser__list_head_filter_prev_entries(self, head->prev);
+               break;
+       default:
+               return;
+       }
+
+       assert(pos != NULL);
+
+       if (offset > 0) {
+               while (offset-- != 0)
+                       pos = ui_browser__list_head_filter_entries(self, pos->next);
+       } else {
+               while (offset++ != 0)
+                       pos = ui_browser__list_head_filter_prev_entries(self, pos->prev);
+       }
+
+       self->top = pos;
+}
+
+void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence)
+{
+       struct rb_root *root = self->entries;
+       struct rb_node *nd;
+
+       switch (whence) {
+       case SEEK_SET:
+               nd = rb_first(root);
+               break;
+       case SEEK_CUR:
+               nd = self->top;
+               break;
+       case SEEK_END:
+               nd = rb_last(root);
+               break;
+       default:
+               return;
+       }
+
+       if (offset > 0) {
+               while (offset-- != 0)
+                       nd = rb_next(nd);
+       } else {
+               while (offset++ != 0)
+                       nd = rb_prev(nd);
+       }
+
+       self->top = nd;
+}
+
+unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self)
+{
+       struct rb_node *nd;
+       int row = 0;
+
+       if (self->top == NULL)
+                self->top = rb_first(self->entries);
+
+       nd = self->top;
+
+       while (nd != NULL) {
+               ui_browser__gotorc(self, row, 0);
+               self->write(self, nd, row);
+               if (++row == self->height)
+                       break;
+               nd = rb_next(nd);
+       }
+
+       return row;
+}
+
+bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row)
+{
+       return self->top_idx + row == self->index;
+}
+
+void ui_browser__refresh_dimensions(struct ui_browser *self)
+{
+       self->width = SLtt_Screen_Cols - 1;
+       self->height = SLtt_Screen_Rows - 2;
+       self->y = 1;
+       self->x = 0;
+}
+
+void ui_browser__handle_resize(struct ui_browser *browser)
+{
+       ui__refresh_dimensions(false);
+       ui_browser__show(browser, browser->title, ui_helpline__current);
+       ui_browser__refresh(browser);
+}
+
+int ui_browser__warning(struct ui_browser *browser, int timeout,
+                       const char *format, ...)
+{
+       va_list args;
+       char *text;
+       int key = 0, err;
+
+       va_start(args, format);
+       err = vasprintf(&text, format, args);
+       va_end(args);
+
+       if (err < 0) {
+               va_start(args, format);
+               ui_helpline__vpush(format, args);
+               va_end(args);
+       } else {
+               while ((key == ui__question_window("Warning!", text,
+                                                  "Press any key...",
+                                                  timeout)) == K_RESIZE)
+                       ui_browser__handle_resize(browser);
+               free(text);
+       }
+
+       return key;
+}
+
+int ui_browser__help_window(struct ui_browser *browser, const char *text)
+{
+       int key;
+
+       while ((key = ui__help_window(text)) == K_RESIZE)
+               ui_browser__handle_resize(browser);
+
+       return key;
+}
+
+bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text)
+{
+       int key;
+
+       while ((key = ui__dialog_yesno(text)) == K_RESIZE)
+               ui_browser__handle_resize(browser);
+
+       return key == K_ENTER || toupper(key) == 'Y';
+}
+
+void ui_browser__reset_index(struct ui_browser *self)
+{
+       self->index = self->top_idx = 0;
+       self->seek(self, 0, SEEK_SET);
+}
+
+void __ui_browser__show_title(struct ui_browser *browser, const char *title)
+{
+       SLsmg_gotorc(0, 0);
+       ui_browser__set_color(browser, NEWT_COLORSET_ROOT);
+       slsmg_write_nstring(title, browser->width + 1);
+}
+
+void ui_browser__show_title(struct ui_browser *browser, const char *title)
+{
+       pthread_mutex_lock(&ui__lock);
+       __ui_browser__show_title(browser, title);
+       pthread_mutex_unlock(&ui__lock);
+}
+
+int ui_browser__show(struct ui_browser *self, const char *title,
+                    const char *helpline, ...)
+{
+       int err;
+       va_list ap;
+
+       ui_browser__refresh_dimensions(self);
+
+       pthread_mutex_lock(&ui__lock);
+       __ui_browser__show_title(self, title);
+
+       self->title = title;
+       free(self->helpline);
+       self->helpline = NULL;
+
+       va_start(ap, helpline);
+       err = vasprintf(&self->helpline, helpline, ap);
+       va_end(ap);
+       if (err > 0)
+               ui_helpline__push(self->helpline);
+       pthread_mutex_unlock(&ui__lock);
+       return err ? 0 : -1;
+}
+
+void ui_browser__hide(struct ui_browser *browser __used)
+{
+       pthread_mutex_lock(&ui__lock);
+       ui_helpline__pop();
+       pthread_mutex_unlock(&ui__lock);
+}
+
+static void ui_browser__scrollbar_set(struct ui_browser *browser)
+{
+       int height = browser->height, h = 0, pct = 0,
+           col = browser->width,
+           row = browser->y - 1;
+
+       if (browser->nr_entries > 1) {
+               pct = ((browser->index * (browser->height - 1)) /
+                      (browser->nr_entries - 1));
+       }
+
+       SLsmg_set_char_set(1);
+
+       while (h < height) {
+               ui_browser__gotorc(browser, row++, col);
+               SLsmg_write_char(h == pct ? SLSMG_DIAMOND_CHAR : SLSMG_CKBRD_CHAR);
+               ++h;
+       }
+
+       SLsmg_set_char_set(0);
+}
+
+static int __ui_browser__refresh(struct ui_browser *browser)
+{
+       int row;
+       int width = browser->width;
+
+       row = browser->refresh(browser);
+       ui_browser__set_color(browser, HE_COLORSET_NORMAL);
+
+       if (!browser->use_navkeypressed || browser->navkeypressed)
+               ui_browser__scrollbar_set(browser);
+       else
+               width += 1;
+
+       SLsmg_fill_region(browser->y + row, browser->x,
+                         browser->height - row, width, ' ');
+
+       return 0;
+}
+
+int ui_browser__refresh(struct ui_browser *browser)
+{
+       pthread_mutex_lock(&ui__lock);
+       __ui_browser__refresh(browser);
+       pthread_mutex_unlock(&ui__lock);
+
+       return 0;
+}
+
+/*
+ * Here we're updating nr_entries _after_ we started browsing, i.e.  we have to
+ * forget about any reference to any entry in the underlying data structure,
+ * that is why we do a SEEK_SET. Think about 'perf top' in the hists browser
+ * after an output_resort and hist decay.
+ */
+void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries)
+{
+       off_t offset = nr_entries - browser->nr_entries;
+
+       browser->nr_entries = nr_entries;
+
+       if (offset < 0) {
+               if (browser->top_idx < (u64)-offset)
+                       offset = -browser->top_idx;
+
+               browser->index += offset;
+               browser->top_idx += offset;
+       }
+
+       browser->top = NULL;
+       browser->seek(browser, browser->top_idx, SEEK_SET);
+}
+
+int ui_browser__run(struct ui_browser *self, int delay_secs)
+{
+       int err, key;
+
+       while (1) {
+               off_t offset;
+
+               pthread_mutex_lock(&ui__lock);
+               err = __ui_browser__refresh(self);
+               SLsmg_refresh();
+               pthread_mutex_unlock(&ui__lock);
+               if (err < 0)
+                       break;
+
+               key = ui__getch(delay_secs);
+
+               if (key == K_RESIZE) {
+                       ui__refresh_dimensions(false);
+                       ui_browser__refresh_dimensions(self);
+                       __ui_browser__show_title(self, self->title);
+                       ui_helpline__puts(self->helpline);
+                       continue;
+               }
+
+               if (self->use_navkeypressed && !self->navkeypressed) {
+                       if (key == K_DOWN || key == K_UP ||
+                           key == K_PGDN || key == K_PGUP ||
+                           key == K_HOME || key == K_END ||
+                           key == ' ') {
+                               self->navkeypressed = true;
+                               continue;
+                       } else
+                               return key;
+               }
+
+               switch (key) {
+               case K_DOWN:
+                       if (self->index == self->nr_entries - 1)
+                               break;
+                       ++self->index;
+                       if (self->index == self->top_idx + self->height) {
+                               ++self->top_idx;
+                               self->seek(self, +1, SEEK_CUR);
+                       }
+                       break;
+               case K_UP:
+                       if (self->index == 0)
+                               break;
+                       --self->index;
+                       if (self->index < self->top_idx) {
+                               --self->top_idx;
+                               self->seek(self, -1, SEEK_CUR);
+                       }
+                       break;
+               case K_PGDN:
+               case ' ':
+                       if (self->top_idx + self->height > self->nr_entries - 1)
+                               break;
+
+                       offset = self->height;
+                       if (self->index + offset > self->nr_entries - 1)
+                               offset = self->nr_entries - 1 - self->index;
+                       self->index += offset;
+                       self->top_idx += offset;
+                       self->seek(self, +offset, SEEK_CUR);
+                       break;
+               case K_PGUP:
+                       if (self->top_idx == 0)
+                               break;
+
+                       if (self->top_idx < self->height)
+                               offset = self->top_idx;
+                       else
+                               offset = self->height;
+
+                       self->index -= offset;
+                       self->top_idx -= offset;
+                       self->seek(self, -offset, SEEK_CUR);
+                       break;
+               case K_HOME:
+                       ui_browser__reset_index(self);
+                       break;
+               case K_END:
+                       offset = self->height - 1;
+                       if (offset >= self->nr_entries)
+                               offset = self->nr_entries - 1;
+
+                       self->index = self->nr_entries - 1;
+                       self->top_idx = self->index - offset;
+                       self->seek(self, -offset, SEEK_END);
+                       break;
+               default:
+                       return key;
+               }
+       }
+       return -1;
+}
+
+unsigned int ui_browser__list_head_refresh(struct ui_browser *self)
+{
+       struct list_head *pos;
+       struct list_head *head = self->entries;
+       int row = 0;
+
+       if (self->top == NULL || self->top == self->entries)
+                self->top = ui_browser__list_head_filter_entries(self, head->next);
+
+       pos = self->top;
+
+       list_for_each_from(pos, head) {
+               if (!self->filter || !self->filter(self, pos)) {
+                       ui_browser__gotorc(self, row, 0);
+                       self->write(self, pos, row);
+                       if (++row == self->height)
+                               break;
+               }
+       }
+
+       return row;
+}
+
+static struct ui_browser__colorset {
+       const char *name, *fg, *bg;
+       int colorset;
+} ui_browser__colorsets[] = {
+       {
+               .colorset = HE_COLORSET_TOP,
+               .name     = "top",
+               .fg       = "red",
+               .bg       = "default",
+       },
+       {
+               .colorset = HE_COLORSET_MEDIUM,
+               .name     = "medium",
+               .fg       = "green",
+               .bg       = "default",
+       },
+       {
+               .colorset = HE_COLORSET_NORMAL,
+               .name     = "normal",
+               .fg       = "default",
+               .bg       = "default",
+       },
+       {
+               .colorset = HE_COLORSET_SELECTED,
+               .name     = "selected",
+               .fg       = "black",
+               .bg       = "lightgray",
+       },
+       {
+               .colorset = HE_COLORSET_CODE,
+               .name     = "code",
+               .fg       = "blue",
+               .bg       = "default",
+       },
+       {
+               .colorset = HE_COLORSET_ADDR,
+               .name     = "addr",
+               .fg       = "magenta",
+               .bg       = "default",
+       },
+       {
+               .name = NULL,
+       }
+};
+
+
+static int ui_browser__color_config(const char *var, const char *value,
+                                   void *data __used)
+{
+       char *fg = NULL, *bg;
+       int i;
+
+       /* same dir for all commands */
+       if (prefixcmp(var, "colors.") != 0)
+               return 0;
+
+       for (i = 0; ui_browser__colorsets[i].name != NULL; ++i) {
+               const char *name = var + 7;
+
+               if (strcmp(ui_browser__colorsets[i].name, name) != 0)
+                       continue;
+
+               fg = strdup(value);
+               if (fg == NULL)
+                       break;
+
+               bg = strchr(fg, ',');
+               if (bg == NULL)
+                       break;
+
+               *bg = '\0';
+               while (isspace(*++bg));
+               ui_browser__colorsets[i].bg = bg;
+               ui_browser__colorsets[i].fg = fg;
+               return 0;
+       }
+
+       free(fg);
+       return -1;
+}
+
+void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence)
+{
+       switch (whence) {
+       case SEEK_SET:
+               browser->top = browser->entries;
+               break;
+       case SEEK_CUR:
+               browser->top = browser->top + browser->top_idx + offset;
+               break;
+       case SEEK_END:
+               browser->top = browser->top + browser->nr_entries + offset;
+               break;
+       default:
+               return;
+       }
+}
+
+unsigned int ui_browser__argv_refresh(struct ui_browser *browser)
+{
+       unsigned int row = 0, idx = browser->top_idx;
+       char **pos;
+
+       if (browser->top == NULL)
+               browser->top = browser->entries;
+
+       pos = (char **)browser->top;
+       while (idx < browser->nr_entries) {
+               if (!browser->filter || !browser->filter(browser, *pos)) {
+                       ui_browser__gotorc(browser, row, 0);
+                       browser->write(browser, pos, row);
+                       if (++row == browser->height)
+                               break;
+               }
+
+               ++idx;
+               ++pos;
+       }
+
+       return row;
+}
+
+void ui_browser__init(void)
+{
+       int i = 0;
+
+       perf_config(ui_browser__color_config, NULL);
+
+       while (ui_browser__colorsets[i].name) {
+               struct ui_browser__colorset *c = &ui_browser__colorsets[i++];
+               sltt_set_color(c->colorset, c->name, c->fg, c->bg);
+       }
+}
diff --git a/tools/perf/ui/browser.h b/tools/perf/ui/browser.h
new file mode 100644 (file)
index 0000000..2550277
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef _PERF_UI_BROWSER_H_
+#define _PERF_UI_BROWSER_H_ 1
+
+#include <stdbool.h>
+#include <sys/types.h>
+#include "../types.h"
+
+#define HE_COLORSET_TOP                50
+#define HE_COLORSET_MEDIUM     51
+#define HE_COLORSET_NORMAL     52
+#define HE_COLORSET_SELECTED   53
+#define HE_COLORSET_CODE       54
+#define HE_COLORSET_ADDR       55
+
+struct ui_browser {
+       u64           index, top_idx;
+       void          *top, *entries;
+       u16           y, x, width, height;
+       int           current_color;
+       void          *priv;
+       const char    *title;
+       char          *helpline;
+       unsigned int  (*refresh)(struct ui_browser *self);
+       void          (*write)(struct ui_browser *self, void *entry, int row);
+       void          (*seek)(struct ui_browser *self, off_t offset, int whence);
+       bool          (*filter)(struct ui_browser *self, void *entry);
+       u32           nr_entries;
+       bool          navkeypressed;
+       bool          use_navkeypressed;
+};
+
+int  ui_browser__set_color(struct ui_browser *browser, int color);
+void ui_browser__set_percent_color(struct ui_browser *self,
+                                  double percent, bool current);
+bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row);
+void ui_browser__refresh_dimensions(struct ui_browser *self);
+void ui_browser__reset_index(struct ui_browser *self);
+
+void ui_browser__gotorc(struct ui_browser *self, int y, int x);
+void __ui_browser__show_title(struct ui_browser *browser, const char *title);
+void ui_browser__show_title(struct ui_browser *browser, const char *title);
+int ui_browser__show(struct ui_browser *self, const char *title,
+                    const char *helpline, ...);
+void ui_browser__hide(struct ui_browser *self);
+int ui_browser__refresh(struct ui_browser *self);
+int ui_browser__run(struct ui_browser *browser, int delay_secs);
+void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries);
+void ui_browser__handle_resize(struct ui_browser *browser);
+
+int ui_browser__warning(struct ui_browser *browser, int timeout,
+                       const char *format, ...);
+int ui_browser__help_window(struct ui_browser *browser, const char *text);
+bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text);
+int ui_browser__input_window(const char *title, const char *text, char *input,
+                            const char *exit_msg, int delay_sec);
+
+void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence);
+unsigned int ui_browser__argv_refresh(struct ui_browser *browser);
+
+void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence);
+unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self);
+
+void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence);
+unsigned int ui_browser__list_head_refresh(struct ui_browser *self);
+
+void ui_browser__init(void);
+#endif /* _PERF_UI_BROWSER_H_ */
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
new file mode 100644 (file)
index 0000000..4db5186
--- /dev/null
@@ -0,0 +1,673 @@
+#include "../../util/util.h"
+#include "../browser.h"
+#include "../helpline.h"
+#include "../libslang.h"
+#include "../ui.h"
+#include "../util.h"
+#include "../../util/annotate.h"
+#include "../../util/hist.h"
+#include "../../util/sort.h"
+#include "../../util/symbol.h"
+#include <pthread.h>
+#include <newt.h>
+
+struct annotate_browser {
+       struct ui_browser b;
+       struct rb_root    entries;
+       struct rb_node    *curr_hot;
+       struct objdump_line *selection;
+       u64                 start;
+       int                 nr_asm_entries;
+       int                 nr_entries;
+       bool                hide_src_code;
+       bool                use_offset;
+       bool                searching_backwards;
+       char                search_bf[128];
+};
+
+struct objdump_line_rb_node {
+       struct rb_node  rb_node;
+       double          percent;
+       u32             idx;
+       int             idx_asm;
+};
+
+static inline
+struct objdump_line_rb_node *objdump_line__rb(struct objdump_line *self)
+{
+       return (struct objdump_line_rb_node *)(self + 1);
+}
+
+static bool objdump_line__filter(struct ui_browser *browser, void *entry)
+{
+       struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
+
+       if (ab->hide_src_code) {
+               struct objdump_line *ol = list_entry(entry, struct objdump_line, node);
+               return ol->offset == -1;
+       }
+
+       return false;
+}
+
+static void annotate_browser__write(struct ui_browser *self, void *entry, int row)
+{
+       struct annotate_browser *ab = container_of(self, struct annotate_browser, b);
+       struct objdump_line *ol = list_entry(entry, struct objdump_line, node);
+       bool current_entry = ui_browser__is_current_entry(self, row);
+       bool change_color = (!ab->hide_src_code &&
+                            (!current_entry || (self->use_navkeypressed &&
+                                                !self->navkeypressed)));
+       int width = self->width;
+
+       if (ol->offset != -1) {
+               struct objdump_line_rb_node *olrb = objdump_line__rb(ol);
+               ui_browser__set_percent_color(self, olrb->percent, current_entry);
+               slsmg_printf(" %7.2f ", olrb->percent);
+       } else {
+               ui_browser__set_percent_color(self, 0, current_entry);
+               slsmg_write_nstring(" ", 9);
+       }
+
+       SLsmg_write_char(':');
+       slsmg_write_nstring(" ", 8);
+
+       /* The scroll bar isn't being used */
+       if (!self->navkeypressed)
+               width += 1;
+
+       if (ol->offset != -1 && change_color)
+               ui_browser__set_color(self, HE_COLORSET_CODE);
+
+       if (!*ol->line)
+               slsmg_write_nstring(" ", width - 18);
+       else if (ol->offset == -1)
+               slsmg_write_nstring(ol->line, width - 18);
+       else {
+               char bf[64];
+               u64 addr = ol->offset;
+               int printed, color = -1;
+
+               if (!ab->use_offset)
+                       addr += ab->start;
+
+               printed = scnprintf(bf, sizeof(bf), " %" PRIx64 ":", addr);
+               if (change_color)
+                       color = ui_browser__set_color(self, HE_COLORSET_ADDR);
+               slsmg_write_nstring(bf, printed);
+               if (change_color)
+                       ui_browser__set_color(self, color);
+               slsmg_write_nstring(ol->line, width - 18 - printed);
+       }
+
+       if (current_entry)
+               ab->selection = ol;
+}
+
+static double objdump_line__calc_percent(struct objdump_line *self,
+                                        struct symbol *sym, int evidx)
+{
+       double percent = 0.0;
+
+       if (self->offset != -1) {
+               int len = sym->end - sym->start;
+               unsigned int hits = 0;
+               struct annotation *notes = symbol__annotation(sym);
+               struct source_line *src_line = notes->src->lines;
+               struct sym_hist *h = annotation__histogram(notes, evidx);
+               s64 offset = self->offset;
+               struct objdump_line *next;
+
+               next = objdump__get_next_ip_line(&notes->src->source, self);
+               while (offset < (s64)len &&
+                      (next == NULL || offset < next->offset)) {
+                       if (src_line) {
+                               percent += src_line[offset].percent;
+                       } else
+                               hits += h->addr[offset];
+
+                       ++offset;
+               }
+               /*
+                * If the percentage wasn't already calculated in
+                * symbol__get_source_line, do it now:
+                */
+               if (src_line == NULL && h->sum)
+                       percent = 100.0 * hits / h->sum;
+       }
+
+       return percent;
+}
+
+static void objdump__insert_line(struct rb_root *self,
+                                struct objdump_line_rb_node *line)
+{
+       struct rb_node **p = &self->rb_node;
+       struct rb_node *parent = NULL;
+       struct objdump_line_rb_node *l;
+
+       while (*p != NULL) {
+               parent = *p;
+               l = rb_entry(parent, struct objdump_line_rb_node, rb_node);
+               if (line->percent < l->percent)
+                       p = &(*p)->rb_left;
+               else
+                       p = &(*p)->rb_right;
+       }
+       rb_link_node(&line->rb_node, parent, p);
+       rb_insert_color(&line->rb_node, self);
+}
+
+static void annotate_browser__set_top(struct annotate_browser *self,
+                                     struct objdump_line *pos, u32 idx)
+{
+       unsigned back;
+
+       ui_browser__refresh_dimensions(&self->b);
+       back = self->b.height / 2;
+       self->b.top_idx = self->b.index = idx;
+
+       while (self->b.top_idx != 0 && back != 0) {
+               pos = list_entry(pos->node.prev, struct objdump_line, node);
+
+               if (objdump_line__filter(&self->b, &pos->node))
+                       continue;
+
+               --self->b.top_idx;
+               --back;
+       }
+
+       self->b.top = pos;
+       self->b.navkeypressed = true;
+}
+
+static void annotate_browser__set_rb_top(struct annotate_browser *browser,
+                                        struct rb_node *nd)
+{
+       struct objdump_line_rb_node *rbpos;
+       struct objdump_line *pos;
+
+       rbpos = rb_entry(nd, struct objdump_line_rb_node, rb_node);
+       pos = ((struct objdump_line *)rbpos) - 1;
+       annotate_browser__set_top(browser, pos, rbpos->idx);
+       browser->curr_hot = nd;
+}
+
+static void annotate_browser__calc_percent(struct annotate_browser *browser,
+                                          int evidx)
+{
+       struct map_symbol *ms = browser->b.priv;
+       struct symbol *sym = ms->sym;
+       struct annotation *notes = symbol__annotation(sym);
+       struct objdump_line *pos;
+
+       browser->entries = RB_ROOT;
+
+       pthread_mutex_lock(&notes->lock);
+
+       list_for_each_entry(pos, &notes->src->source, node) {
+               struct objdump_line_rb_node *rbpos = objdump_line__rb(pos);
+               rbpos->percent = objdump_line__calc_percent(pos, sym, evidx);
+               if (rbpos->percent < 0.01) {
+                       RB_CLEAR_NODE(&rbpos->rb_node);
+                       continue;
+               }
+               objdump__insert_line(&browser->entries, rbpos);
+       }
+       pthread_mutex_unlock(&notes->lock);
+
+       browser->curr_hot = rb_last(&browser->entries);
+}
+
+static bool annotate_browser__toggle_source(struct annotate_browser *browser)
+{
+       struct objdump_line *ol;
+       struct objdump_line_rb_node *olrb;
+       off_t offset = browser->b.index - browser->b.top_idx;
+
+       browser->b.seek(&browser->b, offset, SEEK_CUR);
+       ol = list_entry(browser->b.top, struct objdump_line, node);
+       olrb = objdump_line__rb(ol);
+
+       if (browser->hide_src_code) {
+               if (olrb->idx_asm < offset)
+                       offset = olrb->idx;
+
+               browser->b.nr_entries = browser->nr_entries;
+               browser->hide_src_code = false;
+               browser->b.seek(&browser->b, -offset, SEEK_CUR);
+               browser->b.top_idx = olrb->idx - offset;
+               browser->b.index = olrb->idx;
+       } else {
+               if (olrb->idx_asm < 0) {
+                       ui_helpline__puts("Only available for assembly lines.");
+                       browser->b.seek(&browser->b, -offset, SEEK_CUR);
+                       return false;
+               }
+
+               if (olrb->idx_asm < offset)
+                       offset = olrb->idx_asm;
+
+               browser->b.nr_entries = browser->nr_asm_entries;
+               browser->hide_src_code = true;
+               browser->b.seek(&browser->b, -offset, SEEK_CUR);
+               browser->b.top_idx = olrb->idx_asm - offset;
+               browser->b.index = olrb->idx_asm;
+       }
+
+       return true;
+}
+
+static bool annotate_browser__callq(struct annotate_browser *browser,
+                                   int evidx, void (*timer)(void *arg),
+                                   void *arg, int delay_secs)
+{
+       struct map_symbol *ms = browser->b.priv;
+       struct symbol *sym = ms->sym;
+       struct annotation *notes;
+       struct symbol *target;
+       char *s = strstr(browser->selection->line, "callq ");
+       u64 ip;
+
+       if (s == NULL)
+               return false;
+
+       s = strchr(s, ' ');
+       if (s++ == NULL) {
+               ui_helpline__puts("Invallid callq instruction.");
+               return true;
+       }
+
+       ip = strtoull(s, NULL, 16);
+       ip = ms->map->map_ip(ms->map, ip);
+       target = map__find_symbol(ms->map, ip, NULL);
+       if (target == NULL) {
+               ui_helpline__puts("The called function was not found.");
+               return true;
+       }
+
+       notes = symbol__annotation(target);
+       pthread_mutex_lock(&notes->lock);
+
+       if (notes->src == NULL && symbol__alloc_hist(target) < 0) {
+               pthread_mutex_unlock(&notes->lock);
+               ui__warning("Not enough memory for annotating '%s' symbol!\n",
+                           target->name);
+               return true;
+       }
+
+       pthread_mutex_unlock(&notes->lock);
+       symbol__tui_annotate(target, ms->map, evidx, timer, arg, delay_secs);
+       ui_browser__show_title(&browser->b, sym->name);
+       return true;
+}
+
+static struct objdump_line *
+       annotate_browser__find_offset(struct annotate_browser *browser,
+                                     s64 offset, s64 *idx)
+{
+       struct map_symbol *ms = browser->b.priv;
+       struct symbol *sym = ms->sym;
+       struct annotation *notes = symbol__annotation(sym);
+       struct objdump_line *pos;
+
+       *idx = 0;
+       list_for_each_entry(pos, &notes->src->source, node) {
+               if (pos->offset == offset)
+                       return pos;
+               if (!objdump_line__filter(&browser->b, &pos->node))
+                       ++*idx;
+       }
+
+       return NULL;
+}
+
+static bool annotate_browser__jump(struct annotate_browser *browser)
+{
+       const char *jumps[] = { "je ", "jne ", "ja ", "jmpq ", "js ", "jmp ", NULL };
+       struct objdump_line *line;
+       s64 idx, offset;
+       char *s = NULL;
+       int i = 0;
+
+       while (jumps[i]) {
+               s = strstr(browser->selection->line, jumps[i++]);
+               if (s)
+                       break;
+       }
+
+       if (s == NULL)
+               return false;
+
+       s = strchr(s, '+');
+       if (s++ == NULL) {
+               ui_helpline__puts("Invallid jump instruction.");
+               return true;
+       }
+
+       offset = strtoll(s, NULL, 16);
+       line = annotate_browser__find_offset(browser, offset, &idx);
+       if (line == NULL) {
+               ui_helpline__puts("Invallid jump offset");
+               return true;
+       }
+
+       annotate_browser__set_top(browser, line, idx);
+       
+       return true;
+}
+
+static struct objdump_line *
+       annotate_browser__find_string(struct annotate_browser *browser,
+                                     char *s, s64 *idx)
+{
+       struct map_symbol *ms = browser->b.priv;
+       struct symbol *sym = ms->sym;
+       struct annotation *notes = symbol__annotation(sym);
+       struct objdump_line *pos = browser->selection;
+
+       *idx = browser->b.index;
+       list_for_each_entry_continue(pos, &notes->src->source, node) {
+               if (objdump_line__filter(&browser->b, &pos->node))
+                       continue;
+
+               ++*idx;
+
+               if (pos->line && strstr(pos->line, s) != NULL)
+                       return pos;
+       }
+
+       return NULL;
+}
+
+static bool __annotate_browser__search(struct annotate_browser *browser)
+{
+       struct objdump_line *line;
+       s64 idx;
+
+       line = annotate_browser__find_string(browser, browser->search_bf, &idx);
+       if (line == NULL) {
+               ui_helpline__puts("String not found!");
+               return false;
+       }
+
+       annotate_browser__set_top(browser, line, idx);
+       browser->searching_backwards = false;
+       return true;
+}
+
+static struct objdump_line *
+       annotate_browser__find_string_reverse(struct annotate_browser *browser,
+                                             char *s, s64 *idx)
+{
+       struct map_symbol *ms = browser->b.priv;
+       struct symbol *sym = ms->sym;
+       struct annotation *notes = symbol__annotation(sym);
+       struct objdump_line *pos = browser->selection;
+
+       *idx = browser->b.index;
+       list_for_each_entry_continue_reverse(pos, &notes->src->source, node) {
+               if (objdump_line__filter(&browser->b, &pos->node))
+                       continue;
+
+               --*idx;
+
+               if (pos->line && strstr(pos->line, s) != NULL)
+                       return pos;
+       }
+
+       return NULL;
+}
+
+static bool __annotate_browser__search_reverse(struct annotate_browser *browser)
+{
+       struct objdump_line *line;
+       s64 idx;
+
+       line = annotate_browser__find_string_reverse(browser, browser->search_bf, &idx);
+       if (line == NULL) {
+               ui_helpline__puts("String not found!");
+               return false;
+       }
+
+       annotate_browser__set_top(browser, line, idx);
+       browser->searching_backwards = true;
+       return true;
+}
+
+static bool annotate_browser__search_window(struct annotate_browser *browser,
+                                           int delay_secs)
+{
+       if (ui_browser__input_window("Search", "String: ", browser->search_bf,
+                                    "ENTER: OK, ESC: Cancel",
+                                    delay_secs * 2) != K_ENTER ||
+           !*browser->search_bf)
+               return false;
+
+       return true;
+}
+
+static bool annotate_browser__search(struct annotate_browser *browser, int delay_secs)
+{
+       if (annotate_browser__search_window(browser, delay_secs))
+               return __annotate_browser__search(browser);
+
+       return false;
+}
+
+static bool annotate_browser__continue_search(struct annotate_browser *browser,
+                                             int delay_secs)
+{
+       if (!*browser->search_bf)
+               return annotate_browser__search(browser, delay_secs);
+
+       return __annotate_browser__search(browser);
+}
+
+static bool annotate_browser__search_reverse(struct annotate_browser *browser,
+                                          int delay_secs)
+{
+       if (annotate_browser__search_window(browser, delay_secs))
+               return __annotate_browser__search_reverse(browser);
+
+       return false;
+}
+
+static
+bool annotate_browser__continue_search_reverse(struct annotate_browser *browser,
+                                              int delay_secs)
+{
+       if (!*browser->search_bf)
+               return annotate_browser__search_reverse(browser, delay_secs);
+
+       return __annotate_browser__search_reverse(browser);
+}
+
+static int annotate_browser__run(struct annotate_browser *self, int evidx,
+                                void(*timer)(void *arg),
+                                void *arg, int delay_secs)
+{
+       struct rb_node *nd = NULL;
+       struct map_symbol *ms = self->b.priv;
+       struct symbol *sym = ms->sym;
+       const char *help = "<-/ESC: Exit, TAB/shift+TAB: Cycle hot lines, "
+                          "H: Go to hottest line, ->/ENTER: Line action, "
+                          "O: Toggle offset view, "
+                          "S: Toggle source code view";
+       int key;
+
+       if (ui_browser__show(&self->b, sym->name, help) < 0)
+               return -1;
+
+       annotate_browser__calc_percent(self, evidx);
+
+       if (self->curr_hot) {
+               annotate_browser__set_rb_top(self, self->curr_hot);
+               self->b.navkeypressed = false;
+       }
+
+       nd = self->curr_hot;
+
+       while (1) {
+               key = ui_browser__run(&self->b, delay_secs);
+
+               if (delay_secs != 0) {
+                       annotate_browser__calc_percent(self, evidx);
+                       /*
+                        * Current line focus got out of the list of most active
+                        * lines, NULL it so that if TAB|UNTAB is pressed, we
+                        * move to curr_hot (current hottest line).
+                        */
+                       if (nd != NULL && RB_EMPTY_NODE(nd))
+                               nd = NULL;
+               }
+
+               switch (key) {
+               case K_TIMER:
+                       if (timer != NULL)
+                               timer(arg);
+
+                       if (delay_secs != 0)
+                               symbol__annotate_decay_histogram(sym, evidx);
+                       continue;
+               case K_TAB:
+                       if (nd != NULL) {
+                               nd = rb_prev(nd);
+                               if (nd == NULL)
+                                       nd = rb_last(&self->entries);
+                       } else
+                               nd = self->curr_hot;
+                       break;
+               case K_UNTAB:
+                       if (nd != NULL)
+                               nd = rb_next(nd);
+                               if (nd == NULL)
+                                       nd = rb_first(&self->entries);
+                       else
+                               nd = self->curr_hot;
+                       break;
+               case 'H':
+               case 'h':
+                       nd = self->curr_hot;
+                       break;
+               case 'S':
+               case 's':
+                       if (annotate_browser__toggle_source(self))
+                               ui_helpline__puts(help);
+                       continue;
+               case 'O':
+               case 'o':
+                       self->use_offset = !self->use_offset;
+                       continue;
+               case '/':
+                       if (annotate_browser__search(self, delay_secs)) {
+show_help:
+                               ui_helpline__puts(help);
+                       }
+                       continue;
+               case 'n':
+                       if (self->searching_backwards ?
+                           annotate_browser__continue_search_reverse(self, delay_secs) :
+                           annotate_browser__continue_search(self, delay_secs))
+                               goto show_help;
+                       continue;
+               case '?':
+                       if (annotate_browser__search_reverse(self, delay_secs))
+                               goto show_help;
+                       continue;
+               case K_ENTER:
+               case K_RIGHT:
+                       if (self->selection == NULL)
+                               ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
+                       else if (self->selection->offset == -1)
+                               ui_helpline__puts("Actions are only available for assembly lines.");
+                       else if (!(annotate_browser__jump(self) ||
+                                  annotate_browser__callq(self, evidx, timer, arg, delay_secs)))
+                               ui_helpline__puts("Actions are only available for the 'callq' and jump instructions.");
+                       continue;
+               case K_LEFT:
+               case K_ESC:
+               case 'q':
+               case CTRL('c'):
+                       goto out;
+               default:
+                       continue;
+               }
+
+               if (nd != NULL)
+                       annotate_browser__set_rb_top(self, nd);
+       }
+out:
+       ui_browser__hide(&self->b);
+       return key;
+}
+
+int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
+                            void(*timer)(void *arg), void *arg, int delay_secs)
+{
+       return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx,
+                                   timer, arg, delay_secs);
+}
+
+int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
+                        void(*timer)(void *arg), void *arg,
+                        int delay_secs)
+{
+       struct objdump_line *pos, *n;
+       struct annotation *notes;
+       struct map_symbol ms = {
+               .map = map,
+               .sym = sym,
+       };
+       struct annotate_browser browser = {
+               .b = {
+                       .refresh = ui_browser__list_head_refresh,
+                       .seek    = ui_browser__list_head_seek,
+                       .write   = annotate_browser__write,
+                       .filter  = objdump_line__filter,
+                       .priv    = &ms,
+                       .use_navkeypressed = true,
+               },
+       };
+       int ret;
+
+       if (sym == NULL)
+               return -1;
+
+       if (map->dso->annotate_warned)
+               return -1;
+
+       if (symbol__annotate(sym, map, sizeof(struct objdump_line_rb_node)) < 0) {
+               ui__error("%s", ui_helpline__last_msg);
+               return -1;
+       }
+
+       ui_helpline__push("Press <- or ESC to exit");
+
+       notes = symbol__annotation(sym);
+       browser.start = map__rip_2objdump(map, sym->start);
+
+       list_for_each_entry(pos, &notes->src->source, node) {
+               struct objdump_line_rb_node *rbpos;
+               size_t line_len = strlen(pos->line);
+
+               if (browser.b.width < line_len)
+                       browser.b.width = line_len;
+               rbpos = objdump_line__rb(pos);
+               rbpos->idx = browser.nr_entries++;
+               if (pos->offset != -1)
+                       rbpos->idx_asm = browser.nr_asm_entries++;
+               else
+                       rbpos->idx_asm = -1;
+       }
+
+       browser.b.nr_entries = browser.nr_entries;
+       browser.b.entries = &notes->src->source,
+       browser.b.width += 18; /* Percentage */
+       ret = annotate_browser__run(&browser, evidx, timer, arg, delay_secs);
+       list_for_each_entry_safe(pos, n, &notes->src->source, node) {
+               list_del(&pos->node);
+               objdump_line__free(pos);
+       }
+       return ret;
+}
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
new file mode 100644 (file)
index 0000000..466827e
--- /dev/null
@@ -0,0 +1,1345 @@
+#include <stdio.h>
+#include "../libslang.h"
+#include <stdlib.h>
+#include <string.h>
+#include <newt.h>
+#include <linux/rbtree.h>
+
+#include "../../util/evsel.h"
+#include "../../util/evlist.h"
+#include "../../util/hist.h"
+#include "../../util/pstack.h"
+#include "../../util/sort.h"
+#include "../../util/util.h"
+
+#include "../browser.h"
+#include "../helpline.h"
+#include "../util.h"
+#include "../ui.h"
+#include "map.h"
+
+struct hist_browser {
+       struct ui_browser   b;
+       struct hists        *hists;
+       struct hist_entry   *he_selection;
+       struct map_symbol   *selection;
+       bool                 has_symbols;
+};
+
+static int hists__browser_title(struct hists *self, char *bf, size_t size,
+                               const char *ev_name);
+
+static void hist_browser__refresh_dimensions(struct hist_browser *self)
+{
+       /* 3 == +/- toggle symbol before actual hist_entry rendering */
+       self->b.width = 3 + (hists__sort_list_width(self->hists) +
+                            sizeof("[k]"));
+}
+
+static void hist_browser__reset(struct hist_browser *self)
+{
+       self->b.nr_entries = self->hists->nr_entries;
+       hist_browser__refresh_dimensions(self);
+       ui_browser__reset_index(&self->b);
+}
+
+static char tree__folded_sign(bool unfolded)
+{
+       return unfolded ? '-' : '+';
+}
+
+static char map_symbol__folded(const struct map_symbol *self)
+{
+       return self->has_children ? tree__folded_sign(self->unfolded) : ' ';
+}
+
+static char hist_entry__folded(const struct hist_entry *self)
+{
+       return map_symbol__folded(&self->ms);
+}
+
+static char callchain_list__folded(const struct callchain_list *self)
+{
+       return map_symbol__folded(&self->ms);
+}
+
+static void map_symbol__set_folding(struct map_symbol *self, bool unfold)
+{
+       self->unfolded = unfold ? self->has_children : false;
+}
+
+static int callchain_node__count_rows_rb_tree(struct callchain_node *self)
+{
+       int n = 0;
+       struct rb_node *nd;
+
+       for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) {
+               struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
+               struct callchain_list *chain;
+               char folded_sign = ' '; /* No children */
+
+               list_for_each_entry(chain, &child->val, list) {
+                       ++n;
+                       /* We need this because we may not have children */
+                       folded_sign = callchain_list__folded(chain);
+                       if (folded_sign == '+')
+                               break;
+               }
+
+               if (folded_sign == '-') /* Have children and they're unfolded */
+                       n += callchain_node__count_rows_rb_tree(child);
+       }
+
+       return n;
+}
+
+static int callchain_node__count_rows(struct callchain_node *node)
+{
+       struct callchain_list *chain;
+       bool unfolded = false;
+       int n = 0;
+
+       list_for_each_entry(chain, &node->val, list) {
+               ++n;
+               unfolded = chain->ms.unfolded;
+       }
+
+       if (unfolded)
+               n += callchain_node__count_rows_rb_tree(node);
+
+       return n;
+}
+
+static int callchain__count_rows(struct rb_root *chain)
+{
+       struct rb_node *nd;
+       int n = 0;
+
+       for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
+               struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
+               n += callchain_node__count_rows(node);
+       }
+
+       return n;
+}
+
+static bool map_symbol__toggle_fold(struct map_symbol *self)
+{
+       if (!self)
+               return false;
+
+       if (!self->has_children)
+               return false;
+
+       self->unfolded = !self->unfolded;
+       return true;
+}
+
+static void callchain_node__init_have_children_rb_tree(struct callchain_node *self)
+{
+       struct rb_node *nd = rb_first(&self->rb_root);
+
+       for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) {
+               struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
+               struct callchain_list *chain;
+               bool first = true;
+
+               list_for_each_entry(chain, &child->val, list) {
+                       if (first) {
+                               first = false;
+                               chain->ms.has_children = chain->list.next != &child->val ||
+                                                        !RB_EMPTY_ROOT(&child->rb_root);
+                       } else
+                               chain->ms.has_children = chain->list.next == &child->val &&
+                                                        !RB_EMPTY_ROOT(&child->rb_root);
+               }
+
+               callchain_node__init_have_children_rb_tree(child);
+       }
+}
+
+static void callchain_node__init_have_children(struct callchain_node *self)
+{
+       struct callchain_list *chain;
+
+       list_for_each_entry(chain, &self->val, list)
+               chain->ms.has_children = !RB_EMPTY_ROOT(&self->rb_root);
+
+       callchain_node__init_have_children_rb_tree(self);
+}
+
+static void callchain__init_have_children(struct rb_root *self)
+{
+       struct rb_node *nd;
+
+       for (nd = rb_first(self); nd; nd = rb_next(nd)) {
+               struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
+               callchain_node__init_have_children(node);
+       }
+}
+
+static void hist_entry__init_have_children(struct hist_entry *self)
+{
+       if (!self->init_have_children) {
+               self->ms.has_children = !RB_EMPTY_ROOT(&self->sorted_chain);
+               callchain__init_have_children(&self->sorted_chain);
+               self->init_have_children = true;
+       }
+}
+
+static bool hist_browser__toggle_fold(struct hist_browser *self)
+{
+       if (map_symbol__toggle_fold(self->selection)) {
+               struct hist_entry *he = self->he_selection;
+
+               hist_entry__init_have_children(he);
+               self->hists->nr_entries -= he->nr_rows;
+
+               if (he->ms.unfolded)
+                       he->nr_rows = callchain__count_rows(&he->sorted_chain);
+               else
+                       he->nr_rows = 0;
+               self->hists->nr_entries += he->nr_rows;
+               self->b.nr_entries = self->hists->nr_entries;
+
+               return true;
+       }
+
+       /* If it doesn't have children, no toggling performed */
+       return false;
+}
+
+static int callchain_node__set_folding_rb_tree(struct callchain_node *self, bool unfold)
+{
+       int n = 0;
+       struct rb_node *nd;
+
+       for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) {
+               struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
+               struct callchain_list *chain;
+               bool has_children = false;
+
+               list_for_each_entry(chain, &child->val, list) {
+                       ++n;
+                       map_symbol__set_folding(&chain->ms, unfold);
+                       has_children = chain->ms.has_children;
+               }
+
+               if (has_children)
+                       n += callchain_node__set_folding_rb_tree(child, unfold);
+       }
+
+       return n;
+}
+
+static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
+{
+       struct callchain_list *chain;
+       bool has_children = false;
+       int n = 0;
+
+       list_for_each_entry(chain, &node->val, list) {
+               ++n;
+               map_symbol__set_folding(&chain->ms, unfold);
+               has_children = chain->ms.has_children;
+       }
+
+       if (has_children)
+               n += callchain_node__set_folding_rb_tree(node, unfold);
+
+       return n;
+}
+
+static int callchain__set_folding(struct rb_root *chain, bool unfold)
+{
+       struct rb_node *nd;
+       int n = 0;
+
+       for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
+               struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
+               n += callchain_node__set_folding(node, unfold);
+       }
+
+       return n;
+}
+
+static void hist_entry__set_folding(struct hist_entry *self, bool unfold)
+{
+       hist_entry__init_have_children(self);
+       map_symbol__set_folding(&self->ms, unfold);
+
+       if (self->ms.has_children) {
+               int n = callchain__set_folding(&self->sorted_chain, unfold);
+               self->nr_rows = unfold ? n : 0;
+       } else
+               self->nr_rows = 0;
+}
+
+static void hists__set_folding(struct hists *self, bool unfold)
+{
+       struct rb_node *nd;
+
+       self->nr_entries = 0;
+
+       for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
+               struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
+               hist_entry__set_folding(he, unfold);
+               self->nr_entries += 1 + he->nr_rows;
+       }
+}
+
+static void hist_browser__set_folding(struct hist_browser *self, bool unfold)
+{
+       hists__set_folding(self->hists, unfold);
+       self->b.nr_entries = self->hists->nr_entries;
+       /* Go to the start, we may be way after valid entries after a collapse */
+       ui_browser__reset_index(&self->b);
+}
+
+static void ui_browser__warn_lost_events(struct ui_browser *browser)
+{
+       ui_browser__warning(browser, 4,
+               "Events are being lost, check IO/CPU overload!\n\n"
+               "You may want to run 'perf' using a RT scheduler policy:\n\n"
+               " perf top -r 80\n\n"
+               "Or reduce the sampling frequency.");
+}
+
+static int hist_browser__run(struct hist_browser *self, const char *ev_name,
+                            void(*timer)(void *arg), void *arg, int delay_secs)
+{
+       int key;
+       char title[160];
+
+       self->b.entries = &self->hists->entries;
+       self->b.nr_entries = self->hists->nr_entries;
+
+       hist_browser__refresh_dimensions(self);
+       hists__browser_title(self->hists, title, sizeof(title), ev_name);
+
+       if (ui_browser__show(&self->b, title,
+                            "Press '?' for help on key bindings") < 0)
+               return -1;
+
+       while (1) {
+               key = ui_browser__run(&self->b, delay_secs);
+
+               switch (key) {
+               case K_TIMER:
+                       timer(arg);
+                       ui_browser__update_nr_entries(&self->b, self->hists->nr_entries);
+
+                       if (self->hists->stats.nr_lost_warned !=
+                           self->hists->stats.nr_events[PERF_RECORD_LOST]) {
+                               self->hists->stats.nr_lost_warned =
+                                       self->hists->stats.nr_events[PERF_RECORD_LOST];
+                               ui_browser__warn_lost_events(&self->b);
+                       }
+
+                       hists__browser_title(self->hists, title, sizeof(title), ev_name);
+                       ui_browser__show_title(&self->b, title);
+                       continue;
+               case 'D': { /* Debug */
+                       static int seq;
+                       struct hist_entry *h = rb_entry(self->b.top,
+                                                       struct hist_entry, rb_node);
+                       ui_helpline__pop();
+                       ui_helpline__fpush("%d: nr_ent=(%d,%d), height=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d",
+                                          seq++, self->b.nr_entries,
+                                          self->hists->nr_entries,
+                                          self->b.height,
+                                          self->b.index,
+                                          self->b.top_idx,
+                                          h->row_offset, h->nr_rows);
+               }
+                       break;
+               case 'C':
+                       /* Collapse the whole world. */
+                       hist_browser__set_folding(self, false);
+                       break;
+               case 'E':
+                       /* Expand the whole world. */
+                       hist_browser__set_folding(self, true);
+                       break;
+               case K_ENTER:
+                       if (hist_browser__toggle_fold(self))
+                               break;
+                       /* fall thru */
+               default:
+                       goto out;
+               }
+       }
+out:
+       ui_browser__hide(&self->b);
+       return key;
+}
+
+static char *callchain_list__sym_name(struct callchain_list *self,
+                                     char *bf, size_t bfsize)
+{
+       if (self->ms.sym)
+               return self->ms.sym->name;
+
+       snprintf(bf, bfsize, "%#" PRIx64, self->ip);
+       return bf;
+}
+
+#define LEVEL_OFFSET_STEP 3
+
+static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *self,
+                                                    struct callchain_node *chain_node,
+                                                    u64 total, int level,
+                                                    unsigned short row,
+                                                    off_t *row_offset,
+                                                    bool *is_current_entry)
+{
+       struct rb_node *node;
+       int first_row = row, width, offset = level * LEVEL_OFFSET_STEP;
+       u64 new_total, remaining;
+
+       if (callchain_param.mode == CHAIN_GRAPH_REL)
+               new_total = chain_node->children_hit;
+       else
+               new_total = total;
+
+       remaining = new_total;
+       node = rb_first(&chain_node->rb_root);
+       while (node) {
+               struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
+               struct rb_node *next = rb_next(node);
+               u64 cumul = callchain_cumul_hits(child);
+               struct callchain_list *chain;
+               char folded_sign = ' ';
+               int first = true;
+               int extra_offset = 0;
+
+               remaining -= cumul;
+
+               list_for_each_entry(chain, &child->val, list) {
+                       char ipstr[BITS_PER_LONG / 4 + 1], *alloc_str;
+                       const char *str;
+                       int color;
+                       bool was_first = first;
+
+                       if (first)
+                               first = false;
+                       else
+                               extra_offset = LEVEL_OFFSET_STEP;
+
+                       folded_sign = callchain_list__folded(chain);
+                       if (*row_offset != 0) {
+                               --*row_offset;
+                               goto do_next;
+                       }
+
+                       alloc_str = NULL;
+                       str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
+                       if (was_first) {
+                               double percent = cumul * 100.0 / new_total;
+
+                               if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
+                                       str = "Not enough memory!";
+                               else
+                                       str = alloc_str;
+                       }
+
+                       color = HE_COLORSET_NORMAL;
+                       width = self->b.width - (offset + extra_offset + 2);
+                       if (ui_browser__is_current_entry(&self->b, row)) {
+                               self->selection = &chain->ms;
+                               color = HE_COLORSET_SELECTED;
+                               *is_current_entry = true;
+                       }
+
+                       ui_browser__set_color(&self->b, color);
+                       ui_browser__gotorc(&self->b, row, 0);
+                       slsmg_write_nstring(" ", offset + extra_offset);
+                       slsmg_printf("%c ", folded_sign);
+                       slsmg_write_nstring(str, width);
+                       free(alloc_str);
+
+                       if (++row == self->b.height)
+                               goto out;
+do_next:
+                       if (folded_sign == '+')
+                               break;
+               }
+
+               if (folded_sign == '-') {
+                       const int new_level = level + (extra_offset ? 2 : 1);
+                       row += hist_browser__show_callchain_node_rb_tree(self, child, new_total,
+                                                                        new_level, row, row_offset,
+                                                                        is_current_entry);
+               }
+               if (row == self->b.height)
+                       goto out;
+               node = next;
+       }
+out:
+       return row - first_row;
+}
+
+static int hist_browser__show_callchain_node(struct hist_browser *self,
+                                            struct callchain_node *node,
+                                            int level, unsigned short row,
+                                            off_t *row_offset,
+                                            bool *is_current_entry)
+{
+       struct callchain_list *chain;
+       int first_row = row,
+            offset = level * LEVEL_OFFSET_STEP,
+            width = self->b.width - offset;
+       char folded_sign = ' ';
+
+       list_for_each_entry(chain, &node->val, list) {
+               char ipstr[BITS_PER_LONG / 4 + 1], *s;
+               int color;
+
+               folded_sign = callchain_list__folded(chain);
+
+               if (*row_offset != 0) {
+                       --*row_offset;
+                       continue;
+               }
+
+               color = HE_COLORSET_NORMAL;
+               if (ui_browser__is_current_entry(&self->b, row)) {
+                       self->selection = &chain->ms;
+                       color = HE_COLORSET_SELECTED;
+                       *is_current_entry = true;
+               }
+
+               s = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
+               ui_browser__gotorc(&self->b, row, 0);
+               ui_browser__set_color(&self->b, color);
+               slsmg_write_nstring(" ", offset);
+               slsmg_printf("%c ", folded_sign);
+               slsmg_write_nstring(s, width - 2);
+
+               if (++row == self->b.height)
+                       goto out;
+       }
+
+       if (folded_sign == '-')
+               row += hist_browser__show_callchain_node_rb_tree(self, node,
+                                                                self->hists->stats.total_period,
+                                                                level + 1, row,
+                                                                row_offset,
+                                                                is_current_entry);
+out:
+       return row - first_row;
+}
+
+static int hist_browser__show_callchain(struct hist_browser *self,
+                                       struct rb_root *chain,
+                                       int level, unsigned short row,
+                                       off_t *row_offset,
+                                       bool *is_current_entry)
+{
+       struct rb_node *nd;
+       int first_row = row;
+
+       for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
+               struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
+
+               row += hist_browser__show_callchain_node(self, node, level,
+                                                        row, row_offset,
+                                                        is_current_entry);
+               if (row == self->b.height)
+                       break;
+       }
+
+       return row - first_row;
+}
+
+static int hist_browser__show_entry(struct hist_browser *self,
+                                   struct hist_entry *entry,
+                                   unsigned short row)
+{
+       char s[256];
+       double percent;
+       int printed = 0;
+       int width = self->b.width - 6; /* The percentage */
+       char folded_sign = ' ';
+       bool current_entry = ui_browser__is_current_entry(&self->b, row);
+       off_t row_offset = entry->row_offset;
+
+       if (current_entry) {
+               self->he_selection = entry;
+               self->selection = &entry->ms;
+       }
+
+       if (symbol_conf.use_callchain) {
+               hist_entry__init_have_children(entry);
+               folded_sign = hist_entry__folded(entry);
+       }
+
+       if (row_offset == 0) {
+               hist_entry__snprintf(entry, s, sizeof(s), self->hists);
+               percent = (entry->period * 100.0) / self->hists->stats.total_period;
+
+               ui_browser__set_percent_color(&self->b, percent, current_entry);
+               ui_browser__gotorc(&self->b, row, 0);
+               if (symbol_conf.use_callchain) {
+                       slsmg_printf("%c ", folded_sign);
+                       width -= 2;
+               }
+
+               slsmg_printf(" %5.2f%%", percent);
+
+               /* The scroll bar isn't being used */
+               if (!self->b.navkeypressed)
+                       width += 1;
+
+               if (!current_entry || !self->b.navkeypressed)
+                       ui_browser__set_color(&self->b, HE_COLORSET_NORMAL);
+
+               if (symbol_conf.show_nr_samples) {
+                       slsmg_printf(" %11u", entry->nr_events);
+                       width -= 12;
+               }
+
+               if (symbol_conf.show_total_period) {
+                       slsmg_printf(" %12" PRIu64, entry->period);
+                       width -= 13;
+               }
+
+               slsmg_write_nstring(s, width);
+               ++row;
+               ++printed;
+       } else
+               --row_offset;
+
+       if (folded_sign == '-' && row != self->b.height) {
+               printed += hist_browser__show_callchain(self, &entry->sorted_chain,
+                                                       1, row, &row_offset,
+                                                       &current_entry);
+               if (current_entry)
+                       self->he_selection = entry;
+       }
+
+       return printed;
+}
+
+static void ui_browser__hists_init_top(struct ui_browser *browser)
+{
+       if (browser->top == NULL) {
+               struct hist_browser *hb;
+
+               hb = container_of(browser, struct hist_browser, b);
+               browser->top = rb_first(&hb->hists->entries);
+       }
+}
+
+static unsigned int hist_browser__refresh(struct ui_browser *self)
+{
+       unsigned row = 0;
+       struct rb_node *nd;
+       struct hist_browser *hb = container_of(self, struct hist_browser, b);
+
+       ui_browser__hists_init_top(self);
+
+       for (nd = self->top; nd; nd = rb_next(nd)) {
+               struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
+
+               if (h->filtered)
+                       continue;
+
+               row += hist_browser__show_entry(hb, h, row);
+               if (row == self->height)
+                       break;
+       }
+
+       return row;
+}
+
+static struct rb_node *hists__filter_entries(struct rb_node *nd)
+{
+       while (nd != NULL) {
+               struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
+               if (!h->filtered)
+                       return nd;
+
+               nd = rb_next(nd);
+       }
+
+       return NULL;
+}
+
+static struct rb_node *hists__filter_prev_entries(struct rb_node *nd)
+{
+       while (nd != NULL) {
+               struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
+               if (!h->filtered)
+                       return nd;
+
+               nd = rb_prev(nd);
+       }
+
+       return NULL;
+}
+
+static void ui_browser__hists_seek(struct ui_browser *self,
+                                  off_t offset, int whence)
+{
+       struct hist_entry *h;
+       struct rb_node *nd;
+       bool first = true;
+
+       if (self->nr_entries == 0)
+               return;
+
+       ui_browser__hists_init_top(self);
+
+       switch (whence) {
+       case SEEK_SET:
+               nd = hists__filter_entries(rb_first(self->entries));
+               break;
+       case SEEK_CUR:
+               nd = self->top;
+               goto do_offset;
+       case SEEK_END:
+               nd = hists__filter_prev_entries(rb_last(self->entries));
+               first = false;
+               break;
+       default:
+               return;
+       }
+
+       /*
+        * Moves not relative to the first visible entry invalidates its
+        * row_offset:
+        */
+       h = rb_entry(self->top, struct hist_entry, rb_node);
+       h->row_offset = 0;
+
+       /*
+        * Here we have to check if nd is expanded (+), if it is we can't go
+        * the next top level hist_entry, instead we must compute an offset of
+        * what _not_ to show and not change the first visible entry.
+        *
+        * This offset increments when we are going from top to bottom and
+        * decreases when we're going from bottom to top.
+        *
+        * As we don't have backpointers to the top level in the callchains
+        * structure, we need to always print the whole hist_entry callchain,
+        * skipping the first ones that are before the first visible entry
+        * and stop when we printed enough lines to fill the screen.
+        */
+do_offset:
+       if (offset > 0) {
+               do {
+                       h = rb_entry(nd, struct hist_entry, rb_node);
+                       if (h->ms.unfolded) {
+                               u16 remaining = h->nr_rows - h->row_offset;
+                               if (offset > remaining) {
+                                       offset -= remaining;
+                                       h->row_offset = 0;
+                               } else {
+                                       h->row_offset += offset;
+                                       offset = 0;
+                                       self->top = nd;
+                                       break;
+                               }
+                       }
+                       nd = hists__filter_entries(rb_next(nd));
+                       if (nd == NULL)
+                               break;
+                       --offset;
+                       self->top = nd;
+               } while (offset != 0);
+       } else if (offset < 0) {
+               while (1) {
+                       h = rb_entry(nd, struct hist_entry, rb_node);
+                       if (h->ms.unfolded) {
+                               if (first) {
+                                       if (-offset > h->row_offset) {
+                                               offset += h->row_offset;
+                                               h->row_offset = 0;
+                                       } else {
+                                               h->row_offset += offset;
+                                               offset = 0;
+                                               self->top = nd;
+                                               break;
+                                       }
+                               } else {
+                                       if (-offset > h->nr_rows) {
+                                               offset += h->nr_rows;
+                                               h->row_offset = 0;
+                                       } else {
+                                               h->row_offset = h->nr_rows + offset;
+                                               offset = 0;
+                                               self->top = nd;
+                                               break;
+                                       }
+                               }
+                       }
+
+                       nd = hists__filter_prev_entries(rb_prev(nd));
+                       if (nd == NULL)
+                               break;
+                       ++offset;
+                       self->top = nd;
+                       if (offset == 0) {
+                               /*
+                                * Last unfiltered hist_entry, check if it is
+                                * unfolded, if it is then we should have
+                                * row_offset at its last entry.
+                                */
+                               h = rb_entry(nd, struct hist_entry, rb_node);
+                               if (h->ms.unfolded)
+                                       h->row_offset = h->nr_rows;
+                               break;
+                       }
+                       first = false;
+               }
+       } else {
+               self->top = nd;
+               h = rb_entry(nd, struct hist_entry, rb_node);
+               h->row_offset = 0;
+       }
+}
+
+static struct hist_browser *hist_browser__new(struct hists *hists)
+{
+       struct hist_browser *self = zalloc(sizeof(*self));
+
+       if (self) {
+               self->hists = hists;
+               self->b.refresh = hist_browser__refresh;
+               self->b.seek = ui_browser__hists_seek;
+               self->b.use_navkeypressed = true;
+               if (sort__branch_mode == 1)
+                       self->has_symbols = sort_sym_from.list.next != NULL;
+               else
+                       self->has_symbols = sort_sym.list.next != NULL;
+       }
+
+       return self;
+}
+
+static void hist_browser__delete(struct hist_browser *self)
+{
+       free(self);
+}
+
+static struct hist_entry *hist_browser__selected_entry(struct hist_browser *self)
+{
+       return self->he_selection;
+}
+
+static struct thread *hist_browser__selected_thread(struct hist_browser *self)
+{
+       return self->he_selection->thread;
+}
+
+static int hists__browser_title(struct hists *self, char *bf, size_t size,
+                               const char *ev_name)
+{
+       char unit;
+       int printed;
+       const struct dso *dso = self->dso_filter;
+       const struct thread *thread = self->thread_filter;
+       unsigned long nr_samples = self->stats.nr_events[PERF_RECORD_SAMPLE];
+       u64 nr_events = self->stats.total_period;
+
+       nr_samples = convert_unit(nr_samples, &unit);
+       printed = scnprintf(bf, size,
+                          "Samples: %lu%c of event '%s', Event count (approx.): %lu",
+                          nr_samples, unit, ev_name, nr_events);
+
+
+       if (self->uid_filter_str)
+               printed += snprintf(bf + printed, size - printed,
+                                   ", UID: %s", self->uid_filter_str);
+       if (thread)
+               printed += scnprintf(bf + printed, size - printed,
+                                   ", Thread: %s(%d)",
+                                   (thread->comm_set ? thread->comm : ""),
+                                   thread->pid);
+       if (dso)
+               printed += scnprintf(bf + printed, size - printed,
+                                   ", DSO: %s", dso->short_name);
+       return printed;
+}
+
+static inline void free_popup_options(char **options, int n)
+{
+       int i;
+
+       for (i = 0; i < n; ++i) {
+               free(options[i]);
+               options[i] = NULL;
+       }
+}
+
+static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
+                                   const char *helpline, const char *ev_name,
+                                   bool left_exits,
+                                   void(*timer)(void *arg), void *arg,
+                                   int delay_secs)
+{
+       struct hists *self = &evsel->hists;
+       struct hist_browser *browser = hist_browser__new(self);
+       struct branch_info *bi;
+       struct pstack *fstack;
+       char *options[16];
+       int nr_options = 0;
+       int key = -1;
+       char buf[64];
+
+       if (browser == NULL)
+               return -1;
+
+       fstack = pstack__new(2);
+       if (fstack == NULL)
+               goto out;
+
+       ui_helpline__push(helpline);
+
+       memset(options, 0, sizeof(options));
+
+       while (1) {
+               const struct thread *thread = NULL;
+               const struct dso *dso = NULL;
+               int choice = 0,
+                   annotate = -2, zoom_dso = -2, zoom_thread = -2,
+                   annotate_f = -2, annotate_t = -2, browse_map = -2;
+
+               nr_options = 0;
+
+               key = hist_browser__run(browser, ev_name, timer, arg, delay_secs);
+
+               if (browser->he_selection != NULL) {
+                       thread = hist_browser__selected_thread(browser);
+                       dso = browser->selection->map ? browser->selection->map->dso : NULL;
+               }
+               switch (key) {
+               case K_TAB:
+               case K_UNTAB:
+                       if (nr_events == 1)
+                               continue;
+                       /*
+                        * Exit the browser, let hists__browser_tree
+                        * go to the next or previous
+                        */
+                       goto out_free_stack;
+               case 'a':
+                       if (!browser->has_symbols) {
+                               ui_browser__warning(&browser->b, delay_secs * 2,
+                       "Annotation is only available for symbolic views, "
+                       "include \"sym*\" in --sort to use it.");
+                               continue;
+                       }
+
+                       if (browser->selection == NULL ||
+                           browser->selection->sym == NULL ||
+                           browser->selection->map->dso->annotate_warned)
+                               continue;
+                       goto do_annotate;
+               case 'd':
+                       goto zoom_dso;
+               case 't':
+                       goto zoom_thread;
+               case 's':
+                       if (ui_browser__input_window("Symbol to show",
+                                       "Please enter the name of symbol you want to see",
+                                       buf, "ENTER: OK, ESC: Cancel",
+                                       delay_secs * 2) == K_ENTER) {
+                               self->symbol_filter_str = *buf ? buf : NULL;
+                               hists__filter_by_symbol(self);
+                               hist_browser__reset(browser);
+                       }
+                       continue;
+               case K_F1:
+               case 'h':
+               case '?':
+                       ui_browser__help_window(&browser->b,
+                                       "h/?/F1        Show this window\n"
+                                       "UP/DOWN/PGUP\n"
+                                       "PGDN/SPACE    Navigate\n"
+                                       "q/ESC/CTRL+C  Exit browser\n\n"
+                                       "For multiple event sessions:\n\n"
+                                       "TAB/UNTAB Switch events\n\n"
+                                       "For symbolic views (--sort has sym):\n\n"
+                                       "->            Zoom into DSO/Threads & Annotate current symbol\n"
+                                       "<-            Zoom out\n"
+                                       "a             Annotate current symbol\n"
+                                       "C             Collapse all callchains\n"
+                                       "E             Expand all callchains\n"
+                                       "d             Zoom into current DSO\n"
+                                       "t             Zoom into current Thread\n"
+                                       "s             Filter symbol by name");
+                       continue;
+               case K_ENTER:
+               case K_RIGHT:
+                       /* menu */
+                       break;
+               case K_LEFT: {
+                       const void *top;
+
+                       if (pstack__empty(fstack)) {
+                               /*
+                                * Go back to the perf_evsel_menu__run or other user
+                                */
+                               if (left_exits)
+                                       goto out_free_stack;
+                               continue;
+                       }
+                       top = pstack__pop(fstack);
+                       if (top == &browser->hists->dso_filter)
+                               goto zoom_out_dso;
+                       if (top == &browser->hists->thread_filter)
+                               goto zoom_out_thread;
+                       continue;
+               }
+               case K_ESC:
+                       if (!left_exits &&
+                           !ui_browser__dialog_yesno(&browser->b,
+                                              "Do you really want to exit?"))
+                               continue;
+                       /* Fall thru */
+               case 'q':
+               case CTRL('c'):
+                       goto out_free_stack;
+               default:
+                       continue;
+               }
+
+               if (!browser->has_symbols)
+                       goto add_exit_option;
+
+               if (sort__branch_mode == 1) {
+                       bi = browser->he_selection->branch_info;
+                       if (browser->selection != NULL &&
+                           bi &&
+                           bi->from.sym != NULL &&
+                           !bi->from.map->dso->annotate_warned &&
+                               asprintf(&options[nr_options], "Annotate %s",
+                                        bi->from.sym->name) > 0)
+                               annotate_f = nr_options++;
+
+                       if (browser->selection != NULL &&
+                           bi &&
+                           bi->to.sym != NULL &&
+                           !bi->to.map->dso->annotate_warned &&
+                           (bi->to.sym != bi->from.sym ||
+                            bi->to.map->dso != bi->from.map->dso) &&
+                               asprintf(&options[nr_options], "Annotate %s",
+                                        bi->to.sym->name) > 0)
+                               annotate_t = nr_options++;
+               } else {
+
+                       if (browser->selection != NULL &&
+                           browser->selection->sym != NULL &&
+                           !browser->selection->map->dso->annotate_warned &&
+                               asprintf(&options[nr_options], "Annotate %s",
+                                        browser->selection->sym->name) > 0)
+                               annotate = nr_options++;
+               }
+
+               if (thread != NULL &&
+                   asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
+                            (browser->hists->thread_filter ? "out of" : "into"),
+                            (thread->comm_set ? thread->comm : ""),
+                            thread->pid) > 0)
+                       zoom_thread = nr_options++;
+
+               if (dso != NULL &&
+                   asprintf(&options[nr_options], "Zoom %s %s DSO",
+                            (browser->hists->dso_filter ? "out of" : "into"),
+                            (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
+                       zoom_dso = nr_options++;
+
+               if (browser->selection != NULL &&
+                   browser->selection->map != NULL &&
+                   asprintf(&options[nr_options], "Browse map details") > 0)
+                       browse_map = nr_options++;
+add_exit_option:
+               options[nr_options++] = (char *)"Exit";
+retry_popup_menu:
+               choice = ui__popup_menu(nr_options, options);
+
+               if (choice == nr_options - 1)
+                       break;
+
+               if (choice == -1) {
+                       free_popup_options(options, nr_options - 1);
+                       continue;
+               }
+
+               if (choice == annotate || choice == annotate_t || choice == annotate_f) {
+                       struct hist_entry *he;
+                       int err;
+do_annotate:
+                       he = hist_browser__selected_entry(browser);
+                       if (he == NULL)
+                               continue;
+
+                       /*
+                        * we stash the branch_info symbol + map into the
+                        * the ms so we don't have to rewrite all the annotation
+                        * code to use branch_info.
+                        * in branch mode, the ms struct is not used
+                        */
+                       if (choice == annotate_f) {
+                               he->ms.sym = he->branch_info->from.sym;
+                               he->ms.map = he->branch_info->from.map;
+                       }  else if (choice == annotate_t) {
+                               he->ms.sym = he->branch_info->to.sym;
+                               he->ms.map = he->branch_info->to.map;
+                       }
+
+                       /*
+                        * Don't let this be freed, say, by hists__decay_entry.
+                        */
+                       he->used = true;
+                       err = hist_entry__tui_annotate(he, evsel->idx,
+                                                      timer, arg, delay_secs);
+                       he->used = false;
+                       /*
+                        * offer option to annotate the other branch source or target
+                        * (if they exists) when returning from annotate
+                        */
+                       if ((err == 'q' || err == CTRL('c'))
+                           && annotate_t != -2 && annotate_f != -2)
+                               goto retry_popup_menu;
+
+                       ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
+                       if (err)
+                               ui_browser__handle_resize(&browser->b);
+
+               } else if (choice == browse_map)
+                       map__browse(browser->selection->map);
+               else if (choice == zoom_dso) {
+zoom_dso:
+                       if (browser->hists->dso_filter) {
+                               pstack__remove(fstack, &browser->hists->dso_filter);
+zoom_out_dso:
+                               ui_helpline__pop();
+                               browser->hists->dso_filter = NULL;
+                               sort_dso.elide = false;
+                       } else {
+                               if (dso == NULL)
+                                       continue;
+                               ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
+                                                  dso->kernel ? "the Kernel" : dso->short_name);
+                               browser->hists->dso_filter = dso;
+                               sort_dso.elide = true;
+                               pstack__push(fstack, &browser->hists->dso_filter);
+                       }
+                       hists__filter_by_dso(self);
+                       hist_browser__reset(browser);
+               } else if (choice == zoom_thread) {
+zoom_thread:
+                       if (browser->hists->thread_filter) {
+                               pstack__remove(fstack, &browser->hists->thread_filter);
+zoom_out_thread:
+                               ui_helpline__pop();
+                               browser->hists->thread_filter = NULL;
+                               sort_thread.elide = false;
+                       } else {
+                               ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
+                                                  thread->comm_set ? thread->comm : "",
+                                                  thread->pid);
+                               browser->hists->thread_filter = thread;
+                               sort_thread.elide = true;
+                               pstack__push(fstack, &browser->hists->thread_filter);
+                       }
+                       hists__filter_by_thread(self);
+                       hist_browser__reset(browser);
+               }
+       }
+out_free_stack:
+       pstack__delete(fstack);
+out:
+       hist_browser__delete(browser);
+       free_popup_options(options, nr_options - 1);
+       return key;
+}
+
+struct perf_evsel_menu {
+       struct ui_browser b;
+       struct perf_evsel *selection;
+       bool lost_events, lost_events_warned;
+};
+
+static void perf_evsel_menu__write(struct ui_browser *browser,
+                                  void *entry, int row)
+{
+       struct perf_evsel_menu *menu = container_of(browser,
+                                                   struct perf_evsel_menu, b);
+       struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
+       bool current_entry = ui_browser__is_current_entry(browser, row);
+       unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE];
+       const char *ev_name = event_name(evsel);
+       char bf[256], unit;
+       const char *warn = " ";
+       size_t printed;
+
+       ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
+                                                      HE_COLORSET_NORMAL);
+
+       nr_events = convert_unit(nr_events, &unit);
+       printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
+                          unit, unit == ' ' ? "" : " ", ev_name);
+       slsmg_printf("%s", bf);
+
+       nr_events = evsel->hists.stats.nr_events[PERF_RECORD_LOST];
+       if (nr_events != 0) {
+               menu->lost_events = true;
+               if (!current_entry)
+                       ui_browser__set_color(browser, HE_COLORSET_TOP);
+               nr_events = convert_unit(nr_events, &unit);
+               printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
+                                    nr_events, unit, unit == ' ' ? "" : " ");
+               warn = bf;
+       }
+
+       slsmg_write_nstring(warn, browser->width - printed);
+
+       if (current_entry)
+               menu->selection = evsel;
+}
+
+static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
+                               int nr_events, const char *help,
+                               void(*timer)(void *arg), void *arg, int delay_secs)
+{
+       struct perf_evlist *evlist = menu->b.priv;
+       struct perf_evsel *pos;
+       const char *ev_name, *title = "Available samples";
+       int key;
+
+       if (ui_browser__show(&menu->b, title,
+                            "ESC: exit, ENTER|->: Browse histograms") < 0)
+               return -1;
+
+       while (1) {
+               key = ui_browser__run(&menu->b, delay_secs);
+
+               switch (key) {
+               case K_TIMER:
+                       timer(arg);
+
+                       if (!menu->lost_events_warned && menu->lost_events) {
+                               ui_browser__warn_lost_events(&menu->b);
+                               menu->lost_events_warned = true;
+                       }
+                       continue;
+               case K_RIGHT:
+               case K_ENTER:
+                       if (!menu->selection)
+                               continue;
+                       pos = menu->selection;
+browse_hists:
+                       perf_evlist__set_selected(evlist, pos);
+                       /*
+                        * Give the calling tool a chance to populate the non
+                        * default evsel resorted hists tree.
+                        */
+                       if (timer)
+                               timer(arg);
+                       ev_name = event_name(pos);
+                       key = perf_evsel__hists_browse(pos, nr_events, help,
+                                                      ev_name, true, timer,
+                                                      arg, delay_secs);
+                       ui_browser__show_title(&menu->b, title);
+                       switch (key) {
+                       case K_TAB:
+                               if (pos->node.next == &evlist->entries)
+                                       pos = list_entry(evlist->entries.next, struct perf_evsel, node);
+                               else
+                                       pos = list_entry(pos->node.next, struct perf_evsel, node);
+                               goto browse_hists;
+                       case K_UNTAB:
+                               if (pos->node.prev == &evlist->entries)
+                                       pos = list_entry(evlist->entries.prev, struct perf_evsel, node);
+                               else
+                                       pos = list_entry(pos->node.prev, struct perf_evsel, node);
+                               goto browse_hists;
+                       case K_ESC:
+                               if (!ui_browser__dialog_yesno(&menu->b,
+                                               "Do you really want to exit?"))
+                                       continue;
+                               /* Fall thru */
+                       case 'q':
+                       case CTRL('c'):
+                               goto out;
+                       default:
+                               continue;
+                       }
+               case K_LEFT:
+                       continue;
+               case K_ESC:
+                       if (!ui_browser__dialog_yesno(&menu->b,
+                                              "Do you really want to exit?"))
+                               continue;
+                       /* Fall thru */
+               case 'q':
+               case CTRL('c'):
+                       goto out;
+               default:
+                       continue;
+               }
+       }
+
+out:
+       ui_browser__hide(&menu->b);
+       return key;
+}
+
+static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
+                                          const char *help,
+                                          void(*timer)(void *arg), void *arg,
+                                          int delay_secs)
+{
+       struct perf_evsel *pos;
+       struct perf_evsel_menu menu = {
+               .b = {
+                       .entries    = &evlist->entries,
+                       .refresh    = ui_browser__list_head_refresh,
+                       .seek       = ui_browser__list_head_seek,
+                       .write      = perf_evsel_menu__write,
+                       .nr_entries = evlist->nr_entries,
+                       .priv       = evlist,
+               },
+       };
+
+       ui_helpline__push("Press ESC to exit");
+
+       list_for_each_entry(pos, &evlist->entries, node) {
+               const char *ev_name = event_name(pos);
+               size_t line_len = strlen(ev_name) + 7;
+
+               if (menu.b.width < line_len)
+                       menu.b.width = line_len;
+               /*
+                * Cache the evsel name, tracepoints have a _high_ cost per
+                * event_name() call.
+                */
+               if (pos->name == NULL)
+                       pos->name = strdup(ev_name);
+       }
+
+       return perf_evsel_menu__run(&menu, evlist->nr_entries, help, timer,
+                                   arg, delay_secs);
+}
+
+int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
+                                 void(*timer)(void *arg), void *arg,
+                                 int delay_secs)
+{
+
+       if (evlist->nr_entries == 1) {
+               struct perf_evsel *first = list_entry(evlist->entries.next,
+                                                     struct perf_evsel, node);
+               const char *ev_name = event_name(first);
+               return perf_evsel__hists_browse(first, evlist->nr_entries, help,
+                                               ev_name, false, timer, arg,
+                                               delay_secs);
+       }
+
+       return __perf_evlist__tui_browse_hists(evlist, help,
+                                              timer, arg, delay_secs);
+}
diff --git a/tools/perf/ui/browsers/map.c b/tools/perf/ui/browsers/map.c
new file mode 100644 (file)
index 0000000..98851d5
--- /dev/null
@@ -0,0 +1,154 @@
+#include "../libslang.h"
+#include <elf.h>
+#include <newt.h>
+#include <inttypes.h>
+#include <sys/ttydefaults.h>
+#include <string.h>
+#include <linux/bitops.h>
+#include "../../util/util.h"
+#include "../../util/debug.h"
+#include "../../util/symbol.h"
+#include "../browser.h"
+#include "../helpline.h"
+#include "map.h"
+
+static int ui_entry__read(const char *title, char *bf, size_t size, int width)
+{
+       struct newtExitStruct es;
+       newtComponent form, entry;
+       const char *result;
+       int err = -1;
+
+       newtCenteredWindow(width, 1, title);
+       form = newtForm(NULL, NULL, 0);
+       if (form == NULL)
+               return -1;
+
+       entry = newtEntry(0, 0, "0x", width, &result, NEWT_FLAG_SCROLL);
+       if (entry == NULL)
+               goto out_free_form;
+
+       newtFormAddComponent(form, entry);
+       newtFormAddHotKey(form, NEWT_KEY_ENTER);
+       newtFormAddHotKey(form, NEWT_KEY_ESCAPE);
+       newtFormAddHotKey(form, NEWT_KEY_LEFT);
+       newtFormAddHotKey(form, CTRL('c'));
+       newtFormRun(form, &es);
+
+       if (result != NULL) {
+               strncpy(bf, result, size);
+               err = 0;
+       }
+out_free_form:
+       newtPopWindow();
+       newtFormDestroy(form);
+       return err;
+}
+
+struct map_browser {
+       struct ui_browser b;
+       struct map        *map;
+       u8                addrlen;
+};
+
+static void map_browser__write(struct ui_browser *self, void *nd, int row)
+{
+       struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
+       struct map_browser *mb = container_of(self, struct map_browser, b);
+       bool current_entry = ui_browser__is_current_entry(self, row);
+       int width;
+
+       ui_browser__set_percent_color(self, 0, current_entry);
+       slsmg_printf("%*" PRIx64 " %*" PRIx64 " %c ",
+                    mb->addrlen, sym->start, mb->addrlen, sym->end,
+                    sym->binding == STB_GLOBAL ? 'g' :
+                    sym->binding == STB_LOCAL  ? 'l' : 'w');
+       width = self->width - ((mb->addrlen * 2) + 4);
+       if (width > 0)
+               slsmg_write_nstring(sym->name, width);
+}
+
+/* FIXME uber-kludgy, see comment on cmd_report... */
+static u32 *symbol__browser_index(struct symbol *self)
+{
+       return ((void *)self) - sizeof(struct rb_node) - sizeof(u32);
+}
+
+static int map_browser__search(struct map_browser *self)
+{
+       char target[512];
+       struct symbol *sym;
+       int err = ui_entry__read("Search by name/addr", target, sizeof(target), 40);
+
+       if (err)
+               return err;
+
+       if (target[0] == '0' && tolower(target[1]) == 'x') {
+               u64 addr = strtoull(target, NULL, 16);
+               sym = map__find_symbol(self->map, addr, NULL);
+       } else
+               sym = map__find_symbol_by_name(self->map, target, NULL);
+
+       if (sym != NULL) {
+               u32 *idx = symbol__browser_index(sym);
+
+               self->b.top = &sym->rb_node;
+               self->b.index = self->b.top_idx = *idx;
+       } else
+               ui_helpline__fpush("%s not found!", target);
+
+       return 0;
+}
+
+static int map_browser__run(struct map_browser *self)
+{
+       int key;
+
+       if (ui_browser__show(&self->b, self->map->dso->long_name,
+                            "Press <- or ESC to exit, %s / to search",
+                            verbose ? "" : "restart with -v to use") < 0)
+               return -1;
+
+       while (1) {
+               key = ui_browser__run(&self->b, 0);
+
+               if (verbose && key == '/')
+                       map_browser__search(self);
+               else
+                       break;
+       }
+
+       ui_browser__hide(&self->b);
+       return key;
+}
+
+int map__browse(struct map *self)
+{
+       struct map_browser mb = {
+               .b = {
+                       .entries = &self->dso->symbols[self->type],
+                       .refresh = ui_browser__rb_tree_refresh,
+                       .seek    = ui_browser__rb_tree_seek,
+                       .write   = map_browser__write,
+               },
+               .map = self,
+       };
+       struct rb_node *nd;
+       char tmp[BITS_PER_LONG / 4];
+       u64 maxaddr = 0;
+
+       for (nd = rb_first(mb.b.entries); nd; nd = rb_next(nd)) {
+               struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
+
+               if (maxaddr < pos->end)
+                       maxaddr = pos->end;
+               if (verbose) {
+                       u32 *idx = symbol__browser_index(pos);
+                       *idx = mb.b.nr_entries;
+               }
+               ++mb.b.nr_entries;
+       }
+
+       mb.addrlen = snprintf(tmp, sizeof(tmp), "%" PRIx64, maxaddr);
+       return map_browser__run(&mb);
+}
diff --git a/tools/perf/ui/browsers/map.h b/tools/perf/ui/browsers/map.h
new file mode 100644 (file)
index 0000000..df8581a
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _PERF_UI_MAP_BROWSER_H_
+#define _PERF_UI_MAP_BROWSER_H_ 1
+struct map;
+
+int map__browse(struct map *self);
+#endif /* _PERF_UI_MAP_BROWSER_H_ */
diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c
new file mode 100644 (file)
index 0000000..258352a
--- /dev/null
@@ -0,0 +1,189 @@
+#include "../evlist.h"
+#include "../cache.h"
+#include "../evsel.h"
+#include "../sort.h"
+#include "../hist.h"
+#include "gtk.h"
+
+#include <signal.h>
+
+#define MAX_COLUMNS                    32
+
+void perf_gtk_setup_browser(int argc, const char *argv[],
+                           bool fallback_to_pager __used)
+{
+       gtk_init(&argc, (char ***)&argv);
+}
+
+void perf_gtk_exit_browser(bool wait_for_ok __used)
+{
+       gtk_main_quit();
+}
+
+static void perf_gtk_signal(int sig)
+{
+       psignal(sig, "perf");
+       gtk_main_quit();
+}
+
+static void perf_gtk_resize_window(GtkWidget *window)
+{
+       GdkRectangle rect;
+       GdkScreen *screen;
+       int monitor;
+       int height;
+       int width;
+
+       screen = gtk_widget_get_screen(window);
+
+       monitor = gdk_screen_get_monitor_at_window(screen, window->window);
+
+       gdk_screen_get_monitor_geometry(screen, monitor, &rect);
+
+       width   = rect.width * 3 / 4;
+       height  = rect.height * 3 / 4;
+
+       gtk_window_resize(GTK_WINDOW(window), width, height);
+}
+
+static void perf_gtk_show_hists(GtkWidget *window, struct hists *hists)
+{
+       GType col_types[MAX_COLUMNS];
+       GtkCellRenderer *renderer;
+       struct sort_entry *se;
+       GtkListStore *store;
+       struct rb_node *nd;
+       u64 total_period;
+       GtkWidget *view;
+       int col_idx;
+       int nr_cols;
+
+       nr_cols = 0;
+
+       /* The percentage column */
+       col_types[nr_cols++] = G_TYPE_STRING;
+
+       list_for_each_entry(se, &hist_entry__sort_list, list) {
+               if (se->elide)
+                       continue;
+
+               col_types[nr_cols++] = G_TYPE_STRING;
+       }
+
+       store = gtk_list_store_newv(nr_cols, col_types);
+
+       view = gtk_tree_view_new();
+
+       renderer = gtk_cell_renderer_text_new();
+
+       col_idx = 0;
+
+       /* The percentage column */
+       gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
+                                                   -1, "Overhead (%)",
+                                                   renderer, "text",
+                                                   col_idx++, NULL);
+
+       list_for_each_entry(se, &hist_entry__sort_list, list) {
+               if (se->elide)
+                       continue;
+
+               gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
+                                                           -1, se->se_header,
+                                                           renderer, "text",
+                                                           col_idx++, NULL);
+       }
+
+       gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
+
+       g_object_unref(GTK_TREE_MODEL(store));
+
+       total_period = hists->stats.total_period;
+
+       for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
+               struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
+               GtkTreeIter iter;
+               double percent;
+               char s[512];
+
+               if (h->filtered)
+                       continue;
+
+               gtk_list_store_append(store, &iter);
+
+               col_idx = 0;
+
+               percent = (h->period * 100.0) / total_period;
+
+               snprintf(s, ARRAY_SIZE(s), "%.2f", percent);
+
+               gtk_list_store_set(store, &iter, col_idx++, s, -1);
+
+               list_for_each_entry(se, &hist_entry__sort_list, list) {
+                       if (se->elide)
+                               continue;
+
+                       se->se_snprintf(h, s, ARRAY_SIZE(s),
+                                       hists__col_len(hists, se->se_width_idx));
+
+                       gtk_list_store_set(store, &iter, col_idx++, s, -1);
+               }
+       }
+
+       gtk_container_add(GTK_CONTAINER(window), view);
+}
+
+int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
+                                 const char *help __used,
+                                 void (*timer) (void *arg)__used,
+                                 void *arg __used, int delay_secs __used)
+{
+       struct perf_evsel *pos;
+       GtkWidget *notebook;
+       GtkWidget *window;
+
+       signal(SIGSEGV, perf_gtk_signal);
+       signal(SIGFPE,  perf_gtk_signal);
+       signal(SIGINT,  perf_gtk_signal);
+       signal(SIGQUIT, perf_gtk_signal);
+       signal(SIGTERM, perf_gtk_signal);
+
+       window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+
+       gtk_window_set_title(GTK_WINDOW(window), "perf report");
+
+       g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
+
+       notebook = gtk_notebook_new();
+
+       list_for_each_entry(pos, &evlist->entries, node) {
+               struct hists *hists = &pos->hists;
+               const char *evname = event_name(pos);
+               GtkWidget *scrolled_window;
+               GtkWidget *tab_label;
+
+               scrolled_window = gtk_scrolled_window_new(NULL, NULL);
+
+               gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
+                                                       GTK_POLICY_AUTOMATIC,
+                                                       GTK_POLICY_AUTOMATIC);
+
+               perf_gtk_show_hists(scrolled_window, hists);
+
+               tab_label = gtk_label_new(evname);
+
+               gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label);
+       }
+
+       gtk_container_add(GTK_CONTAINER(window), notebook);
+
+       gtk_widget_show_all(window);
+
+       perf_gtk_resize_window(window);
+
+       gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
+
+       gtk_main();
+
+       return 0;
+}
diff --git a/tools/perf/ui/gtk/gtk.h b/tools/perf/ui/gtk/gtk.h
new file mode 100644 (file)
index 0000000..75177ee
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _PERF_GTK_H_
+#define _PERF_GTK_H_ 1
+
+#pragma GCC diagnostic ignored "-Wstrict-prototypes"
+#include <gtk/gtk.h>
+#pragma GCC diagnostic error "-Wstrict-prototypes"
+
+#endif /* _PERF_GTK_H_ */
diff --git a/tools/perf/ui/helpline.c b/tools/perf/ui/helpline.c
new file mode 100644 (file)
index 0000000..2f950c2
--- /dev/null
@@ -0,0 +1,79 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../debug.h"
+#include "helpline.h"
+#include "ui.h"
+#include "libslang.h"
+
+void ui_helpline__pop(void)
+{
+}
+
+char ui_helpline__current[512];
+
+void ui_helpline__push(const char *msg)
+{
+       const size_t sz = sizeof(ui_helpline__current);
+
+       SLsmg_gotorc(SLtt_Screen_Rows - 1, 0);
+       SLsmg_set_color(0);
+       SLsmg_write_nstring((char *)msg, SLtt_Screen_Cols);
+       SLsmg_refresh();
+       strncpy(ui_helpline__current, msg, sz)[sz - 1] = '\0';
+}
+
+void ui_helpline__vpush(const char *fmt, va_list ap)
+{
+       char *s;
+
+       if (vasprintf(&s, fmt, ap) < 0)
+               vfprintf(stderr, fmt, ap);
+       else {
+               ui_helpline__push(s);
+               free(s);
+       }
+}
+
+void ui_helpline__fpush(const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       ui_helpline__vpush(fmt, ap);
+       va_end(ap);
+}
+
+void ui_helpline__puts(const char *msg)
+{
+       ui_helpline__pop();
+       ui_helpline__push(msg);
+}
+
+void ui_helpline__init(void)
+{
+       ui_helpline__puts(" ");
+}
+
+char ui_helpline__last_msg[1024];
+
+int ui_helpline__show_help(const char *format, va_list ap)
+{
+       int ret;
+       static int backlog;
+
+       pthread_mutex_lock(&ui__lock);
+       ret = vscnprintf(ui_helpline__last_msg + backlog,
+                       sizeof(ui_helpline__last_msg) - backlog, format, ap);
+       backlog += ret;
+
+       if (ui_helpline__last_msg[backlog - 1] == '\n') {
+               ui_helpline__puts(ui_helpline__last_msg);
+               SLsmg_refresh();
+               backlog = 0;
+       }
+       pthread_mutex_unlock(&ui__lock);
+
+       return ret;
+}
diff --git a/tools/perf/ui/helpline.h b/tools/perf/ui/helpline.h
new file mode 100644 (file)
index 0000000..7bab6b3
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _PERF_UI_HELPLINE_H_
+#define _PERF_UI_HELPLINE_H_ 1
+
+#include <stdio.h>
+#include <stdarg.h>
+
+void ui_helpline__init(void);
+void ui_helpline__pop(void);
+void ui_helpline__push(const char *msg);
+void ui_helpline__vpush(const char *fmt, va_list ap);
+void ui_helpline__fpush(const char *fmt, ...);
+void ui_helpline__puts(const char *msg);
+
+extern char ui_helpline__current[];
+
+#endif /* _PERF_UI_HELPLINE_H_ */
diff --git a/tools/perf/ui/keysyms.h b/tools/perf/ui/keysyms.h
new file mode 100644 (file)
index 0000000..809eca5
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef _PERF_KEYSYMS_H_
+#define _PERF_KEYSYMS_H_ 1
+
+#include "libslang.h"
+
+#define K_DOWN SL_KEY_DOWN
+#define K_END  SL_KEY_END
+#define K_ENTER        '\r'
+#define K_ESC  033
+#define K_F1   SL_KEY_F(1)
+#define K_HOME SL_KEY_HOME
+#define K_LEFT SL_KEY_LEFT
+#define K_PGDN SL_KEY_NPAGE
+#define K_PGUP SL_KEY_PPAGE
+#define K_RIGHT        SL_KEY_RIGHT
+#define K_TAB  '\t'
+#define K_UNTAB        SL_KEY_UNTAB
+#define K_UP   SL_KEY_UP
+#define K_BKSPC 0x7f
+#define K_DEL  SL_KEY_DELETE
+
+/* Not really keys */
+#define K_TIMER         -1
+#define K_ERROR         -2
+#define K_RESIZE -3
+
+#endif /* _PERF_KEYSYMS_H_ */
diff --git a/tools/perf/ui/libslang.h b/tools/perf/ui/libslang.h
new file mode 100644 (file)
index 0000000..4d54b64
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef _PERF_UI_SLANG_H_
+#define _PERF_UI_SLANG_H_ 1
+/*
+ * slang versions <= 2.0.6 have a "#if HAVE_LONG_LONG" that breaks
+ * the build if it isn't defined. Use the equivalent one that glibc
+ * has on features.h.
+ */
+#include <features.h>
+#ifndef HAVE_LONG_LONG
+#define HAVE_LONG_LONG __GLIBC_HAVE_LONG_LONG
+#endif
+#include <slang.h>
+
+#if SLANG_VERSION < 20104
+#define slsmg_printf(msg, args...) \
+       SLsmg_printf((char *)(msg), ##args)
+#define slsmg_write_nstring(msg, len) \
+       SLsmg_write_nstring((char *)(msg), len)
+#define sltt_set_color(obj, name, fg, bg) \
+       SLtt_set_color(obj,(char *)(name), (char *)(fg), (char *)(bg))
+#else
+#define slsmg_printf SLsmg_printf
+#define slsmg_write_nstring SLsmg_write_nstring
+#define sltt_set_color SLtt_set_color
+#endif
+
+#define SL_KEY_UNTAB 0x1000
+
+#endif /* _PERF_UI_SLANG_H_ */
diff --git a/tools/perf/ui/progress.c b/tools/perf/ui/progress.c
new file mode 100644 (file)
index 0000000..13aa64e
--- /dev/null
@@ -0,0 +1,32 @@
+#include "../cache.h"
+#include "progress.h"
+#include "libslang.h"
+#include "ui.h"
+#include "browser.h"
+
+void ui_progress__update(u64 curr, u64 total, const char *title)
+{
+       int bar, y;
+       /*
+        * FIXME: We should have a per UI backend way of showing progress,
+        * stdio will just show a percentage as NN%, etc.
+        */
+       if (use_browser <= 0)
+               return;
+
+       if (total == 0)
+               return;
+
+       ui__refresh_dimensions(true);
+       pthread_mutex_lock(&ui__lock);
+       y = SLtt_Screen_Rows / 2 - 2;
+       SLsmg_set_color(0);
+       SLsmg_draw_box(y, 0, 3, SLtt_Screen_Cols);
+       SLsmg_gotorc(y++, 1);
+       SLsmg_write_string((char *)title);
+       SLsmg_set_color(HE_COLORSET_SELECTED);
+       bar = ((SLtt_Screen_Cols - 2) * curr) / total;
+       SLsmg_fill_region(y, 1, 1, bar, ' ');
+       SLsmg_refresh();
+       pthread_mutex_unlock(&ui__lock);
+}
diff --git a/tools/perf/ui/progress.h b/tools/perf/ui/progress.h
new file mode 100644 (file)
index 0000000..d9c205b
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _PERF_UI_PROGRESS_H_
+#define _PERF_UI_PROGRESS_H_ 1
+
+#include <../types.h>
+
+void ui_progress__update(u64 curr, u64 total, const char *title);
+
+#endif
diff --git a/tools/perf/ui/setup.c b/tools/perf/ui/setup.c
new file mode 100644 (file)
index 0000000..85a69fa
--- /dev/null
@@ -0,0 +1,155 @@
+#include <newt.h>
+#include <signal.h>
+#include <stdbool.h>
+
+#include "../cache.h"
+#include "../debug.h"
+#include "browser.h"
+#include "helpline.h"
+#include "ui.h"
+#include "util.h"
+#include "libslang.h"
+#include "keysyms.h"
+
+pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER;
+
+static volatile int ui__need_resize;
+
+void ui__refresh_dimensions(bool force)
+{
+       if (force || ui__need_resize) {
+               ui__need_resize = 0;
+               pthread_mutex_lock(&ui__lock);
+               SLtt_get_screen_size();
+               SLsmg_reinit_smg();
+               pthread_mutex_unlock(&ui__lock);
+       }
+}
+
+static void ui__sigwinch(int sig __used)
+{
+       ui__need_resize = 1;
+}
+
+static void ui__setup_sigwinch(void)
+{
+       static bool done;
+
+       if (done)
+               return;
+
+       done = true;
+       pthread__unblock_sigwinch();
+       signal(SIGWINCH, ui__sigwinch);
+}
+
+int ui__getch(int delay_secs)
+{
+       struct timeval timeout, *ptimeout = delay_secs ? &timeout : NULL;
+       fd_set read_set;
+       int err, key;
+
+       ui__setup_sigwinch();
+
+       FD_ZERO(&read_set);
+       FD_SET(0, &read_set);
+
+       if (delay_secs) {
+               timeout.tv_sec = delay_secs;
+               timeout.tv_usec = 0;
+       }
+
+        err = select(1, &read_set, NULL, NULL, ptimeout);
+
+       if (err == 0)
+               return K_TIMER;
+
+       if (err == -1) {
+               if (errno == EINTR)
+                       return K_RESIZE;
+               return K_ERROR;
+       }
+
+       key = SLang_getkey();
+       if (key != K_ESC)
+               return key;
+
+       FD_ZERO(&read_set);
+       FD_SET(0, &read_set);
+       timeout.tv_sec = 0;
+       timeout.tv_usec = 20;
+        err = select(1, &read_set, NULL, NULL, &timeout);
+       if (err == 0)
+               return K_ESC;
+
+       SLang_ungetkey(key);
+       return SLkp_getkey();
+}
+
+static void newt_suspend(void *d __used)
+{
+       newtSuspend();
+       raise(SIGTSTP);
+       newtResume();
+}
+
+static int ui__init(void)
+{
+       int err = SLkp_init();
+
+       if (err < 0)
+               goto out;
+
+       SLkp_define_keysym((char *)"^(kB)", SL_KEY_UNTAB);
+out:
+       return err;
+}
+
+static void ui__exit(void)
+{
+       SLtt_set_cursor_visibility(1);
+       SLsmg_refresh();
+       SLsmg_reset_smg();
+       SLang_reset_tty();
+}
+
+static void ui__signal(int sig)
+{
+       ui__exit();
+       psignal(sig, "perf");
+       exit(0);
+}
+
+void setup_browser(bool fallback_to_pager)
+{
+       if (!isatty(1) || !use_browser || dump_trace) {
+               use_browser = 0;
+               if (fallback_to_pager)
+                       setup_pager();
+               return;
+       }
+
+       use_browser = 1;
+       newtInit();
+       ui__init();
+       newtSetSuspendCallback(newt_suspend, NULL);
+       ui_helpline__init();
+       ui_browser__init();
+
+       signal(SIGSEGV, ui__signal);
+       signal(SIGFPE, ui__signal);
+       signal(SIGINT, ui__signal);
+       signal(SIGQUIT, ui__signal);
+       signal(SIGTERM, ui__signal);
+}
+
+void exit_browser(bool wait_for_ok)
+{
+       if (use_browser > 0) {
+               if (wait_for_ok)
+                       ui__question_window("Fatal Error",
+                                           ui_helpline__last_msg,
+                                           "Press any key...", 0);
+               ui__exit();
+       }
+}
diff --git a/tools/perf/ui/ui.h b/tools/perf/ui/ui.h
new file mode 100644 (file)
index 0000000..7b67045
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef _PERF_UI_H_
+#define _PERF_UI_H_ 1
+
+#include <pthread.h>
+#include <stdbool.h>
+
+extern pthread_mutex_t ui__lock;
+
+void ui__refresh_dimensions(bool force);
+
+#endif /* _PERF_UI_H_ */
diff --git a/tools/perf/ui/util.c b/tools/perf/ui/util.c
new file mode 100644 (file)
index 0000000..ad4374a
--- /dev/null
@@ -0,0 +1,250 @@
+#include "../util.h"
+#include <signal.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/ttydefaults.h>
+
+#include "../cache.h"
+#include "../debug.h"
+#include "browser.h"
+#include "keysyms.h"
+#include "helpline.h"
+#include "ui.h"
+#include "util.h"
+#include "libslang.h"
+
+static void ui_browser__argv_write(struct ui_browser *browser,
+                                  void *entry, int row)
+{
+       char **arg = entry;
+       bool current_entry = ui_browser__is_current_entry(browser, row);
+
+       ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
+                                                      HE_COLORSET_NORMAL);
+       slsmg_write_nstring(*arg, browser->width);
+}
+
+static int popup_menu__run(struct ui_browser *menu)
+{
+       int key;
+
+       if (ui_browser__show(menu, " ", "ESC: exit, ENTER|->: Select option") < 0)
+               return -1;
+
+       while (1) {
+               key = ui_browser__run(menu, 0);
+
+               switch (key) {
+               case K_RIGHT:
+               case K_ENTER:
+                       key = menu->index;
+                       break;
+               case K_LEFT:
+               case K_ESC:
+               case 'q':
+               case CTRL('c'):
+                       key = -1;
+                       break;
+               default:
+                       continue;
+               }
+
+               break;
+       }
+
+       ui_browser__hide(menu);
+       return key;
+}
+
+int ui__popup_menu(int argc, char * const argv[])
+{
+       struct ui_browser menu = {
+               .entries    = (void *)argv,
+               .refresh    = ui_browser__argv_refresh,
+               .seek       = ui_browser__argv_seek,
+               .write      = ui_browser__argv_write,
+               .nr_entries = argc,
+       };
+
+       return popup_menu__run(&menu);
+}
+
+int ui_browser__input_window(const char *title, const char *text, char *input,
+                            const char *exit_msg, int delay_secs)
+{
+       int x, y, len, key;
+       int max_len = 60, nr_lines = 0;
+       static char buf[50];
+       const char *t;
+
+       t = text;
+       while (1) {
+               const char *sep = strchr(t, '\n');
+
+               if (sep == NULL)
+                       sep = strchr(t, '\0');
+               len = sep - t;
+               if (max_len < len)
+                       max_len = len;
+               ++nr_lines;
+               if (*sep == '\0')
+                       break;
+               t = sep + 1;
+       }
+
+       max_len += 2;
+       nr_lines += 8;
+       y = SLtt_Screen_Rows / 2 - nr_lines / 2;
+       x = SLtt_Screen_Cols / 2 - max_len / 2;
+
+       SLsmg_set_color(0);
+       SLsmg_draw_box(y, x++, nr_lines, max_len);
+       if (title) {
+               SLsmg_gotorc(y, x + 1);
+               SLsmg_write_string((char *)title);
+       }
+       SLsmg_gotorc(++y, x);
+       nr_lines -= 7;
+       max_len -= 2;
+       SLsmg_write_wrapped_string((unsigned char *)text, y, x,
+                                  nr_lines, max_len, 1);
+       y += nr_lines;
+       len = 5;
+       while (len--) {
+               SLsmg_gotorc(y + len - 1, x);
+               SLsmg_write_nstring((char *)" ", max_len);
+       }
+       SLsmg_draw_box(y++, x + 1, 3, max_len - 2);
+
+       SLsmg_gotorc(y + 3, x);
+       SLsmg_write_nstring((char *)exit_msg, max_len);
+       SLsmg_refresh();
+
+       x += 2;
+       len = 0;
+       key = ui__getch(delay_secs);
+       while (key != K_TIMER && key != K_ENTER && key != K_ESC) {
+               if (key == K_BKSPC) {
+                       if (len == 0)
+                               goto next_key;
+                       SLsmg_gotorc(y, x + --len);
+                       SLsmg_write_char(' ');
+               } else {
+                       buf[len] = key;
+                       SLsmg_gotorc(y, x + len++);
+                       SLsmg_write_char(key);
+               }
+               SLsmg_refresh();
+
+               /* XXX more graceful overflow handling needed */
+               if (len == sizeof(buf) - 1) {
+                       ui_helpline__push("maximum size of symbol name reached!");
+                       key = K_ENTER;
+                       break;
+               }
+next_key:
+               key = ui__getch(delay_secs);
+       }
+
+       buf[len] = '\0';
+       strncpy(input, buf, len+1);
+       return key;
+}
+
+int ui__question_window(const char *title, const char *text,
+                       const char *exit_msg, int delay_secs)
+{
+       int x, y;
+       int max_len = 0, nr_lines = 0;
+       const char *t;
+
+       t = text;
+       while (1) {
+               const char *sep = strchr(t, '\n');
+               int len;
+
+               if (sep == NULL)
+                       sep = strchr(t, '\0');
+               len = sep - t;
+               if (max_len < len)
+                       max_len = len;
+               ++nr_lines;
+               if (*sep == '\0')
+                       break;
+               t = sep + 1;
+       }
+
+       max_len += 2;
+       nr_lines += 4;
+       y = SLtt_Screen_Rows / 2 - nr_lines / 2,
+       x = SLtt_Screen_Cols / 2 - max_len / 2;
+
+       SLsmg_set_color(0);
+       SLsmg_draw_box(y, x++, nr_lines, max_len);
+       if (title) {
+               SLsmg_gotorc(y, x + 1);
+               SLsmg_write_string((char *)title);
+       }
+       SLsmg_gotorc(++y, x);
+       nr_lines -= 2;
+       max_len -= 2;
+       SLsmg_write_wrapped_string((unsigned char *)text, y, x,
+                                  nr_lines, max_len, 1);
+       SLsmg_gotorc(y + nr_lines - 2, x);
+       SLsmg_write_nstring((char *)" ", max_len);
+       SLsmg_gotorc(y + nr_lines - 1, x);
+       SLsmg_write_nstring((char *)exit_msg, max_len);
+       SLsmg_refresh();
+       return ui__getch(delay_secs);
+}
+
+int ui__help_window(const char *text)
+{
+       return ui__question_window("Help", text, "Press any key...", 0);
+}
+
+int ui__dialog_yesno(const char *msg)
+{
+       return ui__question_window(NULL, msg, "Enter: Yes, ESC: No", 0);
+}
+
+int __ui__warning(const char *title, const char *format, va_list args)
+{
+       char *s;
+
+       if (use_browser > 0 && vasprintf(&s, format, args) > 0) {
+               int key;
+
+               pthread_mutex_lock(&ui__lock);
+               key = ui__question_window(title, s, "Press any key...", 0);
+               pthread_mutex_unlock(&ui__lock);
+               free(s);
+               return key;
+       }
+
+       fprintf(stderr, "%s:\n", title);
+       vfprintf(stderr, format, args);
+       return K_ESC;
+}
+
+int ui__warning(const char *format, ...)
+{
+       int key;
+       va_list args;
+
+       va_start(args, format);
+       key = __ui__warning("Warning", format, args);
+       va_end(args);
+       return key;
+}
+
+int ui__error(const char *format, ...)
+{
+       int key;
+       va_list args;
+
+       va_start(args, format);
+       key = __ui__warning("Error", format, args);
+       va_end(args);
+       return key;
+}
diff --git a/tools/perf/ui/util.h b/tools/perf/ui/util.h
new file mode 100644 (file)
index 0000000..2d1738b
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef _PERF_UI_UTIL_H_
+#define _PERF_UI_UTIL_H_ 1
+
+#include <stdarg.h>
+
+int ui__getch(int delay_secs);
+int ui__popup_menu(int argc, char * const argv[]);
+int ui__help_window(const char *text);
+int ui__dialog_yesno(const char *msg);
+int ui__question_window(const char *title, const char *text,
+                       const char *exit_msg, int delay_secs);
+int __ui__warning(const char *title, const char *format, va_list args);
+
+#endif /* _PERF_UI_UTIL_H_ */
index 08c6d138a655c09398f05c6b1c4affdf1cb0ec56..1e7fd52bd29dfea7cfd0b9c518f5d1743c386304 100644 (file)
@@ -84,10 +84,15 @@ static struct objdump_line *objdump_line__new(s64 offset, char *line, size_t pri
 
        if (self != NULL) {
                self->offset = offset;
-               self->line = line;
+               self->line = strdup(line);
+               if (self->line == NULL)
+                       goto out_delete;
        }
 
        return self;
+out_delete:
+       free(self);
+       return NULL;
 }
 
 void objdump_line__free(struct objdump_line *self)
@@ -112,7 +117,7 @@ struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
 }
 
 static int objdump_line__print(struct objdump_line *oline, struct symbol *sym,
-                              int evidx, u64 len, int min_pcnt,
+                              u64 start, int evidx, u64 len, int min_pcnt,
                               int printed, int max_lines,
                               struct objdump_line *queue)
 {
@@ -128,6 +133,7 @@ static int objdump_line__print(struct objdump_line *oline, struct symbol *sym,
                struct source_line *src_line = notes->src->lines;
                struct sym_hist *h = annotation__histogram(notes, evidx);
                s64 offset = oline->offset;
+               const u64 addr = start + offset;
                struct objdump_line *next;
 
                next = objdump__get_next_ip_line(&notes->src->source, oline);
@@ -157,7 +163,7 @@ static int objdump_line__print(struct objdump_line *oline, struct symbol *sym,
                        list_for_each_entry_from(queue, &notes->src->source, node) {
                                if (queue == oline)
                                        break;
-                               objdump_line__print(queue, sym, evidx, len,
+                               objdump_line__print(queue, sym, start, evidx, len,
                                                    0, 0, 1, NULL);
                        }
                }
@@ -180,6 +186,7 @@ static int objdump_line__print(struct objdump_line *oline, struct symbol *sym,
 
                color_fprintf(stdout, color, " %7.2f", percent);
                printf(" :      ");
+               color_fprintf(stdout, PERF_COLOR_MAGENTA, "  %" PRIx64 ":", addr);
                color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", oline->line);
        } else if (max_lines && printed >= max_lines)
                return 1;
@@ -201,7 +208,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
 {
        struct annotation *notes = symbol__annotation(sym);
        struct objdump_line *objdump_line;
-       char *line = NULL, *tmp, *tmp2, *c;
+       char *line = NULL, *parsed_line, *tmp, *tmp2, *c;
        size_t line_len;
        s64 line_ip, offset = -1;
 
@@ -219,6 +226,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
                *c = 0;
 
        line_ip = -1;
+       parsed_line = line;
 
        /*
         * Strip leading spaces:
@@ -246,13 +254,16 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
                offset = line_ip - start;
                if (offset < 0 || (u64)line_ip > end)
                        offset = -1;
+               else
+                       parsed_line = tmp2 + 1;
        }
 
-       objdump_line = objdump_line__new(offset, line, privsize);
-       if (objdump_line == NULL) {
-               free(line);
+       objdump_line = objdump_line__new(offset, parsed_line, privsize);
+       free(line);
+
+       if (objdump_line == NULL)
                return -1;
-       }
+
        objdump__add_line(&notes->src->source, objdump_line);
 
        return 0;
@@ -493,6 +504,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
        const char *filename = dso->long_name, *d_filename;
        struct annotation *notes = symbol__annotation(sym);
        struct objdump_line *pos, *queue = NULL;
+       u64 start = map__rip_2objdump(map, sym->start);
        int printed = 2, queue_len = 0;
        int more = 0;
        u64 len;
@@ -516,8 +528,9 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
                        queue_len = 0;
                }
 
-               switch (objdump_line__print(pos, sym, evidx, len, min_pcnt,
-                                           printed, max_lines, queue)) {
+               switch (objdump_line__print(pos, sym, start, evidx, len,
+                                           min_pcnt, printed, max_lines,
+                                           queue)) {
                case 0:
                        ++printed;
                        if (context) {
index f2ce88d04f54be1cc71c0b5f9969070e9b2a61c3..6bebe7f0a20c6cb6b12cac9d041203d3221f2b1a 100644 (file)
@@ -26,7 +26,7 @@ static inline void ui_progress__update(u64 curr __used, u64 total __used,
 #else
 extern char ui_helpline__last_msg[];
 int ui_helpline__show_help(const char *format, va_list ap);
-#include "ui/progress.h"
+#include "../ui/progress.h"
 int ui__error(const char *format, ...) __attribute__((format(printf, 1, 2)));
 #endif
 
diff --git a/tools/perf/util/gtk/browser.c b/tools/perf/util/gtk/browser.c
deleted file mode 100644 (file)
index 258352a..0000000
+++ /dev/null
@@ -1,189 +0,0 @@
-#include "../evlist.h"
-#include "../cache.h"
-#include "../evsel.h"
-#include "../sort.h"
-#include "../hist.h"
-#include "gtk.h"
-
-#include <signal.h>
-
-#define MAX_COLUMNS                    32
-
-void perf_gtk_setup_browser(int argc, const char *argv[],
-                           bool fallback_to_pager __used)
-{
-       gtk_init(&argc, (char ***)&argv);
-}
-
-void perf_gtk_exit_browser(bool wait_for_ok __used)
-{
-       gtk_main_quit();
-}
-
-static void perf_gtk_signal(int sig)
-{
-       psignal(sig, "perf");
-       gtk_main_quit();
-}
-
-static void perf_gtk_resize_window(GtkWidget *window)
-{
-       GdkRectangle rect;
-       GdkScreen *screen;
-       int monitor;
-       int height;
-       int width;
-
-       screen = gtk_widget_get_screen(window);
-
-       monitor = gdk_screen_get_monitor_at_window(screen, window->window);
-
-       gdk_screen_get_monitor_geometry(screen, monitor, &rect);
-
-       width   = rect.width * 3 / 4;
-       height  = rect.height * 3 / 4;
-
-       gtk_window_resize(GTK_WINDOW(window), width, height);
-}
-
-static void perf_gtk_show_hists(GtkWidget *window, struct hists *hists)
-{
-       GType col_types[MAX_COLUMNS];
-       GtkCellRenderer *renderer;
-       struct sort_entry *se;
-       GtkListStore *store;
-       struct rb_node *nd;
-       u64 total_period;
-       GtkWidget *view;
-       int col_idx;
-       int nr_cols;
-
-       nr_cols = 0;
-
-       /* The percentage column */
-       col_types[nr_cols++] = G_TYPE_STRING;
-
-       list_for_each_entry(se, &hist_entry__sort_list, list) {
-               if (se->elide)
-                       continue;
-
-               col_types[nr_cols++] = G_TYPE_STRING;
-       }
-
-       store = gtk_list_store_newv(nr_cols, col_types);
-
-       view = gtk_tree_view_new();
-
-       renderer = gtk_cell_renderer_text_new();
-
-       col_idx = 0;
-
-       /* The percentage column */
-       gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
-                                                   -1, "Overhead (%)",
-                                                   renderer, "text",
-                                                   col_idx++, NULL);
-
-       list_for_each_entry(se, &hist_entry__sort_list, list) {
-               if (se->elide)
-                       continue;
-
-               gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
-                                                           -1, se->se_header,
-                                                           renderer, "text",
-                                                           col_idx++, NULL);
-       }
-
-       gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
-
-       g_object_unref(GTK_TREE_MODEL(store));
-
-       total_period = hists->stats.total_period;
-
-       for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
-               struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
-               GtkTreeIter iter;
-               double percent;
-               char s[512];
-
-               if (h->filtered)
-                       continue;
-
-               gtk_list_store_append(store, &iter);
-
-               col_idx = 0;
-
-               percent = (h->period * 100.0) / total_period;
-
-               snprintf(s, ARRAY_SIZE(s), "%.2f", percent);
-
-               gtk_list_store_set(store, &iter, col_idx++, s, -1);
-
-               list_for_each_entry(se, &hist_entry__sort_list, list) {
-                       if (se->elide)
-                               continue;
-
-                       se->se_snprintf(h, s, ARRAY_SIZE(s),
-                                       hists__col_len(hists, se->se_width_idx));
-
-                       gtk_list_store_set(store, &iter, col_idx++, s, -1);
-               }
-       }
-
-       gtk_container_add(GTK_CONTAINER(window), view);
-}
-
-int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
-                                 const char *help __used,
-                                 void (*timer) (void *arg)__used,
-                                 void *arg __used, int delay_secs __used)
-{
-       struct perf_evsel *pos;
-       GtkWidget *notebook;
-       GtkWidget *window;
-
-       signal(SIGSEGV, perf_gtk_signal);
-       signal(SIGFPE,  perf_gtk_signal);
-       signal(SIGINT,  perf_gtk_signal);
-       signal(SIGQUIT, perf_gtk_signal);
-       signal(SIGTERM, perf_gtk_signal);
-
-       window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-
-       gtk_window_set_title(GTK_WINDOW(window), "perf report");
-
-       g_signal_connect(window, "delete_event", gtk_main_quit, NULL);
-
-       notebook = gtk_notebook_new();
-
-       list_for_each_entry(pos, &evlist->entries, node) {
-               struct hists *hists = &pos->hists;
-               const char *evname = event_name(pos);
-               GtkWidget *scrolled_window;
-               GtkWidget *tab_label;
-
-               scrolled_window = gtk_scrolled_window_new(NULL, NULL);
-
-               gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
-                                                       GTK_POLICY_AUTOMATIC,
-                                                       GTK_POLICY_AUTOMATIC);
-
-               perf_gtk_show_hists(scrolled_window, hists);
-
-               tab_label = gtk_label_new(evname);
-
-               gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label);
-       }
-
-       gtk_container_add(GTK_CONTAINER(window), notebook);
-
-       gtk_widget_show_all(window);
-
-       perf_gtk_resize_window(window);
-
-       gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
-
-       gtk_main();
-
-       return 0;
-}
diff --git a/tools/perf/util/gtk/gtk.h b/tools/perf/util/gtk/gtk.h
deleted file mode 100644 (file)
index 75177ee..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef _PERF_GTK_H_
-#define _PERF_GTK_H_ 1
-
-#pragma GCC diagnostic ignored "-Wstrict-prototypes"
-#include <gtk/gtk.h>
-#pragma GCC diagnostic error "-Wstrict-prototypes"
-
-#endif /* _PERF_GTK_H_ */
index 2cae9df40e04c0663ba5b2ccc753595b2731626d..cfc64e293f90b6f3e065d42379da8bb00302616b 100644 (file)
@@ -138,7 +138,7 @@ static inline int hist_entry__tui_annotate(struct hist_entry *self __used,
 #define K_LEFT -1
 #define K_RIGHT -2
 #else
-#include "ui/keysyms.h"
+#include "../ui/keysyms.h"
 int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
                             void(*timer)(void *arg), void *arg, int delay_secs);
 
index 7da80f14418bc12795bab11d9bfb9fe04eb2669f..f718df8a3c59d1d80dad5e372b96bd4f6e92120b 100644 (file)
@@ -6,7 +6,7 @@
 
 struct thread_map {
        int nr;
-       int map[];
+       pid_t map[];
 };
 
 struct thread_map *thread_map__new_by_pid(pid_t pid);
diff --git a/tools/perf/util/ui/browser.c b/tools/perf/util/ui/browser.c
deleted file mode 100644 (file)
index 5568291..0000000
+++ /dev/null
@@ -1,597 +0,0 @@
-#include "../util.h"
-#include "../cache.h"
-#include "../../perf.h"
-#include "libslang.h"
-#include <newt.h>
-#include "ui.h"
-#include "util.h"
-#include <linux/compiler.h>
-#include <linux/list.h>
-#include <linux/rbtree.h>
-#include <stdlib.h>
-#include <sys/ttydefaults.h>
-#include "browser.h"
-#include "helpline.h"
-#include "keysyms.h"
-#include "../color.h"
-
-static int ui_browser__percent_color(struct ui_browser *browser,
-                                    double percent, bool current)
-{
-       if (current && (!browser->use_navkeypressed || browser->navkeypressed))
-               return HE_COLORSET_SELECTED;
-       if (percent >= MIN_RED)
-               return HE_COLORSET_TOP;
-       if (percent >= MIN_GREEN)
-               return HE_COLORSET_MEDIUM;
-       return HE_COLORSET_NORMAL;
-}
-
-void ui_browser__set_color(struct ui_browser *self __used, int color)
-{
-       SLsmg_set_color(color);
-}
-
-void ui_browser__set_percent_color(struct ui_browser *self,
-                                  double percent, bool current)
-{
-        int color = ui_browser__percent_color(self, percent, current);
-        ui_browser__set_color(self, color);
-}
-
-void ui_browser__gotorc(struct ui_browser *self, int y, int x)
-{
-       SLsmg_gotorc(self->y + y, self->x + x);
-}
-
-static struct list_head *
-ui_browser__list_head_filter_entries(struct ui_browser *browser,
-                                    struct list_head *pos)
-{
-       do {
-               if (!browser->filter || !browser->filter(browser, pos))
-                       return pos;
-               pos = pos->next;
-       } while (pos != browser->entries);
-
-       return NULL;
-}
-
-static struct list_head *
-ui_browser__list_head_filter_prev_entries(struct ui_browser *browser,
-                                         struct list_head *pos)
-{
-       do {
-               if (!browser->filter || !browser->filter(browser, pos))
-                       return pos;
-               pos = pos->prev;
-       } while (pos != browser->entries);
-
-       return NULL;
-}
-
-void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence)
-{
-       struct list_head *head = self->entries;
-       struct list_head *pos;
-
-       if (self->nr_entries == 0)
-               return;
-
-       switch (whence) {
-       case SEEK_SET:
-               pos = ui_browser__list_head_filter_entries(self, head->next);
-               break;
-       case SEEK_CUR:
-               pos = self->top;
-               break;
-       case SEEK_END:
-               pos = ui_browser__list_head_filter_prev_entries(self, head->prev);
-               break;
-       default:
-               return;
-       }
-
-       assert(pos != NULL);
-
-       if (offset > 0) {
-               while (offset-- != 0)
-                       pos = ui_browser__list_head_filter_entries(self, pos->next);
-       } else {
-               while (offset++ != 0)
-                       pos = ui_browser__list_head_filter_prev_entries(self, pos->prev);
-       }
-
-       self->top = pos;
-}
-
-void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence)
-{
-       struct rb_root *root = self->entries;
-       struct rb_node *nd;
-
-       switch (whence) {
-       case SEEK_SET:
-               nd = rb_first(root);
-               break;
-       case SEEK_CUR:
-               nd = self->top;
-               break;
-       case SEEK_END:
-               nd = rb_last(root);
-               break;
-       default:
-               return;
-       }
-
-       if (offset > 0) {
-               while (offset-- != 0)
-                       nd = rb_next(nd);
-       } else {
-               while (offset++ != 0)
-                       nd = rb_prev(nd);
-       }
-
-       self->top = nd;
-}
-
-unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self)
-{
-       struct rb_node *nd;
-       int row = 0;
-
-       if (self->top == NULL)
-                self->top = rb_first(self->entries);
-
-       nd = self->top;
-
-       while (nd != NULL) {
-               ui_browser__gotorc(self, row, 0);
-               self->write(self, nd, row);
-               if (++row == self->height)
-                       break;
-               nd = rb_next(nd);
-       }
-
-       return row;
-}
-
-bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row)
-{
-       return self->top_idx + row == self->index;
-}
-
-void ui_browser__refresh_dimensions(struct ui_browser *self)
-{
-       self->width = SLtt_Screen_Cols - 1;
-       self->height = SLtt_Screen_Rows - 2;
-       self->y = 1;
-       self->x = 0;
-}
-
-void ui_browser__handle_resize(struct ui_browser *browser)
-{
-       ui__refresh_dimensions(false);
-       ui_browser__show(browser, browser->title, ui_helpline__current);
-       ui_browser__refresh(browser);
-}
-
-int ui_browser__warning(struct ui_browser *browser, int timeout,
-                       const char *format, ...)
-{
-       va_list args;
-       char *text;
-       int key = 0, err;
-
-       va_start(args, format);
-       err = vasprintf(&text, format, args);
-       va_end(args);
-
-       if (err < 0) {
-               va_start(args, format);
-               ui_helpline__vpush(format, args);
-               va_end(args);
-       } else {
-               while ((key == ui__question_window("Warning!", text,
-                                                  "Press any key...",
-                                                  timeout)) == K_RESIZE)
-                       ui_browser__handle_resize(browser);
-               free(text);
-       }
-
-       return key;
-}
-
-int ui_browser__help_window(struct ui_browser *browser, const char *text)
-{
-       int key;
-
-       while ((key = ui__help_window(text)) == K_RESIZE)
-               ui_browser__handle_resize(browser);
-
-       return key;
-}
-
-bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text)
-{
-       int key;
-
-       while ((key = ui__dialog_yesno(text)) == K_RESIZE)
-               ui_browser__handle_resize(browser);
-
-       return key == K_ENTER || toupper(key) == 'Y';
-}
-
-void ui_browser__reset_index(struct ui_browser *self)
-{
-       self->index = self->top_idx = 0;
-       self->seek(self, 0, SEEK_SET);
-}
-
-void __ui_browser__show_title(struct ui_browser *browser, const char *title)
-{
-       SLsmg_gotorc(0, 0);
-       ui_browser__set_color(browser, NEWT_COLORSET_ROOT);
-       slsmg_write_nstring(title, browser->width + 1);
-}
-
-void ui_browser__show_title(struct ui_browser *browser, const char *title)
-{
-       pthread_mutex_lock(&ui__lock);
-       __ui_browser__show_title(browser, title);
-       pthread_mutex_unlock(&ui__lock);
-}
-
-int ui_browser__show(struct ui_browser *self, const char *title,
-                    const char *helpline, ...)
-{
-       int err;
-       va_list ap;
-
-       ui_browser__refresh_dimensions(self);
-
-       pthread_mutex_lock(&ui__lock);
-       __ui_browser__show_title(self, title);
-
-       self->title = title;
-       free(self->helpline);
-       self->helpline = NULL;
-
-       va_start(ap, helpline);
-       err = vasprintf(&self->helpline, helpline, ap);
-       va_end(ap);
-       if (err > 0)
-               ui_helpline__push(self->helpline);
-       pthread_mutex_unlock(&ui__lock);
-       return err ? 0 : -1;
-}
-
-void ui_browser__hide(struct ui_browser *browser __used)
-{
-       pthread_mutex_lock(&ui__lock);
-       ui_helpline__pop();
-       pthread_mutex_unlock(&ui__lock);
-}
-
-static void ui_browser__scrollbar_set(struct ui_browser *browser)
-{
-       int height = browser->height, h = 0, pct = 0,
-           col = browser->width,
-           row = browser->y - 1;
-
-       if (browser->nr_entries > 1) {
-               pct = ((browser->index * (browser->height - 1)) /
-                      (browser->nr_entries - 1));
-       }
-
-       SLsmg_set_char_set(1);
-
-       while (h < height) {
-               ui_browser__gotorc(browser, row++, col);
-               SLsmg_write_char(h == pct ? SLSMG_DIAMOND_CHAR : SLSMG_CKBRD_CHAR);
-               ++h;
-       }
-
-       SLsmg_set_char_set(0);
-}
-
-static int __ui_browser__refresh(struct ui_browser *browser)
-{
-       int row;
-       int width = browser->width;
-
-       row = browser->refresh(browser);
-       ui_browser__set_color(browser, HE_COLORSET_NORMAL);
-
-       if (!browser->use_navkeypressed || browser->navkeypressed)
-               ui_browser__scrollbar_set(browser);
-       else
-               width += 1;
-
-       SLsmg_fill_region(browser->y + row, browser->x,
-                         browser->height - row, width, ' ');
-
-       return 0;
-}
-
-int ui_browser__refresh(struct ui_browser *browser)
-{
-       pthread_mutex_lock(&ui__lock);
-       __ui_browser__refresh(browser);
-       pthread_mutex_unlock(&ui__lock);
-
-       return 0;
-}
-
-/*
- * Here we're updating nr_entries _after_ we started browsing, i.e.  we have to
- * forget about any reference to any entry in the underlying data structure,
- * that is why we do a SEEK_SET. Think about 'perf top' in the hists browser
- * after an output_resort and hist decay.
- */
-void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries)
-{
-       off_t offset = nr_entries - browser->nr_entries;
-
-       browser->nr_entries = nr_entries;
-
-       if (offset < 0) {
-               if (browser->top_idx < (u64)-offset)
-                       offset = -browser->top_idx;
-
-               browser->index += offset;
-               browser->top_idx += offset;
-       }
-
-       browser->top = NULL;
-       browser->seek(browser, browser->top_idx, SEEK_SET);
-}
-
-int ui_browser__run(struct ui_browser *self, int delay_secs)
-{
-       int err, key;
-
-       while (1) {
-               off_t offset;
-
-               pthread_mutex_lock(&ui__lock);
-               err = __ui_browser__refresh(self);
-               SLsmg_refresh();
-               pthread_mutex_unlock(&ui__lock);
-               if (err < 0)
-                       break;
-
-               key = ui__getch(delay_secs);
-
-               if (key == K_RESIZE) {
-                       ui__refresh_dimensions(false);
-                       ui_browser__refresh_dimensions(self);
-                       __ui_browser__show_title(self, self->title);
-                       ui_helpline__puts(self->helpline);
-                       continue;
-               }
-
-               if (self->use_navkeypressed && !self->navkeypressed) {
-                       if (key == K_DOWN || key == K_UP ||
-                           key == K_PGDN || key == K_PGUP ||
-                           key == K_HOME || key == K_END ||
-                           key == ' ') {
-                               self->navkeypressed = true;
-                               continue;
-                       } else
-                               return key;
-               }
-
-               switch (key) {
-               case K_DOWN:
-                       if (self->index == self->nr_entries - 1)
-                               break;
-                       ++self->index;
-                       if (self->index == self->top_idx + self->height) {
-                               ++self->top_idx;
-                               self->seek(self, +1, SEEK_CUR);
-                       }
-                       break;
-               case K_UP:
-                       if (self->index == 0)
-                               break;
-                       --self->index;
-                       if (self->index < self->top_idx) {
-                               --self->top_idx;
-                               self->seek(self, -1, SEEK_CUR);
-                       }
-                       break;
-               case K_PGDN:
-               case ' ':
-                       if (self->top_idx + self->height > self->nr_entries - 1)
-                               break;
-
-                       offset = self->height;
-                       if (self->index + offset > self->nr_entries - 1)
-                               offset = self->nr_entries - 1 - self->index;
-                       self->index += offset;
-                       self->top_idx += offset;
-                       self->seek(self, +offset, SEEK_CUR);
-                       break;
-               case K_PGUP:
-                       if (self->top_idx == 0)
-                               break;
-
-                       if (self->top_idx < self->height)
-                               offset = self->top_idx;
-                       else
-                               offset = self->height;
-
-                       self->index -= offset;
-                       self->top_idx -= offset;
-                       self->seek(self, -offset, SEEK_CUR);
-                       break;
-               case K_HOME:
-                       ui_browser__reset_index(self);
-                       break;
-               case K_END:
-                       offset = self->height - 1;
-                       if (offset >= self->nr_entries)
-                               offset = self->nr_entries - 1;
-
-                       self->index = self->nr_entries - 1;
-                       self->top_idx = self->index - offset;
-                       self->seek(self, -offset, SEEK_END);
-                       break;
-               default:
-                       return key;
-               }
-       }
-       return -1;
-}
-
-unsigned int ui_browser__list_head_refresh(struct ui_browser *self)
-{
-       struct list_head *pos;
-       struct list_head *head = self->entries;
-       int row = 0;
-
-       if (self->top == NULL || self->top == self->entries)
-                self->top = ui_browser__list_head_filter_entries(self, head->next);
-
-       pos = self->top;
-
-       list_for_each_from(pos, head) {
-               if (!self->filter || !self->filter(self, pos)) {
-                       ui_browser__gotorc(self, row, 0);
-                       self->write(self, pos, row);
-                       if (++row == self->height)
-                               break;
-               }
-       }
-
-       return row;
-}
-
-static struct ui_browser__colorset {
-       const char *name, *fg, *bg;
-       int colorset;
-} ui_browser__colorsets[] = {
-       {
-               .colorset = HE_COLORSET_TOP,
-               .name     = "top",
-               .fg       = "red",
-               .bg       = "default",
-       },
-       {
-               .colorset = HE_COLORSET_MEDIUM,
-               .name     = "medium",
-               .fg       = "green",
-               .bg       = "default",
-       },
-       {
-               .colorset = HE_COLORSET_NORMAL,
-               .name     = "normal",
-               .fg       = "default",
-               .bg       = "default",
-       },
-       {
-               .colorset = HE_COLORSET_SELECTED,
-               .name     = "selected",
-               .fg       = "black",
-               .bg       = "lightgray",
-       },
-       {
-               .colorset = HE_COLORSET_CODE,
-               .name     = "code",
-               .fg       = "blue",
-               .bg       = "default",
-       },
-       {
-               .name = NULL,
-       }
-};
-
-
-static int ui_browser__color_config(const char *var, const char *value,
-                                   void *data __used)
-{
-       char *fg = NULL, *bg;
-       int i;
-
-       /* same dir for all commands */
-       if (prefixcmp(var, "colors.") != 0)
-               return 0;
-
-       for (i = 0; ui_browser__colorsets[i].name != NULL; ++i) {
-               const char *name = var + 7;
-
-               if (strcmp(ui_browser__colorsets[i].name, name) != 0)
-                       continue;
-
-               fg = strdup(value);
-               if (fg == NULL)
-                       break;
-
-               bg = strchr(fg, ',');
-               if (bg == NULL)
-                       break;
-
-               *bg = '\0';
-               while (isspace(*++bg));
-               ui_browser__colorsets[i].bg = bg;
-               ui_browser__colorsets[i].fg = fg;
-               return 0;
-       }
-
-       free(fg);
-       return -1;
-}
-
-void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence)
-{
-       switch (whence) {
-       case SEEK_SET:
-               browser->top = browser->entries;
-               break;
-       case SEEK_CUR:
-               browser->top = browser->top + browser->top_idx + offset;
-               break;
-       case SEEK_END:
-               browser->top = browser->top + browser->nr_entries + offset;
-               break;
-       default:
-               return;
-       }
-}
-
-unsigned int ui_browser__argv_refresh(struct ui_browser *browser)
-{
-       unsigned int row = 0, idx = browser->top_idx;
-       char **pos;
-
-       if (browser->top == NULL)
-               browser->top = browser->entries;
-
-       pos = (char **)browser->top;
-       while (idx < browser->nr_entries) {
-               if (!browser->filter || !browser->filter(browser, *pos)) {
-                       ui_browser__gotorc(browser, row, 0);
-                       browser->write(browser, pos, row);
-                       if (++row == browser->height)
-                               break;
-               }
-
-               ++idx;
-               ++pos;
-       }
-
-       return row;
-}
-
-void ui_browser__init(void)
-{
-       int i = 0;
-
-       perf_config(ui_browser__color_config, NULL);
-
-       while (ui_browser__colorsets[i].name) {
-               struct ui_browser__colorset *c = &ui_browser__colorsets[i++];
-               sltt_set_color(c->colorset, c->name, c->fg, c->bg);
-       }
-}
diff --git a/tools/perf/util/ui/browser.h b/tools/perf/util/ui/browser.h
deleted file mode 100644 (file)
index 6ee82f6..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-#ifndef _PERF_UI_BROWSER_H_
-#define _PERF_UI_BROWSER_H_ 1
-
-#include <stdbool.h>
-#include <sys/types.h>
-#include "../types.h"
-
-#define HE_COLORSET_TOP                50
-#define HE_COLORSET_MEDIUM     51
-#define HE_COLORSET_NORMAL     52
-#define HE_COLORSET_SELECTED   53
-#define HE_COLORSET_CODE       54
-
-struct ui_browser {
-       u64           index, top_idx;
-       void          *top, *entries;
-       u16           y, x, width, height;
-       void          *priv;
-       const char    *title;
-       char          *helpline;
-       unsigned int  (*refresh)(struct ui_browser *self);
-       void          (*write)(struct ui_browser *self, void *entry, int row);
-       void          (*seek)(struct ui_browser *self, off_t offset, int whence);
-       bool          (*filter)(struct ui_browser *self, void *entry);
-       u32           nr_entries;
-       bool          navkeypressed;
-       bool          use_navkeypressed;
-};
-
-void ui_browser__set_color(struct ui_browser *self, int color);
-void ui_browser__set_percent_color(struct ui_browser *self,
-                                  double percent, bool current);
-bool ui_browser__is_current_entry(struct ui_browser *self, unsigned row);
-void ui_browser__refresh_dimensions(struct ui_browser *self);
-void ui_browser__reset_index(struct ui_browser *self);
-
-void ui_browser__gotorc(struct ui_browser *self, int y, int x);
-void __ui_browser__show_title(struct ui_browser *browser, const char *title);
-void ui_browser__show_title(struct ui_browser *browser, const char *title);
-int ui_browser__show(struct ui_browser *self, const char *title,
-                    const char *helpline, ...);
-void ui_browser__hide(struct ui_browser *self);
-int ui_browser__refresh(struct ui_browser *self);
-int ui_browser__run(struct ui_browser *browser, int delay_secs);
-void ui_browser__update_nr_entries(struct ui_browser *browser, u32 nr_entries);
-void ui_browser__handle_resize(struct ui_browser *browser);
-
-int ui_browser__warning(struct ui_browser *browser, int timeout,
-                       const char *format, ...);
-int ui_browser__help_window(struct ui_browser *browser, const char *text);
-bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text);
-int ui_browser__input_window(const char *title, const char *text, char *input,
-                            const char *exit_msg, int delay_sec);
-
-void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence);
-unsigned int ui_browser__argv_refresh(struct ui_browser *browser);
-
-void ui_browser__rb_tree_seek(struct ui_browser *self, off_t offset, int whence);
-unsigned int ui_browser__rb_tree_refresh(struct ui_browser *self);
-
-void ui_browser__list_head_seek(struct ui_browser *self, off_t offset, int whence);
-unsigned int ui_browser__list_head_refresh(struct ui_browser *self);
-
-void ui_browser__init(void);
-#endif /* _PERF_UI_BROWSER_H_ */
diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c
deleted file mode 100644 (file)
index 57a4c6e..0000000
+++ /dev/null
@@ -1,433 +0,0 @@
-#include "../../util.h"
-#include "../browser.h"
-#include "../helpline.h"
-#include "../libslang.h"
-#include "../ui.h"
-#include "../util.h"
-#include "../../annotate.h"
-#include "../../hist.h"
-#include "../../sort.h"
-#include "../../symbol.h"
-#include <pthread.h>
-#include <newt.h>
-
-struct annotate_browser {
-       struct ui_browser b;
-       struct rb_root    entries;
-       struct rb_node    *curr_hot;
-       struct objdump_line *selection;
-       int                 nr_asm_entries;
-       int                 nr_entries;
-       bool                hide_src_code;
-};
-
-struct objdump_line_rb_node {
-       struct rb_node  rb_node;
-       double          percent;
-       u32             idx;
-       int             idx_asm;
-};
-
-static inline
-struct objdump_line_rb_node *objdump_line__rb(struct objdump_line *self)
-{
-       return (struct objdump_line_rb_node *)(self + 1);
-}
-
-static bool objdump_line__filter(struct ui_browser *browser, void *entry)
-{
-       struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
-
-       if (ab->hide_src_code) {
-               struct objdump_line *ol = list_entry(entry, struct objdump_line, node);
-               return ol->offset == -1;
-       }
-
-       return false;
-}
-
-static void annotate_browser__write(struct ui_browser *self, void *entry, int row)
-{
-       struct annotate_browser *ab = container_of(self, struct annotate_browser, b);
-       struct objdump_line *ol = list_entry(entry, struct objdump_line, node);
-       bool current_entry = ui_browser__is_current_entry(self, row);
-       int width = self->width;
-
-       if (ol->offset != -1) {
-               struct objdump_line_rb_node *olrb = objdump_line__rb(ol);
-               ui_browser__set_percent_color(self, olrb->percent, current_entry);
-               slsmg_printf(" %7.2f ", olrb->percent);
-       } else {
-               ui_browser__set_percent_color(self, 0, current_entry);
-               slsmg_write_nstring(" ", 9);
-       }
-
-       SLsmg_write_char(':');
-       slsmg_write_nstring(" ", 8);
-
-       /* The scroll bar isn't being used */
-       if (!self->navkeypressed)
-               width += 1;
-
-       if (!ab->hide_src_code && ol->offset != -1)
-               if (!current_entry || (self->use_navkeypressed &&
-                                      !self->navkeypressed))
-                       ui_browser__set_color(self, HE_COLORSET_CODE);
-
-       if (!*ol->line)
-               slsmg_write_nstring(" ", width - 18);
-       else
-               slsmg_write_nstring(ol->line, width - 18);
-
-       if (current_entry)
-               ab->selection = ol;
-}
-
-static double objdump_line__calc_percent(struct objdump_line *self,
-                                        struct symbol *sym, int evidx)
-{
-       double percent = 0.0;
-
-       if (self->offset != -1) {
-               int len = sym->end - sym->start;
-               unsigned int hits = 0;
-               struct annotation *notes = symbol__annotation(sym);
-               struct source_line *src_line = notes->src->lines;
-               struct sym_hist *h = annotation__histogram(notes, evidx);
-               s64 offset = self->offset;
-               struct objdump_line *next;
-
-               next = objdump__get_next_ip_line(&notes->src->source, self);
-               while (offset < (s64)len &&
-                      (next == NULL || offset < next->offset)) {
-                       if (src_line) {
-                               percent += src_line[offset].percent;
-                       } else
-                               hits += h->addr[offset];
-
-                       ++offset;
-               }
-               /*
-                * If the percentage wasn't already calculated in
-                * symbol__get_source_line, do it now:
-                */
-               if (src_line == NULL && h->sum)
-                       percent = 100.0 * hits / h->sum;
-       }
-
-       return percent;
-}
-
-static void objdump__insert_line(struct rb_root *self,
-                                struct objdump_line_rb_node *line)
-{
-       struct rb_node **p = &self->rb_node;
-       struct rb_node *parent = NULL;
-       struct objdump_line_rb_node *l;
-
-       while (*p != NULL) {
-               parent = *p;
-               l = rb_entry(parent, struct objdump_line_rb_node, rb_node);
-               if (line->percent < l->percent)
-                       p = &(*p)->rb_left;
-               else
-                       p = &(*p)->rb_right;
-       }
-       rb_link_node(&line->rb_node, parent, p);
-       rb_insert_color(&line->rb_node, self);
-}
-
-static void annotate_browser__set_top(struct annotate_browser *self,
-                                     struct rb_node *nd)
-{
-       struct objdump_line_rb_node *rbpos;
-       struct objdump_line *pos;
-       unsigned back;
-
-       ui_browser__refresh_dimensions(&self->b);
-       back = self->b.height / 2;
-       rbpos = rb_entry(nd, struct objdump_line_rb_node, rb_node);
-       pos = ((struct objdump_line *)rbpos) - 1;
-       self->b.top_idx = self->b.index = rbpos->idx;
-
-       while (self->b.top_idx != 0 && back != 0) {
-               pos = list_entry(pos->node.prev, struct objdump_line, node);
-
-               --self->b.top_idx;
-               --back;
-       }
-
-       self->b.top = pos;
-       self->curr_hot = nd;
-}
-
-static void annotate_browser__calc_percent(struct annotate_browser *browser,
-                                          int evidx)
-{
-       struct map_symbol *ms = browser->b.priv;
-       struct symbol *sym = ms->sym;
-       struct annotation *notes = symbol__annotation(sym);
-       struct objdump_line *pos;
-
-       browser->entries = RB_ROOT;
-
-       pthread_mutex_lock(&notes->lock);
-
-       list_for_each_entry(pos, &notes->src->source, node) {
-               struct objdump_line_rb_node *rbpos = objdump_line__rb(pos);
-               rbpos->percent = objdump_line__calc_percent(pos, sym, evidx);
-               if (rbpos->percent < 0.01) {
-                       RB_CLEAR_NODE(&rbpos->rb_node);
-                       continue;
-               }
-               objdump__insert_line(&browser->entries, rbpos);
-       }
-       pthread_mutex_unlock(&notes->lock);
-
-       browser->curr_hot = rb_last(&browser->entries);
-}
-
-static bool annotate_browser__toggle_source(struct annotate_browser *browser)
-{
-       struct objdump_line *ol;
-       struct objdump_line_rb_node *olrb;
-       off_t offset = browser->b.index - browser->b.top_idx;
-
-       browser->b.seek(&browser->b, offset, SEEK_CUR);
-       ol = list_entry(browser->b.top, struct objdump_line, node);
-       olrb = objdump_line__rb(ol);
-
-       if (browser->hide_src_code) {
-               if (olrb->idx_asm < offset)
-                       offset = olrb->idx;
-
-               browser->b.nr_entries = browser->nr_entries;
-               browser->hide_src_code = false;
-               browser->b.seek(&browser->b, -offset, SEEK_CUR);
-               browser->b.top_idx = olrb->idx - offset;
-               browser->b.index = olrb->idx;
-       } else {
-               if (olrb->idx_asm < 0) {
-                       ui_helpline__puts("Only available for assembly lines.");
-                       browser->b.seek(&browser->b, -offset, SEEK_CUR);
-                       return false;
-               }
-
-               if (olrb->idx_asm < offset)
-                       offset = olrb->idx_asm;
-
-               browser->b.nr_entries = browser->nr_asm_entries;
-               browser->hide_src_code = true;
-               browser->b.seek(&browser->b, -offset, SEEK_CUR);
-               browser->b.top_idx = olrb->idx_asm - offset;
-               browser->b.index = olrb->idx_asm;
-       }
-
-       return true;
-}
-
-static int annotate_browser__run(struct annotate_browser *self, int evidx,
-                                void(*timer)(void *arg),
-                                void *arg, int delay_secs)
-{
-       struct rb_node *nd = NULL;
-       struct map_symbol *ms = self->b.priv;
-       struct symbol *sym = ms->sym;
-       const char *help = "<-/ESC: Exit, TAB/shift+TAB: Cycle hot lines, "
-                          "H: Go to hottest line, ->/ENTER: Line action, "
-                          "S: Toggle source code view";
-       int key;
-
-       if (ui_browser__show(&self->b, sym->name, help) < 0)
-               return -1;
-
-       annotate_browser__calc_percent(self, evidx);
-
-       if (self->curr_hot)
-               annotate_browser__set_top(self, self->curr_hot);
-
-       nd = self->curr_hot;
-
-       while (1) {
-               key = ui_browser__run(&self->b, delay_secs);
-
-               if (delay_secs != 0) {
-                       annotate_browser__calc_percent(self, evidx);
-                       /*
-                        * Current line focus got out of the list of most active
-                        * lines, NULL it so that if TAB|UNTAB is pressed, we
-                        * move to curr_hot (current hottest line).
-                        */
-                       if (nd != NULL && RB_EMPTY_NODE(nd))
-                               nd = NULL;
-               }
-
-               switch (key) {
-               case K_TIMER:
-                       if (timer != NULL)
-                               timer(arg);
-
-                       if (delay_secs != 0)
-                               symbol__annotate_decay_histogram(sym, evidx);
-                       continue;
-               case K_TAB:
-                       if (nd != NULL) {
-                               nd = rb_prev(nd);
-                               if (nd == NULL)
-                                       nd = rb_last(&self->entries);
-                       } else
-                               nd = self->curr_hot;
-                       break;
-               case K_UNTAB:
-                       if (nd != NULL)
-                               nd = rb_next(nd);
-                               if (nd == NULL)
-                                       nd = rb_first(&self->entries);
-                       else
-                               nd = self->curr_hot;
-                       break;
-               case 'H':
-               case 'h':
-                       nd = self->curr_hot;
-                       break;
-               case 'S':
-               case 's':
-                       if (annotate_browser__toggle_source(self))
-                               ui_helpline__puts(help);
-                       continue;
-               case K_ENTER:
-               case K_RIGHT:
-                       if (self->selection == NULL) {
-                               ui_helpline__puts("Huh? No selection. Report to linux-kernel@vger.kernel.org");
-                               continue;
-                       }
-
-                       if (self->selection->offset == -1) {
-                               ui_helpline__puts("Actions are only available for assembly lines.");
-                               continue;
-                       } else {
-                               char *s = strstr(self->selection->line, "callq ");
-                               struct annotation *notes;
-                               struct symbol *target;
-                               u64 ip;
-
-                               if (s == NULL) {
-                                       ui_helpline__puts("Actions are only available for the 'callq' instruction.");
-                                       continue;
-                               }
-
-                               s = strchr(s, ' ');
-                               if (s++ == NULL) {
-                                       ui_helpline__puts("Invallid callq instruction.");
-                                       continue;
-                               }
-
-                               ip = strtoull(s, NULL, 16);
-                               ip = ms->map->map_ip(ms->map, ip);
-                               target = map__find_symbol(ms->map, ip, NULL);
-                               if (target == NULL) {
-                                       ui_helpline__puts("The called function was not found.");
-                                       continue;
-                               }
-
-                               notes = symbol__annotation(target);
-                               pthread_mutex_lock(&notes->lock);
-
-                               if (notes->src == NULL && symbol__alloc_hist(target) < 0) {
-                                       pthread_mutex_unlock(&notes->lock);
-                                       ui__warning("Not enough memory for annotating '%s' symbol!\n",
-                                                   target->name);
-                                       continue;
-                               }
-
-                               pthread_mutex_unlock(&notes->lock);
-                               symbol__tui_annotate(target, ms->map, evidx,
-                                                    timer, arg, delay_secs);
-                               ui_browser__show_title(&self->b, sym->name);
-                       }
-                       continue;
-               case K_LEFT:
-               case K_ESC:
-               case 'q':
-               case CTRL('c'):
-                       goto out;
-               default:
-                       continue;
-               }
-
-               if (nd != NULL)
-                       annotate_browser__set_top(self, nd);
-       }
-out:
-       ui_browser__hide(&self->b);
-       return key;
-}
-
-int hist_entry__tui_annotate(struct hist_entry *he, int evidx,
-                            void(*timer)(void *arg), void *arg, int delay_secs)
-{
-       return symbol__tui_annotate(he->ms.sym, he->ms.map, evidx,
-                                   timer, arg, delay_secs);
-}
-
-int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx,
-                        void(*timer)(void *arg), void *arg,
-                        int delay_secs)
-{
-       struct objdump_line *pos, *n;
-       struct annotation *notes;
-       struct map_symbol ms = {
-               .map = map,
-               .sym = sym,
-       };
-       struct annotate_browser browser = {
-               .b = {
-                       .refresh = ui_browser__list_head_refresh,
-                       .seek    = ui_browser__list_head_seek,
-                       .write   = annotate_browser__write,
-                       .filter  = objdump_line__filter,
-                       .priv    = &ms,
-                       .use_navkeypressed = true,
-               },
-       };
-       int ret;
-
-       if (sym == NULL)
-               return -1;
-
-       if (map->dso->annotate_warned)
-               return -1;
-
-       if (symbol__annotate(sym, map, sizeof(struct objdump_line_rb_node)) < 0) {
-               ui__error("%s", ui_helpline__last_msg);
-               return -1;
-       }
-
-       ui_helpline__push("Press <- or ESC to exit");
-
-       notes = symbol__annotation(sym);
-
-       list_for_each_entry(pos, &notes->src->source, node) {
-               struct objdump_line_rb_node *rbpos;
-               size_t line_len = strlen(pos->line);
-
-               if (browser.b.width < line_len)
-                       browser.b.width = line_len;
-               rbpos = objdump_line__rb(pos);
-               rbpos->idx = browser.nr_entries++;
-               if (pos->offset != -1)
-                       rbpos->idx_asm = browser.nr_asm_entries++;
-               else
-                       rbpos->idx_asm = -1;
-       }
-
-       browser.b.nr_entries = browser.nr_entries;
-       browser.b.entries = &notes->src->source,
-       browser.b.width += 18; /* Percentage */
-       ret = annotate_browser__run(&browser, evidx, timer, arg, delay_secs);
-       list_for_each_entry_safe(pos, n, &notes->src->source, node) {
-               list_del(&pos->node);
-               objdump_line__free(pos);
-       }
-       return ret;
-}
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c
deleted file mode 100644 (file)
index 2f83e5d..0000000
+++ /dev/null
@@ -1,1341 +0,0 @@
-#include <stdio.h>
-#include "../libslang.h"
-#include <stdlib.h>
-#include <string.h>
-#include <newt.h>
-#include <linux/rbtree.h>
-
-#include "../../evsel.h"
-#include "../../evlist.h"
-#include "../../hist.h"
-#include "../../pstack.h"
-#include "../../sort.h"
-#include "../../util.h"
-
-#include "../browser.h"
-#include "../helpline.h"
-#include "../util.h"
-#include "../ui.h"
-#include "map.h"
-
-struct hist_browser {
-       struct ui_browser   b;
-       struct hists        *hists;
-       struct hist_entry   *he_selection;
-       struct map_symbol   *selection;
-       bool                 has_symbols;
-};
-
-static int hists__browser_title(struct hists *self, char *bf, size_t size,
-                               const char *ev_name);
-
-static void hist_browser__refresh_dimensions(struct hist_browser *self)
-{
-       /* 3 == +/- toggle symbol before actual hist_entry rendering */
-       self->b.width = 3 + (hists__sort_list_width(self->hists) +
-                            sizeof("[k]"));
-}
-
-static void hist_browser__reset(struct hist_browser *self)
-{
-       self->b.nr_entries = self->hists->nr_entries;
-       hist_browser__refresh_dimensions(self);
-       ui_browser__reset_index(&self->b);
-}
-
-static char tree__folded_sign(bool unfolded)
-{
-       return unfolded ? '-' : '+';
-}
-
-static char map_symbol__folded(const struct map_symbol *self)
-{
-       return self->has_children ? tree__folded_sign(self->unfolded) : ' ';
-}
-
-static char hist_entry__folded(const struct hist_entry *self)
-{
-       return map_symbol__folded(&self->ms);
-}
-
-static char callchain_list__folded(const struct callchain_list *self)
-{
-       return map_symbol__folded(&self->ms);
-}
-
-static void map_symbol__set_folding(struct map_symbol *self, bool unfold)
-{
-       self->unfolded = unfold ? self->has_children : false;
-}
-
-static int callchain_node__count_rows_rb_tree(struct callchain_node *self)
-{
-       int n = 0;
-       struct rb_node *nd;
-
-       for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) {
-               struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
-               struct callchain_list *chain;
-               char folded_sign = ' '; /* No children */
-
-               list_for_each_entry(chain, &child->val, list) {
-                       ++n;
-                       /* We need this because we may not have children */
-                       folded_sign = callchain_list__folded(chain);
-                       if (folded_sign == '+')
-                               break;
-               }
-
-               if (folded_sign == '-') /* Have children and they're unfolded */
-                       n += callchain_node__count_rows_rb_tree(child);
-       }
-
-       return n;
-}
-
-static int callchain_node__count_rows(struct callchain_node *node)
-{
-       struct callchain_list *chain;
-       bool unfolded = false;
-       int n = 0;
-
-       list_for_each_entry(chain, &node->val, list) {
-               ++n;
-               unfolded = chain->ms.unfolded;
-       }
-
-       if (unfolded)
-               n += callchain_node__count_rows_rb_tree(node);
-
-       return n;
-}
-
-static int callchain__count_rows(struct rb_root *chain)
-{
-       struct rb_node *nd;
-       int n = 0;
-
-       for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
-               struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
-               n += callchain_node__count_rows(node);
-       }
-
-       return n;
-}
-
-static bool map_symbol__toggle_fold(struct map_symbol *self)
-{
-       if (!self)
-               return false;
-
-       if (!self->has_children)
-               return false;
-
-       self->unfolded = !self->unfolded;
-       return true;
-}
-
-static void callchain_node__init_have_children_rb_tree(struct callchain_node *self)
-{
-       struct rb_node *nd = rb_first(&self->rb_root);
-
-       for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) {
-               struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
-               struct callchain_list *chain;
-               bool first = true;
-
-               list_for_each_entry(chain, &child->val, list) {
-                       if (first) {
-                               first = false;
-                               chain->ms.has_children = chain->list.next != &child->val ||
-                                                        !RB_EMPTY_ROOT(&child->rb_root);
-                       } else
-                               chain->ms.has_children = chain->list.next == &child->val &&
-                                                        !RB_EMPTY_ROOT(&child->rb_root);
-               }
-
-               callchain_node__init_have_children_rb_tree(child);
-       }
-}
-
-static void callchain_node__init_have_children(struct callchain_node *self)
-{
-       struct callchain_list *chain;
-
-       list_for_each_entry(chain, &self->val, list)
-               chain->ms.has_children = !RB_EMPTY_ROOT(&self->rb_root);
-
-       callchain_node__init_have_children_rb_tree(self);
-}
-
-static void callchain__init_have_children(struct rb_root *self)
-{
-       struct rb_node *nd;
-
-       for (nd = rb_first(self); nd; nd = rb_next(nd)) {
-               struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
-               callchain_node__init_have_children(node);
-       }
-}
-
-static void hist_entry__init_have_children(struct hist_entry *self)
-{
-       if (!self->init_have_children) {
-               self->ms.has_children = !RB_EMPTY_ROOT(&self->sorted_chain);
-               callchain__init_have_children(&self->sorted_chain);
-               self->init_have_children = true;
-       }
-}
-
-static bool hist_browser__toggle_fold(struct hist_browser *self)
-{
-       if (map_symbol__toggle_fold(self->selection)) {
-               struct hist_entry *he = self->he_selection;
-
-               hist_entry__init_have_children(he);
-               self->hists->nr_entries -= he->nr_rows;
-
-               if (he->ms.unfolded)
-                       he->nr_rows = callchain__count_rows(&he->sorted_chain);
-               else
-                       he->nr_rows = 0;
-               self->hists->nr_entries += he->nr_rows;
-               self->b.nr_entries = self->hists->nr_entries;
-
-               return true;
-       }
-
-       /* If it doesn't have children, no toggling performed */
-       return false;
-}
-
-static int callchain_node__set_folding_rb_tree(struct callchain_node *self, bool unfold)
-{
-       int n = 0;
-       struct rb_node *nd;
-
-       for (nd = rb_first(&self->rb_root); nd; nd = rb_next(nd)) {
-               struct callchain_node *child = rb_entry(nd, struct callchain_node, rb_node);
-               struct callchain_list *chain;
-               bool has_children = false;
-
-               list_for_each_entry(chain, &child->val, list) {
-                       ++n;
-                       map_symbol__set_folding(&chain->ms, unfold);
-                       has_children = chain->ms.has_children;
-               }
-
-               if (has_children)
-                       n += callchain_node__set_folding_rb_tree(child, unfold);
-       }
-
-       return n;
-}
-
-static int callchain_node__set_folding(struct callchain_node *node, bool unfold)
-{
-       struct callchain_list *chain;
-       bool has_children = false;
-       int n = 0;
-
-       list_for_each_entry(chain, &node->val, list) {
-               ++n;
-               map_symbol__set_folding(&chain->ms, unfold);
-               has_children = chain->ms.has_children;
-       }
-
-       if (has_children)
-               n += callchain_node__set_folding_rb_tree(node, unfold);
-
-       return n;
-}
-
-static int callchain__set_folding(struct rb_root *chain, bool unfold)
-{
-       struct rb_node *nd;
-       int n = 0;
-
-       for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
-               struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
-               n += callchain_node__set_folding(node, unfold);
-       }
-
-       return n;
-}
-
-static void hist_entry__set_folding(struct hist_entry *self, bool unfold)
-{
-       hist_entry__init_have_children(self);
-       map_symbol__set_folding(&self->ms, unfold);
-
-       if (self->ms.has_children) {
-               int n = callchain__set_folding(&self->sorted_chain, unfold);
-               self->nr_rows = unfold ? n : 0;
-       } else
-               self->nr_rows = 0;
-}
-
-static void hists__set_folding(struct hists *self, bool unfold)
-{
-       struct rb_node *nd;
-
-       self->nr_entries = 0;
-
-       for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
-               struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
-               hist_entry__set_folding(he, unfold);
-               self->nr_entries += 1 + he->nr_rows;
-       }
-}
-
-static void hist_browser__set_folding(struct hist_browser *self, bool unfold)
-{
-       hists__set_folding(self->hists, unfold);
-       self->b.nr_entries = self->hists->nr_entries;
-       /* Go to the start, we may be way after valid entries after a collapse */
-       ui_browser__reset_index(&self->b);
-}
-
-static void ui_browser__warn_lost_events(struct ui_browser *browser)
-{
-       ui_browser__warning(browser, 4,
-               "Events are being lost, check IO/CPU overload!\n\n"
-               "You may want to run 'perf' using a RT scheduler policy:\n\n"
-               " perf top -r 80\n\n"
-               "Or reduce the sampling frequency.");
-}
-
-static int hist_browser__run(struct hist_browser *self, const char *ev_name,
-                            void(*timer)(void *arg), void *arg, int delay_secs)
-{
-       int key;
-       char title[160];
-
-       self->b.entries = &self->hists->entries;
-       self->b.nr_entries = self->hists->nr_entries;
-
-       hist_browser__refresh_dimensions(self);
-       hists__browser_title(self->hists, title, sizeof(title), ev_name);
-
-       if (ui_browser__show(&self->b, title,
-                            "Press '?' for help on key bindings") < 0)
-               return -1;
-
-       while (1) {
-               key = ui_browser__run(&self->b, delay_secs);
-
-               switch (key) {
-               case K_TIMER:
-                       timer(arg);
-                       ui_browser__update_nr_entries(&self->b, self->hists->nr_entries);
-
-                       if (self->hists->stats.nr_lost_warned !=
-                           self->hists->stats.nr_events[PERF_RECORD_LOST]) {
-                               self->hists->stats.nr_lost_warned =
-                                       self->hists->stats.nr_events[PERF_RECORD_LOST];
-                               ui_browser__warn_lost_events(&self->b);
-                       }
-
-                       hists__browser_title(self->hists, title, sizeof(title), ev_name);
-                       ui_browser__show_title(&self->b, title);
-                       continue;
-               case 'D': { /* Debug */
-                       static int seq;
-                       struct hist_entry *h = rb_entry(self->b.top,
-                                                       struct hist_entry, rb_node);
-                       ui_helpline__pop();
-                       ui_helpline__fpush("%d: nr_ent=(%d,%d), height=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d",
-                                          seq++, self->b.nr_entries,
-                                          self->hists->nr_entries,
-                                          self->b.height,
-                                          self->b.index,
-                                          self->b.top_idx,
-                                          h->row_offset, h->nr_rows);
-               }
-                       break;
-               case 'C':
-                       /* Collapse the whole world. */
-                       hist_browser__set_folding(self, false);
-                       break;
-               case 'E':
-                       /* Expand the whole world. */
-                       hist_browser__set_folding(self, true);
-                       break;
-               case K_ENTER:
-                       if (hist_browser__toggle_fold(self))
-                               break;
-                       /* fall thru */
-               default:
-                       goto out;
-               }
-       }
-out:
-       ui_browser__hide(&self->b);
-       return key;
-}
-
-static char *callchain_list__sym_name(struct callchain_list *self,
-                                     char *bf, size_t bfsize)
-{
-       if (self->ms.sym)
-               return self->ms.sym->name;
-
-       snprintf(bf, bfsize, "%#" PRIx64, self->ip);
-       return bf;
-}
-
-#define LEVEL_OFFSET_STEP 3
-
-static int hist_browser__show_callchain_node_rb_tree(struct hist_browser *self,
-                                                    struct callchain_node *chain_node,
-                                                    u64 total, int level,
-                                                    unsigned short row,
-                                                    off_t *row_offset,
-                                                    bool *is_current_entry)
-{
-       struct rb_node *node;
-       int first_row = row, width, offset = level * LEVEL_OFFSET_STEP;
-       u64 new_total, remaining;
-
-       if (callchain_param.mode == CHAIN_GRAPH_REL)
-               new_total = chain_node->children_hit;
-       else
-               new_total = total;
-
-       remaining = new_total;
-       node = rb_first(&chain_node->rb_root);
-       while (node) {
-               struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
-               struct rb_node *next = rb_next(node);
-               u64 cumul = callchain_cumul_hits(child);
-               struct callchain_list *chain;
-               char folded_sign = ' ';
-               int first = true;
-               int extra_offset = 0;
-
-               remaining -= cumul;
-
-               list_for_each_entry(chain, &child->val, list) {
-                       char ipstr[BITS_PER_LONG / 4 + 1], *alloc_str;
-                       const char *str;
-                       int color;
-                       bool was_first = first;
-
-                       if (first)
-                               first = false;
-                       else
-                               extra_offset = LEVEL_OFFSET_STEP;
-
-                       folded_sign = callchain_list__folded(chain);
-                       if (*row_offset != 0) {
-                               --*row_offset;
-                               goto do_next;
-                       }
-
-                       alloc_str = NULL;
-                       str = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
-                       if (was_first) {
-                               double percent = cumul * 100.0 / new_total;
-
-                               if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
-                                       str = "Not enough memory!";
-                               else
-                                       str = alloc_str;
-                       }
-
-                       color = HE_COLORSET_NORMAL;
-                       width = self->b.width - (offset + extra_offset + 2);
-                       if (ui_browser__is_current_entry(&self->b, row)) {
-                               self->selection = &chain->ms;
-                               color = HE_COLORSET_SELECTED;
-                               *is_current_entry = true;
-                       }
-
-                       ui_browser__set_color(&self->b, color);
-                       ui_browser__gotorc(&self->b, row, 0);
-                       slsmg_write_nstring(" ", offset + extra_offset);
-                       slsmg_printf("%c ", folded_sign);
-                       slsmg_write_nstring(str, width);
-                       free(alloc_str);
-
-                       if (++row == self->b.height)
-                               goto out;
-do_next:
-                       if (folded_sign == '+')
-                               break;
-               }
-
-               if (folded_sign == '-') {
-                       const int new_level = level + (extra_offset ? 2 : 1);
-                       row += hist_browser__show_callchain_node_rb_tree(self, child, new_total,
-                                                                        new_level, row, row_offset,
-                                                                        is_current_entry);
-               }
-               if (row == self->b.height)
-                       goto out;
-               node = next;
-       }
-out:
-       return row - first_row;
-}
-
-static int hist_browser__show_callchain_node(struct hist_browser *self,
-                                            struct callchain_node *node,
-                                            int level, unsigned short row,
-                                            off_t *row_offset,
-                                            bool *is_current_entry)
-{
-       struct callchain_list *chain;
-       int first_row = row,
-            offset = level * LEVEL_OFFSET_STEP,
-            width = self->b.width - offset;
-       char folded_sign = ' ';
-
-       list_for_each_entry(chain, &node->val, list) {
-               char ipstr[BITS_PER_LONG / 4 + 1], *s;
-               int color;
-
-               folded_sign = callchain_list__folded(chain);
-
-               if (*row_offset != 0) {
-                       --*row_offset;
-                       continue;
-               }
-
-               color = HE_COLORSET_NORMAL;
-               if (ui_browser__is_current_entry(&self->b, row)) {
-                       self->selection = &chain->ms;
-                       color = HE_COLORSET_SELECTED;
-                       *is_current_entry = true;
-               }
-
-               s = callchain_list__sym_name(chain, ipstr, sizeof(ipstr));
-               ui_browser__gotorc(&self->b, row, 0);
-               ui_browser__set_color(&self->b, color);
-               slsmg_write_nstring(" ", offset);
-               slsmg_printf("%c ", folded_sign);
-               slsmg_write_nstring(s, width - 2);
-
-               if (++row == self->b.height)
-                       goto out;
-       }
-
-       if (folded_sign == '-')
-               row += hist_browser__show_callchain_node_rb_tree(self, node,
-                                                                self->hists->stats.total_period,
-                                                                level + 1, row,
-                                                                row_offset,
-                                                                is_current_entry);
-out:
-       return row - first_row;
-}
-
-static int hist_browser__show_callchain(struct hist_browser *self,
-                                       struct rb_root *chain,
-                                       int level, unsigned short row,
-                                       off_t *row_offset,
-                                       bool *is_current_entry)
-{
-       struct rb_node *nd;
-       int first_row = row;
-
-       for (nd = rb_first(chain); nd; nd = rb_next(nd)) {
-               struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
-
-               row += hist_browser__show_callchain_node(self, node, level,
-                                                        row, row_offset,
-                                                        is_current_entry);
-               if (row == self->b.height)
-                       break;
-       }
-
-       return row - first_row;
-}
-
-static int hist_browser__show_entry(struct hist_browser *self,
-                                   struct hist_entry *entry,
-                                   unsigned short row)
-{
-       char s[256];
-       double percent;
-       int printed = 0;
-       int width = self->b.width - 6; /* The percentage */
-       char folded_sign = ' ';
-       bool current_entry = ui_browser__is_current_entry(&self->b, row);
-       off_t row_offset = entry->row_offset;
-
-       if (current_entry) {
-               self->he_selection = entry;
-               self->selection = &entry->ms;
-       }
-
-       if (symbol_conf.use_callchain) {
-               hist_entry__init_have_children(entry);
-               folded_sign = hist_entry__folded(entry);
-       }
-
-       if (row_offset == 0) {
-               hist_entry__snprintf(entry, s, sizeof(s), self->hists);
-               percent = (entry->period * 100.0) / self->hists->stats.total_period;
-
-               ui_browser__set_percent_color(&self->b, percent, current_entry);
-               ui_browser__gotorc(&self->b, row, 0);
-               if (symbol_conf.use_callchain) {
-                       slsmg_printf("%c ", folded_sign);
-                       width -= 2;
-               }
-
-               slsmg_printf(" %5.2f%%", percent);
-
-               /* The scroll bar isn't being used */
-               if (!self->b.navkeypressed)
-                       width += 1;
-
-               if (!current_entry || !self->b.navkeypressed)
-                       ui_browser__set_color(&self->b, HE_COLORSET_NORMAL);
-
-               if (symbol_conf.show_nr_samples) {
-                       slsmg_printf(" %11u", entry->nr_events);
-                       width -= 12;
-               }
-
-               if (symbol_conf.show_total_period) {
-                       slsmg_printf(" %12" PRIu64, entry->period);
-                       width -= 13;
-               }
-
-               slsmg_write_nstring(s, width);
-               ++row;
-               ++printed;
-       } else
-               --row_offset;
-
-       if (folded_sign == '-' && row != self->b.height) {
-               printed += hist_browser__show_callchain(self, &entry->sorted_chain,
-                                                       1, row, &row_offset,
-                                                       &current_entry);
-               if (current_entry)
-                       self->he_selection = entry;
-       }
-
-       return printed;
-}
-
-static void ui_browser__hists_init_top(struct ui_browser *browser)
-{
-       if (browser->top == NULL) {
-               struct hist_browser *hb;
-
-               hb = container_of(browser, struct hist_browser, b);
-               browser->top = rb_first(&hb->hists->entries);
-       }
-}
-
-static unsigned int hist_browser__refresh(struct ui_browser *self)
-{
-       unsigned row = 0;
-       struct rb_node *nd;
-       struct hist_browser *hb = container_of(self, struct hist_browser, b);
-
-       ui_browser__hists_init_top(self);
-
-       for (nd = self->top; nd; nd = rb_next(nd)) {
-               struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
-
-               if (h->filtered)
-                       continue;
-
-               row += hist_browser__show_entry(hb, h, row);
-               if (row == self->height)
-                       break;
-       }
-
-       return row;
-}
-
-static struct rb_node *hists__filter_entries(struct rb_node *nd)
-{
-       while (nd != NULL) {
-               struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
-               if (!h->filtered)
-                       return nd;
-
-               nd = rb_next(nd);
-       }
-
-       return NULL;
-}
-
-static struct rb_node *hists__filter_prev_entries(struct rb_node *nd)
-{
-       while (nd != NULL) {
-               struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
-               if (!h->filtered)
-                       return nd;
-
-               nd = rb_prev(nd);
-       }
-
-       return NULL;
-}
-
-static void ui_browser__hists_seek(struct ui_browser *self,
-                                  off_t offset, int whence)
-{
-       struct hist_entry *h;
-       struct rb_node *nd;
-       bool first = true;
-
-       if (self->nr_entries == 0)
-               return;
-
-       ui_browser__hists_init_top(self);
-
-       switch (whence) {
-       case SEEK_SET:
-               nd = hists__filter_entries(rb_first(self->entries));
-               break;
-       case SEEK_CUR:
-               nd = self->top;
-               goto do_offset;
-       case SEEK_END:
-               nd = hists__filter_prev_entries(rb_last(self->entries));
-               first = false;
-               break;
-       default:
-               return;
-       }
-
-       /*
-        * Moves not relative to the first visible entry invalidates its
-        * row_offset:
-        */
-       h = rb_entry(self->top, struct hist_entry, rb_node);
-       h->row_offset = 0;
-
-       /*
-        * Here we have to check if nd is expanded (+), if it is we can't go
-        * the next top level hist_entry, instead we must compute an offset of
-        * what _not_ to show and not change the first visible entry.
-        *
-        * This offset increments when we are going from top to bottom and
-        * decreases when we're going from bottom to top.
-        *
-        * As we don't have backpointers to the top level in the callchains
-        * structure, we need to always print the whole hist_entry callchain,
-        * skipping the first ones that are before the first visible entry
-        * and stop when we printed enough lines to fill the screen.
-        */
-do_offset:
-       if (offset > 0) {
-               do {
-                       h = rb_entry(nd, struct hist_entry, rb_node);
-                       if (h->ms.unfolded) {
-                               u16 remaining = h->nr_rows - h->row_offset;
-                               if (offset > remaining) {
-                                       offset -= remaining;
-                                       h->row_offset = 0;
-                               } else {
-                                       h->row_offset += offset;
-                                       offset = 0;
-                                       self->top = nd;
-                                       break;
-                               }
-                       }
-                       nd = hists__filter_entries(rb_next(nd));
-                       if (nd == NULL)
-                               break;
-                       --offset;
-                       self->top = nd;
-               } while (offset != 0);
-       } else if (offset < 0) {
-               while (1) {
-                       h = rb_entry(nd, struct hist_entry, rb_node);
-                       if (h->ms.unfolded) {
-                               if (first) {
-                                       if (-offset > h->row_offset) {
-                                               offset += h->row_offset;
-                                               h->row_offset = 0;
-                                       } else {
-                                               h->row_offset += offset;
-                                               offset = 0;
-                                               self->top = nd;
-                                               break;
-                                       }
-                               } else {
-                                       if (-offset > h->nr_rows) {
-                                               offset += h->nr_rows;
-                                               h->row_offset = 0;
-                                       } else {
-                                               h->row_offset = h->nr_rows + offset;
-                                               offset = 0;
-                                               self->top = nd;
-                                               break;
-                                       }
-                               }
-                       }
-
-                       nd = hists__filter_prev_entries(rb_prev(nd));
-                       if (nd == NULL)
-                               break;
-                       ++offset;
-                       self->top = nd;
-                       if (offset == 0) {
-                               /*
-                                * Last unfiltered hist_entry, check if it is
-                                * unfolded, if it is then we should have
-                                * row_offset at its last entry.
-                                */
-                               h = rb_entry(nd, struct hist_entry, rb_node);
-                               if (h->ms.unfolded)
-                                       h->row_offset = h->nr_rows;
-                               break;
-                       }
-                       first = false;
-               }
-       } else {
-               self->top = nd;
-               h = rb_entry(nd, struct hist_entry, rb_node);
-               h->row_offset = 0;
-       }
-}
-
-static struct hist_browser *hist_browser__new(struct hists *hists)
-{
-       struct hist_browser *self = zalloc(sizeof(*self));
-
-       if (self) {
-               self->hists = hists;
-               self->b.refresh = hist_browser__refresh;
-               self->b.seek = ui_browser__hists_seek;
-               self->b.use_navkeypressed = true;
-               if (sort__branch_mode == 1)
-                       self->has_symbols = sort_sym_from.list.next != NULL;
-               else
-                       self->has_symbols = sort_sym.list.next != NULL;
-       }
-
-       return self;
-}
-
-static void hist_browser__delete(struct hist_browser *self)
-{
-       free(self);
-}
-
-static struct hist_entry *hist_browser__selected_entry(struct hist_browser *self)
-{
-       return self->he_selection;
-}
-
-static struct thread *hist_browser__selected_thread(struct hist_browser *self)
-{
-       return self->he_selection->thread;
-}
-
-static int hists__browser_title(struct hists *self, char *bf, size_t size,
-                               const char *ev_name)
-{
-       char unit;
-       int printed;
-       const struct dso *dso = self->dso_filter;
-       const struct thread *thread = self->thread_filter;
-       unsigned long nr_events = self->stats.nr_events[PERF_RECORD_SAMPLE];
-
-       nr_events = convert_unit(nr_events, &unit);
-       printed = scnprintf(bf, size, "Events: %lu%c %s", nr_events, unit, ev_name);
-
-       if (self->uid_filter_str)
-               printed += snprintf(bf + printed, size - printed,
-                                   ", UID: %s", self->uid_filter_str);
-       if (thread)
-               printed += scnprintf(bf + printed, size - printed,
-                                   ", Thread: %s(%d)",
-                                   (thread->comm_set ? thread->comm : ""),
-                                   thread->pid);
-       if (dso)
-               printed += scnprintf(bf + printed, size - printed,
-                                   ", DSO: %s", dso->short_name);
-       return printed;
-}
-
-static inline void free_popup_options(char **options, int n)
-{
-       int i;
-
-       for (i = 0; i < n; ++i) {
-               free(options[i]);
-               options[i] = NULL;
-       }
-}
-
-static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
-                                   const char *helpline, const char *ev_name,
-                                   bool left_exits,
-                                   void(*timer)(void *arg), void *arg,
-                                   int delay_secs)
-{
-       struct hists *self = &evsel->hists;
-       struct hist_browser *browser = hist_browser__new(self);
-       struct branch_info *bi;
-       struct pstack *fstack;
-       char *options[16];
-       int nr_options = 0;
-       int key = -1;
-       char buf[64];
-
-       if (browser == NULL)
-               return -1;
-
-       fstack = pstack__new(2);
-       if (fstack == NULL)
-               goto out;
-
-       ui_helpline__push(helpline);
-
-       memset(options, 0, sizeof(options));
-
-       while (1) {
-               const struct thread *thread = NULL;
-               const struct dso *dso = NULL;
-               int choice = 0,
-                   annotate = -2, zoom_dso = -2, zoom_thread = -2,
-                   annotate_f = -2, annotate_t = -2, browse_map = -2;
-
-               nr_options = 0;
-
-               key = hist_browser__run(browser, ev_name, timer, arg, delay_secs);
-
-               if (browser->he_selection != NULL) {
-                       thread = hist_browser__selected_thread(browser);
-                       dso = browser->selection->map ? browser->selection->map->dso : NULL;
-               }
-               switch (key) {
-               case K_TAB:
-               case K_UNTAB:
-                       if (nr_events == 1)
-                               continue;
-                       /*
-                        * Exit the browser, let hists__browser_tree
-                        * go to the next or previous
-                        */
-                       goto out_free_stack;
-               case 'a':
-                       if (!browser->has_symbols) {
-                               ui_browser__warning(&browser->b, delay_secs * 2,
-                       "Annotation is only available for symbolic views, "
-                       "include \"sym*\" in --sort to use it.");
-                               continue;
-                       }
-
-                       if (browser->selection == NULL ||
-                           browser->selection->sym == NULL ||
-                           browser->selection->map->dso->annotate_warned)
-                               continue;
-                       goto do_annotate;
-               case 'd':
-                       goto zoom_dso;
-               case 't':
-                       goto zoom_thread;
-               case 's':
-                       if (ui_browser__input_window("Symbol to show",
-                                       "Please enter the name of symbol you want to see",
-                                       buf, "ENTER: OK, ESC: Cancel",
-                                       delay_secs * 2) == K_ENTER) {
-                               self->symbol_filter_str = *buf ? buf : NULL;
-                               hists__filter_by_symbol(self);
-                               hist_browser__reset(browser);
-                       }
-                       continue;
-               case K_F1:
-               case 'h':
-               case '?':
-                       ui_browser__help_window(&browser->b,
-                                       "h/?/F1        Show this window\n"
-                                       "UP/DOWN/PGUP\n"
-                                       "PGDN/SPACE    Navigate\n"
-                                       "q/ESC/CTRL+C  Exit browser\n\n"
-                                       "For multiple event sessions:\n\n"
-                                       "TAB/UNTAB Switch events\n\n"
-                                       "For symbolic views (--sort has sym):\n\n"
-                                       "->            Zoom into DSO/Threads & Annotate current symbol\n"
-                                       "<-            Zoom out\n"
-                                       "a             Annotate current symbol\n"
-                                       "C             Collapse all callchains\n"
-                                       "E             Expand all callchains\n"
-                                       "d             Zoom into current DSO\n"
-                                       "t             Zoom into current Thread\n"
-                                       "s             Filter symbol by name");
-                       continue;
-               case K_ENTER:
-               case K_RIGHT:
-                       /* menu */
-                       break;
-               case K_LEFT: {
-                       const void *top;
-
-                       if (pstack__empty(fstack)) {
-                               /*
-                                * Go back to the perf_evsel_menu__run or other user
-                                */
-                               if (left_exits)
-                                       goto out_free_stack;
-                               continue;
-                       }
-                       top = pstack__pop(fstack);
-                       if (top == &browser->hists->dso_filter)
-                               goto zoom_out_dso;
-                       if (top == &browser->hists->thread_filter)
-                               goto zoom_out_thread;
-                       continue;
-               }
-               case K_ESC:
-                       if (!left_exits &&
-                           !ui_browser__dialog_yesno(&browser->b,
-                                              "Do you really want to exit?"))
-                               continue;
-                       /* Fall thru */
-               case 'q':
-               case CTRL('c'):
-                       goto out_free_stack;
-               default:
-                       continue;
-               }
-
-               if (!browser->has_symbols)
-                       goto add_exit_option;
-
-               if (sort__branch_mode == 1) {
-                       bi = browser->he_selection->branch_info;
-                       if (browser->selection != NULL &&
-                           bi &&
-                           bi->from.sym != NULL &&
-                           !bi->from.map->dso->annotate_warned &&
-                               asprintf(&options[nr_options], "Annotate %s",
-                                        bi->from.sym->name) > 0)
-                               annotate_f = nr_options++;
-
-                       if (browser->selection != NULL &&
-                           bi &&
-                           bi->to.sym != NULL &&
-                           !bi->to.map->dso->annotate_warned &&
-                           (bi->to.sym != bi->from.sym ||
-                            bi->to.map->dso != bi->from.map->dso) &&
-                               asprintf(&options[nr_options], "Annotate %s",
-                                        bi->to.sym->name) > 0)
-                               annotate_t = nr_options++;
-               } else {
-
-                       if (browser->selection != NULL &&
-                           browser->selection->sym != NULL &&
-                           !browser->selection->map->dso->annotate_warned &&
-                               asprintf(&options[nr_options], "Annotate %s",
-                                        browser->selection->sym->name) > 0)
-                               annotate = nr_options++;
-               }
-
-               if (thread != NULL &&
-                   asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
-                            (browser->hists->thread_filter ? "out of" : "into"),
-                            (thread->comm_set ? thread->comm : ""),
-                            thread->pid) > 0)
-                       zoom_thread = nr_options++;
-
-               if (dso != NULL &&
-                   asprintf(&options[nr_options], "Zoom %s %s DSO",
-                            (browser->hists->dso_filter ? "out of" : "into"),
-                            (dso->kernel ? "the Kernel" : dso->short_name)) > 0)
-                       zoom_dso = nr_options++;
-
-               if (browser->selection != NULL &&
-                   browser->selection->map != NULL &&
-                   asprintf(&options[nr_options], "Browse map details") > 0)
-                       browse_map = nr_options++;
-add_exit_option:
-               options[nr_options++] = (char *)"Exit";
-retry_popup_menu:
-               choice = ui__popup_menu(nr_options, options);
-
-               if (choice == nr_options - 1)
-                       break;
-
-               if (choice == -1) {
-                       free_popup_options(options, nr_options - 1);
-                       continue;
-               }
-
-               if (choice == annotate || choice == annotate_t || choice == annotate_f) {
-                       struct hist_entry *he;
-                       int err;
-do_annotate:
-                       he = hist_browser__selected_entry(browser);
-                       if (he == NULL)
-                               continue;
-
-                       /*
-                        * we stash the branch_info symbol + map into the
-                        * the ms so we don't have to rewrite all the annotation
-                        * code to use branch_info.
-                        * in branch mode, the ms struct is not used
-                        */
-                       if (choice == annotate_f) {
-                               he->ms.sym = he->branch_info->from.sym;
-                               he->ms.map = he->branch_info->from.map;
-                       }  else if (choice == annotate_t) {
-                               he->ms.sym = he->branch_info->to.sym;
-                               he->ms.map = he->branch_info->to.map;
-                       }
-
-                       /*
-                        * Don't let this be freed, say, by hists__decay_entry.
-                        */
-                       he->used = true;
-                       err = hist_entry__tui_annotate(he, evsel->idx,
-                                                      timer, arg, delay_secs);
-                       he->used = false;
-                       /*
-                        * offer option to annotate the other branch source or target
-                        * (if they exists) when returning from annotate
-                        */
-                       if ((err == 'q' || err == CTRL('c'))
-                           && annotate_t != -2 && annotate_f != -2)
-                               goto retry_popup_menu;
-
-                       ui_browser__update_nr_entries(&browser->b, browser->hists->nr_entries);
-                       if (err)
-                               ui_browser__handle_resize(&browser->b);
-
-               } else if (choice == browse_map)
-                       map__browse(browser->selection->map);
-               else if (choice == zoom_dso) {
-zoom_dso:
-                       if (browser->hists->dso_filter) {
-                               pstack__remove(fstack, &browser->hists->dso_filter);
-zoom_out_dso:
-                               ui_helpline__pop();
-                               browser->hists->dso_filter = NULL;
-                               sort_dso.elide = false;
-                       } else {
-                               if (dso == NULL)
-                                       continue;
-                               ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"",
-                                                  dso->kernel ? "the Kernel" : dso->short_name);
-                               browser->hists->dso_filter = dso;
-                               sort_dso.elide = true;
-                               pstack__push(fstack, &browser->hists->dso_filter);
-                       }
-                       hists__filter_by_dso(self);
-                       hist_browser__reset(browser);
-               } else if (choice == zoom_thread) {
-zoom_thread:
-                       if (browser->hists->thread_filter) {
-                               pstack__remove(fstack, &browser->hists->thread_filter);
-zoom_out_thread:
-                               ui_helpline__pop();
-                               browser->hists->thread_filter = NULL;
-                               sort_thread.elide = false;
-                       } else {
-                               ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
-                                                  thread->comm_set ? thread->comm : "",
-                                                  thread->pid);
-                               browser->hists->thread_filter = thread;
-                               sort_thread.elide = true;
-                               pstack__push(fstack, &browser->hists->thread_filter);
-                       }
-                       hists__filter_by_thread(self);
-                       hist_browser__reset(browser);
-               }
-       }
-out_free_stack:
-       pstack__delete(fstack);
-out:
-       hist_browser__delete(browser);
-       free_popup_options(options, nr_options - 1);
-       return key;
-}
-
-struct perf_evsel_menu {
-       struct ui_browser b;
-       struct perf_evsel *selection;
-       bool lost_events, lost_events_warned;
-};
-
-static void perf_evsel_menu__write(struct ui_browser *browser,
-                                  void *entry, int row)
-{
-       struct perf_evsel_menu *menu = container_of(browser,
-                                                   struct perf_evsel_menu, b);
-       struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node);
-       bool current_entry = ui_browser__is_current_entry(browser, row);
-       unsigned long nr_events = evsel->hists.stats.nr_events[PERF_RECORD_SAMPLE];
-       const char *ev_name = event_name(evsel);
-       char bf[256], unit;
-       const char *warn = " ";
-       size_t printed;
-
-       ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
-                                                      HE_COLORSET_NORMAL);
-
-       nr_events = convert_unit(nr_events, &unit);
-       printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events,
-                          unit, unit == ' ' ? "" : " ", ev_name);
-       slsmg_printf("%s", bf);
-
-       nr_events = evsel->hists.stats.nr_events[PERF_RECORD_LOST];
-       if (nr_events != 0) {
-               menu->lost_events = true;
-               if (!current_entry)
-                       ui_browser__set_color(browser, HE_COLORSET_TOP);
-               nr_events = convert_unit(nr_events, &unit);
-               printed += scnprintf(bf, sizeof(bf), ": %ld%c%schunks LOST!",
-                                    nr_events, unit, unit == ' ' ? "" : " ");
-               warn = bf;
-       }
-
-       slsmg_write_nstring(warn, browser->width - printed);
-
-       if (current_entry)
-               menu->selection = evsel;
-}
-
-static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
-                               int nr_events, const char *help,
-                               void(*timer)(void *arg), void *arg, int delay_secs)
-{
-       struct perf_evlist *evlist = menu->b.priv;
-       struct perf_evsel *pos;
-       const char *ev_name, *title = "Available samples";
-       int key;
-
-       if (ui_browser__show(&menu->b, title,
-                            "ESC: exit, ENTER|->: Browse histograms") < 0)
-               return -1;
-
-       while (1) {
-               key = ui_browser__run(&menu->b, delay_secs);
-
-               switch (key) {
-               case K_TIMER:
-                       timer(arg);
-
-                       if (!menu->lost_events_warned && menu->lost_events) {
-                               ui_browser__warn_lost_events(&menu->b);
-                               menu->lost_events_warned = true;
-                       }
-                       continue;
-               case K_RIGHT:
-               case K_ENTER:
-                       if (!menu->selection)
-                               continue;
-                       pos = menu->selection;
-browse_hists:
-                       perf_evlist__set_selected(evlist, pos);
-                       /*
-                        * Give the calling tool a chance to populate the non
-                        * default evsel resorted hists tree.
-                        */
-                       if (timer)
-                               timer(arg);
-                       ev_name = event_name(pos);
-                       key = perf_evsel__hists_browse(pos, nr_events, help,
-                                                      ev_name, true, timer,
-                                                      arg, delay_secs);
-                       ui_browser__show_title(&menu->b, title);
-                       switch (key) {
-                       case K_TAB:
-                               if (pos->node.next == &evlist->entries)
-                                       pos = list_entry(evlist->entries.next, struct perf_evsel, node);
-                               else
-                                       pos = list_entry(pos->node.next, struct perf_evsel, node);
-                               goto browse_hists;
-                       case K_UNTAB:
-                               if (pos->node.prev == &evlist->entries)
-                                       pos = list_entry(evlist->entries.prev, struct perf_evsel, node);
-                               else
-                                       pos = list_entry(pos->node.prev, struct perf_evsel, node);
-                               goto browse_hists;
-                       case K_ESC:
-                               if (!ui_browser__dialog_yesno(&menu->b,
-                                               "Do you really want to exit?"))
-                                       continue;
-                               /* Fall thru */
-                       case 'q':
-                       case CTRL('c'):
-                               goto out;
-                       default:
-                               continue;
-                       }
-               case K_LEFT:
-                       continue;
-               case K_ESC:
-                       if (!ui_browser__dialog_yesno(&menu->b,
-                                              "Do you really want to exit?"))
-                               continue;
-                       /* Fall thru */
-               case 'q':
-               case CTRL('c'):
-                       goto out;
-               default:
-                       continue;
-               }
-       }
-
-out:
-       ui_browser__hide(&menu->b);
-       return key;
-}
-
-static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
-                                          const char *help,
-                                          void(*timer)(void *arg), void *arg,
-                                          int delay_secs)
-{
-       struct perf_evsel *pos;
-       struct perf_evsel_menu menu = {
-               .b = {
-                       .entries    = &evlist->entries,
-                       .refresh    = ui_browser__list_head_refresh,
-                       .seek       = ui_browser__list_head_seek,
-                       .write      = perf_evsel_menu__write,
-                       .nr_entries = evlist->nr_entries,
-                       .priv       = evlist,
-               },
-       };
-
-       ui_helpline__push("Press ESC to exit");
-
-       list_for_each_entry(pos, &evlist->entries, node) {
-               const char *ev_name = event_name(pos);
-               size_t line_len = strlen(ev_name) + 7;
-
-               if (menu.b.width < line_len)
-                       menu.b.width = line_len;
-               /*
-                * Cache the evsel name, tracepoints have a _high_ cost per
-                * event_name() call.
-                */
-               if (pos->name == NULL)
-                       pos->name = strdup(ev_name);
-       }
-
-       return perf_evsel_menu__run(&menu, evlist->nr_entries, help, timer,
-                                   arg, delay_secs);
-}
-
-int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
-                                 void(*timer)(void *arg), void *arg,
-                                 int delay_secs)
-{
-
-       if (evlist->nr_entries == 1) {
-               struct perf_evsel *first = list_entry(evlist->entries.next,
-                                                     struct perf_evsel, node);
-               const char *ev_name = event_name(first);
-               return perf_evsel__hists_browse(first, evlist->nr_entries, help,
-                                               ev_name, false, timer, arg,
-                                               delay_secs);
-       }
-
-       return __perf_evlist__tui_browse_hists(evlist, help,
-                                              timer, arg, delay_secs);
-}
diff --git a/tools/perf/util/ui/browsers/map.c b/tools/perf/util/ui/browsers/map.c
deleted file mode 100644 (file)
index eca6575..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-#include "../libslang.h"
-#include <elf.h>
-#include <newt.h>
-#include <inttypes.h>
-#include <sys/ttydefaults.h>
-#include <string.h>
-#include <linux/bitops.h>
-#include "../../util.h"
-#include "../../debug.h"
-#include "../../symbol.h"
-#include "../browser.h"
-#include "../helpline.h"
-#include "map.h"
-
-static int ui_entry__read(const char *title, char *bf, size_t size, int width)
-{
-       struct newtExitStruct es;
-       newtComponent form, entry;
-       const char *result;
-       int err = -1;
-
-       newtCenteredWindow(width, 1, title);
-       form = newtForm(NULL, NULL, 0);
-       if (form == NULL)
-               return -1;
-
-       entry = newtEntry(0, 0, "0x", width, &result, NEWT_FLAG_SCROLL);
-       if (entry == NULL)
-               goto out_free_form;
-
-       newtFormAddComponent(form, entry);
-       newtFormAddHotKey(form, NEWT_KEY_ENTER);
-       newtFormAddHotKey(form, NEWT_KEY_ESCAPE);
-       newtFormAddHotKey(form, NEWT_KEY_LEFT);
-       newtFormAddHotKey(form, CTRL('c'));
-       newtFormRun(form, &es);
-
-       if (result != NULL) {
-               strncpy(bf, result, size);
-               err = 0;
-       }
-out_free_form:
-       newtPopWindow();
-       newtFormDestroy(form);
-       return err;
-}
-
-struct map_browser {
-       struct ui_browser b;
-       struct map        *map;
-       u8                addrlen;
-};
-
-static void map_browser__write(struct ui_browser *self, void *nd, int row)
-{
-       struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
-       struct map_browser *mb = container_of(self, struct map_browser, b);
-       bool current_entry = ui_browser__is_current_entry(self, row);
-       int width;
-
-       ui_browser__set_percent_color(self, 0, current_entry);
-       slsmg_printf("%*" PRIx64 " %*" PRIx64 " %c ",
-                    mb->addrlen, sym->start, mb->addrlen, sym->end,
-                    sym->binding == STB_GLOBAL ? 'g' :
-                    sym->binding == STB_LOCAL  ? 'l' : 'w');
-       width = self->width - ((mb->addrlen * 2) + 4);
-       if (width > 0)
-               slsmg_write_nstring(sym->name, width);
-}
-
-/* FIXME uber-kludgy, see comment on cmd_report... */
-static u32 *symbol__browser_index(struct symbol *self)
-{
-       return ((void *)self) - sizeof(struct rb_node) - sizeof(u32);
-}
-
-static int map_browser__search(struct map_browser *self)
-{
-       char target[512];
-       struct symbol *sym;
-       int err = ui_entry__read("Search by name/addr", target, sizeof(target), 40);
-
-       if (err)
-               return err;
-
-       if (target[0] == '0' && tolower(target[1]) == 'x') {
-               u64 addr = strtoull(target, NULL, 16);
-               sym = map__find_symbol(self->map, addr, NULL);
-       } else
-               sym = map__find_symbol_by_name(self->map, target, NULL);
-
-       if (sym != NULL) {
-               u32 *idx = symbol__browser_index(sym);
-
-               self->b.top = &sym->rb_node;
-               self->b.index = self->b.top_idx = *idx;
-       } else
-               ui_helpline__fpush("%s not found!", target);
-
-       return 0;
-}
-
-static int map_browser__run(struct map_browser *self)
-{
-       int key;
-
-       if (ui_browser__show(&self->b, self->map->dso->long_name,
-                            "Press <- or ESC to exit, %s / to search",
-                            verbose ? "" : "restart with -v to use") < 0)
-               return -1;
-
-       while (1) {
-               key = ui_browser__run(&self->b, 0);
-
-               if (verbose && key == '/')
-                       map_browser__search(self);
-               else
-                       break;
-       }
-
-       ui_browser__hide(&self->b);
-       return key;
-}
-
-int map__browse(struct map *self)
-{
-       struct map_browser mb = {
-               .b = {
-                       .entries = &self->dso->symbols[self->type],
-                       .refresh = ui_browser__rb_tree_refresh,
-                       .seek    = ui_browser__rb_tree_seek,
-                       .write   = map_browser__write,
-               },
-               .map = self,
-       };
-       struct rb_node *nd;
-       char tmp[BITS_PER_LONG / 4];
-       u64 maxaddr = 0;
-
-       for (nd = rb_first(mb.b.entries); nd; nd = rb_next(nd)) {
-               struct symbol *pos = rb_entry(nd, struct symbol, rb_node);
-
-               if (maxaddr < pos->end)
-                       maxaddr = pos->end;
-               if (verbose) {
-                       u32 *idx = symbol__browser_index(pos);
-                       *idx = mb.b.nr_entries;
-               }
-               ++mb.b.nr_entries;
-       }
-
-       mb.addrlen = snprintf(tmp, sizeof(tmp), "%" PRIx64, maxaddr);
-       return map_browser__run(&mb);
-}
diff --git a/tools/perf/util/ui/browsers/map.h b/tools/perf/util/ui/browsers/map.h
deleted file mode 100644 (file)
index df8581a..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _PERF_UI_MAP_BROWSER_H_
-#define _PERF_UI_MAP_BROWSER_H_ 1
-struct map;
-
-int map__browse(struct map *self);
-#endif /* _PERF_UI_MAP_BROWSER_H_ */
diff --git a/tools/perf/util/ui/helpline.c b/tools/perf/util/ui/helpline.c
deleted file mode 100644 (file)
index 2f950c2..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "../debug.h"
-#include "helpline.h"
-#include "ui.h"
-#include "libslang.h"
-
-void ui_helpline__pop(void)
-{
-}
-
-char ui_helpline__current[512];
-
-void ui_helpline__push(const char *msg)
-{
-       const size_t sz = sizeof(ui_helpline__current);
-
-       SLsmg_gotorc(SLtt_Screen_Rows - 1, 0);
-       SLsmg_set_color(0);
-       SLsmg_write_nstring((char *)msg, SLtt_Screen_Cols);
-       SLsmg_refresh();
-       strncpy(ui_helpline__current, msg, sz)[sz - 1] = '\0';
-}
-
-void ui_helpline__vpush(const char *fmt, va_list ap)
-{
-       char *s;
-
-       if (vasprintf(&s, fmt, ap) < 0)
-               vfprintf(stderr, fmt, ap);
-       else {
-               ui_helpline__push(s);
-               free(s);
-       }
-}
-
-void ui_helpline__fpush(const char *fmt, ...)
-{
-       va_list ap;
-
-       va_start(ap, fmt);
-       ui_helpline__vpush(fmt, ap);
-       va_end(ap);
-}
-
-void ui_helpline__puts(const char *msg)
-{
-       ui_helpline__pop();
-       ui_helpline__push(msg);
-}
-
-void ui_helpline__init(void)
-{
-       ui_helpline__puts(" ");
-}
-
-char ui_helpline__last_msg[1024];
-
-int ui_helpline__show_help(const char *format, va_list ap)
-{
-       int ret;
-       static int backlog;
-
-       pthread_mutex_lock(&ui__lock);
-       ret = vscnprintf(ui_helpline__last_msg + backlog,
-                       sizeof(ui_helpline__last_msg) - backlog, format, ap);
-       backlog += ret;
-
-       if (ui_helpline__last_msg[backlog - 1] == '\n') {
-               ui_helpline__puts(ui_helpline__last_msg);
-               SLsmg_refresh();
-               backlog = 0;
-       }
-       pthread_mutex_unlock(&ui__lock);
-
-       return ret;
-}
diff --git a/tools/perf/util/ui/helpline.h b/tools/perf/util/ui/helpline.h
deleted file mode 100644 (file)
index 7bab6b3..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef _PERF_UI_HELPLINE_H_
-#define _PERF_UI_HELPLINE_H_ 1
-
-#include <stdio.h>
-#include <stdarg.h>
-
-void ui_helpline__init(void);
-void ui_helpline__pop(void);
-void ui_helpline__push(const char *msg);
-void ui_helpline__vpush(const char *fmt, va_list ap);
-void ui_helpline__fpush(const char *fmt, ...);
-void ui_helpline__puts(const char *msg);
-
-extern char ui_helpline__current[];
-
-#endif /* _PERF_UI_HELPLINE_H_ */
diff --git a/tools/perf/util/ui/keysyms.h b/tools/perf/util/ui/keysyms.h
deleted file mode 100644 (file)
index 809eca5..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef _PERF_KEYSYMS_H_
-#define _PERF_KEYSYMS_H_ 1
-
-#include "libslang.h"
-
-#define K_DOWN SL_KEY_DOWN
-#define K_END  SL_KEY_END
-#define K_ENTER        '\r'
-#define K_ESC  033
-#define K_F1   SL_KEY_F(1)
-#define K_HOME SL_KEY_HOME
-#define K_LEFT SL_KEY_LEFT
-#define K_PGDN SL_KEY_NPAGE
-#define K_PGUP SL_KEY_PPAGE
-#define K_RIGHT        SL_KEY_RIGHT
-#define K_TAB  '\t'
-#define K_UNTAB        SL_KEY_UNTAB
-#define K_UP   SL_KEY_UP
-#define K_BKSPC 0x7f
-#define K_DEL  SL_KEY_DELETE
-
-/* Not really keys */
-#define K_TIMER         -1
-#define K_ERROR         -2
-#define K_RESIZE -3
-
-#endif /* _PERF_KEYSYMS_H_ */
diff --git a/tools/perf/util/ui/libslang.h b/tools/perf/util/ui/libslang.h
deleted file mode 100644 (file)
index 4d54b64..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef _PERF_UI_SLANG_H_
-#define _PERF_UI_SLANG_H_ 1
-/*
- * slang versions <= 2.0.6 have a "#if HAVE_LONG_LONG" that breaks
- * the build if it isn't defined. Use the equivalent one that glibc
- * has on features.h.
- */
-#include <features.h>
-#ifndef HAVE_LONG_LONG
-#define HAVE_LONG_LONG __GLIBC_HAVE_LONG_LONG
-#endif
-#include <slang.h>
-
-#if SLANG_VERSION < 20104
-#define slsmg_printf(msg, args...) \
-       SLsmg_printf((char *)(msg), ##args)
-#define slsmg_write_nstring(msg, len) \
-       SLsmg_write_nstring((char *)(msg), len)
-#define sltt_set_color(obj, name, fg, bg) \
-       SLtt_set_color(obj,(char *)(name), (char *)(fg), (char *)(bg))
-#else
-#define slsmg_printf SLsmg_printf
-#define slsmg_write_nstring SLsmg_write_nstring
-#define sltt_set_color SLtt_set_color
-#endif
-
-#define SL_KEY_UNTAB 0x1000
-
-#endif /* _PERF_UI_SLANG_H_ */
diff --git a/tools/perf/util/ui/progress.c b/tools/perf/util/ui/progress.c
deleted file mode 100644 (file)
index 13aa64e..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-#include "../cache.h"
-#include "progress.h"
-#include "libslang.h"
-#include "ui.h"
-#include "browser.h"
-
-void ui_progress__update(u64 curr, u64 total, const char *title)
-{
-       int bar, y;
-       /*
-        * FIXME: We should have a per UI backend way of showing progress,
-        * stdio will just show a percentage as NN%, etc.
-        */
-       if (use_browser <= 0)
-               return;
-
-       if (total == 0)
-               return;
-
-       ui__refresh_dimensions(true);
-       pthread_mutex_lock(&ui__lock);
-       y = SLtt_Screen_Rows / 2 - 2;
-       SLsmg_set_color(0);
-       SLsmg_draw_box(y, 0, 3, SLtt_Screen_Cols);
-       SLsmg_gotorc(y++, 1);
-       SLsmg_write_string((char *)title);
-       SLsmg_set_color(HE_COLORSET_SELECTED);
-       bar = ((SLtt_Screen_Cols - 2) * curr) / total;
-       SLsmg_fill_region(y, 1, 1, bar, ' ');
-       SLsmg_refresh();
-       pthread_mutex_unlock(&ui__lock);
-}
diff --git a/tools/perf/util/ui/progress.h b/tools/perf/util/ui/progress.h
deleted file mode 100644 (file)
index d9c205b..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef _PERF_UI_PROGRESS_H_
-#define _PERF_UI_PROGRESS_H_ 1
-
-#include <../types.h>
-
-void ui_progress__update(u64 curr, u64 total, const char *title);
-
-#endif
diff --git a/tools/perf/util/ui/setup.c b/tools/perf/util/ui/setup.c
deleted file mode 100644 (file)
index 85a69fa..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-#include <newt.h>
-#include <signal.h>
-#include <stdbool.h>
-
-#include "../cache.h"
-#include "../debug.h"
-#include "browser.h"
-#include "helpline.h"
-#include "ui.h"
-#include "util.h"
-#include "libslang.h"
-#include "keysyms.h"
-
-pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER;
-
-static volatile int ui__need_resize;
-
-void ui__refresh_dimensions(bool force)
-{
-       if (force || ui__need_resize) {
-               ui__need_resize = 0;
-               pthread_mutex_lock(&ui__lock);
-               SLtt_get_screen_size();
-               SLsmg_reinit_smg();
-               pthread_mutex_unlock(&ui__lock);
-       }
-}
-
-static void ui__sigwinch(int sig __used)
-{
-       ui__need_resize = 1;
-}
-
-static void ui__setup_sigwinch(void)
-{
-       static bool done;
-
-       if (done)
-               return;
-
-       done = true;
-       pthread__unblock_sigwinch();
-       signal(SIGWINCH, ui__sigwinch);
-}
-
-int ui__getch(int delay_secs)
-{
-       struct timeval timeout, *ptimeout = delay_secs ? &timeout : NULL;
-       fd_set read_set;
-       int err, key;
-
-       ui__setup_sigwinch();
-
-       FD_ZERO(&read_set);
-       FD_SET(0, &read_set);
-
-       if (delay_secs) {
-               timeout.tv_sec = delay_secs;
-               timeout.tv_usec = 0;
-       }
-
-        err = select(1, &read_set, NULL, NULL, ptimeout);
-
-       if (err == 0)
-               return K_TIMER;
-
-       if (err == -1) {
-               if (errno == EINTR)
-                       return K_RESIZE;
-               return K_ERROR;
-       }
-
-       key = SLang_getkey();
-       if (key != K_ESC)
-               return key;
-
-       FD_ZERO(&read_set);
-       FD_SET(0, &read_set);
-       timeout.tv_sec = 0;
-       timeout.tv_usec = 20;
-        err = select(1, &read_set, NULL, NULL, &timeout);
-       if (err == 0)
-               return K_ESC;
-
-       SLang_ungetkey(key);
-       return SLkp_getkey();
-}
-
-static void newt_suspend(void *d __used)
-{
-       newtSuspend();
-       raise(SIGTSTP);
-       newtResume();
-}
-
-static int ui__init(void)
-{
-       int err = SLkp_init();
-
-       if (err < 0)
-               goto out;
-
-       SLkp_define_keysym((char *)"^(kB)", SL_KEY_UNTAB);
-out:
-       return err;
-}
-
-static void ui__exit(void)
-{
-       SLtt_set_cursor_visibility(1);
-       SLsmg_refresh();
-       SLsmg_reset_smg();
-       SLang_reset_tty();
-}
-
-static void ui__signal(int sig)
-{
-       ui__exit();
-       psignal(sig, "perf");
-       exit(0);
-}
-
-void setup_browser(bool fallback_to_pager)
-{
-       if (!isatty(1) || !use_browser || dump_trace) {
-               use_browser = 0;
-               if (fallback_to_pager)
-                       setup_pager();
-               return;
-       }
-
-       use_browser = 1;
-       newtInit();
-       ui__init();
-       newtSetSuspendCallback(newt_suspend, NULL);
-       ui_helpline__init();
-       ui_browser__init();
-
-       signal(SIGSEGV, ui__signal);
-       signal(SIGFPE, ui__signal);
-       signal(SIGINT, ui__signal);
-       signal(SIGQUIT, ui__signal);
-       signal(SIGTERM, ui__signal);
-}
-
-void exit_browser(bool wait_for_ok)
-{
-       if (use_browser > 0) {
-               if (wait_for_ok)
-                       ui__question_window("Fatal Error",
-                                           ui_helpline__last_msg,
-                                           "Press any key...", 0);
-               ui__exit();
-       }
-}
diff --git a/tools/perf/util/ui/ui.h b/tools/perf/util/ui/ui.h
deleted file mode 100644 (file)
index 7b67045..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef _PERF_UI_H_
-#define _PERF_UI_H_ 1
-
-#include <pthread.h>
-#include <stdbool.h>
-
-extern pthread_mutex_t ui__lock;
-
-void ui__refresh_dimensions(bool force);
-
-#endif /* _PERF_UI_H_ */
diff --git a/tools/perf/util/ui/util.c b/tools/perf/util/ui/util.c
deleted file mode 100644 (file)
index ad4374a..0000000
+++ /dev/null
@@ -1,250 +0,0 @@
-#include "../util.h"
-#include <signal.h>
-#include <stdbool.h>
-#include <string.h>
-#include <sys/ttydefaults.h>
-
-#include "../cache.h"
-#include "../debug.h"
-#include "browser.h"
-#include "keysyms.h"
-#include "helpline.h"
-#include "ui.h"
-#include "util.h"
-#include "libslang.h"
-
-static void ui_browser__argv_write(struct ui_browser *browser,
-                                  void *entry, int row)
-{
-       char **arg = entry;
-       bool current_entry = ui_browser__is_current_entry(browser, row);
-
-       ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED :
-                                                      HE_COLORSET_NORMAL);
-       slsmg_write_nstring(*arg, browser->width);
-}
-
-static int popup_menu__run(struct ui_browser *menu)
-{
-       int key;
-
-       if (ui_browser__show(menu, " ", "ESC: exit, ENTER|->: Select option") < 0)
-               return -1;
-
-       while (1) {
-               key = ui_browser__run(menu, 0);
-
-               switch (key) {
-               case K_RIGHT:
-               case K_ENTER:
-                       key = menu->index;
-                       break;
-               case K_LEFT:
-               case K_ESC:
-               case 'q':
-               case CTRL('c'):
-                       key = -1;
-                       break;
-               default:
-                       continue;
-               }
-
-               break;
-       }
-
-       ui_browser__hide(menu);
-       return key;
-}
-
-int ui__popup_menu(int argc, char * const argv[])
-{
-       struct ui_browser menu = {
-               .entries    = (void *)argv,
-               .refresh    = ui_browser__argv_refresh,
-               .seek       = ui_browser__argv_seek,
-               .write      = ui_browser__argv_write,
-               .nr_entries = argc,
-       };
-
-       return popup_menu__run(&menu);
-}
-
-int ui_browser__input_window(const char *title, const char *text, char *input,
-                            const char *exit_msg, int delay_secs)
-{
-       int x, y, len, key;
-       int max_len = 60, nr_lines = 0;
-       static char buf[50];
-       const char *t;
-
-       t = text;
-       while (1) {
-               const char *sep = strchr(t, '\n');
-
-               if (sep == NULL)
-                       sep = strchr(t, '\0');
-               len = sep - t;
-               if (max_len < len)
-                       max_len = len;
-               ++nr_lines;
-               if (*sep == '\0')
-                       break;
-               t = sep + 1;
-       }
-
-       max_len += 2;
-       nr_lines += 8;
-       y = SLtt_Screen_Rows / 2 - nr_lines / 2;
-       x = SLtt_Screen_Cols / 2 - max_len / 2;
-
-       SLsmg_set_color(0);
-       SLsmg_draw_box(y, x++, nr_lines, max_len);
-       if (title) {
-               SLsmg_gotorc(y, x + 1);
-               SLsmg_write_string((char *)title);
-       }
-       SLsmg_gotorc(++y, x);
-       nr_lines -= 7;
-       max_len -= 2;
-       SLsmg_write_wrapped_string((unsigned char *)text, y, x,
-                                  nr_lines, max_len, 1);
-       y += nr_lines;
-       len = 5;
-       while (len--) {
-               SLsmg_gotorc(y + len - 1, x);
-               SLsmg_write_nstring((char *)" ", max_len);
-       }
-       SLsmg_draw_box(y++, x + 1, 3, max_len - 2);
-
-       SLsmg_gotorc(y + 3, x);
-       SLsmg_write_nstring((char *)exit_msg, max_len);
-       SLsmg_refresh();
-
-       x += 2;
-       len = 0;
-       key = ui__getch(delay_secs);
-       while (key != K_TIMER && key != K_ENTER && key != K_ESC) {
-               if (key == K_BKSPC) {
-                       if (len == 0)
-                               goto next_key;
-                       SLsmg_gotorc(y, x + --len);
-                       SLsmg_write_char(' ');
-               } else {
-                       buf[len] = key;
-                       SLsmg_gotorc(y, x + len++);
-                       SLsmg_write_char(key);
-               }
-               SLsmg_refresh();
-
-               /* XXX more graceful overflow handling needed */
-               if (len == sizeof(buf) - 1) {
-                       ui_helpline__push("maximum size of symbol name reached!");
-                       key = K_ENTER;
-                       break;
-               }
-next_key:
-               key = ui__getch(delay_secs);
-       }
-
-       buf[len] = '\0';
-       strncpy(input, buf, len+1);
-       return key;
-}
-
-int ui__question_window(const char *title, const char *text,
-                       const char *exit_msg, int delay_secs)
-{
-       int x, y;
-       int max_len = 0, nr_lines = 0;
-       const char *t;
-
-       t = text;
-       while (1) {
-               const char *sep = strchr(t, '\n');
-               int len;
-
-               if (sep == NULL)
-                       sep = strchr(t, '\0');
-               len = sep - t;
-               if (max_len < len)
-                       max_len = len;
-               ++nr_lines;
-               if (*sep == '\0')
-                       break;
-               t = sep + 1;
-       }
-
-       max_len += 2;
-       nr_lines += 4;
-       y = SLtt_Screen_Rows / 2 - nr_lines / 2,
-       x = SLtt_Screen_Cols / 2 - max_len / 2;
-
-       SLsmg_set_color(0);
-       SLsmg_draw_box(y, x++, nr_lines, max_len);
-       if (title) {
-               SLsmg_gotorc(y, x + 1);
-               SLsmg_write_string((char *)title);
-       }
-       SLsmg_gotorc(++y, x);
-       nr_lines -= 2;
-       max_len -= 2;
-       SLsmg_write_wrapped_string((unsigned char *)text, y, x,
-                                  nr_lines, max_len, 1);
-       SLsmg_gotorc(y + nr_lines - 2, x);
-       SLsmg_write_nstring((char *)" ", max_len);
-       SLsmg_gotorc(y + nr_lines - 1, x);
-       SLsmg_write_nstring((char *)exit_msg, max_len);
-       SLsmg_refresh();
-       return ui__getch(delay_secs);
-}
-
-int ui__help_window(const char *text)
-{
-       return ui__question_window("Help", text, "Press any key...", 0);
-}
-
-int ui__dialog_yesno(const char *msg)
-{
-       return ui__question_window(NULL, msg, "Enter: Yes, ESC: No", 0);
-}
-
-int __ui__warning(const char *title, const char *format, va_list args)
-{
-       char *s;
-
-       if (use_browser > 0 && vasprintf(&s, format, args) > 0) {
-               int key;
-
-               pthread_mutex_lock(&ui__lock);
-               key = ui__question_window(title, s, "Press any key...", 0);
-               pthread_mutex_unlock(&ui__lock);
-               free(s);
-               return key;
-       }
-
-       fprintf(stderr, "%s:\n", title);
-       vfprintf(stderr, format, args);
-       return K_ESC;
-}
-
-int ui__warning(const char *format, ...)
-{
-       int key;
-       va_list args;
-
-       va_start(args, format);
-       key = __ui__warning("Warning", format, args);
-       va_end(args);
-       return key;
-}
-
-int ui__error(const char *format, ...)
-{
-       int key;
-       va_list args;
-
-       va_start(args, format);
-       key = __ui__warning("Error", format, args);
-       va_end(args);
-       return key;
-}
diff --git a/tools/perf/util/ui/util.h b/tools/perf/util/ui/util.h
deleted file mode 100644 (file)
index 2d1738b..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef _PERF_UI_UTIL_H_
-#define _PERF_UI_UTIL_H_ 1
-
-#include <stdarg.h>
-
-int ui__getch(int delay_secs);
-int ui__popup_menu(int argc, char * const argv[]);
-int ui__help_window(const char *text);
-int ui__dialog_yesno(const char *msg);
-int ui__question_window(const char *title, const char *text,
-                       const char *exit_msg, int delay_secs);
-int __ui__warning(const char *title, const char *format, va_list args);
-
-#endif /* _PERF_UI_UTIL_H_ */
diff --git a/tools/scripts/Makefile.include b/tools/scripts/Makefile.include
new file mode 100644 (file)
index 0000000..87b55a7
--- /dev/null
@@ -0,0 +1,57 @@
+ifeq ("$(origin O)", "command line")
+       OUTPUT := $(O)/
+endif
+
+ifneq ($(OUTPUT),)
+# check that the output directory actually exists
+OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd)
+$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist))
+endif
+
+#
+# Include saner warnings here, which can catch bugs:
+#
+EXTRA_WARNINGS := -Wbad-function-cast
+EXTRA_WARNINGS += -Wdeclaration-after-statement
+EXTRA_WARNINGS += -Wformat-security
+EXTRA_WARNINGS += -Wformat-y2k
+EXTRA_WARNINGS += -Winit-self
+EXTRA_WARNINGS += -Wmissing-declarations
+EXTRA_WARNINGS += -Wmissing-prototypes
+EXTRA_WARNINGS += -Wnested-externs
+EXTRA_WARNINGS += -Wno-system-headers
+EXTRA_WARNINGS += -Wold-style-definition
+EXTRA_WARNINGS += -Wpacked
+EXTRA_WARNINGS += -Wredundant-decls
+EXTRA_WARNINGS += -Wshadow
+EXTRA_WARNINGS += -Wstrict-aliasing=3
+EXTRA_WARNINGS += -Wstrict-prototypes
+EXTRA_WARNINGS += -Wswitch-default
+EXTRA_WARNINGS += -Wswitch-enum
+EXTRA_WARNINGS += -Wundef
+EXTRA_WARNINGS += -Wwrite-strings
+EXTRA_WARNINGS += -Wformat
+
+ifneq ($(findstring $(MAKEFLAGS), w),w)
+PRINT_DIR = --no-print-directory
+else
+NO_SUBDIR = :
+endif
+
+QUIET_SUBDIR0  = +$(MAKE) -C # space to separate -C and subdir
+QUIET_SUBDIR1  =
+
+ifneq ($(findstring $(MAKEFLAGS),s),s)
+ifndef V
+       QUIET_CC       = @echo '   ' CC $@;
+       QUIET_AR       = @echo '   ' AR $@;
+       QUIET_LINK     = @echo '   ' LINK $@;
+       QUIET_MKDIR    = @echo '   ' MKDIR $@;
+       QUIET_GEN      = @echo '   ' GEN $@;
+       QUIET_SUBDIR0  = +@subdir=
+       QUIET_SUBDIR1  = ;$(NO_SUBDIR) echo '   ' SUBDIR $$subdir; \
+                        $(MAKE) $(PRINT_DIR) -C $$subdir
+       QUIET_FLEX     = @echo '   ' FLEX $@;
+       QUIET_BISON    = @echo '   ' BISON $@;
+endif
+endif