Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 4 Jul 2015 15:17:29 +0000 (08:17 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 4 Jul 2015 15:17:29 +0000 (08:17 -0700)
Pull perf updates from Ingo Molnar:
 "This tree includes an x86 PMU scheduling fix, but most changes are
  late breaking tooling fixes and updates:

  User visible fixes:

   - Create config.detected into OUTPUT directory, fixing parallel
     builds sharing the same source directory (Aaro Kiskinen)

   - Allow to specify custom linker command, fixing some MIPS64 builds.
     (Aaro Kiskinen)

   - Fix to show proper convergence stats in 'perf bench numa' (Srikar
     Dronamraju)

  User visible changes:

   - Validate syscall list passed via -e argument to 'perf trace'.
     (Arnaldo Carvalho de Melo)

   - Introduce 'perf stat --per-thread' (Jiri Olsa)

   - Check access permission for --kallsyms and --vmlinux (Li Zhang)

   - Move toggling event logic from 'perf top' and into hists browser,
     allowing freeze/unfreeze with event lists with more than one entry
     (Namhyung Kim)

   - Add missing newlines when dumping PERF_RECORD_FINISHED_ROUND and
     showing the Aggregated stats in 'perf report -D' (Adrian Hunter)

  Infrastructure fixes:

   - Add missing break for PERF_RECORD_ITRACE_START, which caused those
     events samples to be parsed as well as PERF_RECORD_LOST_SAMPLES.
     ITRACE_START only appears when Intel PT or BTS are present, so..
     (Jiri Olsa)

   - Call the perf_session destructor when bailing out in the inject,
     kmem, report, kvm and mem tools (Taeung Song)

  Infrastructure changes:

   - Move stuff out of 'perf stat' and into the lib for further use
     (Jiri Olsa)

   - Reference count the cpu_map and thread_map classes (Jiri Olsa)

   - Set evsel->{cpus,threads} from the evlist, if not set, allowing the
     generalization of some 'perf stat' functions that previously were
     accessing private static evlist variable (Jiri Olsa)

   - Delete an unnecessary check before the calling free_event_desc()
     (Markus Elfring)

   - Allow auxtrace data alignment (Adrian Hunter)

   - Allow events with dot (Andi Kleen)

   - Fix failure to 'perf probe' events on arm (He Kuang)

   - Add testing for Makefile.perf (Jiri Olsa)

   - Add test for make install with prefix (Jiri Olsa)

   - Fix single target build dependency check (Jiri Olsa)

   - Access thread_map entries via accessors, prep patch to hold more
     info per entry, for ongoing 'perf stat --per-thread' work (Jiri
     Olsa)

   - Use __weak definition from compiler.h (Sukadev Bhattiprolu)

   - Split perf_pmu__new_alias() (Sukadev Bhattiprolu)"

* 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (54 commits)
  perf tools: Allow to specify custom linker command
  perf tools: Create config.detected into OUTPUT directory
  perf mem: Fill in the missing session freeing after an error occurs
  perf kvm: Fill in the missing session freeing after an error occurs
  perf report: Fill in the missing session freeing after an error occurs
  perf kmem: Fill in the missing session freeing after an error occurs
  perf inject: Fill in the missing session freeing after an error occurs
  perf tools: Add missing break for PERF_RECORD_ITRACE_START
  perf/x86: Fix 'active_events' imbalance
  perf symbols: Check access permission when reading symbol files
  perf stat: Introduce --per-thread option
  perf stat: Introduce print_counters function
  perf stat: Using init_stats instead of memset
  perf stat: Rename print_interval to process_interval
  perf stat: Remove perf_evsel__read_cb function
  perf stat: Move perf_stat initialization counter process code
  perf stat: Move zero_per_pkg into counter process code
  perf stat: Separate counters reading and processing
  perf stat: Introduce read_counters function
  perf stat: Introduce perf_evsel__read function
  ...

54 files changed:
arch/x86/kernel/cpu/perf_event.c
tools/build/Makefile.build
tools/perf/Documentation/perf-stat.txt
tools/perf/Makefile
tools/perf/Makefile.perf
tools/perf/builtin-inject.c
tools/perf/builtin-kmem.c
tools/perf/builtin-kvm.c
tools/perf/builtin-mem.c
tools/perf/builtin-report.c
tools/perf/builtin-stat.c
tools/perf/builtin-top.c
tools/perf/builtin-trace.c
tools/perf/config/Makefile
tools/perf/tests/Build
tools/perf/tests/builtin-test.c
tools/perf/tests/code-reading.c
tools/perf/tests/keep-tracking.c
tools/perf/tests/make
tools/perf/tests/mmap-basic.c
tools/perf/tests/mmap-thread-lookup.c
tools/perf/tests/openat-syscall-all-cpus.c
tools/perf/tests/openat-syscall-tp-fields.c
tools/perf/tests/openat-syscall.c
tools/perf/tests/switch-tracking.c
tools/perf/tests/tests.h
tools/perf/tests/thread-map.c [new file with mode: 0644]
tools/perf/ui/browsers/hists.c
tools/perf/util/auxtrace.c
tools/perf/util/auxtrace.h
tools/perf/util/cloexec.c
tools/perf/util/cpumap.c
tools/perf/util/cpumap.h
tools/perf/util/event.c
tools/perf/util/evlist.c
tools/perf/util/evlist.h
tools/perf/util/evsel.c
tools/perf/util/evsel.h
tools/perf/util/header.c
tools/perf/util/machine.c
tools/perf/util/parse-events.c
tools/perf/util/parse-events.l
tools/perf/util/pmu.c
tools/perf/util/probe-event.c
tools/perf/util/python-ext-sources
tools/perf/util/python.c
tools/perf/util/record.c
tools/perf/util/session.c
tools/perf/util/stat.c
tools/perf/util/stat.h
tools/perf/util/svghelper.c
tools/perf/util/symbol.c
tools/perf/util/thread_map.c
tools/perf/util/thread_map.h

index 5801a14f7524315a7318fe5a0f60509704fdb756..3658de47900f9a921a0f8373db962e061d42db3a 100644 (file)
@@ -357,34 +357,24 @@ void x86_release_hardware(void)
  */
 int x86_add_exclusive(unsigned int what)
 {
-       int ret = -EBUSY, i;
-
-       if (atomic_inc_not_zero(&x86_pmu.lbr_exclusive[what]))
-               return 0;
+       int i;
 
-       mutex_lock(&pmc_reserve_mutex);
-       for (i = 0; i < ARRAY_SIZE(x86_pmu.lbr_exclusive); i++) {
-               if (i != what && atomic_read(&x86_pmu.lbr_exclusive[i]))
-                       goto out;
+       if (!atomic_inc_not_zero(&x86_pmu.lbr_exclusive[what])) {
+               mutex_lock(&pmc_reserve_mutex);
+               for (i = 0; i < ARRAY_SIZE(x86_pmu.lbr_exclusive); i++) {
+                       if (i != what && atomic_read(&x86_pmu.lbr_exclusive[i]))
+                               goto fail_unlock;
+               }
+               atomic_inc(&x86_pmu.lbr_exclusive[what]);
+               mutex_unlock(&pmc_reserve_mutex);
        }
 
-       atomic_inc(&x86_pmu.lbr_exclusive[what]);
-       ret = 0;
+       atomic_inc(&active_events);
+       return 0;
 
-out:
+fail_unlock:
        mutex_unlock(&pmc_reserve_mutex);
-
-       /*
-        * Assuming that all exclusive events will share the PMI handler
-        * (which checks active_events for whether there is work to do),
-        * we can bump active_events counter right here, except for
-        * x86_lbr_exclusive_lbr events that go through x86_pmu_event_init()
-        * path, which already bumps active_events for them.
-        */
-       if (!ret && what != x86_lbr_exclusive_lbr)
-               atomic_inc(&active_events);
-
-       return ret;
+       return -EBUSY;
 }
 
 void x86_del_exclusive(unsigned int what)
index a51244a8022f91c26591b9553d16e0020c9f9d12..faca2bf6a430e1805ea125c663af392d51f89036 100644 (file)
@@ -25,7 +25,7 @@ build-dir := $(srctree)/tools/build
 include $(build-dir)/Build.include
 
 # do not force detected configuration
--include .config-detected
+-include $(OUTPUT).config-detected
 
 # Init all relevant variables used in build files so
 # 1) they have correct type
index 04e150d83e7da6fefaa0af14151b26458f6a01a9..47469abdcc1c11e2256effc86845232f78785075 100644 (file)
@@ -144,6 +144,10 @@ is a useful mode to detect imbalance between physical cores.  To enable this mod
 use --per-core in addition to -a. (system-wide).  The output includes the
 core number and the number of online logical processors on that physical processor.
 
+--per-thread::
+Aggregate counts per monitored threads, when monitoring threads (-t option)
+or processes (-p option).
+
 -D msecs::
 --delay msecs::
 After starting the program, wait msecs before measuring. This is useful to
index d31a7bbd7cee8610db236c7842cfb5ec63dc56b0..480546d5f13b205b85790c9512d51f33693e73a1 100644 (file)
@@ -83,8 +83,8 @@ build-test:
 #
 # All other targets get passed through:
 #
-%:
+%: FORCE
        $(print_msg)
        $(make)
 
-.PHONY: tags TAGS
+.PHONY: tags TAGS FORCE Makefile
index 1af0cfeb7a57824980ef64fdf4d26f643fa7ab6c..7a4b549214e34715aaf2ff7b834598ef2bae8080 100644 (file)
@@ -110,7 +110,7 @@ $(OUTPUT)PERF-VERSION-FILE: ../../.git/HEAD
        $(Q)touch $(OUTPUT)PERF-VERSION-FILE
 
 CC = $(CROSS_COMPILE)gcc
-LD = $(CROSS_COMPILE)ld
+LD ?= $(CROSS_COMPILE)ld
 AR = $(CROSS_COMPILE)ar
 PKG_CONFIG = $(CROSS_COMPILE)pkg-config
 
@@ -545,7 +545,7 @@ config-clean:
 clean: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean config-clean
        $(call QUIET_CLEAN, core-objs)  $(RM) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(LANG_BINDINGS)
        $(Q)find . -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete
-       $(Q)$(RM) .config-detected
+       $(Q)$(RM) $(OUTPUT).config-detected
        $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32
        $(call QUIET_CLEAN, core-gen)   $(RM)  *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)FEATURE-DUMP $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex*
        $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
index 52ec66b236076c46c1bd0666967d1d204d2c95c3..01b06492bd6a9cd74eb3d71dce8a57e7df71c593 100644 (file)
@@ -630,12 +630,13 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
        if (inject.session == NULL)
                return -1;
 
-       if (symbol__init(&inject.session->header.env) < 0)
-               return -1;
+       ret = symbol__init(&inject.session->header.env);
+       if (ret < 0)
+               goto out_delete;
 
        ret = __cmd_inject(&inject);
 
+out_delete:
        perf_session__delete(inject.session);
-
        return ret;
 }
index 950f296dfcf7a402ebbad0df1edf16e4d62a52bd..23b1faaaa4cc5f83c263ffbc9a0f14733c0dcae2 100644 (file)
@@ -1916,7 +1916,7 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
                if (!perf_evlist__find_tracepoint_by_name(session->evlist,
                                                          "kmem:kmalloc")) {
                        pr_err(errmsg, "slab", "slab");
-                       return -1;
+                       goto out_delete;
                }
        }
 
@@ -1927,7 +1927,7 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
                                                             "kmem:mm_page_alloc");
                if (evsel == NULL) {
                        pr_err(errmsg, "page", "page");
-                       return -1;
+                       goto out_delete;
                }
 
                kmem_page_size = pevent_get_page_size(evsel->tp_format->pevent);
index 74878cd75078055e437396fc9a6b201603586076..fc1cffb1b7a28c9b0d9856770530a0e8b3bf9606 100644 (file)
@@ -1061,8 +1061,10 @@ static int read_events(struct perf_kvm_stat *kvm)
 
        symbol__init(&kvm->session->header.env);
 
-       if (!perf_session__has_traces(kvm->session, "kvm record"))
-               return -EINVAL;
+       if (!perf_session__has_traces(kvm->session, "kvm record")) {
+               ret = -EINVAL;
+               goto out_delete;
+       }
 
        /*
         * Do not use 'isa' recorded in kvm_exit tracepoint since it is not
@@ -1070,9 +1072,13 @@ static int read_events(struct perf_kvm_stat *kvm)
         */
        ret = cpu_isa_config(kvm);
        if (ret < 0)
-               return ret;
+               goto out_delete;
 
-       return perf_session__process_events(kvm->session);
+       ret = perf_session__process_events(kvm->session);
+
+out_delete:
+       perf_session__delete(kvm->session);
+       return ret;
 }
 
 static int parse_target_str(struct perf_kvm_stat *kvm)
index da2ec06f0742dc6acf98c1c9b74d7cf45ff0fcb2..80170aace5d4c893b99a842427759c8f5766066e 100644 (file)
@@ -124,7 +124,6 @@ static int report_raw_events(struct perf_mem *mem)
                .mode = PERF_DATA_MODE_READ,
                .force = mem->force,
        };
-       int err = -EINVAL;
        int ret;
        struct perf_session *session = perf_session__new(&file, false,
                                                         &mem->tool);
@@ -135,24 +134,21 @@ static int report_raw_events(struct perf_mem *mem)
        if (mem->cpu_list) {
                ret = perf_session__cpu_bitmap(session, mem->cpu_list,
                                               mem->cpu_bitmap);
-               if (ret)
+               if (ret < 0)
                        goto out_delete;
        }
 
-       if (symbol__init(&session->header.env) < 0)
-               return -1;
+       ret = symbol__init(&session->header.env);
+       if (ret < 0)
+               goto out_delete;
 
        printf("# PID, TID, IP, ADDR, LOCAL WEIGHT, DSRC, SYMBOL\n");
 
-       err = perf_session__process_events(session);
-       if (err)
-               return err;
-
-       return 0;
+       ret = perf_session__process_events(session);
 
 out_delete:
        perf_session__delete(session);
-       return err;
+       return ret;
 }
 
 static int report_events(int argc, const char **argv, struct perf_mem *mem)
index 32626ea3e2276b11279db88207e42c29eeed391a..95a47719aec302318defcb8de17fd8789012b819 100644 (file)
@@ -742,6 +742,17 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
 
        argc = parse_options(argc, argv, options, report_usage, 0);
 
+       if (symbol_conf.vmlinux_name &&
+           access(symbol_conf.vmlinux_name, R_OK)) {
+               pr_err("Invalid file: %s\n", symbol_conf.vmlinux_name);
+               return -EINVAL;
+       }
+       if (symbol_conf.kallsyms_name &&
+           access(symbol_conf.kallsyms_name, R_OK)) {
+               pr_err("Invalid file: %s\n", symbol_conf.kallsyms_name);
+               return -EINVAL;
+       }
+
        if (report.use_stdio)
                use_browser = 0;
        else if (report.use_tui)
@@ -828,8 +839,10 @@ repeat:
        if (report.header || report.header_only) {
                perf_session__fprintf_info(session, stdout,
                                           report.show_full_info);
-               if (report.header_only)
-                       return 0;
+               if (report.header_only) {
+                       ret = 0;
+                       goto error;
+               }
        } else if (use_browser == 0) {
                fputs("# To display the perf.data header info, please use --header/--header-only options.\n#\n",
                      stdout);
index fcf99bdeb19e1cf73c54e0b6edc6d4426dfe1f48..37e301a32f437eb6004ba4f4ccc6b90c73b9aa5c 100644 (file)
 #define CNTR_NOT_SUPPORTED     "<not supported>"
 #define CNTR_NOT_COUNTED       "<not counted>"
 
-static void print_stat(int argc, const char **argv);
-static void print_counter_aggr(struct perf_evsel *counter, char *prefix);
-static void print_counter(struct perf_evsel *counter, char *prefix);
-static void print_aggr(char *prefix);
+static void print_counters(struct timespec *ts, int argc, const char **argv);
 
 /* Default events used for perf stat -T */
 static const char *transaction_attrs = {
@@ -141,96 +138,9 @@ static inline void diff_timespec(struct timespec *r, struct timespec *a,
        }
 }
 
-static inline struct cpu_map *perf_evsel__cpus(struct perf_evsel *evsel)
+static void perf_stat__reset_stats(void)
 {
-       return (evsel->cpus && !target.cpu_list) ? evsel->cpus : evsel_list->cpus;
-}
-
-static inline int perf_evsel__nr_cpus(struct perf_evsel *evsel)
-{
-       return perf_evsel__cpus(evsel)->nr;
-}
-
-static void perf_evsel__reset_stat_priv(struct perf_evsel *evsel)
-{
-       int i;
-       struct perf_stat *ps = evsel->priv;
-
-       for (i = 0; i < 3; i++)
-               init_stats(&ps->res_stats[i]);
-
-       perf_stat_evsel_id_init(evsel);
-}
-
-static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel)
-{
-       evsel->priv = zalloc(sizeof(struct perf_stat));
-       if (evsel->priv == NULL)
-               return -ENOMEM;
-       perf_evsel__reset_stat_priv(evsel);
-       return 0;
-}
-
-static void perf_evsel__free_stat_priv(struct perf_evsel *evsel)
-{
-       zfree(&evsel->priv);
-}
-
-static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel)
-{
-       struct perf_counts *counts;
-
-       counts = perf_counts__new(perf_evsel__nr_cpus(evsel));
-       if (counts)
-               evsel->prev_raw_counts = counts;
-
-       return counts ? 0 : -ENOMEM;
-}
-
-static void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel)
-{
-       perf_counts__delete(evsel->prev_raw_counts);
-       evsel->prev_raw_counts = NULL;
-}
-
-static void perf_evlist__free_stats(struct perf_evlist *evlist)
-{
-       struct perf_evsel *evsel;
-
-       evlist__for_each(evlist, evsel) {
-               perf_evsel__free_stat_priv(evsel);
-               perf_evsel__free_counts(evsel);
-               perf_evsel__free_prev_raw_counts(evsel);
-       }
-}
-
-static int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw)
-{
-       struct perf_evsel *evsel;
-
-       evlist__for_each(evlist, evsel) {
-               if (perf_evsel__alloc_stat_priv(evsel) < 0 ||
-                   perf_evsel__alloc_counts(evsel, perf_evsel__nr_cpus(evsel)) < 0 ||
-                   (alloc_raw && perf_evsel__alloc_prev_raw_counts(evsel) < 0))
-                       goto out_free;
-       }
-
-       return 0;
-
-out_free:
-       perf_evlist__free_stats(evlist);
-       return -1;
-}
-
-static void perf_stat__reset_stats(struct perf_evlist *evlist)
-{
-       struct perf_evsel *evsel;
-
-       evlist__for_each(evlist, evsel) {
-               perf_evsel__reset_stat_priv(evsel);
-               perf_evsel__reset_counts(evsel, perf_evsel__nr_cpus(evsel));
-       }
-
+       perf_evlist__reset_stats(evsel_list);
        perf_stat__reset_shadow_stats();
 }
 
@@ -304,8 +214,9 @@ static int check_per_pkg(struct perf_evsel *counter, int cpu, bool *skip)
        return 0;
 }
 
-static int read_cb(struct perf_evsel *evsel, int cpu, int thread __maybe_unused,
-                  struct perf_counts_values *count)
+static int
+process_counter_values(struct perf_evsel *evsel, int cpu, int thread,
+                      struct perf_counts_values *count)
 {
        struct perf_counts_values *aggr = &evsel->counts->aggr;
        static struct perf_counts_values zero;
@@ -320,13 +231,13 @@ static int read_cb(struct perf_evsel *evsel, int cpu, int thread __maybe_unused,
                count = &zero;
 
        switch (aggr_mode) {
+       case AGGR_THREAD:
        case AGGR_CORE:
        case AGGR_SOCKET:
        case AGGR_NONE:
                if (!evsel->snapshot)
-                       perf_evsel__compute_deltas(evsel, cpu, count);
+                       perf_evsel__compute_deltas(evsel, cpu, thread, count);
                perf_counts_values__scale(count, scale, NULL);
-               evsel->counts->cpu[cpu] = *count;
                if (aggr_mode == AGGR_NONE)
                        perf_stat__update_shadow_stats(evsel, count->values, cpu);
                break;
@@ -343,26 +254,48 @@ static int read_cb(struct perf_evsel *evsel, int cpu, int thread __maybe_unused,
        return 0;
 }
 
-static int read_counter(struct perf_evsel *counter);
+static int process_counter_maps(struct perf_evsel *counter)
+{
+       int nthreads = thread_map__nr(counter->threads);
+       int ncpus = perf_evsel__nr_cpus(counter);
+       int cpu, thread;
 
-/*
- * Read out the results of a single counter:
- * aggregate counts across CPUs in system-wide mode
- */
-static int read_counter_aggr(struct perf_evsel *counter)
+       if (counter->system_wide)
+               nthreads = 1;
+
+       for (thread = 0; thread < nthreads; thread++) {
+               for (cpu = 0; cpu < ncpus; cpu++) {
+                       if (process_counter_values(counter, cpu, thread,
+                                                  perf_counts(counter->counts, cpu, thread)))
+                               return -1;
+               }
+       }
+
+       return 0;
+}
+
+static int process_counter(struct perf_evsel *counter)
 {
        struct perf_counts_values *aggr = &counter->counts->aggr;
        struct perf_stat *ps = counter->priv;
        u64 *count = counter->counts->aggr.values;
-       int i;
+       int i, ret;
 
        aggr->val = aggr->ena = aggr->run = 0;
+       init_stats(ps->res_stats);
 
-       if (read_counter(counter))
-               return -1;
+       if (counter->per_pkg)
+               zero_per_pkg(counter);
+
+       ret = process_counter_maps(counter);
+       if (ret)
+               return ret;
+
+       if (aggr_mode != AGGR_GLOBAL)
+               return 0;
 
        if (!counter->snapshot)
-               perf_evsel__compute_deltas(counter, -1, aggr);
+               perf_evsel__compute_deltas(counter, -1, -1, aggr);
        perf_counts_values__scale(aggr, scale, &counter->counts->scaled);
 
        for (i = 0; i < 3; i++)
@@ -397,12 +330,12 @@ static int read_counter(struct perf_evsel *counter)
        if (counter->system_wide)
                nthreads = 1;
 
-       if (counter->per_pkg)
-               zero_per_pkg(counter);
-
        for (thread = 0; thread < nthreads; thread++) {
                for (cpu = 0; cpu < ncpus; cpu++) {
-                       if (perf_evsel__read_cb(counter, cpu, thread, read_cb))
+                       struct perf_counts_values *count;
+
+                       count = perf_counts(counter->counts, cpu, thread);
+                       if (perf_evsel__read(counter, cpu, thread, count))
                                return -1;
                }
        }
@@ -410,68 +343,34 @@ static int read_counter(struct perf_evsel *counter)
        return 0;
 }
 
-static void print_interval(void)
+static void read_counters(bool close)
 {
-       static int num_print_interval;
        struct perf_evsel *counter;
-       struct perf_stat *ps;
-       struct timespec ts, rs;
-       char prefix[64];
 
-       if (aggr_mode == AGGR_GLOBAL) {
-               evlist__for_each(evsel_list, counter) {
-                       ps = counter->priv;
-                       memset(ps->res_stats, 0, sizeof(ps->res_stats));
-                       read_counter_aggr(counter);
-               }
-       } else  {
-               evlist__for_each(evsel_list, counter) {
-                       ps = counter->priv;
-                       memset(ps->res_stats, 0, sizeof(ps->res_stats));
-                       read_counter(counter);
-               }
-       }
+       evlist__for_each(evsel_list, counter) {
+               if (read_counter(counter))
+                       pr_warning("failed to read counter %s\n", counter->name);
 
-       clock_gettime(CLOCK_MONOTONIC, &ts);
-       diff_timespec(&rs, &ts, &ref_time);
-       sprintf(prefix, "%6lu.%09lu%s", rs.tv_sec, rs.tv_nsec, csv_sep);
+               if (process_counter(counter))
+                       pr_warning("failed to process counter %s\n", counter->name);
 
-       if (num_print_interval == 0 && !csv_output) {
-               switch (aggr_mode) {
-               case AGGR_SOCKET:
-                       fprintf(output, "#           time socket cpus             counts %*s events\n", unit_width, "unit");
-                       break;
-               case AGGR_CORE:
-                       fprintf(output, "#           time core         cpus             counts %*s events\n", unit_width, "unit");
-                       break;
-               case AGGR_NONE:
-                       fprintf(output, "#           time CPU                counts %*s events\n", unit_width, "unit");
-                       break;
-               case AGGR_GLOBAL:
-               default:
-                       fprintf(output, "#           time             counts %*s events\n", unit_width, "unit");
+               if (close) {
+                       perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter),
+                                            thread_map__nr(evsel_list->threads));
                }
        }
+}
 
-       if (++num_print_interval == 25)
-               num_print_interval = 0;
+static void process_interval(void)
+{
+       struct timespec ts, rs;
 
-       switch (aggr_mode) {
-       case AGGR_CORE:
-       case AGGR_SOCKET:
-               print_aggr(prefix);
-               break;
-       case AGGR_NONE:
-               evlist__for_each(evsel_list, counter)
-                       print_counter(counter, prefix);
-               break;
-       case AGGR_GLOBAL:
-       default:
-               evlist__for_each(evsel_list, counter)
-                       print_counter_aggr(counter, prefix);
-       }
+       read_counters(false);
 
-       fflush(output);
+       clock_gettime(CLOCK_MONOTONIC, &ts);
+       diff_timespec(&rs, &ts, &ref_time);
+
+       print_counters(&rs, 0, NULL);
 }
 
 static void handle_initial_delay(void)
@@ -586,7 +485,7 @@ static int __run_perf_stat(int argc, const char **argv)
                if (interval) {
                        while (!waitpid(child_pid, &status, WNOHANG)) {
                                nanosleep(&ts, NULL);
-                               print_interval();
+                               process_interval();
                        }
                }
                wait(&status);
@@ -604,7 +503,7 @@ static int __run_perf_stat(int argc, const char **argv)
                while (!done) {
                        nanosleep(&ts, NULL);
                        if (interval)
-                               print_interval();
+                               process_interval();
                }
        }
 
@@ -612,18 +511,7 @@ static int __run_perf_stat(int argc, const char **argv)
 
        update_stats(&walltime_nsecs_stats, t1 - t0);
 
-       if (aggr_mode == AGGR_GLOBAL) {
-               evlist__for_each(evsel_list, counter) {
-                       read_counter_aggr(counter);
-                       perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter),
-                                            thread_map__nr(evsel_list->threads));
-               }
-       } else {
-               evlist__for_each(evsel_list, counter) {
-                       read_counter(counter);
-                       perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), 1);
-               }
-       }
+       read_counters(true);
 
        return WEXITSTATUS(status);
 }
@@ -715,6 +603,14 @@ static void aggr_printout(struct perf_evsel *evsel, int id, int nr)
                        csv_output ? 0 : -4,
                        perf_evsel__cpus(evsel)->map[id], csv_sep);
                break;
+       case AGGR_THREAD:
+               fprintf(output, "%*s-%*d%s",
+                       csv_output ? 0 : 16,
+                       thread_map__comm(evsel->threads, id),
+                       csv_output ? 0 : -8,
+                       thread_map__pid(evsel->threads, id),
+                       csv_sep);
+               break;
        case AGGR_GLOBAL:
        default:
                break;
@@ -815,9 +711,9 @@ static void print_aggr(char *prefix)
                                s2 = aggr_get_id(evsel_list->cpus, cpu2);
                                if (s2 != id)
                                        continue;
-                               val += counter->counts->cpu[cpu].val;
-                               ena += counter->counts->cpu[cpu].ena;
-                               run += counter->counts->cpu[cpu].run;
+                               val += perf_counts(counter->counts, cpu, 0)->val;
+                               ena += perf_counts(counter->counts, cpu, 0)->ena;
+                               run += perf_counts(counter->counts, cpu, 0)->run;
                                nr++;
                        }
                        if (prefix)
@@ -863,6 +759,40 @@ static void print_aggr(char *prefix)
        }
 }
 
+static void print_aggr_thread(struct perf_evsel *counter, char *prefix)
+{
+       int nthreads = thread_map__nr(counter->threads);
+       int ncpus = cpu_map__nr(counter->cpus);
+       int cpu, thread;
+       double uval;
+
+       for (thread = 0; thread < nthreads; thread++) {
+               u64 ena = 0, run = 0, val = 0;
+
+               for (cpu = 0; cpu < ncpus; cpu++) {
+                       val += perf_counts(counter->counts, cpu, thread)->val;
+                       ena += perf_counts(counter->counts, cpu, thread)->ena;
+                       run += perf_counts(counter->counts, cpu, thread)->run;
+               }
+
+               if (prefix)
+                       fprintf(output, "%s", prefix);
+
+               uval = val * counter->scale;
+
+               if (nsec_counter(counter))
+                       nsec_printout(thread, 0, counter, uval);
+               else
+                       abs_printout(thread, 0, counter, uval);
+
+               if (!csv_output)
+                       print_noise(counter, 1.0);
+
+               print_running(run, ena);
+               fputc('\n', output);
+       }
+}
+
 /*
  * Print out the results of a single counter:
  * aggregated counts in system-wide mode
@@ -925,9 +855,9 @@ static void print_counter(struct perf_evsel *counter, char *prefix)
        int cpu;
 
        for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
-               val = counter->counts->cpu[cpu].val;
-               ena = counter->counts->cpu[cpu].ena;
-               run = counter->counts->cpu[cpu].run;
+               val = perf_counts(counter->counts, cpu, 0)->val;
+               ena = perf_counts(counter->counts, cpu, 0)->ena;
+               run = perf_counts(counter->counts, cpu, 0)->run;
 
                if (prefix)
                        fprintf(output, "%s", prefix);
@@ -972,9 +902,38 @@ static void print_counter(struct perf_evsel *counter, char *prefix)
        }
 }
 
-static void print_stat(int argc, const char **argv)
+static void print_interval(char *prefix, struct timespec *ts)
+{
+       static int num_print_interval;
+
+       sprintf(prefix, "%6lu.%09lu%s", ts->tv_sec, ts->tv_nsec, csv_sep);
+
+       if (num_print_interval == 0 && !csv_output) {
+               switch (aggr_mode) {
+               case AGGR_SOCKET:
+                       fprintf(output, "#           time socket cpus             counts %*s events\n", unit_width, "unit");
+                       break;
+               case AGGR_CORE:
+                       fprintf(output, "#           time core         cpus             counts %*s events\n", unit_width, "unit");
+                       break;
+               case AGGR_NONE:
+                       fprintf(output, "#           time CPU                counts %*s events\n", unit_width, "unit");
+                       break;
+               case AGGR_THREAD:
+                       fprintf(output, "#           time             comm-pid                  counts %*s events\n", unit_width, "unit");
+                       break;
+               case AGGR_GLOBAL:
+               default:
+                       fprintf(output, "#           time             counts %*s events\n", unit_width, "unit");
+               }
+       }
+
+       if (++num_print_interval == 25)
+               num_print_interval = 0;
+}
+
+static void print_header(int argc, const char **argv)
 {
-       struct perf_evsel *counter;
        int i;
 
        fflush(stdout);
@@ -1000,36 +959,57 @@ static void print_stat(int argc, const char **argv)
                        fprintf(output, " (%d runs)", run_count);
                fprintf(output, ":\n\n");
        }
+}
+
+static void print_footer(void)
+{
+       if (!null_run)
+               fprintf(output, "\n");
+       fprintf(output, " %17.9f seconds time elapsed",
+                       avg_stats(&walltime_nsecs_stats)/1e9);
+       if (run_count > 1) {
+               fprintf(output, "                                        ");
+               print_noise_pct(stddev_stats(&walltime_nsecs_stats),
+                               avg_stats(&walltime_nsecs_stats));
+       }
+       fprintf(output, "\n\n");
+}
+
+static void print_counters(struct timespec *ts, int argc, const char **argv)
+{
+       struct perf_evsel *counter;
+       char buf[64], *prefix = NULL;
+
+       if (interval)
+               print_interval(prefix = buf, ts);
+       else
+               print_header(argc, argv);
 
        switch (aggr_mode) {
        case AGGR_CORE:
        case AGGR_SOCKET:
-               print_aggr(NULL);
+               print_aggr(prefix);
+               break;
+       case AGGR_THREAD:
+               evlist__for_each(evsel_list, counter)
+                       print_aggr_thread(counter, prefix);
                break;
        case AGGR_GLOBAL:
                evlist__for_each(evsel_list, counter)
-                       print_counter_aggr(counter, NULL);
+                       print_counter_aggr(counter, prefix);
                break;
        case AGGR_NONE:
                evlist__for_each(evsel_list, counter)
-                       print_counter(counter, NULL);
+                       print_counter(counter, prefix);
                break;
        default:
                break;
        }
 
-       if (!csv_output) {
-               if (!null_run)
-                       fprintf(output, "\n");
-               fprintf(output, " %17.9f seconds time elapsed",
-                               avg_stats(&walltime_nsecs_stats)/1e9);
-               if (run_count > 1) {
-                       fprintf(output, "                                        ");
-                       print_noise_pct(stddev_stats(&walltime_nsecs_stats),
-                                       avg_stats(&walltime_nsecs_stats));
-               }
-               fprintf(output, "\n\n");
-       }
+       if (!interval && !csv_output)
+               print_footer();
+
+       fflush(output);
 }
 
 static volatile int signr = -1;
@@ -1101,6 +1081,7 @@ static int perf_stat_init_aggr_mode(void)
                break;
        case AGGR_NONE:
        case AGGR_GLOBAL:
+       case AGGR_THREAD:
        default:
                break;
        }
@@ -1325,6 +1306,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
                     "aggregate counts per processor socket", AGGR_SOCKET),
        OPT_SET_UINT(0, "per-core", &aggr_mode,
                     "aggregate counts per physical processor core", AGGR_CORE),
+       OPT_SET_UINT(0, "per-thread", &aggr_mode,
+                    "aggregate counts per thread", AGGR_THREAD),
        OPT_UINTEGER('D', "delay", &initial_delay,
                     "ms to wait before starting measurement after program start"),
        OPT_END()
@@ -1416,8 +1399,19 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
                run_count = 1;
        }
 
-       /* no_aggr, cgroup are for system-wide only */
-       if ((aggr_mode != AGGR_GLOBAL || nr_cgroups) &&
+       if ((aggr_mode == AGGR_THREAD) && !target__has_task(&target)) {
+               fprintf(stderr, "The --per-thread option is only available "
+                       "when monitoring via -p -t options.\n");
+               parse_options_usage(NULL, options, "p", 1);
+               parse_options_usage(NULL, options, "t", 1);
+               goto out;
+       }
+
+       /*
+        * no_aggr, cgroup are for system-wide only
+        * --per-thread is aggregated per thread, we dont mix it with cpu mode
+        */
+       if (((aggr_mode != AGGR_GLOBAL && aggr_mode != AGGR_THREAD) || nr_cgroups) &&
            !target__has_cpu(&target)) {
                fprintf(stderr, "both cgroup and no-aggregation "
                        "modes only available in system-wide mode\n");
@@ -1445,6 +1439,14 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
                }
                goto out;
        }
+
+       /*
+        * Initialize thread_map with comm names,
+        * so we could print it out on output.
+        */
+       if (aggr_mode == AGGR_THREAD)
+               thread_map__read_comms(evsel_list->threads);
+
        if (interval && interval < 100) {
                pr_err("print interval must be >= 100ms\n");
                parse_options_usage(stat_usage, options, "I", 1);
@@ -1478,13 +1480,13 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
 
                status = run_perf_stat(argc, argv);
                if (forever && status != -1) {
-                       print_stat(argc, argv);
-                       perf_stat__reset_stats(evsel_list);
+                       print_counters(NULL, argc, argv);
+                       perf_stat__reset_stats();
                }
        }
 
        if (!forever && status != -1 && !interval)
-               print_stat(argc, argv);
+               print_counters(NULL, argc, argv);
 
        perf_evlist__free_stats(evsel_list);
 out:
index 619a8696fda7c939cd0e6497abab5845813bda12..ecf319728f25d649768e33b3e1f274d04432f3fc 100644 (file)
@@ -586,27 +586,9 @@ static void *display_thread_tui(void *arg)
                hists->uid_filter_str = top->record_opts.target.uid_str;
        }
 
-       while (true)  {
-               int key = perf_evlist__tui_browse_hists(top->evlist, help, &hbt,
-                                                       top->min_percent,
-                                                       &top->session->header.env);
-
-               if (key != 'f')
-                       break;
-
-               perf_evlist__toggle_enable(top->evlist);
-               /*
-                * No need to refresh, resort/decay histogram entries
-                * if we are not collecting samples:
-                */
-               if (top->evlist->enabled) {
-                       hbt.refresh = top->delay_secs;
-                       help = "Press 'f' to disable the events or 'h' to see other hotkeys";
-               } else {
-                       help = "Press 'f' again to re-enable the events";
-                       hbt.refresh = 0;
-               }
-       }
+       perf_evlist__tui_browse_hists(top->evlist, help, &hbt,
+                                     top->min_percent,
+                                     &top->session->header.env);
 
        done = 1;
        return NULL;
index de5d277d1ad7cb97cac2c5da67032fc8a12ffdf6..39ad4d0ca88427cb222fa3ce7c0a35c7b77ed243 100644 (file)
@@ -1617,6 +1617,34 @@ static int trace__read_syscall_info(struct trace *trace, int id)
        return syscall__set_arg_fmts(sc);
 }
 
+static int trace__validate_ev_qualifier(struct trace *trace)
+{
+       int err = 0;
+       struct str_node *pos;
+
+       strlist__for_each(pos, trace->ev_qualifier) {
+               const char *sc = pos->s;
+
+               if (audit_name_to_syscall(sc, trace->audit.machine) < 0) {
+                       if (err == 0) {
+                               fputs("Error:\tInvalid syscall ", trace->output);
+                               err = -EINVAL;
+                       } else {
+                               fputs(", ", trace->output);
+                       }
+
+                       fputs(sc, trace->output);
+               }
+       }
+
+       if (err < 0) {
+               fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
+                     "\nHint:\tand: 'man syscalls'\n", trace->output);
+       }
+
+       return err;
+}
+
 /*
  * args is to be interpreted as a series of longs but we need to handle
  * 8-byte unaligned accesses. args points to raw_data within the event
@@ -2325,7 +2353,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
         */
        if (trace->filter_pids.nr > 0)
                err = perf_evlist__set_filter_pids(evlist, trace->filter_pids.nr, trace->filter_pids.entries);
-       else if (evlist->threads->map[0] == -1)
+       else if (thread_map__pid(evlist->threads, 0) == -1)
                err = perf_evlist__set_filter_pid(evlist, getpid());
 
        if (err < 0) {
@@ -2343,7 +2371,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
        if (forks)
                perf_evlist__start_workload(evlist);
 
-       trace->multiple_threads = evlist->threads->map[0] == -1 ||
+       trace->multiple_threads = thread_map__pid(evlist->threads, 0) == -1 ||
                                  evlist->threads->nr > 1 ||
                                  perf_evlist__first(evlist)->attr.inherit;
 again:
@@ -2862,6 +2890,10 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
                        err = -ENOMEM;
                        goto out_close;
                }
+
+               err = trace__validate_ev_qualifier(&trace);
+               if (err)
+                       goto out_close;
        }
 
        err = target__validate(&trace.opts.target);
index 317001c946608be1430d03d485fe19586f1e0446..094ddaee104c73d7caae22d851d79629c4715cd3 100644 (file)
@@ -11,9 +11,9 @@ ifneq ($(obj-perf),)
 obj-perf := $(abspath $(obj-perf))/
 endif
 
-$(shell echo -n > .config-detected)
-detected     = $(shell echo "$(1)=y"       >> .config-detected)
-detected_var = $(shell echo "$(1)=$($(1))" >> .config-detected)
+$(shell echo -n > $(OUTPUT).config-detected)
+detected     = $(shell echo "$(1)=y"       >> $(OUTPUT).config-detected)
+detected_var = $(shell echo "$(1)=$($(1))" >> $(OUTPUT).config-detected)
 
 CFLAGS := $(EXTRA_CFLAGS) $(EXTRA_WARNINGS)
 
index ee41e705b2eba7b726e417a1fdd73a421b7a985b..d20d6e6ab65beb1d433e06a769cd09510e4ced9b 100644 (file)
@@ -31,6 +31,7 @@ perf-y += code-reading.o
 perf-y += sample-parsing.o
 perf-y += parse-no-sample-id-all.o
 perf-y += kmod-path.o
+perf-y += thread-map.o
 
 perf-$(CONFIG_X86) += perf-time-to-tsc.o
 
index 87b9961646e4a5f08728e694549195d9eeb2ad86..c1dde733c3a6b594ccab52a2a0077c3504c95fc2 100644 (file)
@@ -170,6 +170,10 @@ static struct test {
                .desc = "Test kmod_path__parse function",
                .func = test__kmod_path__parse,
        },
+       {
+               .desc = "Test thread map",
+               .func = test__thread_map,
+       },
        {
                .func = NULL,
        },
index 22f8a00446e1f1b3cb6b447dbc1bc21ccfda3108..39c784a100a955143e401fc46cbcb93a2a3d8136 100644 (file)
@@ -545,8 +545,8 @@ out_err:
        if (evlist) {
                perf_evlist__delete(evlist);
        } else {
-               cpu_map__delete(cpus);
-               thread_map__delete(threads);
+               cpu_map__put(cpus);
+               thread_map__put(threads);
        }
        machines__destroy_kernel_maps(&machines);
        machine__delete_threads(machine);
index 5b171d1e338bdd26bcf1343f58e8b0bdb314b71c..4d4b9837b630ae9fd72cb0a404a4bae0e3864e14 100644 (file)
@@ -144,8 +144,8 @@ out_err:
                perf_evlist__disable(evlist);
                perf_evlist__delete(evlist);
        } else {
-               cpu_map__delete(cpus);
-               thread_map__delete(threads);
+               cpu_map__put(cpus);
+               thread_map__put(threads);
        }
 
        return err;
index 65280d28662e4c72177a20a3cfa56f968a10c359..729112f4cfaaaa66b91bcacc57c8a1d9af49203d 100644 (file)
@@ -1,5 +1,16 @@
+ifndef MK
+ifeq ($(MAKECMDGOALS),)
+# no target specified, trigger the whole suite
+all:
+       @echo "Testing Makefile";      $(MAKE) -sf tests/make MK=Makefile
+       @echo "Testing Makefile.perf"; $(MAKE) -sf tests/make MK=Makefile.perf
+else
+# run only specific test over 'Makefile'
+%:
+       @echo "Testing Makefile";      $(MAKE) -sf tests/make MK=Makefile $@
+endif
+else
 PERF := .
-MK   := Makefile
 
 include config/Makefile.arch
 
@@ -47,6 +58,7 @@ make_install_man    := install-man
 make_install_html   := install-html
 make_install_info   := install-info
 make_install_pdf    := install-pdf
+make_install_prefix := install prefix=/tmp/krava
 make_static         := LDFLAGS=-static
 
 # all the NO_* variable combined
@@ -57,7 +69,12 @@ make_minimal        += NO_LIBDW_DWARF_UNWIND=1 NO_AUXTRACE=1
 
 # $(run) contains all available tests
 run := make_pure
+# Targets 'clean all' can be run together only through top level
+# Makefile because we detect clean target in Makefile.perf and
+# disable features detection
+ifeq ($(MK),Makefile)
 run += make_clean_all
+endif
 run += make_python_perf_so
 run += make_debug
 run += make_no_libperl
@@ -83,6 +100,7 @@ run += make_util_map_o
 run += make_util_pmu_bison_o
 run += make_install
 run += make_install_bin
+run += make_install_prefix
 # FIXME 'install-*' commented out till they're fixed
 # run += make_install_doc
 # run += make_install_man
@@ -157,6 +175,12 @@ test_make_install_O     := $(call test_dest_files,$(installed_files_all))
 test_make_install_bin   := $(call test_dest_files,$(installed_files_bin))
 test_make_install_bin_O := $(call test_dest_files,$(installed_files_bin))
 
+# We prefix all installed files for make_install_prefix
+# with '/tmp/krava' to match installed/prefix-ed files.
+installed_files_all_prefix := $(addprefix /tmp/krava/,$(installed_files_all))
+test_make_install_prefix   := $(call test_dest_files,$(installed_files_all_prefix))
+test_make_install_prefix_O := $(call test_dest_files,$(installed_files_all_prefix))
+
 # FIXME nothing gets installed
 test_make_install_man    := test -f $$TMP_DEST/share/man/man1/perf.1
 test_make_install_man_O  := $(test_make_install_man)
@@ -226,13 +250,13 @@ tarpkg:
        ( eval $$cmd ) >> $@ 2>&1
 
 make_kernelsrc:
-       @echo " - make -C <kernelsrc> tools/perf"
+       @echo "- make -C <kernelsrc> tools/perf"
        $(call clean); \
        (make -C ../.. tools/perf) > $@ 2>&1 && \
        test -x perf && rm -f $@ || (cat $@ ; false)
 
 make_kernelsrc_tools:
-       @echo " - make -C <kernelsrc>/tools perf"
+       @echo "- make -C <kernelsrc>/tools perf"
        $(call clean); \
        (make -C ../../tools perf) > $@ 2>&1 && \
        test -x perf && rm -f $@ || (cat $@ ; false)
@@ -244,3 +268,4 @@ out: $(run_O)
        @echo OK
 
 .PHONY: all $(run) $(run_O) tarpkg clean
+endif # ifndef MK
index 5855cf47121003479ae63e859059a5ad8809c5ec..666b67a4df9dd0d8ea8d41736af4355008c11464 100644 (file)
@@ -140,8 +140,8 @@ out_delete_evlist:
        cpus    = NULL;
        threads = NULL;
 out_free_cpus:
-       cpu_map__delete(cpus);
+       cpu_map__put(cpus);
 out_free_threads:
-       thread_map__delete(threads);
+       thread_map__put(threads);
        return err;
 }
index 7f48efa7e295f63a72f0aa083857658ce68c45cb..145050e2e5446166f900f8d9405859b15bfcfff3 100644 (file)
@@ -143,7 +143,7 @@ static int synth_process(struct machine *machine)
                                                perf_event__process,
                                                machine, 0, 500);
 
-       thread_map__delete(map);
+       thread_map__put(map);
        return err;
 }
 
index 9a7a116e09b8087ef5f19e63113f6f65c1e0b5bf..a572f87e9c8d8e25665bf75e1c45b1f86ff8a6e9 100644 (file)
@@ -78,7 +78,7 @@ int test__openat_syscall_event_on_all_cpus(void)
         * we use the auto allocation it will allocate just for 1 cpu,
         * as we start by cpu 0.
         */
-       if (perf_evsel__alloc_counts(evsel, cpus->nr) < 0) {
+       if (perf_evsel__alloc_counts(evsel, cpus->nr, 1) < 0) {
                pr_debug("perf_evsel__alloc_counts(ncpus=%d)\n", cpus->nr);
                goto out_close_fd;
        }
@@ -98,9 +98,9 @@ int test__openat_syscall_event_on_all_cpus(void)
                }
 
                expected = nr_openat_calls + cpu;
-               if (evsel->counts->cpu[cpu].val != expected) {
+               if (perf_counts(evsel->counts, cpu, 0)->val != expected) {
                        pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls on cpu %d, got %" PRIu64 "\n",
-                                expected, cpus->map[cpu], evsel->counts->cpu[cpu].val);
+                                expected, cpus->map[cpu], perf_counts(evsel->counts, cpu, 0)->val);
                        err = -1;
                }
        }
@@ -111,6 +111,6 @@ out_close_fd:
 out_evsel_delete:
        perf_evsel__delete(evsel);
 out_thread_map_delete:
-       thread_map__delete(threads);
+       thread_map__put(threads);
        return err;
 }
index 6245221479d766fb9e227064bcdc42742cae65d3..01a19626c84624136d909e1c3d3e58ef877d1b39 100644 (file)
@@ -45,7 +45,7 @@ int test__syscall_openat_tp_fields(void)
 
        perf_evsel__config(evsel, &opts);
 
-       evlist->threads->map[0] = getpid();
+       thread_map__set_pid(evlist->threads, 0, getpid());
 
        err = perf_evlist__open(evlist);
        if (err < 0) {
index 9f9491bb8e4897faddcffed824b3d094f73b7d3d..c9a37bc6b33ac336a128a4948623a1a93a5b388f 100644 (file)
@@ -44,9 +44,9 @@ int test__openat_syscall_event(void)
                goto out_close_fd;
        }
 
-       if (evsel->counts->cpu[0].val != nr_openat_calls) {
+       if (perf_counts(evsel->counts, 0, 0)->val != nr_openat_calls) {
                pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls, got %" PRIu64 "\n",
-                        nr_openat_calls, evsel->counts->cpu[0].val);
+                        nr_openat_calls, perf_counts(evsel->counts, 0, 0)->val);
                goto out_close_fd;
        }
 
@@ -56,6 +56,6 @@ out_close_fd:
 out_evsel_delete:
        perf_evsel__delete(evsel);
 out_thread_map_delete:
-       thread_map__delete(threads);
+       thread_map__put(threads);
        return err;
 }
index 0d31403ea593c7d2e689056af1670a18423a39ed..e698742d4fec3300ac6c6b00bf55696414567dd4 100644 (file)
@@ -560,8 +560,8 @@ out:
                perf_evlist__disable(evlist);
                perf_evlist__delete(evlist);
        } else {
-               cpu_map__delete(cpus);
-               thread_map__delete(threads);
+               cpu_map__put(cpus);
+               thread_map__put(threads);
        }
 
        return err;
index 8e5038b48ba8dfe3313d9c508156ae9b4ecb8c5a..ebb47d96bc0b09fdf5c7b0bbba6022e209fc72ab 100644 (file)
@@ -61,6 +61,7 @@ int test__switch_tracking(void);
 int test__fdarray__filter(void);
 int test__fdarray__add(void);
 int test__kmod_path__parse(void);
+int test__thread_map(void);
 
 #if defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__)
 #ifdef HAVE_DWARF_UNWIND_SUPPORT
diff --git a/tools/perf/tests/thread-map.c b/tools/perf/tests/thread-map.c
new file mode 100644 (file)
index 0000000..5acf000
--- /dev/null
@@ -0,0 +1,38 @@
+#include <sys/types.h>
+#include <unistd.h>
+#include "tests.h"
+#include "thread_map.h"
+#include "debug.h"
+
+int test__thread_map(void)
+{
+       struct thread_map *map;
+
+       /* test map on current pid */
+       map = thread_map__new_by_pid(getpid());
+       TEST_ASSERT_VAL("failed to alloc map", map);
+
+       thread_map__read_comms(map);
+
+       TEST_ASSERT_VAL("wrong nr", map->nr == 1);
+       TEST_ASSERT_VAL("wrong pid",
+                       thread_map__pid(map, 0) == getpid());
+       TEST_ASSERT_VAL("wrong comm",
+                       thread_map__comm(map, 0) &&
+                       !strcmp(thread_map__comm(map, 0), "perf"));
+       thread_map__put(map);
+
+       /* test dummy pid */
+       map = thread_map__new_dummy();
+       TEST_ASSERT_VAL("failed to alloc map", map);
+
+       thread_map__read_comms(map);
+
+       TEST_ASSERT_VAL("wrong nr", map->nr == 1);
+       TEST_ASSERT_VAL("wrong pid", thread_map__pid(map, 0) == -1);
+       TEST_ASSERT_VAL("wrong comm",
+                       thread_map__comm(map, 0) &&
+                       !strcmp(thread_map__comm(map, 0), "dummy"));
+       thread_map__put(map);
+       return 0;
+}
index c42adb6000914554bf0d109e02d9ad5cec801313..7629bef2fd791b41f64e49da53bc895e62d3dab4 100644 (file)
@@ -1902,8 +1902,23 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
                case CTRL('c'):
                        goto out_free_stack;
                case 'f':
-                       if (!is_report_browser(hbt))
-                               goto out_free_stack;
+                       if (!is_report_browser(hbt)) {
+                               struct perf_top *top = hbt->arg;
+
+                               perf_evlist__toggle_enable(top->evlist);
+                               /*
+                                * No need to refresh, resort/decay histogram
+                                * entries if we are not collecting samples:
+                                */
+                               if (top->evlist->enabled) {
+                                       helpline = "Press 'f' to disable the events or 'h' to see other hotkeys";
+                                       hbt->refresh = delay_secs;
+                               } else {
+                                       helpline = "Press 'f' again to re-enable the events";
+                                       hbt->refresh = 0;
+                               }
+                               continue;
+                       }
                        /* Fall thru */
                default:
                        helpline = "Press '?' for help on key bindings";
index df66966cfde7ab1e78f9f5da6610ad8d707dea9c..7e7405c9b9361638f649820ae369bdec64e89c20 100644 (file)
@@ -119,12 +119,12 @@ void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp,
        if (per_cpu) {
                mp->cpu = evlist->cpus->map[idx];
                if (evlist->threads)
-                       mp->tid = evlist->threads->map[0];
+                       mp->tid = thread_map__pid(evlist->threads, 0);
                else
                        mp->tid = -1;
        } else {
                mp->cpu = -1;
-               mp->tid = evlist->threads->map[idx];
+               mp->tid = thread_map__pid(evlist->threads, idx);
        }
 }
 
@@ -1182,6 +1182,13 @@ static int __auxtrace_mmap__read(struct auxtrace_mmap *mm,
                data2 = NULL;
        }
 
+       if (itr->alignment) {
+               unsigned int unwanted = len1 % itr->alignment;
+
+               len1 -= unwanted;
+               size -= unwanted;
+       }
+
        /* padding must be written by fn() e.g. record__process_auxtrace() */
        padding = size & 7;
        if (padding)
index a171abbe730146c2ec6394c417250c57e3d84482..471aecbc4d684018f21d8e7696c39fe027f2430f 100644 (file)
@@ -303,6 +303,7 @@ struct auxtrace_record {
                                      const char *str);
        u64 (*reference)(struct auxtrace_record *itr);
        int (*read_finish)(struct auxtrace_record *itr, int idx);
+       unsigned int alignment;
 };
 
 #ifdef HAVE_AUXTRACE_SUPPORT
index 85b523885f9d70d3e708cb0688e4933b43a1f388..2babddaa24813102c0c9d7525ec8ab615b621775 100644 (file)
@@ -7,11 +7,15 @@
 
 static unsigned long flag = PERF_FLAG_FD_CLOEXEC;
 
+#ifdef __GLIBC_PREREQ
+#if !__GLIBC_PREREQ(2, 6)
 int __weak sched_getcpu(void)
 {
        errno = ENOSYS;
        return -1;
 }
+#endif
+#endif
 
 static int perf_flag_probe(void)
 {
index c4e55b71010c6b52f2be7bc6c3af053c6f4183d0..3667e2123e5b44414a483c23b239e61b955dd7f7 100644 (file)
@@ -5,6 +5,7 @@
 #include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include "asm/bug.h"
 
 static struct cpu_map *cpu_map__default_new(void)
 {
@@ -22,6 +23,7 @@ static struct cpu_map *cpu_map__default_new(void)
                        cpus->map[i] = i;
 
                cpus->nr = nr_cpus;
+               atomic_set(&cpus->refcnt, 1);
        }
 
        return cpus;
@@ -35,6 +37,7 @@ static struct cpu_map *cpu_map__trim_new(int nr_cpus, int *tmp_cpus)
        if (cpus != NULL) {
                cpus->nr = nr_cpus;
                memcpy(cpus->map, tmp_cpus, payload_size);
+               atomic_set(&cpus->refcnt, 1);
        }
 
        return cpus;
@@ -194,14 +197,32 @@ struct cpu_map *cpu_map__dummy_new(void)
        if (cpus != NULL) {
                cpus->nr = 1;
                cpus->map[0] = -1;
+               atomic_set(&cpus->refcnt, 1);
        }
 
        return cpus;
 }
 
-void cpu_map__delete(struct cpu_map *map)
+static void cpu_map__delete(struct cpu_map *map)
 {
-       free(map);
+       if (map) {
+               WARN_ONCE(atomic_read(&map->refcnt) != 0,
+                         "cpu_map refcnt unbalanced\n");
+               free(map);
+       }
+}
+
+struct cpu_map *cpu_map__get(struct cpu_map *map)
+{
+       if (map)
+               atomic_inc(&map->refcnt);
+       return map;
+}
+
+void cpu_map__put(struct cpu_map *map)
+{
+       if (map && atomic_dec_and_test(&map->refcnt))
+               cpu_map__delete(map);
 }
 
 int cpu_map__get_socket(struct cpu_map *map, int idx)
@@ -263,6 +284,7 @@ static int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res,
        /* ensure we process id in increasing order */
        qsort(c->map, c->nr, sizeof(int), cmp_ids);
 
+       atomic_set(&cpus->refcnt, 1);
        *res = c;
        return 0;
 }
index 61a6548490025e209f6232293578e662e62d610a..0af9cecb4c519d44da13d392baa9abca37ebe6ec 100644 (file)
@@ -3,18 +3,19 @@
 
 #include <stdio.h>
 #include <stdbool.h>
+#include <linux/atomic.h>
 
 #include "perf.h"
 #include "util/debug.h"
 
 struct cpu_map {
+       atomic_t refcnt;
        int nr;
        int map[];
 };
 
 struct cpu_map *cpu_map__new(const char *cpu_list);
 struct cpu_map *cpu_map__dummy_new(void);
-void cpu_map__delete(struct cpu_map *map);
 struct cpu_map *cpu_map__read(FILE *file);
 size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
 int cpu_map__get_socket(struct cpu_map *map, int idx);
@@ -22,6 +23,9 @@ int cpu_map__get_core(struct cpu_map *map, int idx);
 int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp);
 int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep);
 
+struct cpu_map *cpu_map__get(struct cpu_map *map);
+void cpu_map__put(struct cpu_map *map);
+
 static inline int cpu_map__socket(struct cpu_map *sock, int s)
 {
        if (!sock || s > sock->nr || s < 0)
index d7d986d8f23e5f890cc295b3b830470343f34063..67a977e5d0abee03a97eb74f914f9329163a6ca7 100644 (file)
@@ -504,7 +504,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
        for (thread = 0; thread < threads->nr; ++thread) {
                if (__event__synthesize_thread(comm_event, mmap_event,
                                               fork_event,
-                                              threads->map[thread], 0,
+                                              thread_map__pid(threads, thread), 0,
                                               process, tool, machine,
                                               mmap_data, proc_map_timeout)) {
                        err = -1;
@@ -515,12 +515,12 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
                 * comm.pid is set to thread group id by
                 * perf_event__synthesize_comm
                 */
-               if ((int) comm_event->comm.pid != threads->map[thread]) {
+               if ((int) comm_event->comm.pid != thread_map__pid(threads, thread)) {
                        bool need_leader = true;
 
                        /* is thread group leader in thread_map? */
                        for (j = 0; j < threads->nr; ++j) {
-                               if ((int) comm_event->comm.pid == threads->map[j]) {
+                               if ((int) comm_event->comm.pid == thread_map__pid(threads, j)) {
                                        need_leader = false;
                                        break;
                                }
index 8366511b45f8327a65dc44e80544f6b08e0df24a..6cfdee68e76398cdb2d53c6950d8c34ea969484a 100644 (file)
@@ -114,8 +114,8 @@ void perf_evlist__delete(struct perf_evlist *evlist)
 {
        perf_evlist__munmap(evlist);
        perf_evlist__close(evlist);
-       cpu_map__delete(evlist->cpus);
-       thread_map__delete(evlist->threads);
+       cpu_map__put(evlist->cpus);
+       thread_map__put(evlist->threads);
        evlist->cpus = NULL;
        evlist->threads = NULL;
        perf_evlist__purge(evlist);
@@ -548,7 +548,7 @@ static void perf_evlist__set_sid_idx(struct perf_evlist *evlist,
        else
                sid->cpu = -1;
        if (!evsel->system_wide && evlist->threads && thread >= 0)
-               sid->tid = evlist->threads->map[thread];
+               sid->tid = thread_map__pid(evlist->threads, thread);
        else
                sid->tid = -1;
 }
@@ -1101,6 +1101,31 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
        return perf_evlist__mmap_ex(evlist, pages, overwrite, 0, false);
 }
 
+static int perf_evlist__propagate_maps(struct perf_evlist *evlist,
+                                      struct target *target)
+{
+       struct perf_evsel *evsel;
+
+       evlist__for_each(evlist, evsel) {
+               /*
+                * We already have cpus for evsel (via PMU sysfs) so
+                * keep it, if there's no target cpu list defined.
+                */
+               if (evsel->cpus && target->cpu_list)
+                       cpu_map__put(evsel->cpus);
+
+               if (!evsel->cpus || target->cpu_list)
+                       evsel->cpus = cpu_map__get(evlist->cpus);
+
+               evsel->threads = thread_map__get(evlist->threads);
+
+               if (!evsel->cpus || !evsel->threads)
+                       return -ENOMEM;
+       }
+
+       return 0;
+}
+
 int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target)
 {
        evlist->threads = thread_map__new_str(target->pid, target->tid,
@@ -1117,10 +1142,10 @@ int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target)
        if (evlist->cpus == NULL)
                goto out_delete_threads;
 
-       return 0;
+       return perf_evlist__propagate_maps(evlist, target);
 
 out_delete_threads:
-       thread_map__delete(evlist->threads);
+       thread_map__put(evlist->threads);
        evlist->threads = NULL;
        return -1;
 }
@@ -1353,7 +1378,7 @@ static int perf_evlist__create_syswide_maps(struct perf_evlist *evlist)
 out:
        return err;
 out_free_cpus:
-       cpu_map__delete(evlist->cpus);
+       cpu_map__put(evlist->cpus);
        evlist->cpus = NULL;
        goto out;
 }
@@ -1475,7 +1500,7 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *tar
                                __func__, __LINE__);
                        goto out_close_pipes;
                }
-               evlist->threads->map[0] = evlist->workload.pid;
+               thread_map__set_pid(evlist->threads, 0, evlist->workload.pid);
        }
 
        close(child_ready_pipe[1]);
index a8489b9d2812baecf1ba4709ff3b6da9787adda0..037633c1da9d0c42402b908294724f92e6caddc8 100644 (file)
@@ -289,5 +289,4 @@ void perf_evlist__to_front(struct perf_evlist *evlist,
 
 void perf_evlist__set_tracking_event(struct perf_evlist *evlist,
                                     struct perf_evsel *tracking_evsel);
-
 #endif /* __PERF_EVLIST_H */
index 33449decf7bd2c24d981fdf30c10042063a503ee..2936b308072200b79f54820a4bf63b0895704bbf 100644 (file)
@@ -885,6 +885,8 @@ void perf_evsel__exit(struct perf_evsel *evsel)
        perf_evsel__free_fd(evsel);
        perf_evsel__free_id(evsel);
        close_cgroup(evsel->cgrp);
+       cpu_map__put(evsel->cpus);
+       thread_map__put(evsel->threads);
        zfree(&evsel->group_name);
        zfree(&evsel->name);
        perf_evsel__object.fini(evsel);
@@ -896,7 +898,7 @@ void perf_evsel__delete(struct perf_evsel *evsel)
        free(evsel);
 }
 
-void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu,
+void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu, int thread,
                                struct perf_counts_values *count)
 {
        struct perf_counts_values tmp;
@@ -908,8 +910,8 @@ void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu,
                tmp = evsel->prev_raw_counts->aggr;
                evsel->prev_raw_counts->aggr = *count;
        } else {
-               tmp = evsel->prev_raw_counts->cpu[cpu];
-               evsel->prev_raw_counts->cpu[cpu] = *count;
+               tmp = *perf_counts(evsel->prev_raw_counts, cpu, thread);
+               *perf_counts(evsel->prev_raw_counts, cpu, thread) = *count;
        }
 
        count->val = count->val - tmp.val;
@@ -937,20 +939,18 @@ void perf_counts_values__scale(struct perf_counts_values *count,
                *pscaled = scaled;
 }
 
-int perf_evsel__read_cb(struct perf_evsel *evsel, int cpu, int thread,
-                       perf_evsel__read_cb_t cb)
+int perf_evsel__read(struct perf_evsel *evsel, int cpu, int thread,
+                    struct perf_counts_values *count)
 {
-       struct perf_counts_values count;
-
-       memset(&count, 0, sizeof(count));
+       memset(count, 0, sizeof(*count));
 
        if (FD(evsel, cpu, thread) < 0)
                return -EINVAL;
 
-       if (readn(FD(evsel, cpu, thread), &count, sizeof(count)) < 0)
+       if (readn(FD(evsel, cpu, thread), count, sizeof(*count)) < 0)
                return -errno;
 
-       return cb(evsel, cpu, thread, &count);
+       return 0;
 }
 
 int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
@@ -962,15 +962,15 @@ int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
        if (FD(evsel, cpu, thread) < 0)
                return -EINVAL;
 
-       if (evsel->counts == NULL && perf_evsel__alloc_counts(evsel, cpu + 1) < 0)
+       if (evsel->counts == NULL && perf_evsel__alloc_counts(evsel, cpu + 1, thread + 1) < 0)
                return -ENOMEM;
 
        if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0)
                return -errno;
 
-       perf_evsel__compute_deltas(evsel, cpu, &count);
+       perf_evsel__compute_deltas(evsel, cpu, thread, &count);
        perf_counts_values__scale(&count, scale, NULL);
-       evsel->counts->cpu[cpu] = count;
+       *perf_counts(evsel->counts, cpu, thread) = count;
        return 0;
 }
 
@@ -1167,7 +1167,7 @@ retry_sample_id:
                        int group_fd;
 
                        if (!evsel->cgrp && !evsel->system_wide)
-                               pid = threads->map[thread];
+                               pid = thread_map__pid(threads, thread);
 
                        group_fd = get_group_fd(evsel, cpu, thread);
 retry_open:
index bb0579e8a10a4556119c5aa313cd22ddacdbc220..4a7ed5656cf0165ffcdd52a1dba063aff6051c8e 100644 (file)
@@ -8,23 +8,8 @@
 #include <linux/types.h>
 #include "xyarray.h"
 #include "symbol.h"
-
-struct perf_counts_values {
-       union {
-               struct {
-                       u64 val;
-                       u64 ena;
-                       u64 run;
-               };
-               u64 values[3];
-       };
-};
-
-struct perf_counts {
-       s8                        scaled;
-       struct perf_counts_values aggr;
-       struct perf_counts_values cpu[];
-};
+#include "cpumap.h"
+#include "stat.h"
 
 struct perf_evsel;
 
@@ -82,6 +67,7 @@ struct perf_evsel {
        struct cgroup_sel       *cgrp;
        void                    *handler;
        struct cpu_map          *cpus;
+       struct thread_map       *threads;
        unsigned int            sample_size;
        int                     id_pos;
        int                     is_pos;
@@ -113,10 +99,20 @@ struct thread_map;
 struct perf_evlist;
 struct record_opts;
 
+static inline struct cpu_map *perf_evsel__cpus(struct perf_evsel *evsel)
+{
+       return evsel->cpus;
+}
+
+static inline int perf_evsel__nr_cpus(struct perf_evsel *evsel)
+{
+       return perf_evsel__cpus(evsel)->nr;
+}
+
 void perf_counts_values__scale(struct perf_counts_values *count,
                               bool scale, s8 *pscaled);
 
-void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu,
+void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu, int thread,
                                struct perf_counts_values *count);
 
 int perf_evsel__object_config(size_t object_size,
@@ -233,12 +229,8 @@ static inline bool perf_evsel__match2(struct perf_evsel *e1,
         (a)->attr.type == (b)->attr.type &&    \
         (a)->attr.config == (b)->attr.config)
 
-typedef int (perf_evsel__read_cb_t)(struct perf_evsel *evsel,
-                                   int cpu, int thread,
-                                   struct perf_counts_values *count);
-
-int perf_evsel__read_cb(struct perf_evsel *evsel, int cpu, int thread,
-                       perf_evsel__read_cb_t cb);
+int perf_evsel__read(struct perf_evsel *evsel, int cpu, int thread,
+                    struct perf_counts_values *count);
 
 int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
                              int cpu, int thread, bool scale);
index 21a77e7a171e8aa0664d5caf0737f141bc96e62f..03ace57a800c58fcc5fb3b2be8cd8bfbf8f50977 100644 (file)
@@ -1063,8 +1063,7 @@ out:
        free(buf);
        return events;
 error:
-       if (events)
-               free_event_desc(events);
+       free_event_desc(events);
        events = NULL;
        goto out;
 }
index 4744673aff1b287de3a091a40edade2a709a8e52..7ff682770fdb16e71b368af16efad0edd9443d87 100644 (file)
@@ -1448,10 +1448,9 @@ int machine__process_event(struct machine *machine, union perf_event *event,
        case PERF_RECORD_AUX:
                ret = machine__process_aux_event(machine, event); break;
        case PERF_RECORD_ITRACE_START:
-               ret = machine__process_itrace_start_event(machine, event);
+               ret = machine__process_itrace_start_event(machine, event); break;
        case PERF_RECORD_LOST_SAMPLES:
                ret = machine__process_lost_samples_event(machine, event, sample); break;
-               break;
        default:
                ret = -1;
                break;
index 2a4d1ec028464757d6723bbd08c2d0ce0a010a14..09f8d23571082ef6698f37eefcd8f9d9815f1fdc 100644 (file)
@@ -17,6 +17,7 @@
 #include "parse-events-flex.h"
 #include "pmu.h"
 #include "thread_map.h"
+#include "cpumap.h"
 #include "asm/bug.h"
 
 #define MAX_NAME_LEN 100
@@ -285,7 +286,9 @@ __add_event(struct list_head *list, int *idx,
        if (!evsel)
                return NULL;
 
-       evsel->cpus = cpus;
+       if (cpus)
+               evsel->cpus = cpu_map__get(cpus);
+
        if (name)
                evsel->name = strdup(name);
        list_add_tail(&evsel->node, list);
index 09e738fe9ea2790a1c304f2015cdb20c03c20614..13cef3c655652764c95cdd33f53d048e00bdc10c 100644 (file)
@@ -119,8 +119,8 @@ event               [^,{}/]+
 num_dec                [0-9]+
 num_hex                0x[a-fA-F0-9]+
 num_raw_hex    [a-fA-F0-9]+
-name           [a-zA-Z_*?][a-zA-Z0-9_*?]*
-name_minus     [a-zA-Z_*?][a-zA-Z0-9\-_*?]*
+name           [a-zA-Z_*?][a-zA-Z0-9_*?.]*
+name_minus     [a-zA-Z_*?][a-zA-Z0-9\-_*?.]*
 /* If you add a modifier you need to update check_modifier() */
 modifier_event [ukhpGHSDI]+
 modifier_bp    [rwx]{1,3}
@@ -165,7 +165,6 @@ modifier_bp [rwx]{1,3}
                        return PE_EVENT_NAME;
                }
 
-.              |
 <<EOF>>                {
                        BEGIN(INITIAL);
                        REWIND(0);
index 0fcc624eb76767b1c3fe211f678a981a71b744ce..7bcb8c315615b1ffdf7123584b2b832f5cfd9d35 100644 (file)
@@ -1,4 +1,5 @@
 #include <linux/list.h>
+#include <linux/compiler.h>
 #include <sys/types.h>
 #include <unistd.h>
 #include <stdio.h>
@@ -205,17 +206,12 @@ static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias,
        return 0;
 }
 
-static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file)
+static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
+                                char *desc __maybe_unused, char *val)
 {
        struct perf_pmu_alias *alias;
-       char buf[256];
        int ret;
 
-       ret = fread(buf, 1, sizeof(buf), file);
-       if (ret == 0)
-               return -EINVAL;
-       buf[ret] = 0;
-
        alias = malloc(sizeof(*alias));
        if (!alias)
                return -ENOMEM;
@@ -225,26 +221,43 @@ static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FI
        alias->unit[0] = '\0';
        alias->per_pkg = false;
 
-       ret = parse_events_terms(&alias->terms, buf);
+       ret = parse_events_terms(&alias->terms, val);
        if (ret) {
+               pr_err("Cannot parse alias %s: %d\n", val, ret);
                free(alias);
                return ret;
        }
 
        alias->name = strdup(name);
-       /*
-        * load unit name and scale if available
-        */
-       perf_pmu__parse_unit(alias, dir, name);
-       perf_pmu__parse_scale(alias, dir, name);
-       perf_pmu__parse_per_pkg(alias, dir, name);
-       perf_pmu__parse_snapshot(alias, dir, name);
+       if (dir) {
+               /*
+                * load unit name and scale if available
+                */
+               perf_pmu__parse_unit(alias, dir, name);
+               perf_pmu__parse_scale(alias, dir, name);
+               perf_pmu__parse_per_pkg(alias, dir, name);
+               perf_pmu__parse_snapshot(alias, dir, name);
+       }
 
        list_add_tail(&alias->list, list);
 
        return 0;
 }
 
+static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file)
+{
+       char buf[256];
+       int ret;
+
+       ret = fread(buf, 1, sizeof(buf), file);
+       if (ret == 0)
+               return -EINVAL;
+
+       buf[ret] = 0;
+
+       return __perf_pmu__new_alias(list, dir, name, NULL, buf);
+}
+
 static inline bool pmu_alias_info_file(char *name)
 {
        size_t len;
@@ -436,7 +449,7 @@ static struct cpu_map *pmu_cpumask(const char *name)
        return cpus;
 }
 
-struct perf_event_attr *__attribute__((weak))
+struct perf_event_attr * __weak
 perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused)
 {
        return NULL;
index 076527b639bdbcab38b4e196f1d388352f7e22c1..381f23a443c7e71a78c008cb2e56a88326830d98 100644 (file)
@@ -249,8 +249,12 @@ static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
 static bool kprobe_blacklist__listed(unsigned long address);
 static bool kprobe_warn_out_range(const char *symbol, unsigned long address)
 {
+       u64 etext_addr;
+
        /* Get the address of _etext for checking non-probable text symbol */
-       if (kernel_get_symbol_address_by_name("_etext", false) < address)
+       etext_addr = kernel_get_symbol_address_by_name("_etext", false);
+
+       if (etext_addr != 0 && etext_addr < address)
                pr_warning("%s is out of .text, skip it.\n", symbol);
        else if (kprobe_blacklist__listed(address))
                pr_warning("%s is blacklisted function, skip it.\n", symbol);
index 5925fec90562fc355514489ae3d33814800f3896..e23ded40c79e3ecd62642bf2a07a34c5fc7662f8 100644 (file)
@@ -20,3 +20,4 @@ util/stat.c
 util/strlist.c
 util/trace-event.c
 ../../lib/rbtree.c
+util/string.c
index d906d0ad5d40a34b49955ad9571130b1f93c7dc3..626422eda7274264c46ebca2aad48a51981788a2 100644 (file)
@@ -384,7 +384,7 @@ static int pyrf_cpu_map__init(struct pyrf_cpu_map *pcpus,
 
 static void pyrf_cpu_map__delete(struct pyrf_cpu_map *pcpus)
 {
-       cpu_map__delete(pcpus->cpus);
+       cpu_map__put(pcpus->cpus);
        pcpus->ob_type->tp_free((PyObject*)pcpus);
 }
 
@@ -453,7 +453,7 @@ static int pyrf_thread_map__init(struct pyrf_thread_map *pthreads,
 
 static void pyrf_thread_map__delete(struct pyrf_thread_map *pthreads)
 {
-       thread_map__delete(pthreads->threads);
+       thread_map__put(pthreads->threads);
        pthreads->ob_type->tp_free((PyObject*)pthreads);
 }
 
index d457c523a33d8bb7d00669dbd09e589eecf6de4b..1f7becbe5e182a4f560dd5f435148d302a5aa787 100644 (file)
@@ -64,7 +64,7 @@ static bool perf_probe_api(setup_probe_fn_t fn)
        if (!cpus)
                return false;
        cpu = cpus->map[0];
-       cpu_map__delete(cpus);
+       cpu_map__put(cpus);
 
        do {
                ret = perf_do_probe_api(fn, cpu, try[i++]);
@@ -226,7 +226,7 @@ bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str)
                struct cpu_map *cpus = cpu_map__new(NULL);
 
                cpu =  cpus ? cpus->map[0] : 0;
-               cpu_map__delete(cpus);
+               cpu_map__put(cpus);
        } else {
                cpu = evlist->cpus->map[0];
        }
index aa482c10469d748fb2c6379ff854ba80f53b2b73..ed9dc2555ec7277d01560c1133718e1066dc5630 100644 (file)
@@ -686,6 +686,8 @@ static int process_finished_round(struct perf_tool *tool __maybe_unused,
                                  union perf_event *event __maybe_unused,
                                  struct ordered_events *oe)
 {
+       if (dump_trace)
+               fprintf(stdout, "\n");
        return ordered_events__flush(oe, OE_FLUSH__ROUND);
 }
 
@@ -1726,7 +1728,7 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
        if (perf_header__has_feat(&session->header, HEADER_AUXTRACE))
                msg = " (excludes AUX area (e.g. instruction trace) decoded / synthesized events)";
 
-       ret = fprintf(fp, "Aggregated stats:%s\n", msg);
+       ret = fprintf(fp, "\nAggregated stats:%s\n", msg);
 
        ret += events_stats__fprintf(&session->evlist->stats, fp);
        return ret;
@@ -1893,7 +1895,7 @@ int perf_session__cpu_bitmap(struct perf_session *session,
        err = 0;
 
 out_delete_map:
-       cpu_map__delete(map);
+       cpu_map__put(map);
        return err;
 }
 
index 4014b709f956b96b86dab3526f3b35fec6d8c166..f2a0d1521e266a32a0df10b60f22d88107fae276 100644 (file)
@@ -1,6 +1,8 @@
 #include <math.h>
 #include "stat.h"
+#include "evlist.h"
 #include "evsel.h"
+#include "thread_map.h"
 
 void update_stats(struct stats *stats, u64 val)
 {
@@ -95,33 +97,46 @@ void perf_stat_evsel_id_init(struct perf_evsel *evsel)
        }
 }
 
-struct perf_counts *perf_counts__new(int ncpus)
+struct perf_counts *perf_counts__new(int ncpus, int nthreads)
 {
-       int size = sizeof(struct perf_counts) +
-                  ncpus * sizeof(struct perf_counts_values);
+       struct perf_counts *counts = zalloc(sizeof(*counts));
 
-       return zalloc(size);
+       if (counts) {
+               struct xyarray *values;
+
+               values = xyarray__new(ncpus, nthreads, sizeof(struct perf_counts_values));
+               if (!values) {
+                       free(counts);
+                       return NULL;
+               }
+
+               counts->values = values;
+       }
+
+       return counts;
 }
 
 void perf_counts__delete(struct perf_counts *counts)
 {
-       free(counts);
+       if (counts) {
+               xyarray__delete(counts->values);
+               free(counts);
+       }
 }
 
-static void perf_counts__reset(struct perf_counts *counts, int ncpus)
+static void perf_counts__reset(struct perf_counts *counts)
 {
-       memset(counts, 0, (sizeof(*counts) +
-              (ncpus * sizeof(struct perf_counts_values))));
+       xyarray__reset(counts->values);
 }
 
-void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus)
+void perf_evsel__reset_counts(struct perf_evsel *evsel)
 {
-       perf_counts__reset(evsel->counts, ncpus);
+       perf_counts__reset(evsel->counts);
 }
 
-int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus)
+int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus, int nthreads)
 {
-       evsel->counts = perf_counts__new(ncpus);
+       evsel->counts = perf_counts__new(ncpus, nthreads);
        return evsel->counts != NULL ? 0 : -ENOMEM;
 }
 
@@ -130,3 +145,96 @@ void perf_evsel__free_counts(struct perf_evsel *evsel)
        perf_counts__delete(evsel->counts);
        evsel->counts = NULL;
 }
+
+void perf_evsel__reset_stat_priv(struct perf_evsel *evsel)
+{
+       int i;
+       struct perf_stat *ps = evsel->priv;
+
+       for (i = 0; i < 3; i++)
+               init_stats(&ps->res_stats[i]);
+
+       perf_stat_evsel_id_init(evsel);
+}
+
+int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel)
+{
+       evsel->priv = zalloc(sizeof(struct perf_stat));
+       if (evsel->priv == NULL)
+               return -ENOMEM;
+       perf_evsel__reset_stat_priv(evsel);
+       return 0;
+}
+
+void perf_evsel__free_stat_priv(struct perf_evsel *evsel)
+{
+       zfree(&evsel->priv);
+}
+
+int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel,
+                                     int ncpus, int nthreads)
+{
+       struct perf_counts *counts;
+
+       counts = perf_counts__new(ncpus, nthreads);
+       if (counts)
+               evsel->prev_raw_counts = counts;
+
+       return counts ? 0 : -ENOMEM;
+}
+
+void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel)
+{
+       perf_counts__delete(evsel->prev_raw_counts);
+       evsel->prev_raw_counts = NULL;
+}
+
+int perf_evsel__alloc_stats(struct perf_evsel *evsel, bool alloc_raw)
+{
+       int ncpus = perf_evsel__nr_cpus(evsel);
+       int nthreads = thread_map__nr(evsel->threads);
+
+       if (perf_evsel__alloc_stat_priv(evsel) < 0 ||
+           perf_evsel__alloc_counts(evsel, ncpus, nthreads) < 0 ||
+           (alloc_raw && perf_evsel__alloc_prev_raw_counts(evsel, ncpus, nthreads) < 0))
+               return -ENOMEM;
+
+       return 0;
+}
+
+int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw)
+{
+       struct perf_evsel *evsel;
+
+       evlist__for_each(evlist, evsel) {
+               if (perf_evsel__alloc_stats(evsel, alloc_raw))
+                       goto out_free;
+       }
+
+       return 0;
+
+out_free:
+       perf_evlist__free_stats(evlist);
+       return -1;
+}
+
+void perf_evlist__free_stats(struct perf_evlist *evlist)
+{
+       struct perf_evsel *evsel;
+
+       evlist__for_each(evlist, evsel) {
+               perf_evsel__free_stat_priv(evsel);
+               perf_evsel__free_counts(evsel);
+               perf_evsel__free_prev_raw_counts(evsel);
+       }
+}
+
+void perf_evlist__reset_stats(struct perf_evlist *evlist)
+{
+       struct perf_evsel *evsel;
+
+       evlist__for_each(evlist, evsel) {
+               perf_evsel__reset_stat_priv(evsel);
+               perf_evsel__reset_counts(evsel);
+       }
+}
index 093dc3cb28dd3f62cb593095dfdc9c59317e0446..1cfbe0a980ac77a1a1af31db8a01141a449a6a4f 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/types.h>
 #include <stdio.h>
+#include "xyarray.h"
 
 struct stats
 {
@@ -29,8 +30,32 @@ enum aggr_mode {
        AGGR_GLOBAL,
        AGGR_SOCKET,
        AGGR_CORE,
+       AGGR_THREAD,
 };
 
+struct perf_counts_values {
+       union {
+               struct {
+                       u64 val;
+                       u64 ena;
+                       u64 run;
+               };
+               u64 values[3];
+       };
+};
+
+struct perf_counts {
+       s8                        scaled;
+       struct perf_counts_values aggr;
+       struct xyarray            *values;
+};
+
+static inline struct perf_counts_values*
+perf_counts(struct perf_counts *counts, int cpu, int thread)
+{
+       return xyarray__entry(counts->values, cpu, thread);
+}
+
 void update_stats(struct stats *stats, u64 val);
 double avg_stats(struct stats *stats);
 double stddev_stats(struct stats *stats);
@@ -46,6 +71,8 @@ static inline void init_stats(struct stats *stats)
 }
 
 struct perf_evsel;
+struct perf_evlist;
+
 bool __perf_evsel_stat__is(struct perf_evsel *evsel,
                           enum perf_stat_evsel_id id);
 
@@ -62,10 +89,24 @@ void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 *count,
 void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel,
                                   double avg, int cpu, enum aggr_mode aggr);
 
-struct perf_counts *perf_counts__new(int ncpus);
+struct perf_counts *perf_counts__new(int ncpus, int nthreads);
 void perf_counts__delete(struct perf_counts *counts);
 
-void perf_evsel__reset_counts(struct perf_evsel *evsel, int ncpus);
-int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus);
+void perf_evsel__reset_counts(struct perf_evsel *evsel);
+int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus, int nthreads);
 void perf_evsel__free_counts(struct perf_evsel *evsel);
+
+void perf_evsel__reset_stat_priv(struct perf_evsel *evsel);
+int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel);
+void perf_evsel__free_stat_priv(struct perf_evsel *evsel);
+
+int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel,
+                                     int ncpus, int nthreads);
+void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel);
+
+int perf_evsel__alloc_stats(struct perf_evsel *evsel, bool alloc_raw);
+
+int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw);
+void perf_evlist__free_stats(struct perf_evlist *evlist);
+void perf_evlist__reset_stats(struct perf_evlist *evlist);
 #endif
index 283d3e73e2f23a66b007dd04790f3c3a1dd486e8..eec6c1149f44758ebe22c37fb07cd4cd6fd0aef7 100644 (file)
@@ -748,7 +748,7 @@ static int str_to_bitmap(char *s, cpumask_t *b)
                set_bit(c, cpumask_bits(b));
        }
 
-       cpu_map__delete(m);
+       cpu_map__put(m);
 
        return ret;
 }
index 504f2d73b7eefe2699349ac75c5cc3b875961375..48b588c6951a9476246d6c71a9ee7b8535a8be37 100644 (file)
@@ -1132,8 +1132,11 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
        INIT_LIST_HEAD(&md.maps);
 
        fd = open(kcore_filename, O_RDONLY);
-       if (fd < 0)
+       if (fd < 0) {
+               pr_err("%s requires CAP_SYS_RAWIO capability to access.\n",
+                       kcore_filename);
                return -EINVAL;
+       }
 
        /* Read new maps into temporary lists */
        err = file__read_maps(fd, md.type == MAP__FUNCTION, kcore_mapfn, &md,
index f4822bd03709af52aba3eed89d50f06bc53e4f86..da7646d767feba14c4f1ad3ba60f3758d5f89413 100644 (file)
@@ -8,8 +8,11 @@
 #include <unistd.h>
 #include "strlist.h"
 #include <string.h>
+#include <api/fs/fs.h>
+#include "asm/bug.h"
 #include "thread_map.h"
 #include "util.h"
+#include "debug.h"
 
 /* Skip "." and ".." directories */
 static int filter(const struct dirent *dir)
@@ -20,11 +23,26 @@ static int filter(const struct dirent *dir)
                return 1;
 }
 
+static void thread_map__reset(struct thread_map *map, int start, int nr)
+{
+       size_t size = (nr - start) * sizeof(map->map[0]);
+
+       memset(&map->map[start], 0, size);
+}
+
 static struct thread_map *thread_map__realloc(struct thread_map *map, int nr)
 {
-       size_t size = sizeof(*map) + sizeof(pid_t) * nr;
+       size_t size = sizeof(*map) + sizeof(map->map[0]) * nr;
+       int start = map ? map->nr : 0;
+
+       map = realloc(map, size);
+       /*
+        * We only realloc to add more items, let's reset new items.
+        */
+       if (map)
+               thread_map__reset(map, start, nr);
 
-       return realloc(map, size);
+       return map;
 }
 
 #define thread_map__alloc(__nr) thread_map__realloc(NULL, __nr)
@@ -45,8 +63,9 @@ struct thread_map *thread_map__new_by_pid(pid_t pid)
        threads = thread_map__alloc(items);
        if (threads != NULL) {
                for (i = 0; i < items; i++)
-                       threads->map[i] = atoi(namelist[i]->d_name);
+                       thread_map__set_pid(threads, i, atoi(namelist[i]->d_name));
                threads->nr = items;
+               atomic_set(&threads->refcnt, 1);
        }
 
        for (i=0; i<items; i++)
@@ -61,8 +80,9 @@ struct thread_map *thread_map__new_by_tid(pid_t tid)
        struct thread_map *threads = thread_map__alloc(1);
 
        if (threads != NULL) {
-               threads->map[0] = tid;
-               threads->nr     = 1;
+               thread_map__set_pid(threads, 0, tid);
+               threads->nr = 1;
+               atomic_set(&threads->refcnt, 1);
        }
 
        return threads;
@@ -84,6 +104,7 @@ struct thread_map *thread_map__new_by_uid(uid_t uid)
                goto out_free_threads;
 
        threads->nr = 0;
+       atomic_set(&threads->refcnt, 1);
 
        while (!readdir_r(proc, &dirent, &next) && next) {
                char *end;
@@ -123,8 +144,10 @@ struct thread_map *thread_map__new_by_uid(uid_t uid)
                        threads = tmp;
                }
 
-               for (i = 0; i < items; i++)
-                       threads->map[threads->nr + i] = atoi(namelist[i]->d_name);
+               for (i = 0; i < items; i++) {
+                       thread_map__set_pid(threads, threads->nr + i,
+                                           atoi(namelist[i]->d_name));
+               }
 
                for (i = 0; i < items; i++)
                        zfree(&namelist[i]);
@@ -201,7 +224,7 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str)
                threads = nt;
 
                for (i = 0; i < items; i++) {
-                       threads->map[j++] = atoi(namelist[i]->d_name);
+                       thread_map__set_pid(threads, j++, atoi(namelist[i]->d_name));
                        zfree(&namelist[i]);
                }
                threads->nr = total_tasks;
@@ -210,6 +233,8 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str)
 
 out:
        strlist__delete(slist);
+       if (threads)
+               atomic_set(&threads->refcnt, 1);
        return threads;
 
 out_free_namelist:
@@ -227,8 +252,9 @@ struct thread_map *thread_map__new_dummy(void)
        struct thread_map *threads = thread_map__alloc(1);
 
        if (threads != NULL) {
-               threads->map[0] = -1;
-               threads->nr     = 1;
+               thread_map__set_pid(threads, 0, -1);
+               threads->nr = 1;
+               atomic_set(&threads->refcnt, 1);
        }
        return threads;
 }
@@ -267,10 +293,12 @@ static struct thread_map *thread_map__new_by_tid_str(const char *tid_str)
                        goto out_free_threads;
 
                threads = nt;
-               threads->map[ntasks - 1] = tid;
-               threads->nr              = ntasks;
+               thread_map__set_pid(threads, ntasks - 1, tid);
+               threads->nr = ntasks;
        }
 out:
+       if (threads)
+               atomic_set(&threads->refcnt, 1);
        return threads;
 
 out_free_threads:
@@ -290,9 +318,30 @@ struct thread_map *thread_map__new_str(const char *pid, const char *tid,
        return thread_map__new_by_tid_str(tid);
 }
 
-void thread_map__delete(struct thread_map *threads)
+static void thread_map__delete(struct thread_map *threads)
 {
-       free(threads);
+       if (threads) {
+               int i;
+
+               WARN_ONCE(atomic_read(&threads->refcnt) != 0,
+                         "thread map refcnt unbalanced\n");
+               for (i = 0; i < threads->nr; i++)
+                       free(thread_map__comm(threads, i));
+               free(threads);
+       }
+}
+
+struct thread_map *thread_map__get(struct thread_map *map)
+{
+       if (map)
+               atomic_inc(&map->refcnt);
+       return map;
+}
+
+void thread_map__put(struct thread_map *map)
+{
+       if (map && atomic_dec_and_test(&map->refcnt))
+               thread_map__delete(map);
 }
 
 size_t thread_map__fprintf(struct thread_map *threads, FILE *fp)
@@ -301,7 +350,60 @@ size_t thread_map__fprintf(struct thread_map *threads, FILE *fp)
        size_t printed = fprintf(fp, "%d thread%s: ",
                                 threads->nr, threads->nr > 1 ? "s" : "");
        for (i = 0; i < threads->nr; ++i)
-               printed += fprintf(fp, "%s%d", i ? ", " : "", threads->map[i]);
+               printed += fprintf(fp, "%s%d", i ? ", " : "", thread_map__pid(threads, i));
 
        return printed + fprintf(fp, "\n");
 }
+
+static int get_comm(char **comm, pid_t pid)
+{
+       char *path;
+       size_t size;
+       int err;
+
+       if (asprintf(&path, "%s/%d/comm", procfs__mountpoint(), pid) == -1)
+               return -ENOMEM;
+
+       err = filename__read_str(path, comm, &size);
+       if (!err) {
+               /*
+                * We're reading 16 bytes, while filename__read_str
+                * allocates data per BUFSIZ bytes, so we can safely
+                * mark the end of the string.
+                */
+               (*comm)[size] = 0;
+               rtrim(*comm);
+       }
+
+       free(path);
+       return err;
+}
+
+static void comm_init(struct thread_map *map, int i)
+{
+       pid_t pid = thread_map__pid(map, i);
+       char *comm = NULL;
+
+       /* dummy pid comm initialization */
+       if (pid == -1) {
+               map->map[i].comm = strdup("dummy");
+               return;
+       }
+
+       /*
+        * The comm name is like extra bonus ;-),
+        * so just warn if we fail for any reason.
+        */
+       if (get_comm(&comm, pid))
+               pr_warning("Couldn't resolve comm name for pid %d\n", pid);
+
+       map->map[i].comm = comm;
+}
+
+void thread_map__read_comms(struct thread_map *threads)
+{
+       int i;
+
+       for (i = 0; i < threads->nr; ++i)
+               comm_init(threads, i);
+}
index 95313f43cc0ffe5280b19a54fc9925ec4b83c498..af679d8a50f852ebb3457491f5dc4b96f6520743 100644 (file)
@@ -3,10 +3,17 @@
 
 #include <sys/types.h>
 #include <stdio.h>
+#include <linux/atomic.h>
+
+struct thread_map_data {
+       pid_t    pid;
+       char    *comm;
+};
 
 struct thread_map {
+       atomic_t refcnt;
        int nr;
-       pid_t map[];
+       struct thread_map_data map[];
 };
 
 struct thread_map *thread_map__new_dummy(void);
@@ -15,11 +22,12 @@ struct thread_map *thread_map__new_by_tid(pid_t tid);
 struct thread_map *thread_map__new_by_uid(uid_t uid);
 struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid);
 
+struct thread_map *thread_map__get(struct thread_map *map);
+void thread_map__put(struct thread_map *map);
+
 struct thread_map *thread_map__new_str(const char *pid,
                const char *tid, uid_t uid);
 
-void thread_map__delete(struct thread_map *threads);
-
 size_t thread_map__fprintf(struct thread_map *threads, FILE *fp);
 
 static inline int thread_map__nr(struct thread_map *threads)
@@ -27,4 +35,21 @@ static inline int thread_map__nr(struct thread_map *threads)
        return threads ? threads->nr : 1;
 }
 
+static inline pid_t thread_map__pid(struct thread_map *map, int thread)
+{
+       return map->map[thread].pid;
+}
+
+static inline void
+thread_map__set_pid(struct thread_map *map, int thread, pid_t pid)
+{
+       map->map[thread].pid = pid;
+}
+
+static inline char *thread_map__comm(struct thread_map *map, int thread)
+{
+       return map->map[thread].comm;
+}
+
+void thread_map__read_comms(struct thread_map *threads);
 #endif /* __PERF_THREAD_MAP_H */