Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorIngo Molnar <mingo@kernel.org>
Wed, 13 Aug 2014 05:06:08 +0000 (07:06 +0200)
committerIngo Molnar <mingo@kernel.org>
Wed, 13 Aug 2014 05:06:08 +0000 (07:06 +0200)
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:

User visible fixes and changes:

  * Show better error message in case we fail to open counters due to EBUSY error,
    for instance, when oprofile is running. (Jiri Olsa)

  * Honour -w in the report tools (report, top), allowing to specify the widths
    for the histogram entries columns. (Namhyung Kim)

  * Don't run workload if not told to, as happens when the user has no
    permission for profiling and even then the specified workload ends
    up running (Arnaldo Carvalho de Melo)

  * Do not ignore mmap events in 'perf kmem report'. This tool was using
    the kernel mmaps in the running machine instead of processing the mmap
    records from the perf.data file. (Namhyung Kim)

  * Properly show submicrosecond times in 'perf kvm stat' (Christian Borntraeger)

  * Honour existing 'perf record' --time/-T command line option (Andi Kleen)

  * Make sure --symfs usage includes the path separator (Arnaldo Carvalho de Melo)

Development infrastructure fixes and changes:

  * Fix arm64 build error (Mark Salter)

  * Fix make PYTHON override (Namhyung Kim)

  * Rename ordered_samples to ordered_events and allow setting a queue
    size for ordering events (Jiri Olsa)

  * Default to python version 2 (Thomas Ilsche)

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
46 files changed:
tools/perf/Documentation/perf-report.txt
tools/perf/Documentation/perf-top.txt
tools/perf/Makefile.perf
tools/perf/arch/arm64/include/perf_regs.h
tools/perf/builtin-annotate.c
tools/perf/builtin-diff.c
tools/perf/builtin-inject.c
tools/perf/builtin-kmem.c
tools/perf/builtin-kvm.c
tools/perf/builtin-lock.c
tools/perf/builtin-mem.c
tools/perf/builtin-record.c
tools/perf/builtin-report.c
tools/perf/builtin-sched.c
tools/perf/builtin-script.c
tools/perf/builtin-timechart.c
tools/perf/builtin-top.c
tools/perf/builtin-trace.c
tools/perf/config/Makefile
tools/perf/config/feature-checks/Makefile
tools/perf/ui/browsers/hists.c
tools/perf/ui/gtk/hists.c
tools/perf/ui/hist.c
tools/perf/ui/stdio/hist.c
tools/perf/util/annotate.c
tools/perf/util/cache.h
tools/perf/util/cloexec.c
tools/perf/util/color.c
tools/perf/util/color.h
tools/perf/util/config.c
tools/perf/util/debug.c
tools/perf/util/debug.h
tools/perf/util/dso.c
tools/perf/util/evlist.c
tools/perf/util/evsel.c
tools/perf/util/hist.h
tools/perf/util/ordered-events.c [new file with mode: 0644]
tools/perf/util/ordered-events.h [new file with mode: 0644]
tools/perf/util/session.c
tools/perf/util/session.h
tools/perf/util/sort.c
tools/perf/util/symbol.c
tools/perf/util/symbol.h
tools/perf/util/tool.h
tools/perf/util/util.c
tools/perf/util/util.h

index d2b59af62bc0ad6ddff918f2aee04a67fbf5541f..d561e0214f52fbcb1ba1562d4bac1d602af31f10 100644 (file)
@@ -147,7 +147,7 @@ OPTIONS
 -w::
 --column-widths=<width[,width...]>::
        Force each column width to the provided list, for large terminal
-       readability.
+       readability.  0 means no limit (default behavior).
 
 -t::
 --field-separator=::
index 180ae02137a519acf1b3d779a92eb651db6b4aff..28fdee3948806896ad38876d4d1c071f7453a60b 100644 (file)
@@ -193,6 +193,12 @@ Default is to monitor all CPUS.
        sum of shown entries will be always 100%. "absolute" means it retains
        the original value before and after the filter is applied.
 
+-w::
+--column-widths=<width[,width...]>::
+       Force each column width to the provided list, for large terminal
+       readability.  0 means no limit (default behavior).
+
+
 INTERACTIVE PROMPTING KEYS
 --------------------------
 
index 2240974b7745874f3e2e39c3ee9f98d18c8c7912..1ea31e275b4dec4298dfa0892c0baa1d435e8c2a 100644 (file)
@@ -263,6 +263,7 @@ LIB_H += util/xyarray.h
 LIB_H += util/header.h
 LIB_H += util/help.h
 LIB_H += util/session.h
+LIB_H += util/ordered-events.h
 LIB_H += util/strbuf.h
 LIB_H += util/strlist.h
 LIB_H += util/strfilter.h
@@ -347,6 +348,7 @@ LIB_OBJS += $(OUTPUT)util/machine.o
 LIB_OBJS += $(OUTPUT)util/map.o
 LIB_OBJS += $(OUTPUT)util/pstack.o
 LIB_OBJS += $(OUTPUT)util/session.o
+LIB_OBJS += $(OUTPUT)util/ordered-events.o
 LIB_OBJS += $(OUTPUT)util/comm.o
 LIB_OBJS += $(OUTPUT)util/thread.o
 LIB_OBJS += $(OUTPUT)util/thread_map.o
index e9441b9e2a302a686e0db2cb03f0f30690f5c2ff..1d3f39c3aa564fd2e85a950fddcb4bba18f5e8db 100644 (file)
@@ -6,6 +6,8 @@
 #include <asm/perf_regs.h>
 
 #define PERF_REGS_MASK ((1ULL << PERF_REG_ARM64_MAX) - 1)
+#define PERF_REGS_MAX  PERF_REG_ARM64_MAX
+
 #define PERF_REG_IP    PERF_REG_ARM64_PC
 #define PERF_REG_SP    PERF_REG_ARM64_SP
 
index 1ec429fef2be9354d79400efe074e707229bef2f..952b5ece6740c3abde175b473c2a706f9fce448a 100644 (file)
@@ -297,7 +297,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
                        .comm   = perf_event__process_comm,
                        .exit   = perf_event__process_exit,
                        .fork   = perf_event__process_fork,
-                       .ordered_samples = true,
+                       .ordered_events = true,
                        .ordering_requires_timestamps = true,
                },
        };
index 9a5a035cb4262afcf1e74986276df8763f1036b9..c10cc44bae19dd3af8cd043ee0745e81d1d57abe 100644 (file)
@@ -360,7 +360,7 @@ static struct perf_tool tool = {
        .exit   = perf_event__process_exit,
        .fork   = perf_event__process_fork,
        .lost   = perf_event__process_lost,
-       .ordered_samples = true,
+       .ordered_events = true,
        .ordering_requires_timestamps = true,
 };
 
index 9a02807387d6c25b9c41236f9404a88da5580a3f..ee875cca13b1a119b6f2aa2ab9972e1821f2dd94 100644 (file)
@@ -366,7 +366,7 @@ static int __cmd_inject(struct perf_inject *inject)
        } else if (inject->sched_stat) {
                struct perf_evsel *evsel;
 
-               inject->tool.ordered_samples = true;
+               inject->tool.ordered_events = true;
 
                evlist__for_each(session->evlist, evsel) {
                        const char *name = perf_evsel__name(evsel);
index bef3376bfaf3a6e093a227fddb15e6cbf7ffbd7f..84b82397a28ea8cf1f8d20b9f7cc164191b85454 100644 (file)
@@ -256,7 +256,9 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
 static struct perf_tool perf_kmem = {
        .sample          = process_sample_event,
        .comm            = perf_event__process_comm,
-       .ordered_samples = true,
+       .mmap            = perf_event__process_mmap,
+       .mmap2           = perf_event__process_mmap2,
+       .ordered_events  = true,
 };
 
 static double fragmentation(unsigned long n_req, unsigned long n_alloc)
@@ -424,9 +426,6 @@ static int __cmd_kmem(void)
        if (session == NULL)
                return -ENOMEM;
 
-       if (perf_session__create_kernel_maps(session) < 0)
-               goto out_delete;
-
        if (!perf_session__has_traces(session, "kmem record"))
                goto out_delete;
 
index 43367eb005100ae939b8c6d372e5d6d0e6649e34..7ccceadcd9f8dbc3a9ef877c912f6fd4ed670100 100644 (file)
@@ -592,8 +592,8 @@ static void print_result(struct perf_kvm_stat *kvm)
        pr_info("%9s ", "Samples%");
 
        pr_info("%9s ", "Time%");
-       pr_info("%10s ", "Min Time");
-       pr_info("%10s ", "Max Time");
+       pr_info("%11s ", "Min Time");
+       pr_info("%11s ", "Max Time");
        pr_info("%16s ", "Avg time");
        pr_info("\n\n");
 
@@ -610,8 +610,8 @@ static void print_result(struct perf_kvm_stat *kvm)
                pr_info("%10llu ", (unsigned long long)ecount);
                pr_info("%8.2f%% ", (double)ecount / kvm->total_count * 100);
                pr_info("%8.2f%% ", (double)etime / kvm->total_time * 100);
-               pr_info("%8" PRIu64 "us ", min / 1000);
-               pr_info("%8" PRIu64 "us ", max / 1000);
+               pr_info("%9.2fus ", (double)min / 1e3);
+               pr_info("%9.2fus ", (double)max / 1e3);
                pr_info("%9.2fus ( +-%7.2f%% )", (double)etime / ecount/1e3,
                        kvm_event_rel_stddev(vcpu, event));
                pr_info("\n");
@@ -732,7 +732,7 @@ static s64 perf_kvm__mmap_read_idx(struct perf_kvm_stat *kvm, int idx,
                        return -1;
                }
 
-               err = perf_session_queue_event(kvm->session, event, &sample, 0);
+               err = perf_session_queue_event(kvm->session, event, &kvm->tool, &sample, 0);
                /*
                 * FIXME: Here we can't consume the event, as perf_session_queue_event will
                 *        point to it, and it'll get possibly overwritten by the kernel.
@@ -785,7 +785,7 @@ static int perf_kvm__mmap_read(struct perf_kvm_stat *kvm)
 
        /* flush queue after each round in which we processed events */
        if (ntotal) {
-               kvm->session->ordered_samples.next_flush = flush_time;
+               kvm->session->ordered_events.next_flush = flush_time;
                err = kvm->tool.finished_round(&kvm->tool, NULL, kvm->session);
                if (err) {
                        if (kvm->lost_events)
@@ -1058,7 +1058,7 @@ static int read_events(struct perf_kvm_stat *kvm)
        struct perf_tool eops = {
                .sample                 = process_sample_event,
                .comm                   = perf_event__process_comm,
-               .ordered_samples        = true,
+               .ordered_events         = true,
        };
        struct perf_data_file file = {
                .path = kvm->file_name,
@@ -1311,7 +1311,7 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
        kvm->tool.exit   = perf_event__process_exit;
        kvm->tool.fork   = perf_event__process_fork;
        kvm->tool.lost   = process_lost_event;
-       kvm->tool.ordered_samples = true;
+       kvm->tool.ordered_events = true;
        perf_tool__fill_defaults(&kvm->tool);
 
        /* set defaults */
index 6148afc995c68a0bd11b61826a741185a69e4294..c8122d323621c34175c94f6674d06b39ca7624c6 100644 (file)
@@ -852,7 +852,7 @@ static int __cmd_report(bool display_info)
        struct perf_tool eops = {
                .sample          = process_sample_event,
                .comm            = perf_event__process_comm,
-               .ordered_samples = true,
+               .ordered_events  = true,
        };
        struct perf_data_file file = {
                .path = input_name,
index 4a1a6c94a5ebcb5b7a08bef5034f22419ce07c77..80e57c84adefdaec2e6356d20abf46ad44982fa9 100644 (file)
@@ -194,7 +194,7 @@ int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused)
                        .lost           = perf_event__process_lost,
                        .fork           = perf_event__process_fork,
                        .build_id       = perf_event__process_build_id,
-                       .ordered_samples = true,
+                       .ordered_events = true,
                },
                .input_name              = "perf.data",
        };
index 4869050e7194c18311da81f165f6f8e5cb5882ea..ca0251e8470d0d12a01e32f6b3e6a1253c47393c 100644 (file)
@@ -781,6 +781,7 @@ static const char * const record_usage[] = {
  */
 static struct record record = {
        .opts = {
+               .sample_time         = true,
                .mmap_pages          = UINT_MAX,
                .user_freq           = UINT_MAX,
                .user_interval       = ULLONG_MAX,
index 21d830bafff32aaa4b38ec0eb2e63ec66dfc00f8..041e93da13e453dfb0c377d6fe46f34ed3345d34 100644 (file)
@@ -58,17 +58,19 @@ struct report {
        const char              *symbol_filter_str;
        float                   min_percent;
        u64                     nr_entries;
+       u64                     queue_size;
        DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
 };
 
 static int report__config(const char *var, const char *value, void *cb)
 {
+       struct report *rep = cb;
+
        if (!strcmp(var, "report.group")) {
                symbol_conf.event_group = perf_config_bool(var, value);
                return 0;
        }
        if (!strcmp(var, "report.percent-limit")) {
-               struct report *rep = cb;
                rep->min_percent = strtof(value, NULL);
                return 0;
        }
@@ -76,6 +78,10 @@ static int report__config(const char *var, const char *value, void *cb)
                symbol_conf.cumulate_callchain = perf_config_bool(var, value);
                return 0;
        }
+       if (!strcmp(var, "report.queue-size")) {
+               rep->queue_size = perf_config_u64(var, value);
+               return 0;
+       }
 
        return perf_default_config(var, value, cb);
 }
@@ -578,7 +584,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
                        .attr            = perf_event__process_attr,
                        .tracing_data    = perf_event__process_tracing_data,
                        .build_id        = perf_event__process_build_id,
-                       .ordered_samples = true,
+                       .ordered_events  = true,
                        .ordering_requires_timestamps = true,
                },
                .max_stack               = PERF_MAX_STACK_DEPTH,
@@ -714,6 +720,11 @@ repeat:
        if (session == NULL)
                return -ENOMEM;
 
+       if (report.queue_size) {
+               ordered_events__set_alloc_size(&session->ordered_events,
+                                              report.queue_size);
+       }
+
        report.session = session;
 
        has_br_stack = perf_header__has_feat(&session->header,
index f83c08c0dd87caaa97a8c0b3958320b65a2ed2ef..7c16aeb6b675ecd489c19246b99499a9abf0e714 100644 (file)
@@ -1662,7 +1662,7 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
                        .comm            = perf_event__process_comm,
                        .lost            = perf_event__process_lost,
                        .fork            = perf_sched__process_fork_event,
-                       .ordered_samples = true,
+                       .ordered_events = true,
                },
                .cmp_pid              = LIST_HEAD_INIT(sched.cmp_pid),
                .sort_list            = LIST_HEAD_INIT(sched.sort_list),
index f57035b89c15d11a5178cd3468cf5bd9b03405c1..868c17d097627cdc05caba29ced95d652a3ab254 100644 (file)
@@ -1488,7 +1488,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
                        .attr            = process_attr,
                        .tracing_data    = perf_event__process_tracing_data,
                        .build_id        = perf_event__process_build_id,
-                       .ordered_samples = true,
+                       .ordered_events  = true,
                        .ordering_requires_timestamps = true,
                },
        };
index 2f1a5220c090f4fd8461b743f85b88b0b812214b..912e3b5bb22b614f233d98ca61f74b54d1c41613 100644 (file)
@@ -1920,7 +1920,7 @@ int cmd_timechart(int argc, const char **argv,
                        .fork            = process_fork_event,
                        .exit            = process_exit_event,
                        .sample          = process_sample_event,
-                       .ordered_samples = true,
+                       .ordered_events  = true,
                },
                .proc_num = 15,
                .min_time = 1000000,
index 377971dc89a3b26ffcd25b9eb3e8c0c01338ea24..bde216b2071c77b8eb24bd161f1f0b1188c48900 100644 (file)
@@ -1131,6 +1131,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
                     "Don't show entries under that percent", parse_percent_limit),
        OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
                     "How to display percentage of filtered entries", parse_filter_percentage),
+       OPT_STRING('w', "column-widths", &symbol_conf.col_width_list_str,
+                  "width[,width...]",
+                  "don't try to adjust column width, use these fixed values"),
        OPT_END()
        };
        const char * const top_usage[] = {
index a6c375224f4613c27ab72d02799f8632d6db505f..36ae51d61be2d77f2d2873c6bc5d7f447a31941a 100644 (file)
@@ -2209,7 +2209,7 @@ static int trace__replay(struct trace *trace)
        trace->tool.tracing_data = perf_event__process_tracing_data;
        trace->tool.build_id      = perf_event__process_build_id;
 
-       trace->tool.ordered_samples = true;
+       trace->tool.ordered_events = true;
        trace->tool.ordering_requires_timestamps = true;
 
        /* add tid to output */
index 1f67aa02d240b0ba5c3ae53a55f0ecc03fbfb76a..75d4c237b03d00ffdb60c9ba62b82537f7b5099c 100644 (file)
@@ -120,6 +120,29 @@ ifdef PARSER_DEBUG
   CFLAGS             += -DPARSER_DEBUG
 endif
 
+ifndef NO_LIBPYTHON
+  # Try different combinations to accommodate systems that only have
+  # python[2][-config] in weird combinations but always preferring
+  # python2 and python2-config as per pep-0394. If we catch a
+  # python[-config] in version 3, the version check will kill it.
+  PYTHON2 := $(if $(call get-executable,python2),python2,python)
+  override PYTHON := $(call get-executable-or-default,PYTHON,$(PYTHON2))
+  PYTHON2_CONFIG := \
+    $(if $(call get-executable,$(PYTHON)-config),$(PYTHON)-config,python-config)
+  override PYTHON_CONFIG := \
+    $(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON2_CONFIG))
+
+  PYTHON_CONFIG_SQ := $(call shell-sq,$(PYTHON_CONFIG))
+
+  PYTHON_EMBED_LDOPTS := $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null)
+  PYTHON_EMBED_CCOPTS := $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
+
+  FEATURE_CHECK_CFLAGS-libpython := $(PYTHON_EMBED_CCOPTS)
+  FEATURE_CHECK_LDFLAGS-libpython := $(PYTHON_EMBED_LDOPTS)
+  FEATURE_CHECK_CFLAGS-libpython-version := $(PYTHON_EMBED_CCOPTS)
+  FEATURE_CHECK_LDFLAGS-libpython-version := $(PYTHON_EMBED_LDOPTS)
+endif
+
 CFLAGS += -fno-omit-frame-pointer
 CFLAGS += -ggdb3
 CFLAGS += -funwind-tables
@@ -482,21 +505,14 @@ define disable-python_code
   NO_LIBPYTHON := 1
 endef
 
-override PYTHON := \
-  $(call get-executable-or-default,PYTHON,python)
-
-ifndef PYTHON
-  $(call disable-python,python interpreter)
+ifdef NO_LIBPYTHON
+  $(call disable-python)
 else
 
-  PYTHON_WORD := $(call shell-wordify,$(PYTHON))
-
-  ifdef NO_LIBPYTHON
-    $(call disable-python)
+  ifndef PYTHON
+    $(call disable-python,python interpreter)
   else
-
-    override PYTHON_CONFIG := \
-      $(call get-executable-or-default,PYTHON_CONFIG,$(PYTHON)-config)
+    PYTHON_WORD := $(call shell-wordify,$(PYTHON))
 
     ifndef PYTHON_CONFIG
       $(call disable-python,python-config tool)
index 6088f8d8a434a2860031b464caa4dac1ad691fad..72ab2984718e341e0a18f2e4ad0953cc3359a4c6 100644 (file)
@@ -101,25 +101,11 @@ FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
 test-libperl.bin:
        $(BUILD) $(FLAGS_PERL_EMBED)
 
-override PYTHON := python
-override PYTHON_CONFIG := python-config
-
-escape-for-shell-sq =  $(subst ','\'',$(1))
-shell-sq = '$(escape-for-shell-sq)'
-
-PYTHON_CONFIG_SQ = $(call shell-sq,$(PYTHON_CONFIG))
-
-PYTHON_EMBED_LDOPTS = $(shell $(PYTHON_CONFIG_SQ) --ldflags 2>/dev/null)
-PYTHON_EMBED_LDFLAGS = $(call strip-libs,$(PYTHON_EMBED_LDOPTS))
-PYTHON_EMBED_LIBADD = $(call grep-libs,$(PYTHON_EMBED_LDOPTS))
-PYTHON_EMBED_CCOPTS = $(shell $(PYTHON_CONFIG_SQ) --cflags 2>/dev/null)
-FLAGS_PYTHON_EMBED = $(PYTHON_EMBED_CCOPTS) $(PYTHON_EMBED_LDOPTS)
-
 test-libpython.bin:
-       $(BUILD) $(FLAGS_PYTHON_EMBED)
+       $(BUILD)
 
 test-libpython-version.bin:
-       $(BUILD) $(FLAGS_PYTHON_EMBED)
+       $(BUILD)
 
 test-libbfd.bin:
        $(BUILD) -DPACKAGE='"perf"' -lbfd -lz -liberty -ldl
index a94b11fc5e00263bd1adf50a456925fbc895d5aa..045c1e16ac59873a69a3ba4d540284bf37755ded 100644 (file)
@@ -653,17 +653,18 @@ struct hpp_arg {
 static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
 {
        struct hpp_arg *arg = hpp->ptr;
-       int ret;
+       int ret, len;
        va_list args;
        double percent;
 
        va_start(args, fmt);
+       len = va_arg(args, int);
        percent = va_arg(args, double);
        va_end(args);
 
        ui_browser__set_percent_color(arg->b, percent, arg->current_entry);
 
-       ret = scnprintf(hpp->buf, hpp->size, fmt, percent);
+       ret = scnprintf(hpp->buf, hpp->size, fmt, len, percent);
        slsmg_printf("%s", hpp->buf);
 
        advance_hpp(hpp, ret);
@@ -677,12 +678,12 @@ static u64 __hpp_get_##_field(struct hist_entry *he)                      \
 }                                                                      \
                                                                        \
 static int                                                             \
-hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
+hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt,              \
                                struct perf_hpp *hpp,                   \
                                struct hist_entry *he)                  \
 {                                                                      \
-       return __hpp__fmt(hpp, he, __hpp_get_##_field, " %6.2f%%",      \
-                         __hpp__slsmg_color_printf, true);             \
+       return hpp__fmt(fmt, hpp, he, __hpp_get_##_field, " %*.2f%%",   \
+                       __hpp__slsmg_color_printf, true);               \
 }
 
 #define __HPP_COLOR_ACC_PERCENT_FN(_type, _field)                      \
@@ -692,18 +693,20 @@ static u64 __hpp_get_acc_##_field(struct hist_entry *he)          \
 }                                                                      \
                                                                        \
 static int                                                             \
-hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
+hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt,              \
                                struct perf_hpp *hpp,                   \
                                struct hist_entry *he)                  \
 {                                                                      \
        if (!symbol_conf.cumulate_callchain) {                          \
-               int ret = scnprintf(hpp->buf, hpp->size, "%8s", "N/A"); \
+               int len = fmt->user_len ?: fmt->len;                    \
+               int ret = scnprintf(hpp->buf, hpp->size,                \
+                                   "%*s", len, "N/A");                 \
                slsmg_printf("%s", hpp->buf);                           \
                                                                        \
                return ret;                                             \
        }                                                               \
-       return __hpp__fmt(hpp, he, __hpp_get_acc_##_field, " %6.2f%%",  \
-                         __hpp__slsmg_color_printf, true);             \
+       return hpp__fmt(fmt, hpp, he, __hpp_get_acc_##_field,           \
+                       " %*.2f%%", __hpp__slsmg_color_printf, true);   \
 }
 
 __HPP_COLOR_PERCENT_FN(overhead, period)
@@ -847,9 +850,6 @@ static int hists__scnprintf_headers(char *buf, size_t size, struct hists *hists)
                if (perf_hpp__should_skip(fmt))
                        continue;
 
-               /* We need to add the length of the columns header. */
-               perf_hpp__reset_width(fmt, hists);
-
                ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
                if (advance_hpp_check(&dummy_hpp, ret))
                        break;
@@ -1498,6 +1498,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
        char buf[64];
        char script_opt[64];
        int delay_secs = hbt ? hbt->refresh : 0;
+       struct perf_hpp_fmt *fmt;
 
 #define HIST_BROWSER_HELP_COMMON                                       \
        "h/?/F1        Show this window\n"                              \
@@ -1547,6 +1548,12 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
 
        memset(options, 0, sizeof(options));
 
+       perf_hpp__for_each_format(fmt)
+               perf_hpp__reset_width(fmt, hists);
+
+       if (symbol_conf.col_width_list_str)
+               perf_hpp__set_user_width(symbol_conf.col_width_list_str);
+
        while (1) {
                const struct thread *thread = NULL;
                const struct dso *dso = NULL;
index 6ca60e482cdc2594382466bbaecdde12462dfbec..f3fa4258b256b9d3a8c4fb9f570172d96cca47f8 100644 (file)
@@ -11,6 +11,7 @@
 static int __percent_color_snprintf(struct perf_hpp *hpp, const char *fmt, ...)
 {
        int ret = 0;
+       int len;
        va_list args;
        double percent;
        const char *markup;
@@ -18,6 +19,7 @@ static int __percent_color_snprintf(struct perf_hpp *hpp, const char *fmt, ...)
        size_t size = hpp->size;
 
        va_start(args, fmt);
+       len = va_arg(args, int);
        percent = va_arg(args, double);
        va_end(args);
 
@@ -25,7 +27,7 @@ static int __percent_color_snprintf(struct perf_hpp *hpp, const char *fmt, ...)
        if (markup)
                ret += scnprintf(buf, size, markup);
 
-       ret += scnprintf(buf + ret, size - ret, fmt, percent);
+       ret += scnprintf(buf + ret, size - ret, fmt, len, percent);
 
        if (markup)
                ret += scnprintf(buf + ret, size - ret, "</span>");
@@ -39,12 +41,12 @@ static u64 he_get_##_field(struct hist_entry *he)                           \
        return he->stat._field;                                                 \
 }                                                                              \
                                                                                \
-static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,        \
+static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt,               \
                                       struct perf_hpp *hpp,                    \
                                       struct hist_entry *he)                   \
 {                                                                              \
-       return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%",                 \
-                         __percent_color_snprintf, true);                      \
+       return hpp__fmt(fmt, hpp, he, he_get_##_field, " %*.2f%%",              \
+                       __percent_color_snprintf, true);                        \
 }
 
 #define __HPP_COLOR_ACC_PERCENT_FN(_type, _field)                              \
@@ -57,8 +59,8 @@ static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,
                                       struct perf_hpp *hpp,                    \
                                       struct hist_entry *he)                   \
 {                                                                              \
-       return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, " %6.2f%%",         \
-                             __percent_color_snprintf, true);                  \
+       return hpp__fmt_acc(fmt, hpp, he, he_get_acc_##_field, " %*.2f%%",      \
+                           __percent_color_snprintf, true);                    \
 }
 
 __HPP_COLOR_PERCENT_FN(overhead, period)
@@ -205,10 +207,8 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
                if (perf_hpp__is_sort_entry(fmt))
                        sym_col = col_idx;
 
-               fmt->header(fmt, &hpp, hists_to_evsel(hists));
-
                gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
-                                                           -1, ltrim(s),
+                                                           -1, fmt->name,
                                                            renderer, "markup",
                                                            col_idx++, NULL);
        }
index 498adb23c02ef9992f82c840aca5aa31220af9bf..b5fa7019d2e2966e16bb1a4b856ae3c30a4a89b3 100644 (file)
@@ -15,9 +15,9 @@
        __ret;                                                  \
 })
 
-int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
-              hpp_field_fn get_field, const char *fmt,
-              hpp_snprint_fn print_fn, bool fmt_percent)
+static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
+                     hpp_field_fn get_field, const char *fmt, int len,
+                     hpp_snprint_fn print_fn, bool fmt_percent)
 {
        int ret;
        struct hists *hists = he->hists;
@@ -32,9 +32,9 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
                if (total)
                        percent = 100.0 * get_field(he) / total;
 
-               ret = hpp__call_print_fn(hpp, print_fn, fmt, percent);
+               ret = hpp__call_print_fn(hpp, print_fn, fmt, len, percent);
        } else
-               ret = hpp__call_print_fn(hpp, print_fn, fmt, get_field(he));
+               ret = hpp__call_print_fn(hpp, print_fn, fmt, len, get_field(he));
 
        if (perf_evsel__is_group_event(evsel)) {
                int prev_idx, idx_delta;
@@ -60,19 +60,19 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
                                 */
                                if (fmt_percent) {
                                        ret += hpp__call_print_fn(hpp, print_fn,
-                                                                 fmt, 0.0);
+                                                                 fmt, len, 0.0);
                                } else {
                                        ret += hpp__call_print_fn(hpp, print_fn,
-                                                                 fmt, 0ULL);
+                                                                 fmt, len, 0ULL);
                                }
                        }
 
                        if (fmt_percent) {
-                               ret += hpp__call_print_fn(hpp, print_fn, fmt,
+                               ret += hpp__call_print_fn(hpp, print_fn, fmt, len,
                                                          100.0 * period / total);
                        } else {
                                ret += hpp__call_print_fn(hpp, print_fn, fmt,
-                                                         period);
+                                                         len, period);
                        }
 
                        prev_idx = perf_evsel__group_idx(evsel);
@@ -86,10 +86,10 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
                         */
                        if (fmt_percent) {
                                ret += hpp__call_print_fn(hpp, print_fn,
-                                                         fmt, 0.0);
+                                                         fmt, len, 0.0);
                        } else {
                                ret += hpp__call_print_fn(hpp, print_fn,
-                                                         fmt, 0ULL);
+                                                         fmt, len, 0ULL);
                        }
                }
        }
@@ -104,16 +104,35 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
        return ret;
 }
 
-int __hpp__fmt_acc(struct perf_hpp *hpp, struct hist_entry *he,
-                  hpp_field_fn get_field, const char *fmt,
-                  hpp_snprint_fn print_fn, bool fmt_percent)
+int hpp__fmt(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
+            struct hist_entry *he, hpp_field_fn get_field,
+            const char *fmtstr, hpp_snprint_fn print_fn, bool fmt_percent)
+{
+       int len = fmt->user_len ?: fmt->len;
+
+       if (symbol_conf.field_sep) {
+               return __hpp__fmt(hpp, he, get_field, fmtstr, 1,
+                                 print_fn, fmt_percent);
+       }
+
+       if (fmt_percent)
+               len -= 2; /* 2 for a space and a % sign */
+       else
+               len -= 1;
+
+       return  __hpp__fmt(hpp, he, get_field, fmtstr, len, print_fn, fmt_percent);
+}
+
+int hpp__fmt_acc(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
+                struct hist_entry *he, hpp_field_fn get_field,
+                const char *fmtstr, hpp_snprint_fn print_fn, bool fmt_percent)
 {
        if (!symbol_conf.cumulate_callchain) {
-               return snprintf(hpp->buf, hpp->size, "%*s",
-                               fmt_percent ? 8 : 12, "N/A");
+               int len = fmt->user_len ?: fmt->len;
+               return snprintf(hpp->buf, hpp->size, " %*s", len - 1, "N/A");
        }
 
-       return __hpp__fmt(hpp, he, get_field, fmt, print_fn, fmt_percent);
+       return hpp__fmt(fmt, hpp, he, get_field, fmtstr, print_fn, fmt_percent);
 }
 
 static int field_cmp(u64 field_a, u64 field_b)
@@ -190,30 +209,26 @@ static int __hpp__sort_acc(struct hist_entry *a, struct hist_entry *b,
        return ret;
 }
 
-#define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width)          \
-static int hpp__header_##_type(struct perf_hpp_fmt *fmt __maybe_unused,        \
-                              struct perf_hpp *hpp,                    \
-                              struct perf_evsel *evsel)                \
-{                                                                      \
-       int len = _min_width;                                           \
-                                                                       \
-       if (symbol_conf.event_group)                                    \
-               len = max(len, evsel->nr_members * _unit_width);        \
-                                                                       \
-       return scnprintf(hpp->buf, hpp->size, "%*s", len, _str);        \
-}
-
-#define __HPP_WIDTH_FN(_type, _min_width, _unit_width)                         \
-static int hpp__width_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
-                             struct perf_hpp *hpp __maybe_unused,      \
-                             struct perf_evsel *evsel)                 \
-{                                                                      \
-       int len = _min_width;                                           \
-                                                                       \
-       if (symbol_conf.event_group)                                    \
-               len = max(len, evsel->nr_members * _unit_width);        \
-                                                                       \
-       return len;                                                     \
+static int hpp__width_fn(struct perf_hpp_fmt *fmt,
+                        struct perf_hpp *hpp __maybe_unused,
+                        struct perf_evsel *evsel)
+{
+       int len = fmt->user_len ?: fmt->len;
+
+       if (symbol_conf.event_group)
+               len = max(len, evsel->nr_members * fmt->len);
+
+       if (len < (int)strlen(fmt->name))
+               len = strlen(fmt->name);
+
+       return len;
+}
+
+static int hpp__header_fn(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
+                         struct perf_evsel *evsel)
+{
+       int len = hpp__width_fn(fmt, hpp, evsel);
+       return scnprintf(hpp->buf, hpp->size, "%*s", len, fmt->name);
 }
 
 static int hpp_color_scnprintf(struct perf_hpp *hpp, const char *fmt, ...)
@@ -221,11 +236,12 @@ static int hpp_color_scnprintf(struct perf_hpp *hpp, const char *fmt, ...)
        va_list args;
        ssize_t ssize = hpp->size;
        double percent;
-       int ret;
+       int ret, len;
 
        va_start(args, fmt);
+       len = va_arg(args, int);
        percent = va_arg(args, double);
-       ret = value_color_snprintf(hpp->buf, hpp->size, fmt, percent);
+       ret = percent_color_len_snprintf(hpp->buf, hpp->size, fmt, len, percent);
        va_end(args);
 
        return (ret >= ssize) ? (ssize - 1) : ret;
@@ -250,20 +266,19 @@ static u64 he_get_##_field(struct hist_entry *he)                         \
        return he->stat._field;                                                 \
 }                                                                              \
                                                                                \
-static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,         \
+static int hpp__color_##_type(struct perf_hpp_fmt *fmt,                                \
                              struct perf_hpp *hpp, struct hist_entry *he)      \
 {                                                                              \
-       return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%",                 \
-                         hpp_color_scnprintf, true);                           \
+       return hpp__fmt(fmt, hpp, he, he_get_##_field, " %*.2f%%",              \
+                       hpp_color_scnprintf, true);                             \
 }
 
 #define __HPP_ENTRY_PERCENT_FN(_type, _field)                                  \
-static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused,                \
+static int hpp__entry_##_type(struct perf_hpp_fmt *fmt,                                \
                              struct perf_hpp *hpp, struct hist_entry *he)      \
 {                                                                              \
-       const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%";         \
-       return __hpp__fmt(hpp, he, he_get_##_field, fmt,                        \
-                         hpp_entry_scnprintf, true);                           \
+       return hpp__fmt(fmt, hpp, he, he_get_##_field, " %*.2f%%",              \
+                       hpp_entry_scnprintf, true);                             \
 }
 
 #define __HPP_SORT_FN(_type, _field)                                           \
@@ -278,20 +293,19 @@ static u64 he_get_acc_##_field(struct hist_entry *he)                             \
        return he->stat_acc->_field;                                            \
 }                                                                              \
                                                                                \
-static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,         \
+static int hpp__color_##_type(struct perf_hpp_fmt *fmt,                                \
                              struct perf_hpp *hpp, struct hist_entry *he)      \
 {                                                                              \
-       return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, " %6.2f%%",         \
-                             hpp_color_scnprintf, true);                       \
+       return hpp__fmt_acc(fmt, hpp, he, he_get_acc_##_field, " %*.2f%%",      \
+                           hpp_color_scnprintf, true);                         \
 }
 
 #define __HPP_ENTRY_ACC_PERCENT_FN(_type, _field)                              \
-static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused,                \
+static int hpp__entry_##_type(struct perf_hpp_fmt *fmt,                                \
                              struct perf_hpp *hpp, struct hist_entry *he)      \
 {                                                                              \
-       const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%";         \
-       return __hpp__fmt_acc(hpp, he, he_get_acc_##_field, fmt,                \
-                             hpp_entry_scnprintf, true);                       \
+       return hpp__fmt_acc(fmt, hpp, he, he_get_##_field, " %*.2f%%",          \
+                           hpp_entry_scnprintf, true);                         \
 }
 
 #define __HPP_SORT_ACC_FN(_type, _field)                                       \
@@ -306,12 +320,11 @@ static u64 he_get_raw_##_field(struct hist_entry *he)                             \
        return he->stat._field;                                                 \
 }                                                                              \
                                                                                \
-static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused,                \
+static int hpp__entry_##_type(struct perf_hpp_fmt *fmt,                                \
                              struct perf_hpp *hpp, struct hist_entry *he)      \
 {                                                                              \
-       const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64;    \
-       return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt,                    \
-                         hpp_entry_scnprintf, false);                          \
+       return hpp__fmt(fmt, hpp, he, he_get_raw_##_field, " %*"PRIu64,         \
+                       hpp_entry_scnprintf, false);                            \
 }
 
 #define __HPP_SORT_RAW_FN(_type, _field)                                       \
@@ -321,37 +334,29 @@ static int64_t hpp__sort_##_type(struct hist_entry *a, struct hist_entry *b)      \
 }
 
 
-#define HPP_PERCENT_FNS(_type, _str, _field, _min_width, _unit_width)  \
-__HPP_HEADER_FN(_type, _str, _min_width, _unit_width)                  \
-__HPP_WIDTH_FN(_type, _min_width, _unit_width)                         \
+#define HPP_PERCENT_FNS(_type, _field)                                 \
 __HPP_COLOR_PERCENT_FN(_type, _field)                                  \
 __HPP_ENTRY_PERCENT_FN(_type, _field)                                  \
 __HPP_SORT_FN(_type, _field)
 
-#define HPP_PERCENT_ACC_FNS(_type, _str, _field, _min_width, _unit_width)\
-__HPP_HEADER_FN(_type, _str, _min_width, _unit_width)                  \
-__HPP_WIDTH_FN(_type, _min_width, _unit_width)                         \
+#define HPP_PERCENT_ACC_FNS(_type, _field)                             \
 __HPP_COLOR_ACC_PERCENT_FN(_type, _field)                              \
 __HPP_ENTRY_ACC_PERCENT_FN(_type, _field)                              \
 __HPP_SORT_ACC_FN(_type, _field)
 
-#define HPP_RAW_FNS(_type, _str, _field, _min_width, _unit_width)      \
-__HPP_HEADER_FN(_type, _str, _min_width, _unit_width)                  \
-__HPP_WIDTH_FN(_type, _min_width, _unit_width)                         \
+#define HPP_RAW_FNS(_type, _field)                                     \
 __HPP_ENTRY_RAW_FN(_type, _field)                                      \
 __HPP_SORT_RAW_FN(_type, _field)
 
-__HPP_HEADER_FN(overhead_self, "Self", 8, 8)
-
-HPP_PERCENT_FNS(overhead, "Overhead", period, 8, 8)
-HPP_PERCENT_FNS(overhead_sys, "sys", period_sys, 8, 8)
-HPP_PERCENT_FNS(overhead_us, "usr", period_us, 8, 8)
-HPP_PERCENT_FNS(overhead_guest_sys, "guest sys", period_guest_sys, 9, 8)
-HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8)
-HPP_PERCENT_ACC_FNS(overhead_acc, "Children", period, 8, 8)
+HPP_PERCENT_FNS(overhead, period)
+HPP_PERCENT_FNS(overhead_sys, period_sys)
+HPP_PERCENT_FNS(overhead_us, period_us)
+HPP_PERCENT_FNS(overhead_guest_sys, period_guest_sys)
+HPP_PERCENT_FNS(overhead_guest_us, period_guest_us)
+HPP_PERCENT_ACC_FNS(overhead_acc, period)
 
-HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12)
-HPP_RAW_FNS(period, "Period", period, 12, 12)
+HPP_RAW_FNS(samples, nr_events)
+HPP_RAW_FNS(period, period)
 
 static int64_t hpp__nop_cmp(struct hist_entry *a __maybe_unused,
                            struct hist_entry *b __maybe_unused)
@@ -359,47 +364,50 @@ static int64_t hpp__nop_cmp(struct hist_entry *a __maybe_unused,
        return 0;
 }
 
-#define HPP__COLOR_PRINT_FNS(_name)                    \
+#define HPP__COLOR_PRINT_FNS(_name, _fn)               \
        {                                               \
-               .header = hpp__header_ ## _name,        \
-               .width  = hpp__width_ ## _name,         \
-               .color  = hpp__color_ ## _name,         \
-               .entry  = hpp__entry_ ## _name,         \
+               .name   = _name,                        \
+               .header = hpp__header_fn,               \
+               .width  = hpp__width_fn,                \
+               .color  = hpp__color_ ## _fn,           \
+               .entry  = hpp__entry_ ## _fn,           \
                .cmp    = hpp__nop_cmp,                 \
                .collapse = hpp__nop_cmp,               \
-               .sort   = hpp__sort_ ## _name,          \
+               .sort   = hpp__sort_ ## _fn,            \
        }
 
-#define HPP__COLOR_ACC_PRINT_FNS(_name)                        \
+#define HPP__COLOR_ACC_PRINT_FNS(_name, _fn)           \
        {                                               \
-               .header = hpp__header_ ## _name,        \
-               .width  = hpp__width_ ## _name,         \
-               .color  = hpp__color_ ## _name,         \
-               .entry  = hpp__entry_ ## _name,         \
+               .name   = _name,                        \
+               .header = hpp__header_fn,               \
+               .width  = hpp__width_fn,                \
+               .color  = hpp__color_ ## _fn,           \
+               .entry  = hpp__entry_ ## _fn,           \
                .cmp    = hpp__nop_cmp,                 \
                .collapse = hpp__nop_cmp,               \
-               .sort   = hpp__sort_ ## _name,          \
+               .sort   = hpp__sort_ ## _fn,            \
        }
 
-#define HPP__PRINT_FNS(_name)                          \
+#define HPP__PRINT_FNS(_name, _fn)                     \
        {                                               \
-               .header = hpp__header_ ## _name,        \
-               .width  = hpp__width_ ## _name,         \
-               .entry  = hpp__entry_ ## _name,         \
+               .name   = _name,                        \
+               .header = hpp__header_fn,               \
+               .width  = hpp__width_fn,                \
+               .entry  = hpp__entry_ ## _fn,           \
                .cmp    = hpp__nop_cmp,                 \
                .collapse = hpp__nop_cmp,               \
-               .sort   = hpp__sort_ ## _name,          \
+               .sort   = hpp__sort_ ## _fn,            \
        }
 
 struct perf_hpp_fmt perf_hpp__format[] = {
-       HPP__COLOR_PRINT_FNS(overhead),
-       HPP__COLOR_PRINT_FNS(overhead_sys),
-       HPP__COLOR_PRINT_FNS(overhead_us),
-       HPP__COLOR_PRINT_FNS(overhead_guest_sys),
-       HPP__COLOR_PRINT_FNS(overhead_guest_us),
-       HPP__COLOR_ACC_PRINT_FNS(overhead_acc),
-       HPP__PRINT_FNS(samples),
-       HPP__PRINT_FNS(period)
+       HPP__COLOR_PRINT_FNS("Overhead", overhead),
+       HPP__COLOR_PRINT_FNS("sys", overhead_sys),
+       HPP__COLOR_PRINT_FNS("usr", overhead_us),
+       HPP__COLOR_PRINT_FNS("guest sys", overhead_guest_sys),
+       HPP__COLOR_PRINT_FNS("guest usr", overhead_guest_us),
+       HPP__COLOR_ACC_PRINT_FNS("Children", overhead_acc),
+       HPP__PRINT_FNS("Samples", samples),
+       HPP__PRINT_FNS("Period", period)
 };
 
 LIST_HEAD(perf_hpp__list);
@@ -449,9 +457,7 @@ void perf_hpp__init(void)
 
        if (symbol_conf.cumulate_callchain) {
                perf_hpp__column_enable(PERF_HPP__OVERHEAD_ACC);
-
-               perf_hpp__format[PERF_HPP__OVERHEAD].header =
-                                               hpp__header_overhead_self;
+               perf_hpp__format[PERF_HPP__OVERHEAD].name = "Self";
        }
 
        perf_hpp__column_enable(PERF_HPP__OVERHEAD);
@@ -517,7 +523,7 @@ void perf_hpp__cancel_cumulate(void)
                return;
 
        perf_hpp__column_disable(PERF_HPP__OVERHEAD_ACC);
-       perf_hpp__format[PERF_HPP__OVERHEAD].header = hpp__header_overhead;
+       perf_hpp__format[PERF_HPP__OVERHEAD].name = "Overhead";
 }
 
 void perf_hpp__setup_output_field(void)
@@ -622,3 +628,59 @@ unsigned int hists__sort_list_width(struct hists *hists)
 
        return ret;
 }
+
+void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists)
+{
+       int idx;
+
+       if (perf_hpp__is_sort_entry(fmt))
+               return perf_hpp__reset_sort_width(fmt, hists);
+
+       for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) {
+               if (fmt == &perf_hpp__format[idx])
+                       break;
+       }
+
+       if (idx == PERF_HPP__MAX_INDEX)
+               return;
+
+       switch (idx) {
+       case PERF_HPP__OVERHEAD:
+       case PERF_HPP__OVERHEAD_SYS:
+       case PERF_HPP__OVERHEAD_US:
+       case PERF_HPP__OVERHEAD_ACC:
+               fmt->len = 8;
+               break;
+
+       case PERF_HPP__OVERHEAD_GUEST_SYS:
+       case PERF_HPP__OVERHEAD_GUEST_US:
+               fmt->len = 9;
+               break;
+
+       case PERF_HPP__SAMPLES:
+       case PERF_HPP__PERIOD:
+               fmt->len = 12;
+               break;
+
+       default:
+               break;
+       }
+}
+
+void perf_hpp__set_user_width(const char *width_list_str)
+{
+       struct perf_hpp_fmt *fmt;
+       const char *ptr = width_list_str;
+
+       perf_hpp__for_each_format(fmt) {
+               char *p;
+
+               int len = strtol(ptr, &p, 10);
+               fmt->user_len = len;
+
+               if (*p == ',')
+                       ptr = p + 1;
+               else
+                       break;
+       }
+}
index 40af0acb4fe95da232e441ebcb69e0c5f1b601a1..15b451acbde61081eaf22aba07a5da3752a9e205 100644 (file)
@@ -395,10 +395,12 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
 
        init_rem_hits();
 
-
        perf_hpp__for_each_format(fmt)
                perf_hpp__reset_width(fmt, hists);
 
+       if (symbol_conf.col_width_list_str)
+               perf_hpp__set_user_width(symbol_conf.col_width_list_str);
+
        if (!show_header)
                goto print_entries;
 
index 809b4c50beaed3e3a57845919b3a034fe7ab8c9e..7745fec01a6bc2c0e96f5bdbcf51197d5844fb0e 100644 (file)
@@ -899,10 +899,8 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
        struct kcore_extract kce;
        bool delete_extract = false;
 
-       if (filename) {
-               snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
-                        symbol_conf.symfs, filename);
-       }
+       if (filename)
+               symbol__join_symfs(symfs_filename, filename);
 
        if (filename == NULL) {
                if (dso->has_build_id) {
@@ -922,8 +920,7 @@ fallback:
                 * DSO is the same as when 'perf record' ran.
                 */
                filename = (char *)dso->long_name;
-               snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
-                        symbol_conf.symfs, filename);
+               symbol__join_symfs(symfs_filename, filename);
                free_filename = false;
        }
 
index 7b176dd02e1ae94e6f5479b78ae4c2e84bb7836c..5cf9e1b5989de40cb677b1bd744d684cd3bfc871 100644 (file)
@@ -22,6 +22,7 @@ typedef int (*config_fn_t)(const char *, const char *, void *);
 extern int perf_default_config(const char *, const char *, void *);
 extern int perf_config(config_fn_t fn, void *);
 extern int perf_config_int(const char *, const char *);
+extern u64 perf_config_u64(const char *, const char *);
 extern int perf_config_bool(const char *, const char *);
 extern int config_error_nonbool(const char *);
 extern const char *perf_config_dirname(const char *, const char *);
index c5d05ec172206d6d86dd1bdc14edfa29a2d7bd0f..5073c01af6180963dbc544a213a9ee578296d8a2 100644 (file)
@@ -9,7 +9,7 @@ static int perf_flag_probe(void)
 {
        /* use 'safest' configuration as used in perf_evsel__fallback() */
        struct perf_event_attr attr = {
-               .type = PERF_COUNT_SW_CPU_CLOCK,
+               .type = PERF_TYPE_SOFTWARE,
                .config = PERF_COUNT_SW_CPU_CLOCK,
        };
        int fd;
@@ -25,7 +25,7 @@ static int perf_flag_probe(void)
                return 1;
        }
 
-       WARN_ONCE(err != EINVAL,
+       WARN_ONCE(err != EINVAL && err != EBUSY,
                  "perf_event_open(..., PERF_FLAG_FD_CLOEXEC) failed with unexpected error %d (%s)\n",
                  err, strerror(err));
 
@@ -33,7 +33,7 @@ static int perf_flag_probe(void)
        fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
        err = errno;
 
-       if (WARN_ONCE(fd < 0,
+       if (WARN_ONCE(fd < 0 && err != EBUSY,
                      "perf_event_open(..., 0) failed unexpectedly with error %d (%s)\n",
                      err, strerror(err)))
                return -1;
index 87b8672eb4134cab6d29b3a2accda19093edb9aa..f4654183d391a4051a970719229d47b2a9027108 100644 (file)
@@ -335,3 +335,19 @@ int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...)
        va_end(args);
        return value_color_snprintf(bf, size, fmt, percent);
 }
+
+int percent_color_len_snprintf(char *bf, size_t size, const char *fmt, ...)
+{
+       va_list args;
+       int len;
+       double percent;
+       const char *color;
+
+       va_start(args, fmt);
+       len = va_arg(args, int);
+       percent = va_arg(args, double);
+       va_end(args);
+
+       color = get_percent_color(percent);
+       return color_snprintf(bf, size, color, fmt, len, percent);
+}
index 7ff30a62a132296a6f82de9fea62629defa8e658..0a594b8a0c26ab2e0753221ea0ae03e2b63e640e 100644 (file)
@@ -41,6 +41,7 @@ int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...);
 int color_fwrite_lines(FILE *fp, const char *color, size_t count, const char *buf);
 int value_color_snprintf(char *bf, size_t size, const char *fmt, double value);
 int percent_color_snprintf(char *bf, size_t size, const char *fmt, ...);
+int percent_color_len_snprintf(char *bf, size_t size, const char *fmt, ...);
 int percent_color_fprintf(FILE *fp, const char *fmt, double percent);
 const char *get_percent_color(double percent);
 
index 1e5e2e5af6b1d05b18b1f6b92b88c4e62e85f33c..9970b8b0190bbd91f161d95cdf0c6e38ffc72e41 100644 (file)
@@ -286,6 +286,21 @@ static int parse_unit_factor(const char *end, unsigned long *val)
        return 0;
 }
 
+static int perf_parse_llong(const char *value, long long *ret)
+{
+       if (value && *value) {
+               char *end;
+               long long val = strtoll(value, &end, 0);
+               unsigned long factor = 1;
+
+               if (!parse_unit_factor(end, &factor))
+                       return 0;
+               *ret = val * factor;
+               return 1;
+       }
+       return 0;
+}
+
 static int perf_parse_long(const char *value, long *ret)
 {
        if (value && *value) {
@@ -307,6 +322,15 @@ static void die_bad_config(const char *name)
        die("bad config value for '%s'", name);
 }
 
+u64 perf_config_u64(const char *name, const char *value)
+{
+       long long ret = 0;
+
+       if (!perf_parse_llong(value, &ret))
+               die_bad_config(name);
+       return (u64) ret;
+}
+
 int perf_config_int(const char *name, const char *value)
 {
        long ret = 0;
index 71d419362634768f32d22862da4a44952e02edd4..ba357f3226c69533c5d79497e3d2fb2207656514 100644 (file)
 #include "util.h"
 #include "target.h"
 
+#define NSECS_PER_SEC  1000000000ULL
+#define NSECS_PER_USEC 1000ULL
+
 int verbose;
 bool dump_trace = false, quiet = false;
+int debug_ordered_events;
 
 static int _eprintf(int level, int var, const char *fmt, va_list args)
 {
@@ -42,6 +46,35 @@ int eprintf(int level, int var, const char *fmt, ...)
        return ret;
 }
 
+static int __eprintf_time(u64 t, const char *fmt, va_list args)
+{
+       int ret = 0;
+       u64 secs, usecs, nsecs = t;
+
+       secs   = nsecs / NSECS_PER_SEC;
+       nsecs -= secs  * NSECS_PER_SEC;
+       usecs  = nsecs / NSECS_PER_USEC;
+
+       ret = fprintf(stderr, "[%13" PRIu64 ".%06" PRIu64 "] ",
+                     secs, usecs);
+       ret += vfprintf(stderr, fmt, args);
+       return ret;
+}
+
+int eprintf_time(int level, int var, u64 t, const char *fmt, ...)
+{
+       int ret = 0;
+       va_list args;
+
+       if (var >= level) {
+               va_start(args, fmt);
+               ret = __eprintf_time(t, fmt, args);
+               va_end(args);
+       }
+
+       return ret;
+}
+
 /*
  * Overloading libtraceevent standard info print
  * function, display with -v in perf.
@@ -110,7 +143,8 @@ static struct debug_variable {
        const char *name;
        int *ptr;
 } debug_variables[] = {
-       { .name = "verbose", .ptr = &verbose },
+       { .name = "verbose",            .ptr = &verbose },
+       { .name = "ordered-events",     .ptr = &debug_ordered_events},
        { .name = NULL, }
 };
 
index 89fb6b0f7ab221d746163b5bb842ce6bf5416fad..6944ea3a119b5f784adf9b02b755f06ea3f5ae6a 100644 (file)
@@ -10,6 +10,7 @@
 
 extern int verbose;
 extern bool quiet, dump_trace;
+extern int debug_ordered_events;
 
 #ifndef pr_fmt
 #define pr_fmt(fmt) fmt
@@ -29,6 +30,12 @@ extern bool quiet, dump_trace;
 #define pr_debug3(fmt, ...) pr_debugN(3, pr_fmt(fmt), ##__VA_ARGS__)
 #define pr_debug4(fmt, ...) pr_debugN(4, pr_fmt(fmt), ##__VA_ARGS__)
 
+#define pr_time_N(n, var, t, fmt, ...) \
+       eprintf_time(n, var, t, fmt, ##__VA_ARGS__)
+
+#define pr_oe_time(t, fmt, ...)  pr_time_N(1, debug_ordered_events, t, pr_fmt(fmt), ##__VA_ARGS__)
+#define pr_oe_time2(t, fmt, ...) pr_time_N(2, debug_ordered_events, t, pr_fmt(fmt), ##__VA_ARGS__)
+
 int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
 void trace_event(union perf_event *event);
 
@@ -38,6 +45,7 @@ int ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2)));
 void pr_stat(const char *fmt, ...);
 
 int eprintf(int level, int var, const char *fmt, ...) __attribute__((format(printf, 3, 4)));
+int eprintf_time(int level, int var, u64 t, const char *fmt, ...) __attribute__((format(printf, 4, 5)));
 
 int perf_debug_option(const char *str);
 
index 90d02c661dd4b5087e4f00759c08cab5290abb9a..bdafd306fb525041ed7aa8634e7ab277e79dd822 100644 (file)
@@ -37,6 +37,7 @@ int dso__read_binary_type_filename(const struct dso *dso,
 {
        char build_id_hex[BUILD_ID_SIZE * 2 + 1];
        int ret = 0;
+       size_t len;
 
        switch (type) {
        case DSO_BINARY_TYPE__DEBUGLINK: {
@@ -60,26 +61,25 @@ int dso__read_binary_type_filename(const struct dso *dso,
                break;
 
        case DSO_BINARY_TYPE__FEDORA_DEBUGINFO:
-               snprintf(filename, size, "%s/usr/lib/debug%s.debug",
-                        symbol_conf.symfs, dso->long_name);
+               len = __symbol__join_symfs(filename, size, "/usr/lib/debug");
+               snprintf(filename + len, size - len, "%s.debug", dso->long_name);
                break;
 
        case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO:
-               snprintf(filename, size, "%s/usr/lib/debug%s",
-                        symbol_conf.symfs, dso->long_name);
+               len = __symbol__join_symfs(filename, size, "/usr/lib/debug");
+               snprintf(filename + len, size - len, "%s", dso->long_name);
                break;
 
        case DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO:
        {
                const char *last_slash;
-               size_t len;
                size_t dir_size;
 
                last_slash = dso->long_name + dso->long_name_len;
                while (last_slash != dso->long_name && *last_slash != '/')
                        last_slash--;
 
-               len = scnprintf(filename, size, "%s", symbol_conf.symfs);
+               len = __symbol__join_symfs(filename, size, "");
                dir_size = last_slash - dso->long_name + 2;
                if (dir_size > (size - len)) {
                        ret = -1;
@@ -100,26 +100,24 @@ int dso__read_binary_type_filename(const struct dso *dso,
                build_id__sprintf(dso->build_id,
                                  sizeof(dso->build_id),
                                  build_id_hex);
-               snprintf(filename, size,
-                        "%s/usr/lib/debug/.build-id/%.2s/%s.debug",
-                        symbol_conf.symfs, build_id_hex, build_id_hex + 2);
+               len = __symbol__join_symfs(filename, size, "/usr/lib/debug/.build-id/");
+               snprintf(filename + len, size - len, "%.2s/%s.debug",
+                        build_id_hex, build_id_hex + 2);
                break;
 
        case DSO_BINARY_TYPE__VMLINUX:
        case DSO_BINARY_TYPE__GUEST_VMLINUX:
        case DSO_BINARY_TYPE__SYSTEM_PATH_DSO:
-               snprintf(filename, size, "%s%s",
-                        symbol_conf.symfs, dso->long_name);
+               __symbol__join_symfs(filename, size, dso->long_name);
                break;
 
        case DSO_BINARY_TYPE__GUEST_KMODULE:
-               snprintf(filename, size, "%s%s%s", symbol_conf.symfs,
-                        root_dir, dso->long_name);
+               path__join3(filename, size, symbol_conf.symfs,
+                           root_dir, dso->long_name);
                break;
 
        case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
-               snprintf(filename, size, "%s%s", symbol_conf.symfs,
-                        dso->long_name);
+               __symbol__join_symfs(filename, size, dso->long_name);
                break;
 
        case DSO_BINARY_TYPE__KCORE:
index 814e954c1318ed04ed1bcf9666927f6a4c64e426..3b366c085021781aefd1e6a4f8c1cc40b299310d 100644 (file)
@@ -1061,6 +1061,8 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *tar
        }
 
        if (!evlist->workload.pid) {
+               int ret;
+
                if (pipe_output)
                        dup2(2, 1);
 
@@ -1078,8 +1080,22 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *tar
                /*
                 * Wait until the parent tells us to go.
                 */
-               if (read(go_pipe[0], &bf, 1) == -1)
-                       perror("unable to read pipe");
+               ret = read(go_pipe[0], &bf, 1);
+               /*
+                * The parent will ask for the execvp() to be performed by
+                * writing exactly one byte, in workload.cork_fd, usually via
+                * perf_evlist__start_workload().
+                *
+                * For cancelling the workload without actuallin running it,
+                * the parent will just close workload.cork_fd, without writing
+                * anything, i.e. read will return zero and we just exit()
+                * here.
+                */
+               if (ret != 1) {
+                       if (ret == -1)
+                               perror("unable to read pipe");
+                       exit(ret);
+               }
 
                execvp(argv[0], (char **)argv);
 
index 21a373ebea226a8208c3ccf2aaee9ad92ad4156d..0c8919decac8d591f426e8a007aa248e53f1706d 100644 (file)
@@ -633,9 +633,12 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
        if (opts->period)
                perf_evsel__set_sample_bit(evsel, PERIOD);
 
-       if (!perf_missing_features.sample_id_all &&
-           (opts->sample_time || !opts->no_inherit ||
-            target__has_cpu(&opts->target) || per_cpu))
+       /*
+        * When the user explicitely disabled time don't force it here.
+        */
+       if (opts->sample_time &&
+           (!perf_missing_features.sample_id_all &&
+           (!opts->no_inherit || target__has_cpu(&opts->target) || per_cpu)))
                perf_evsel__set_sample_bit(evsel, TIME);
 
        if (opts->raw_samples && !evsel->no_aux_samples) {
@@ -2036,6 +2039,12 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target,
        "No APIC? If so then you can boot the kernel with the \"lapic\" boot parameter to force-enable it.");
 #endif
                break;
+       case EBUSY:
+               if (find_process("oprofiled"))
+                       return scnprintf(msg, size,
+       "The PMU counters are busy/taken by another profiler.\n"
+       "We found oprofile daemon running, please stop it and try again.");
+               break;
        default:
                break;
        }
index 742f49a85725733e90f7342ca5f7728946574be8..95405a8fbd9525484eeaae75e88897b7eb2fd20a 100644 (file)
@@ -192,6 +192,7 @@ struct perf_hpp {
 };
 
 struct perf_hpp_fmt {
+       const char *name;
        int (*header)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
                      struct perf_evsel *evsel);
        int (*width)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
@@ -207,6 +208,8 @@ struct perf_hpp_fmt {
        struct list_head list;
        struct list_head sort_list;
        bool elide;
+       int len;
+       int user_len;
 };
 
 extern struct list_head perf_hpp__list;
@@ -261,17 +264,19 @@ static inline bool perf_hpp__should_skip(struct perf_hpp_fmt *format)
 }
 
 void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists);
+void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists);
+void perf_hpp__set_user_width(const char *width_list_str);
 
 typedef u64 (*hpp_field_fn)(struct hist_entry *he);
 typedef int (*hpp_callback_fn)(struct perf_hpp *hpp, bool front);
 typedef int (*hpp_snprint_fn)(struct perf_hpp *hpp, const char *fmt, ...);
 
-int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
-              hpp_field_fn get_field, const char *fmt,
-              hpp_snprint_fn print_fn, bool fmt_percent);
-int __hpp__fmt_acc(struct perf_hpp *hpp, struct hist_entry *he,
-                  hpp_field_fn get_field, const char *fmt,
-                  hpp_snprint_fn print_fn, bool fmt_percent);
+int hpp__fmt(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
+            struct hist_entry *he, hpp_field_fn get_field,
+            const char *fmtstr, hpp_snprint_fn print_fn, bool fmt_percent);
+int hpp__fmt_acc(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
+                struct hist_entry *he, hpp_field_fn get_field,
+                const char *fmtstr, hpp_snprint_fn print_fn, bool fmt_percent);
 
 static inline void advance_hpp(struct perf_hpp *hpp, int inc)
 {
diff --git a/tools/perf/util/ordered-events.c b/tools/perf/util/ordered-events.c
new file mode 100644 (file)
index 0000000..706ce1a
--- /dev/null
@@ -0,0 +1,245 @@
+#include <linux/list.h>
+#include <linux/compiler.h>
+#include "ordered-events.h"
+#include "evlist.h"
+#include "session.h"
+#include "asm/bug.h"
+#include "debug.h"
+
+#define pr_N(n, fmt, ...) \
+       eprintf(n, debug_ordered_events, fmt, ##__VA_ARGS__)
+
+#define pr(fmt, ...) pr_N(1, pr_fmt(fmt), ##__VA_ARGS__)
+
+static void queue_event(struct ordered_events *oe, struct ordered_event *new)
+{
+       struct ordered_event *last = oe->last;
+       u64 timestamp = new->timestamp;
+       struct list_head *p;
+
+       ++oe->nr_events;
+       oe->last = new;
+
+       pr_oe_time2(timestamp, "queue_event nr_events %u\n", oe->nr_events);
+
+       if (!last) {
+               list_add(&new->list, &oe->events);
+               oe->max_timestamp = timestamp;
+               return;
+       }
+
+       /*
+        * last event might point to some random place in the list as it's
+        * the last queued event. We expect that the new event is close to
+        * this.
+        */
+       if (last->timestamp <= timestamp) {
+               while (last->timestamp <= timestamp) {
+                       p = last->list.next;
+                       if (p == &oe->events) {
+                               list_add_tail(&new->list, &oe->events);
+                               oe->max_timestamp = timestamp;
+                               return;
+                       }
+                       last = list_entry(p, struct ordered_event, list);
+               }
+               list_add_tail(&new->list, &last->list);
+       } else {
+               while (last->timestamp > timestamp) {
+                       p = last->list.prev;
+                       if (p == &oe->events) {
+                               list_add(&new->list, &oe->events);
+                               return;
+                       }
+                       last = list_entry(p, struct ordered_event, list);
+               }
+               list_add(&new->list, &last->list);
+       }
+}
+
+#define MAX_SAMPLE_BUFFER      (64 * 1024 / sizeof(struct ordered_event))
+static struct ordered_event *alloc_event(struct ordered_events *oe)
+{
+       struct list_head *cache = &oe->cache;
+       struct ordered_event *new = NULL;
+
+       if (!list_empty(cache)) {
+               new = list_entry(cache->next, struct ordered_event, list);
+               list_del(&new->list);
+       } else if (oe->buffer) {
+               new = oe->buffer + oe->buffer_idx;
+               if (++oe->buffer_idx == MAX_SAMPLE_BUFFER)
+                       oe->buffer = NULL;
+       } else if (oe->cur_alloc_size < oe->max_alloc_size) {
+               size_t size = MAX_SAMPLE_BUFFER * sizeof(*new);
+
+               oe->buffer = malloc(size);
+               if (!oe->buffer)
+                       return NULL;
+
+               pr("alloc size %" PRIu64 "B (+%zu), max %" PRIu64 "B\n",
+                  oe->cur_alloc_size, size, oe->max_alloc_size);
+
+               oe->cur_alloc_size += size;
+               list_add(&oe->buffer->list, &oe->to_free);
+
+               /* First entry is abused to maintain the to_free list. */
+               oe->buffer_idx = 2;
+               new = oe->buffer + 1;
+       } else {
+               pr("allocation limit reached %" PRIu64 "B\n", oe->max_alloc_size);
+       }
+
+       return new;
+}
+
+struct ordered_event *
+ordered_events__new(struct ordered_events *oe, u64 timestamp)
+{
+       struct ordered_event *new;
+
+       new = alloc_event(oe);
+       if (new) {
+               new->timestamp = timestamp;
+               queue_event(oe, new);
+       }
+
+       return new;
+}
+
+void ordered_events__delete(struct ordered_events *oe, struct ordered_event *event)
+{
+       list_move(&event->list, &oe->cache);
+       oe->nr_events--;
+}
+
+static int __ordered_events__flush(struct perf_session *s,
+                                  struct perf_tool *tool)
+{
+       struct ordered_events *oe = &s->ordered_events;
+       struct list_head *head = &oe->events;
+       struct ordered_event *tmp, *iter;
+       struct perf_sample sample;
+       u64 limit = oe->next_flush;
+       u64 last_ts = oe->last ? oe->last->timestamp : 0ULL;
+       bool show_progress = limit == ULLONG_MAX;
+       struct ui_progress prog;
+       int ret;
+
+       if (!tool->ordered_events || !limit)
+               return 0;
+
+       if (show_progress)
+               ui_progress__init(&prog, oe->nr_events, "Processing time ordered events...");
+
+       list_for_each_entry_safe(iter, tmp, head, list) {
+               if (session_done())
+                       return 0;
+
+               if (iter->timestamp > limit)
+                       break;
+
+               ret = perf_evlist__parse_sample(s->evlist, iter->event, &sample);
+               if (ret)
+                       pr_err("Can't parse sample, err = %d\n", ret);
+               else {
+                       ret = perf_session__deliver_event(s, iter->event, &sample, tool,
+                                                         iter->file_offset);
+                       if (ret)
+                               return ret;
+               }
+
+               ordered_events__delete(oe, iter);
+               oe->last_flush = iter->timestamp;
+
+               if (show_progress)
+                       ui_progress__update(&prog, 1);
+       }
+
+       if (list_empty(head))
+               oe->last = NULL;
+       else if (last_ts <= limit)
+               oe->last = list_entry(head->prev, struct ordered_event, list);
+
+       return 0;
+}
+
+int ordered_events__flush(struct perf_session *s, struct perf_tool *tool,
+                         enum oe_flush how)
+{
+       struct ordered_events *oe = &s->ordered_events;
+       static const char * const str[] = {
+               "NONE",
+               "FINAL",
+               "ROUND",
+               "HALF ",
+       };
+       int err;
+
+       switch (how) {
+       case OE_FLUSH__FINAL:
+               oe->next_flush = ULLONG_MAX;
+               break;
+
+       case OE_FLUSH__HALF:
+       {
+               struct ordered_event *first, *last;
+               struct list_head *head = &oe->events;
+
+               first = list_entry(head->next, struct ordered_event, list);
+               last = oe->last;
+
+               /* Warn if we are called before any event got allocated. */
+               if (WARN_ONCE(!last || list_empty(head), "empty queue"))
+                       return 0;
+
+               oe->next_flush  = first->timestamp;
+               oe->next_flush += (last->timestamp - first->timestamp) / 2;
+               break;
+       }
+
+       case OE_FLUSH__ROUND:
+       case OE_FLUSH__NONE:
+       default:
+               break;
+       };
+
+       pr_oe_time(oe->next_flush, "next_flush - ordered_events__flush PRE  %s, nr_events %u\n",
+                  str[how], oe->nr_events);
+       pr_oe_time(oe->max_timestamp, "max_timestamp\n");
+
+       err = __ordered_events__flush(s, tool);
+
+       if (!err) {
+               if (how == OE_FLUSH__ROUND)
+                       oe->next_flush = oe->max_timestamp;
+
+               oe->last_flush_type = how;
+       }
+
+       pr_oe_time(oe->next_flush, "next_flush - ordered_events__flush POST %s, nr_events %u\n",
+                  str[how], oe->nr_events);
+       pr_oe_time(oe->last_flush, "last_flush\n");
+
+       return err;
+}
+
+void ordered_events__init(struct ordered_events *oe)
+{
+       INIT_LIST_HEAD(&oe->events);
+       INIT_LIST_HEAD(&oe->cache);
+       INIT_LIST_HEAD(&oe->to_free);
+       oe->max_alloc_size = (u64) -1;
+       oe->cur_alloc_size = 0;
+}
+
+void ordered_events__free(struct ordered_events *oe)
+{
+       while (!list_empty(&oe->to_free)) {
+               struct ordered_event *event;
+
+               event = list_entry(oe->to_free.next, struct ordered_event, list);
+               list_del(&event->list);
+               free(event);
+       }
+}
diff --git a/tools/perf/util/ordered-events.h b/tools/perf/util/ordered-events.h
new file mode 100644 (file)
index 0000000..3b2f205
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef __ORDERED_EVENTS_H
+#define __ORDERED_EVENTS_H
+
+#include <linux/types.h>
+#include "tool.h"
+
+struct perf_session;
+
+struct ordered_event {
+       u64                     timestamp;
+       u64                     file_offset;
+       union perf_event        *event;
+       struct list_head        list;
+};
+
+enum oe_flush {
+       OE_FLUSH__NONE,
+       OE_FLUSH__FINAL,
+       OE_FLUSH__ROUND,
+       OE_FLUSH__HALF,
+};
+
+struct ordered_events {
+       u64                     last_flush;
+       u64                     next_flush;
+       u64                     max_timestamp;
+       u64                     max_alloc_size;
+       u64                     cur_alloc_size;
+       struct list_head        events;
+       struct list_head        cache;
+       struct list_head        to_free;
+       struct ordered_event    *buffer;
+       struct ordered_event    *last;
+       int                     buffer_idx;
+       unsigned int            nr_events;
+       enum oe_flush           last_flush_type;
+};
+
+struct ordered_event *ordered_events__new(struct ordered_events *oe, u64 timestamp);
+void ordered_events__delete(struct ordered_events *oe, struct ordered_event *event);
+int ordered_events__flush(struct perf_session *s, struct perf_tool *tool,
+                         enum oe_flush how);
+void ordered_events__init(struct ordered_events *oe);
+void ordered_events__free(struct ordered_events *oe);
+
+static inline
+void ordered_events__set_alloc_size(struct ordered_events *oe, u64 size)
+{
+       oe->max_alloc_size = size;
+}
+#endif /* __ORDERED_EVENTS_H */
index 88dfef70c13dbeb4ae75635e35762da5b19a974d..7e27f1eb260cf86118d551d3d0b82f0b0278d1c6 100644 (file)
@@ -14,6 +14,7 @@
 #include "util.h"
 #include "cpumap.h"
 #include "perf_regs.h"
+#include "asm/bug.h"
 
 static int perf_session__open(struct perf_session *session)
 {
@@ -75,9 +76,7 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
                goto out;
 
        session->repipe = repipe;
-       INIT_LIST_HEAD(&session->ordered_samples.samples);
-       INIT_LIST_HEAD(&session->ordered_samples.sample_cache);
-       INIT_LIST_HEAD(&session->ordered_samples.to_free);
+       ordered_events__init(&session->ordered_events);
        machines__init(&session->machines);
 
        if (file) {
@@ -104,9 +103,9 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
        }
 
        if (tool && tool->ordering_requires_timestamps &&
-           tool->ordered_samples && !perf_evlist__sample_id_all(session->evlist)) {
+           tool->ordered_events && !perf_evlist__sample_id_all(session->evlist)) {
                dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n");
-               tool->ordered_samples = false;
+               tool->ordered_events = false;
        }
 
        return session;
@@ -238,7 +237,7 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
        if (tool->build_id == NULL)
                tool->build_id = process_finished_round_stub;
        if (tool->finished_round == NULL) {
-               if (tool->ordered_samples)
+               if (tool->ordered_events)
                        tool->finished_round = process_finished_round;
                else
                        tool->finished_round = process_finished_round_stub;
@@ -444,87 +443,6 @@ static perf_event__swap_op perf_event__swap_ops[] = {
        [PERF_RECORD_HEADER_MAX]          = NULL,
 };
 
-struct sample_queue {
-       u64                     timestamp;
-       u64                     file_offset;
-       union perf_event        *event;
-       struct list_head        list;
-};
-
-static void perf_session_free_sample_buffers(struct perf_session *session)
-{
-       struct ordered_samples *os = &session->ordered_samples;
-
-       while (!list_empty(&os->to_free)) {
-               struct sample_queue *sq;
-
-               sq = list_entry(os->to_free.next, struct sample_queue, list);
-               list_del(&sq->list);
-               free(sq);
-       }
-}
-
-static int perf_session_deliver_event(struct perf_session *session,
-                                     union perf_event *event,
-                                     struct perf_sample *sample,
-                                     struct perf_tool *tool,
-                                     u64 file_offset);
-
-static int flush_sample_queue(struct perf_session *s,
-                      struct perf_tool *tool)
-{
-       struct ordered_samples *os = &s->ordered_samples;
-       struct list_head *head = &os->samples;
-       struct sample_queue *tmp, *iter;
-       struct perf_sample sample;
-       u64 limit = os->next_flush;
-       u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL;
-       bool show_progress = limit == ULLONG_MAX;
-       struct ui_progress prog;
-       int ret;
-
-       if (!tool->ordered_samples || !limit)
-               return 0;
-
-       if (show_progress)
-               ui_progress__init(&prog, os->nr_samples, "Processing time ordered events...");
-
-       list_for_each_entry_safe(iter, tmp, head, list) {
-               if (session_done())
-                       return 0;
-
-               if (iter->timestamp > limit)
-                       break;
-
-               ret = perf_evlist__parse_sample(s->evlist, iter->event, &sample);
-               if (ret)
-                       pr_err("Can't parse sample, err = %d\n", ret);
-               else {
-                       ret = perf_session_deliver_event(s, iter->event, &sample, tool,
-                                                        iter->file_offset);
-                       if (ret)
-                               return ret;
-               }
-
-               os->last_flush = iter->timestamp;
-               list_del(&iter->list);
-               list_add(&iter->list, &os->sample_cache);
-               os->nr_samples--;
-
-               if (show_progress)
-                       ui_progress__update(&prog, 1);
-       }
-
-       if (list_empty(head)) {
-               os->last_sample = NULL;
-       } else if (last_ts <= limit) {
-               os->last_sample =
-                       list_entry(head->prev, struct sample_queue, list);
-       }
-
-       return 0;
-}
-
 /*
  * When perf record finishes a pass on every buffers, it records this pseudo
  * event.
@@ -568,99 +486,43 @@ static int process_finished_round(struct perf_tool *tool,
                                  union perf_event *event __maybe_unused,
                                  struct perf_session *session)
 {
-       int ret = flush_sample_queue(session, tool);
-       if (!ret)
-               session->ordered_samples.next_flush = session->ordered_samples.max_timestamp;
-
-       return ret;
-}
-
-/* The queue is ordered by time */
-static void __queue_event(struct sample_queue *new, struct perf_session *s)
-{
-       struct ordered_samples *os = &s->ordered_samples;
-       struct sample_queue *sample = os->last_sample;
-       u64 timestamp = new->timestamp;
-       struct list_head *p;
-
-       ++os->nr_samples;
-       os->last_sample = new;
-
-       if (!sample) {
-               list_add(&new->list, &os->samples);
-               os->max_timestamp = timestamp;
-               return;
-       }
-
-       /*
-        * last_sample might point to some random place in the list as it's
-        * the last queued event. We expect that the new event is close to
-        * this.
-        */
-       if (sample->timestamp <= timestamp) {
-               while (sample->timestamp <= timestamp) {
-                       p = sample->list.next;
-                       if (p == &os->samples) {
-                               list_add_tail(&new->list, &os->samples);
-                               os->max_timestamp = timestamp;
-                               return;
-                       }
-                       sample = list_entry(p, struct sample_queue, list);
-               }
-               list_add_tail(&new->list, &sample->list);
-       } else {
-               while (sample->timestamp > timestamp) {
-                       p = sample->list.prev;
-                       if (p == &os->samples) {
-                               list_add(&new->list, &os->samples);
-                               return;
-                       }
-                       sample = list_entry(p, struct sample_queue, list);
-               }
-               list_add(&new->list, &sample->list);
-       }
+       return ordered_events__flush(session, tool, OE_FLUSH__ROUND);
 }
 
-#define MAX_SAMPLE_BUFFER      (64 * 1024 / sizeof(struct sample_queue))
-
 int perf_session_queue_event(struct perf_session *s, union perf_event *event,
-                                   struct perf_sample *sample, u64 file_offset)
+                            struct perf_tool *tool, struct perf_sample *sample,
+                            u64 file_offset)
 {
-       struct ordered_samples *os = &s->ordered_samples;
-       struct list_head *sc = &os->sample_cache;
+       struct ordered_events *oe = &s->ordered_events;
        u64 timestamp = sample->time;
-       struct sample_queue *new;
+       struct ordered_event *new;
 
        if (!timestamp || timestamp == ~0ULL)
                return -ETIME;
 
-       if (timestamp < s->ordered_samples.last_flush) {
-               printf("Warning: Timestamp below last timeslice flush\n");
-               return -EINVAL;
+       if (timestamp < oe->last_flush) {
+               WARN_ONCE(1, "Timestamp below last timeslice flush\n");
+
+               pr_oe_time(timestamp,      "out of order event");
+               pr_oe_time(oe->last_flush, "last flush, last_flush_type %d\n",
+                          oe->last_flush_type);
+
+               /* We could get out of order messages after forced flush. */
+               if (oe->last_flush_type != OE_FLUSH__HALF)
+                       return -EINVAL;
        }
 
-       if (!list_empty(sc)) {
-               new = list_entry(sc->next, struct sample_queue, list);
-               list_del(&new->list);
-       } else if (os->sample_buffer) {
-               new = os->sample_buffer + os->sample_buffer_idx;
-               if (++os->sample_buffer_idx == MAX_SAMPLE_BUFFER)
-                       os->sample_buffer = NULL;
-       } else {
-               os->sample_buffer = malloc(MAX_SAMPLE_BUFFER * sizeof(*new));
-               if (!os->sample_buffer)
-                       return -ENOMEM;
-               list_add(&os->sample_buffer->list, &os->to_free);
-               os->sample_buffer_idx = 2;
-               new = os->sample_buffer + 1;
+       new = ordered_events__new(oe, timestamp);
+       if (!new) {
+               ordered_events__flush(s, tool, OE_FLUSH__HALF);
+               new = ordered_events__new(oe, timestamp);
        }
 
-       new->timestamp = timestamp;
+       if (!new)
+               return -ENOMEM;
+
        new->file_offset = file_offset;
        new->event = event;
-
-       __queue_event(new, s);
-
        return 0;
 }
 
@@ -920,11 +782,10 @@ perf_session__deliver_sample(struct perf_session *session,
                                            &sample->read.one, machine);
 }
 
-static int perf_session_deliver_event(struct perf_session *session,
-                                     union perf_event *event,
-                                     struct perf_sample *sample,
-                                     struct perf_tool *tool,
-                                     u64 file_offset)
+int perf_session__deliver_event(struct perf_session *session,
+                               union perf_event *event,
+                               struct perf_sample *sample,
+                               struct perf_tool *tool, u64 file_offset)
 {
        struct perf_evsel *evsel;
        struct machine *machine;
@@ -1062,15 +923,15 @@ static s64 perf_session__process_event(struct perf_session *session,
        if (ret)
                return ret;
 
-       if (tool->ordered_samples) {
-               ret = perf_session_queue_event(session, event, &sample,
+       if (tool->ordered_events) {
+               ret = perf_session_queue_event(session, event, tool, &sample,
                                               file_offset);
                if (ret != -ETIME)
                        return ret;
        }
 
-       return perf_session_deliver_event(session, event, &sample, tool,
-                                         file_offset);
+       return perf_session__deliver_event(session, event, &sample, tool,
+                                          file_offset);
 }
 
 void perf_event_header__bswap(struct perf_event_header *hdr)
@@ -1222,12 +1083,11 @@ more:
                goto more;
 done:
        /* do the final flush for ordered samples */
-       session->ordered_samples.next_flush = ULLONG_MAX;
-       err = flush_sample_queue(session, tool);
+       err = ordered_events__flush(session, tool, OE_FLUSH__FINAL);
 out_err:
        free(buf);
        perf_session__warn_about_errors(session, tool);
-       perf_session_free_sample_buffers(session);
+       ordered_events__free(&session->ordered_events);
        return err;
 }
 
@@ -1368,12 +1228,11 @@ more:
 
 out:
        /* do the final flush for ordered samples */
-       session->ordered_samples.next_flush = ULLONG_MAX;
-       err = flush_sample_queue(session, tool);
+       err = ordered_events__flush(session, tool, OE_FLUSH__FINAL);
 out_err:
        ui_progress__finish();
        perf_session__warn_about_errors(session, tool);
-       perf_session_free_sample_buffers(session);
+       ordered_events__free(&session->ordered_events);
        session->one_mmap = false;
        return err;
 }
index 0321013bd9fde625f823fb2d15923cefc3eea965..0630e658f8beadb4736f4637d5531bf621e07083 100644 (file)
@@ -9,26 +9,13 @@
 #include "symbol.h"
 #include "thread.h"
 #include "data.h"
+#include "ordered-events.h"
 #include <linux/rbtree.h>
 #include <linux/perf_event.h>
 
-struct sample_queue;
 struct ip_callchain;
 struct thread;
 
-struct ordered_samples {
-       u64                     last_flush;
-       u64                     next_flush;
-       u64                     max_timestamp;
-       struct list_head        samples;
-       struct list_head        sample_cache;
-       struct list_head        to_free;
-       struct sample_queue     *sample_buffer;
-       struct sample_queue     *last_sample;
-       int                     sample_buffer_idx;
-       unsigned int            nr_samples;
-};
-
 struct perf_session {
        struct perf_header      header;
        struct machines         machines;
@@ -39,7 +26,7 @@ struct perf_session {
        bool                    one_mmap;
        void                    *one_mmap_addr;
        u64                     one_mmap_offset;
-       struct ordered_samples  ordered_samples;
+       struct ordered_events   ordered_events;
        struct perf_data_file   *file;
 };
 
@@ -65,10 +52,16 @@ int perf_session__process_events(struct perf_session *session,
                                 struct perf_tool *tool);
 
 int perf_session_queue_event(struct perf_session *s, union perf_event *event,
-                            struct perf_sample *sample, u64 file_offset);
+                            struct perf_tool *tool, struct perf_sample *sample,
+                            u64 file_offset);
 
 void perf_tool__fill_defaults(struct perf_tool *tool);
 
+int perf_session__deliver_event(struct perf_session *session,
+                               union perf_event *event,
+                               struct perf_sample *sample,
+                               struct perf_tool *tool, u64 file_offset);
+
 int perf_session__resolve_callchain(struct perf_session *session,
                                    struct perf_evsel *evsel,
                                    struct thread *thread,
index 14e5a039bc4546652ee9332dcc2751225ffaa4a8..b4a805e5e44035fe26c2689b8eb29f0f7497a791 100644 (file)
@@ -70,12 +70,14 @@ static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf,
                                       size_t size, unsigned int width)
 {
        const char *comm = thread__comm_str(he->thread);
-       return repsep_snprintf(bf, size, "%*s:%5d", width - 6,
-                              comm ?: "", he->thread->tid);
+
+       width = max(7U, width) - 6;
+       return repsep_snprintf(bf, size, "%5d:%-*.*s", he->thread->tid,
+                              width, width, comm ?: "");
 }
 
 struct sort_entry sort_thread = {
-       .se_header      = "Command:  Pid",
+       .se_header      = "  Pid:Command",
        .se_cmp         = sort__thread_cmp,
        .se_snprintf    = hist_entry__thread_snprintf,
        .se_width_idx   = HISTC_THREAD,
@@ -106,7 +108,7 @@ sort__comm_sort(struct hist_entry *left, struct hist_entry *right)
 static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
                                     size_t size, unsigned int width)
 {
-       return repsep_snprintf(bf, size, "%*s", width, comm__str(he->comm));
+       return repsep_snprintf(bf, size, "%-*.*s", width, width, comm__str(he->comm));
 }
 
 struct sort_entry sort_comm = {
@@ -152,10 +154,10 @@ static int _hist_entry__dso_snprintf(struct map *map, char *bf,
        if (map && map->dso) {
                const char *dso_name = !verbose ? map->dso->short_name :
                        map->dso->long_name;
-               return repsep_snprintf(bf, size, "%-*s", width, dso_name);
+               return repsep_snprintf(bf, size, "%-*.*s", width, width, dso_name);
        }
 
-       return repsep_snprintf(bf, size, "%-*s", width, "[unknown]");
+       return repsep_snprintf(bf, size, "%-*.*s", width, width, "[unknown]");
 }
 
 static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf,
@@ -257,7 +259,10 @@ static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
                                       width - ret, "");
        }
 
-       return ret;
+       if (ret > width)
+               bf[width] = '\0';
+
+       return width;
 }
 
 static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
@@ -302,10 +307,9 @@ sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
 }
 
 static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
-                                       size_t size,
-                                       unsigned int width __maybe_unused)
+                                       size_t size, unsigned int width)
 {
-       return repsep_snprintf(bf, size, "%s", he->srcline);
+       return repsep_snprintf(bf, size, "%*.*-s", width, width, he->srcline);
 }
 
 struct sort_entry sort_srcline = {
@@ -332,7 +336,7 @@ sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
 static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
                                       size_t size, unsigned int width)
 {
-       return repsep_snprintf(bf, size, "%-*s", width,
+       return repsep_snprintf(bf, size, "%-*.*s", width, width,
                              he->parent ? he->parent->name : "[other]");
 }
 
@@ -354,7 +358,7 @@ sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
 static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf,
                                    size_t size, unsigned int width)
 {
-       return repsep_snprintf(bf, size, "%*d", width, he->cpu);
+       return repsep_snprintf(bf, size, "%*.*d", width, width, he->cpu);
 }
 
 struct sort_entry sort_cpu = {
@@ -484,7 +488,7 @@ static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
        else if (he->branch_info->flags.mispred)
                out = "Y";
 
-       return repsep_snprintf(bf, size, "%-*s", width, out);
+       return repsep_snprintf(bf, size, "%-*.*s", width, width, out);
 }
 
 /* --sort daddr_sym */
@@ -1194,7 +1198,7 @@ bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
        return hse_a->se == hse_b->se;
 }
 
-void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists)
+void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists)
 {
        struct hpp_sort_entry *hse;
 
@@ -1202,20 +1206,21 @@ void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists)
                return;
 
        hse = container_of(fmt, struct hpp_sort_entry, hpp);
-       hists__new_col_len(hists, hse->se->se_width_idx,
-                          strlen(hse->se->se_header));
+       hists__new_col_len(hists, hse->se->se_width_idx, strlen(fmt->name));
 }
 
 static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
                              struct perf_evsel *evsel)
 {
        struct hpp_sort_entry *hse;
-       size_t len;
+       size_t len = fmt->user_len;
 
        hse = container_of(fmt, struct hpp_sort_entry, hpp);
-       len = hists__col_len(&evsel->hists, hse->se->se_width_idx);
 
-       return scnprintf(hpp->buf, hpp->size, "%-*s", len, hse->se->se_header);
+       if (!len)
+               len = hists__col_len(&evsel->hists, hse->se->se_width_idx);
+
+       return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name);
 }
 
 static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
@@ -1223,20 +1228,26 @@ static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
                             struct perf_evsel *evsel)
 {
        struct hpp_sort_entry *hse;
+       size_t len = fmt->user_len;
 
        hse = container_of(fmt, struct hpp_sort_entry, hpp);
 
-       return hists__col_len(&evsel->hists, hse->se->se_width_idx);
+       if (!len)
+               len = hists__col_len(&evsel->hists, hse->se->se_width_idx);
+
+       return len;
 }
 
 static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
                             struct hist_entry *he)
 {
        struct hpp_sort_entry *hse;
-       size_t len;
+       size_t len = fmt->user_len;
 
        hse = container_of(fmt, struct hpp_sort_entry, hpp);
-       len = hists__col_len(he->hists, hse->se->se_width_idx);
+
+       if (!len)
+               len = hists__col_len(he->hists, hse->se->se_width_idx);
 
        return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
 }
@@ -1253,6 +1264,7 @@ __sort_dimension__alloc_hpp(struct sort_dimension *sd)
        }
 
        hse->se = sd->entry;
+       hse->hpp.name = sd->entry->se_header;
        hse->hpp.header = __sort__hpp_header;
        hse->hpp.width = __sort__hpp_width;
        hse->hpp.entry = __sort__hpp_entry;
@@ -1265,6 +1277,8 @@ __sort_dimension__alloc_hpp(struct sort_dimension *sd)
        INIT_LIST_HEAD(&hse->hpp.list);
        INIT_LIST_HEAD(&hse->hpp.sort_list);
        hse->hpp.elide = false;
+       hse->hpp.len = 0;
+       hse->hpp.user_len = 0;
 
        return hse;
 }
index eb06746b06b291786721de6643ea9e3034ae49b7..f134ec1389347422731839f17d49a23ee77e3e52 100644 (file)
@@ -1468,8 +1468,7 @@ int dso__load_vmlinux(struct dso *dso, struct map *map,
        if (vmlinux[0] == '/')
                snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s", vmlinux);
        else
-               snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s",
-                        symbol_conf.symfs, vmlinux);
+               symbol__join_symfs(symfs_vmlinux, vmlinux);
 
        if (dso->kernel == DSO_TYPE_GUEST_KERNEL)
                symtab_type = DSO_BINARY_TYPE__GUEST_VMLINUX;
index e7295e93cff9bff87ec7cce513280d5ed26ca7c2..196b29104276c92964d0198e4e86e9e47c0ae586 100644 (file)
@@ -13,6 +13,7 @@
 #include <libgen.h>
 #include "build-id.h"
 #include "event.h"
+#include "util.h"
 
 #ifdef HAVE_LIBELF_SUPPORT
 #include <libelf.h>
@@ -143,6 +144,14 @@ struct symbol_conf {
 };
 
 extern struct symbol_conf symbol_conf;
+
+static inline int __symbol__join_symfs(char *bf, size_t size, const char *path)
+{
+       return path__join(bf, size, symbol_conf.symfs, path);
+}
+
+#define symbol__join_symfs(bf, path) __symbol__join_symfs(bf, sizeof(bf), path)
+
 extern int vmlinux_path__nr_entries;
 extern char **vmlinux_path;
 
index 4385816d3d49643c981f64a310eaaef6d9838738..f11636966a0f19ee3e77b8e16f0f55e6db505827 100644 (file)
@@ -40,7 +40,7 @@ struct perf_tool {
        event_op2       tracing_data;
        event_op2       finished_round,
                        build_id;
-       bool            ordered_samples;
+       bool            ordered_events;
        bool            ordering_requires_timestamps;
 };
 
index e52e7461911b978838e868b92f024aa642c2bf53..b82a93cb1694d08742301b6a71de016da0456ef6 100644 (file)
@@ -536,3 +536,39 @@ void mem_bswap_64(void *src, int byte_size)
                ++m;
        }
 }
+
+bool find_process(const char *name)
+{
+       size_t len = strlen(name);
+       DIR *dir;
+       struct dirent *d;
+       int ret = -1;
+
+       dir = opendir(procfs__mountpoint());
+       if (!dir)
+               return -1;
+
+       /* Walk through the directory. */
+       while (ret && (d = readdir(dir)) != NULL) {
+               char path[PATH_MAX];
+               char *data;
+               size_t size;
+
+               if ((d->d_type != DT_DIR) ||
+                    !strcmp(".", d->d_name) ||
+                    !strcmp("..", d->d_name))
+                       continue;
+
+               scnprintf(path, sizeof(path), "%s/%s/comm",
+                         procfs__mountpoint(), d->d_name);
+
+               if (filename__read_str(path, &data, &size))
+                       continue;
+
+               ret = strncmp(name, data, len);
+               free(data);
+       }
+
+       closedir(dir);
+       return ret ? false : true;
+}
index 66864364ccb482230e203b5369ee1fe004fadf78..03a1ea2266b874b831dbf208c66af7ead0d2d179 100644 (file)
@@ -68,6 +68,7 @@
 #include <sys/socket.h>
 #include <sys/ioctl.h>
 #include <inttypes.h>
+#include <linux/kernel.h>
 #include <linux/magic.h>
 #include <linux/types.h>
 #include <sys/ttydefaults.h>
@@ -317,6 +318,21 @@ unsigned long parse_tag_value(const char *str, struct parse_tag *tags);
 
 #define SRCLINE_UNKNOWN  ((char *) "??:0")
 
+static inline int path__join(char *bf, size_t size,
+                            const char *path1, const char *path2)
+{
+       return scnprintf(bf, size, "%s%s%s", path1, path1[0] ? "/" : "", path2);
+}
+
+static inline int path__join3(char *bf, size_t size,
+                             const char *path1, const char *path2,
+                             const char *path3)
+{
+       return scnprintf(bf, size, "%s%s%s%s%s",
+                        path1, path1[0] ? "/" : "",
+                        path2, path2[0] ? "/" : "", path3);
+}
+
 struct dso;
 
 char *get_srcline(struct dso *dso, unsigned long addr);
@@ -330,4 +346,5 @@ void mem_bswap_64(void *src, int byte_size);
 void mem_bswap_32(void *src, int byte_size);
 
 const char *get_filename_for_perf_kvm(void);
+bool find_process(const char *name);
 #endif /* GIT_COMPAT_UTIL_H */