Merge tag 'perf-core-for-mingo-20160630' of git://git.kernel.org/pub/scm/linux/kernel...
authorIngo Molnar <mingo@kernel.org>
Fri, 1 Jul 2016 06:40:39 +0000 (08:40 +0200)
committerIngo Molnar <mingo@kernel.org>
Fri, 1 Jul 2016 06:40:39 +0000 (08:40 +0200)
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:

New features:

 - Allow running 'perf test' entries in the same process, not forking to
   test each testcase, useful for debugging (Jiri Olsa)

 - Show number of samples in the stdio annotate header (Peter Zijlstra)

Documentation changes:

 - Add documentation for perf.data on disk format (Andi Kleen)

Build fixes:

 - Fix 'perf trace' build on old systems wrt missing SCHED_RESET_ON_FORK and
   eventfd.h (Arnaldo Carvalho de Melo)

Infrastructure changes:

 - Utility function to fetch arch from evsel/evlist (Ravi Bangoria)

Trivial changes:

 - Fix spelling mistake: "missmatch" -> "mismatch" in libbpf (Colin Ian King)

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
19 files changed:
tools/lib/bpf/libbpf.c
tools/lib/bpf/libbpf.h
tools/perf/Documentation/perf-test.txt
tools/perf/Documentation/perf.data-file-format.txt [new file with mode: 0644]
tools/perf/tests/builtin-test.c
tools/perf/tests/cpumap.c
tools/perf/tests/dso-data.c
tools/perf/tests/tests.h
tools/perf/tests/thread-map.c
tools/perf/trace/beauty/eventfd.c
tools/perf/trace/beauty/sched_policy.c
tools/perf/util/annotate.c
tools/perf/util/cpumap.c
tools/perf/util/cpumap.h
tools/perf/util/dso.c
tools/perf/util/dso.h
tools/perf/util/event.c
tools/perf/util/evsel.c
tools/perf/util/evsel.h

index 462e526..a7cb40a 100644 (file)
@@ -71,7 +71,7 @@ static const char *libbpf_strerror_table[NR_ERRNO] = {
        [ERRCODE_OFFSET(LIBELF)]        = "Something wrong in libelf",
        [ERRCODE_OFFSET(FORMAT)]        = "BPF object format invalid",
        [ERRCODE_OFFSET(KVERSION)]      = "'version' section incorrect or lost",
-       [ERRCODE_OFFSET(ENDIAN)]        = "Endian missmatch",
+       [ERRCODE_OFFSET(ENDIAN)]        = "Endian mismatch",
        [ERRCODE_OFFSET(INTERNAL)]      = "Internal error in libbpf",
        [ERRCODE_OFFSET(RELOC)]         = "Relocation failed",
        [ERRCODE_OFFSET(VERIFY)]        = "Kernel verifier blocks program loading",
index 722f46b..148df36 100644 (file)
@@ -19,7 +19,7 @@ enum libbpf_errno {
        LIBBPF_ERRNO__LIBELF = __LIBBPF_ERRNO__START,
        LIBBPF_ERRNO__FORMAT,   /* BPF object format invalid */
        LIBBPF_ERRNO__KVERSION, /* Incorrect or no 'version' section */
-       LIBBPF_ERRNO__ENDIAN,   /* Endian missmatch */
+       LIBBPF_ERRNO__ENDIAN,   /* Endian mismatch */
        LIBBPF_ERRNO__INTERNAL, /* Internal error in libbpf */
        LIBBPF_ERRNO__RELOC,    /* Relocation failed */
        LIBBPF_ERRNO__LOAD,     /* Load program failure for unknown reason */
index 31a5c3e..b329c65 100644 (file)
@@ -30,3 +30,7 @@ OPTIONS
 -v::
 --verbose::
        Be more verbose.
+
+-F::
+--dont-fork::
+       Do not fork child for each test, run all tests within single process.
diff --git a/tools/perf/Documentation/perf.data-file-format.txt b/tools/perf/Documentation/perf.data-file-format.txt
new file mode 100644 (file)
index 0000000..fdc99fe
--- /dev/null
@@ -0,0 +1,442 @@
+perf.data format
+
+Uptodate as of v4.7
+
+This document describes the on-disk perf.data format, generated by perf record
+or perf inject and consumed by the other perf tools.
+
+On a high level perf.data contains the events generated by the PMUs, plus metadata.
+
+All fields are in native-endian of the machine that generated the perf.data.
+
+When perf is writing to a pipe it uses a special version of the file
+format that does not rely on seeking to adjust data offsets.  This
+format is not described here. The pipe version can be converted to
+normal perf.data with perf inject.
+
+The file starts with a perf_header:
+
+struct perf_header {
+       char magic[8];          /* PERFILE2 */
+       uint64_t size;          /* size of the header */
+       uint64_t attr_size;     /* size of an attribute in attrs */
+       struct perf_file_section attrs;
+       struct perf_file_section data;
+       struct perf_file_section event_types;
+       uint64_t flags;
+       uint64_t flags1[3];
+};
+
+The magic number identifies the perf file and the version. Current perf versions
+use PERFILE2. Old perf versions generated a version 1 format (PERFFILE). Version 1
+is not described here. The magic number also identifies the endian. When the
+magic value is 64bit byte swapped compared the file is in non-native
+endian.
+
+A perf_file_section contains a pointer to another section of the perf file.
+The header contains three such pointers: for attributes, data and event types.
+
+struct perf_file_section {
+       uint64_t offset;        /* offset from start of file */
+       uint64_t size;          /* size of the section */
+};
+
+Flags section:
+
+The header is followed by different optional headers, described by the bits set
+in flags. Only headers for which the bit is set are included. Each header
+consists of a perf_file_section located after the initial header.
+The respective perf_file_section points to the data of the additional
+header and defines its size.
+
+Some headers consist of strings, which are defined like this:
+
+struct perf_header_string {
+       uint32_t len;
+       char string[len]; /* zero terminated */
+};
+
+Some headers consist of a sequence of strings, which start with a
+
+struct perf_header_string_list {
+     uint32_t nr;
+     struct perf_header_string strings[nr]; /* variable length records */
+};
+
+The bits are the flags bits in a 256 bit bitmap starting with
+flags. These define the valid bits:
+
+       HEADER_RESERVED         = 0,    /* always cleared */
+       HEADER_FIRST_FEATURE    = 1,
+       HEADER_TRACING_DATA     = 1,
+
+Describe me.
+
+       HEADER_BUILD_ID = 2,
+
+The header consists of an sequence of build_id_event. The size of each record
+is defined by header.size (see perf_event.h). Each event defines a ELF build id
+for a executable file name for a pid. An ELF build id is a unique identifier
+assigned by the linker to an executable.
+
+struct build_id_event {
+       struct perf_event_header header;
+       pid_t                    pid;
+       uint8_t                  build_id[24];
+       char                     filename[header.size - offsetof(struct build_id_event, filename)];
+};
+
+       HEADER_HOSTNAME = 3,
+
+A perf_header_string with the hostname where the data was collected
+(uname -n)
+
+       HEADER_OSRELEASE = 4,
+
+A perf_header_string with the os release where the data was collected
+(uname -r)
+
+       HEADER_VERSION = 5,
+
+A perf_header_string with the perf user tool version where the
+data was collected. This is the same as the version of the source tree
+the perf tool was built from.
+
+       HEADER_ARCH = 6,
+
+A perf_header_string with the CPU architecture (uname -m)
+
+       HEADER_NRCPUS = 7,
+
+A structure defining the number of CPUs.
+
+struct nr_cpus {
+       uint32_t nr_cpus_online;
+       uint32_t nr_cpus_available; /* CPUs not yet onlined */
+};
+
+       HEADER_CPUDESC = 8,
+
+A perf_header_string with description of the CPU. On x86 this is the model name
+in /proc/cpuinfo
+
+       HEADER_CPUID = 9,
+
+A perf_header_string with the exact CPU type. On x86 this is
+vendor,family,model,stepping. For example: GenuineIntel,6,69,1
+
+       HEADER_TOTAL_MEM = 10,
+
+An uint64_t with the total memory in bytes.
+
+       HEADER_CMDLINE = 11,
+
+A perf_header_string with the perf command line used to collect the data.
+
+       HEADER_EVENT_DESC = 12,
+
+Another description of the perf_event_attrs, more detailed than header.attrs
+including IDs and names. See perf_event.h or the man page for a description
+of a struct perf_event_attr.
+
+struct {
+       uint32_t nr; /* number of events */
+       uint32_t attr_size; /* size of each perf_event_attr */
+       struct {
+             struct perf_event_attr attr;  /* size of attr_size */
+             uint32_t nr_ids;
+             struct perf_header_string event_string;
+             uint64_t ids[nr_ids];
+       } events[nr]; /* Variable length records */
+};
+
+       HEADER_CPU_TOPOLOGY = 13,
+
+String lists defining the core and CPU threads topology.
+
+struct {
+       struct perf_header_string_list cores; /* Variable length */
+       struct perf_header_string_list threads; /* Variable length */
+};
+
+Example:
+       sibling cores   : 0-3
+       sibling threads : 0-1
+       sibling threads : 2-3
+
+       HEADER_NUMA_TOPOLOGY = 14,
+
+       A list of NUMA node descriptions
+
+struct {
+       uint32_t nr;
+       struct {
+             uint32_t nodenr;
+             uint64_t mem_total;
+             uint64_t mem_free;
+             struct perf_header_string cpus;
+       } nodes[nr]; /* Variable length records */
+};
+
+       HEADER_BRANCH_STACK = 15,
+
+Not implemented in perf.
+
+       HEADER_PMU_MAPPINGS = 16,
+
+       A list of PMU structures, defining the different PMUs supported by perf.
+
+struct {
+       uint32_t nr;
+       struct pmu {
+             uint32_t pmu_type;
+             struct perf_header_string pmu_name;
+       } [nr]; /* Variable length records */
+};
+
+       HEADER_GROUP_DESC = 17,
+
+       Description of counter groups ({...} in perf syntax)
+
+struct {
+         uint32_t nr;
+         struct {
+               struct perf_header_string string;
+               uint32_t leader_idx;
+               uint32_t nr_members;
+        } [nr]; /* Variable length records */
+};
+
+       HEADER_AUXTRACE = 18,
+
+Define additional auxtrace areas in the perf.data. auxtrace is used to store
+undecoded hardware tracing information, such as Intel Processor Trace data.
+
+/**
+ * struct auxtrace_index_entry - indexes a AUX area tracing event within a
+ *                               perf.data file.
+ * @file_offset: offset within the perf.data file
+ * @sz: size of the event
+ */
+struct auxtrace_index_entry {
+       u64                     file_offset;
+       u64                     sz;
+};
+
+#define PERF_AUXTRACE_INDEX_ENTRY_COUNT 256
+
+/**
+ * struct auxtrace_index - index of AUX area tracing events within a perf.data
+ *                         file.
+ * @list: linking a number of arrays of entries
+ * @nr: number of entries
+ * @entries: array of entries
+ */
+struct auxtrace_index {
+       struct list_head        list;
+       size_t                  nr;
+       struct auxtrace_index_entry entries[PERF_AUXTRACE_INDEX_ENTRY_COUNT];
+};
+
+       other bits are reserved and should ignored for now
+       HEADER_FEAT_BITS        = 256,
+
+Attributes
+
+This is an array of perf_event_attrs, each attr_size bytes long, which defines
+each event collected. See perf_event.h or the man page for a detailed
+description.
+
+Data
+
+This section is the bulk of the file. It consist of a stream of perf_events
+describing events. This matches the format generated by the kernel.
+See perf_event.h or the manpage for a detailed description.
+
+Some notes on parsing:
+
+Ordering
+
+The events are not necessarily in time stamp order, as they can be
+collected in parallel on different CPUs. If the events should be
+processed in time order they need to be sorted first. It is possible
+to only do a partial sort using the FINISHED_ROUND event header (see
+below). perf record guarantees that there is no reordering over a
+FINISHED_ROUND.
+
+ID vs IDENTIFIER
+
+When the event stream contains multiple events each event is identified
+by an ID. This can be either through the PERF_SAMPLE_ID or the
+PERF_SAMPLE_IDENTIFIER header. The PERF_SAMPLE_IDENTIFIER header is
+at a fixed offset from the event header, which allows reliable
+parsing of the header. Relying on ID may be ambigious.
+IDENTIFIER is only supported by newer Linux kernels.
+
+Perf record specific events:
+
+In addition to the kernel generated event types perf record adds its
+own event types (in addition it also synthesizes some kernel events,
+for example MMAP events)
+
+       PERF_RECORD_USER_TYPE_START             = 64,
+       PERF_RECORD_HEADER_ATTR                 = 64,
+
+struct attr_event {
+       struct perf_event_header header;
+       struct perf_event_attr attr;
+       uint64_t id[];
+};
+
+       PERF_RECORD_HEADER_EVENT_TYPE           = 65, /* depreceated */
+
+#define MAX_EVENT_NAME 64
+
+struct perf_trace_event_type {
+       uint64_t        event_id;
+       char    name[MAX_EVENT_NAME];
+};
+
+struct event_type_event {
+       struct perf_event_header header;
+       struct perf_trace_event_type event_type;
+};
+
+
+       PERF_RECORD_HEADER_TRACING_DATA         = 66,
+
+Describe me
+
+struct tracing_data_event {
+       struct perf_event_header header;
+       uint32_t size;
+};
+
+       PERF_RECORD_HEADER_BUILD_ID             = 67,
+
+Define a ELF build ID for a referenced executable.
+
+       struct build_id_event;   /* See above */
+
+       PERF_RECORD_FINISHED_ROUND              = 68,
+
+No event reordering over this header. No payload.
+
+       PERF_RECORD_ID_INDEX                    = 69,
+
+Map event ids to CPUs and TIDs.
+
+struct id_index_entry {
+       uint64_t id;
+       uint64_t idx;
+       uint64_t cpu;
+       uint64_t tid;
+};
+
+struct id_index_event {
+       struct perf_event_header header;
+       uint64_t nr;
+       struct id_index_entry entries[nr];
+};
+
+       PERF_RECORD_AUXTRACE_INFO               = 70,
+
+Auxtrace type specific information. Describe me
+
+struct auxtrace_info_event {
+       struct perf_event_header header;
+       uint32_t type;
+       uint32_t reserved__; /* For alignment */
+       uint64_t priv[];
+};
+
+       PERF_RECORD_AUXTRACE                    = 71,
+
+Defines auxtrace data. Followed by the actual data. The contents of
+the auxtrace data is dependent on the event and the CPU. For example
+for Intel Processor Trace it contains Processor Trace data generated
+by the CPU.
+
+struct auxtrace_event {
+       struct perf_event_header header;
+       uint64_t size;
+       uint64_t offset;
+       uint64_t reference;
+       uint32_t idx;
+       uint32_t tid;
+       uint32_t cpu;
+       uint32_t reserved__; /* For alignment */
+};
+
+struct aux_event {
+       struct perf_event_header header;
+       uint64_t        aux_offset;
+       uint64_t        aux_size;
+       uint64_t        flags;
+};
+
+       PERF_RECORD_AUXTRACE_ERROR              = 72,
+
+Describes an error in hardware tracing
+
+enum auxtrace_error_type {
+       PERF_AUXTRACE_ERROR_ITRACE  = 1,
+       PERF_AUXTRACE_ERROR_MAX
+};
+
+#define MAX_AUXTRACE_ERROR_MSG 64
+
+struct auxtrace_error_event {
+       struct perf_event_header header;
+       uint32_t type;
+       uint32_t code;
+       uint32_t cpu;
+       uint32_t pid;
+       uint32_t tid;
+       uint32_t reserved__; /* For alignment */
+       uint64_t ip;
+       char msg[MAX_AUXTRACE_ERROR_MSG];
+};
+
+Event types
+
+Define the event attributes with their IDs.
+
+An array bound by the perf_file_section size.
+
+       struct {
+               struct perf_event_attr attr;   /* Size defined by header.attr_size */
+               struct perf_file_section ids;
+       }
+
+ids points to a array of uint64_t defining the ids for event attr attr.
+
+References:
+
+include/uapi/linux/perf_event.h
+
+This is the canonical description of the kernel generated perf_events
+and the perf_event_attrs.
+
+perf_events manpage
+
+A manpage describing perf_event and perf_event_attr is here:
+http://web.eece.maine.edu/~vweaver/projects/perf_events/programming.html
+This tends to be slightly behind the kernel include, but has better
+descriptions.  An (typically older) version of the man page may be
+included with the standard Linux man pages, available with "man
+perf_events"
+
+pmu-tools
+
+https://github.com/andikleen/pmu-tools/tree/master/parser
+
+A definition of the perf.data format in python "construct" format is available
+in pmu-tools parser. This allows to read perf.data from python and dump it.
+
+quipper
+
+The quipper C++ parser is available at
+https://chromium.googlesource.com/chromiumos/platform/chromiumos-wide-profiling/
+Unfortunately this parser tends to be many versions behind and may not be able
+to parse data files generated by recent perf.
index 0e95c20..07c14e9 100644 (file)
@@ -14,6 +14,8 @@
 #include <subcmd/parse-options.h>
 #include "symbol.h"
 
+static bool dont_fork;
+
 struct test __weak arch_tests[] = {
        {
                .func = NULL,
@@ -211,6 +213,10 @@ static struct test generic_tests[] = {
                .desc = "Test backward reading from ring buffer",
                .func = test__backward_ring_buffer,
        },
+       {
+               .desc = "Test cpu map print",
+               .func = test__cpu_map_print,
+       },
        {
                .func = NULL,
        },
@@ -247,7 +253,7 @@ static bool perf_test__matches(struct test *test, int curr, int argc, const char
 
 static int run_test(struct test *test, int subtest)
 {
-       int status, err = -1, child = fork();
+       int status, err = -1, child = dont_fork ? 0 : fork();
        char sbuf[STRERR_BUFSIZE];
 
        if (child < 0) {
@@ -257,34 +263,41 @@ static int run_test(struct test *test, int subtest)
        }
 
        if (!child) {
-               pr_debug("test child forked, pid %d\n", getpid());
-               if (!verbose) {
-                       int nullfd = open("/dev/null", O_WRONLY);
-                       if (nullfd >= 0) {
-                               close(STDERR_FILENO);
-                               close(STDOUT_FILENO);
-
-                               dup2(nullfd, STDOUT_FILENO);
-                               dup2(STDOUT_FILENO, STDERR_FILENO);
-                               close(nullfd);
+               if (!dont_fork) {
+                       pr_debug("test child forked, pid %d\n", getpid());
+
+                       if (!verbose) {
+                               int nullfd = open("/dev/null", O_WRONLY);
+
+                               if (nullfd >= 0) {
+                                       close(STDERR_FILENO);
+                                       close(STDOUT_FILENO);
+
+                                       dup2(nullfd, STDOUT_FILENO);
+                                       dup2(STDOUT_FILENO, STDERR_FILENO);
+                                       close(nullfd);
+                               }
+                       } else {
+                               signal(SIGSEGV, sighandler_dump_stack);
+                               signal(SIGFPE, sighandler_dump_stack);
                        }
-               } else {
-                       signal(SIGSEGV, sighandler_dump_stack);
-                       signal(SIGFPE, sighandler_dump_stack);
                }
 
                err = test->func(subtest);
-               exit(err);
+               if (!dont_fork)
+                       exit(err);
        }
 
-       wait(&status);
+       if (!dont_fork) {
+               wait(&status);
 
-       if (WIFEXITED(status)) {
-               err = (signed char)WEXITSTATUS(status);
-               pr_debug("test child finished with %d\n", err);
-       } else if (WIFSIGNALED(status)) {
-               err = -1;
-               pr_debug("test child interrupted\n");
+               if (WIFEXITED(status)) {
+                       err = (signed char)WEXITSTATUS(status);
+                       pr_debug("test child finished with %d\n", err);
+               } else if (WIFSIGNALED(status)) {
+                       err = -1;
+                       pr_debug("test child interrupted\n");
+               }
        }
 
        return err;
@@ -425,6 +438,8 @@ int cmd_test(int argc, const char **argv, const char *prefix __maybe_unused)
        OPT_STRING('s', "skip", &skip, "tests", "tests to skip"),
        OPT_INCR('v', "verbose", &verbose,
                    "be more verbose (show symbol address, etc)"),
+       OPT_BOOLEAN('F', "dont-fork", &dont_fork,
+                   "Do not fork for testcase"),
        OPT_END()
        };
        const char * const test_subcommands[] = { "list", NULL };
index 4cb6418..c9ec5f8 100644 (file)
@@ -86,3 +86,27 @@ int test__cpu_map_synthesize(int subtest __maybe_unused)
        cpu_map__put(cpus);
        return 0;
 }
+
+static int cpu_map_print(const char *str)
+{
+       struct cpu_map *map = cpu_map__new(str);
+       char buf[100];
+
+       if (!map)
+               return -1;
+
+       cpu_map__snprint(map, buf, sizeof(buf));
+       return !strcmp(buf, str);
+}
+
+int test__cpu_map_print(int subtest __maybe_unused)
+{
+       TEST_ASSERT_VAL("failed to convert map", cpu_map_print("1"));
+       TEST_ASSERT_VAL("failed to convert map", cpu_map_print("1,5"));
+       TEST_ASSERT_VAL("failed to convert map", cpu_map_print("1,3,5,7,9,11,13,15,17,19,21-40"));
+       TEST_ASSERT_VAL("failed to convert map", cpu_map_print("2-5"));
+       TEST_ASSERT_VAL("failed to convert map", cpu_map_print("1,3-6,8-10,24,35-37"));
+       TEST_ASSERT_VAL("failed to convert map", cpu_map_print("1,3-6,8-10,24,35-37"));
+       TEST_ASSERT_VAL("failed to convert map", cpu_map_print("1-10,12-20,22-30,32-40"));
+       return 0;
+}
index 8cf0d9e..13725e0 100644 (file)
@@ -251,6 +251,9 @@ int test__dso_data_cache(int subtest __maybe_unused)
        long nr_end, nr = open_files_cnt();
        int dso_cnt, limit, i, fd;
 
+       /* Rest the internal dso open counter limit. */
+       reset_fd_limit();
+
        memset(&machine, 0, sizeof(machine));
 
        /* set as system limit */
@@ -312,6 +315,9 @@ int test__dso_data_reopen(int subtest __maybe_unused)
 #define dso_1 (dsos[1])
 #define dso_2 (dsos[2])
 
+       /* Rest the internal dso open counter limit. */
+       reset_fd_limit();
+
        memset(&machine, 0, sizeof(machine));
 
        /*
index c57e72c..52f9695 100644 (file)
@@ -87,6 +87,7 @@ int test__synthesize_stat_round(int subtest);
 int test__event_update(int subtest);
 int test__event_times(int subtest);
 int test__backward_ring_buffer(int subtest);
+int test__cpu_map_print(int subtest);
 
 #if defined(__arm__) || defined(__aarch64__)
 #ifdef HAVE_DWARF_UNWIND_SUPPORT
index fccde84..cee2a2c 100644 (file)
@@ -1,13 +1,20 @@
 #include <sys/types.h>
 #include <unistd.h>
+#include <sys/prctl.h>
 #include "tests.h"
 #include "thread_map.h"
 #include "debug.h"
 
+#define NAME   (const char *) "perf"
+#define NAMEUL (unsigned long) NAME
+
 int test__thread_map(int subtest __maybe_unused)
 {
        struct thread_map *map;
 
+       TEST_ASSERT_VAL("failed to set process name",
+                       !prctl(PR_SET_NAME, NAMEUL, 0, 0, 0));
+
        /* test map on current pid */
        map = thread_map__new_by_pid(getpid());
        TEST_ASSERT_VAL("failed to alloc map", map);
@@ -19,7 +26,7 @@ int test__thread_map(int subtest __maybe_unused)
                        thread_map__pid(map, 0) == getpid());
        TEST_ASSERT_VAL("wrong comm",
                        thread_map__comm(map, 0) &&
-                       !strcmp(thread_map__comm(map, 0), "perf"));
+                       !strcmp(thread_map__comm(map, 0), NAME));
        TEST_ASSERT_VAL("wrong refcnt",
                        atomic_read(&map->refcnt) == 1);
        thread_map__put(map);
@@ -51,7 +58,7 @@ static int process_event(struct perf_tool *tool __maybe_unused,
 
        TEST_ASSERT_VAL("wrong nr",   map->nr == 1);
        TEST_ASSERT_VAL("wrong pid",  map->entries[0].pid == (u64) getpid());
-       TEST_ASSERT_VAL("wrong comm", !strcmp(map->entries[0].comm, "perf"));
+       TEST_ASSERT_VAL("wrong comm", !strcmp(map->entries[0].comm, NAME));
 
        threads = thread_map__new_event(&event->thread_map);
        TEST_ASSERT_VAL("failed to alloc map", threads);
@@ -61,7 +68,7 @@ static int process_event(struct perf_tool *tool __maybe_unused,
                        thread_map__pid(threads, 0) == getpid());
        TEST_ASSERT_VAL("wrong comm",
                        thread_map__comm(threads, 0) &&
-                       !strcmp(thread_map__comm(threads, 0), "perf"));
+                       !strcmp(thread_map__comm(threads, 0), NAME));
        TEST_ASSERT_VAL("wrong refcnt",
                        atomic_read(&threads->refcnt) == 1);
        thread_map__put(threads);
@@ -72,6 +79,9 @@ int test__thread_map_synthesize(int subtest __maybe_unused)
 {
        struct thread_map *threads;
 
+       TEST_ASSERT_VAL("failed to set process name",
+                       !prctl(PR_SET_NAME, NAMEUL, 0, 0, 0));
+
        /* test map on current pid */
        threads = thread_map__new_by_pid(getpid());
        TEST_ASSERT_VAL("failed to alloc map", threads);
index d64f4a9..b08f21e 100644 (file)
@@ -1,5 +1,3 @@
-#include <sys/eventfd.h>
-
 #ifndef EFD_SEMAPHORE
 #define EFD_SEMAPHORE          1
 #endif
index c205bc6..3477529 100644 (file)
@@ -9,6 +9,9 @@
 #ifndef SCHED_DEADLINE
 #define SCHED_DEADLINE 6
 #endif
+#ifndef SCHED_RESET_ON_FORK
+#define SCHED_RESET_ON_FORK 0x40000000
+#endif
 
 static size_t syscall_arg__scnprintf_sched_policy(char *bf, size_t size,
                                                  struct syscall_arg *arg)
index c385fec..e9825fe 100644 (file)
@@ -1522,13 +1522,14 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map,
        const char *d_filename;
        const char *evsel_name = perf_evsel__name(evsel);
        struct annotation *notes = symbol__annotation(sym);
+       struct sym_hist *h = annotation__histogram(notes, evsel->idx);
        struct disasm_line *pos, *queue = NULL;
        u64 start = map__rip_2objdump(map, sym->start);
        int printed = 2, queue_len = 0;
        int more = 0;
        u64 len;
        int width = 8;
-       int namelen, evsel_name_len, graph_dotted_len;
+       int graph_dotted_len;
 
        filename = strdup(dso->long_name);
        if (!filename)
@@ -1540,17 +1541,14 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map,
                d_filename = basename(filename);
 
        len = symbol__size(sym);
-       namelen = strlen(d_filename);
-       evsel_name_len = strlen(evsel_name);
 
        if (perf_evsel__is_group_event(evsel))
                width *= evsel->nr_members;
 
-       printf(" %-*.*s|        Source code & Disassembly of %s for %s\n",
-              width, width, "Percent", d_filename, evsel_name);
+       graph_dotted_len = printf(" %-*.*s|     Source code & Disassembly of %s for %s (%" PRIu64 " samples)\n",
+              width, width, "Percent", d_filename, evsel_name, h->sum);
 
-       graph_dotted_len = width + namelen + evsel_name_len;
-       printf("-%-*.*s-----------------------------------------\n",
+       printf("%-*.*s----\n",
               graph_dotted_len, graph_dotted_len, graph_dotted_line);
 
        if (verbose)
index 02d8016..15f83ac 100644 (file)
@@ -236,13 +236,12 @@ struct cpu_map *cpu_map__new_data(struct cpu_map_data *data)
 
 size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp)
 {
-       int i;
-       size_t printed = fprintf(fp, "%d cpu%s: ",
-                                map->nr, map->nr > 1 ? "s" : "");
-       for (i = 0; i < map->nr; ++i)
-               printed += fprintf(fp, "%s%d", i ? ", " : "", map->map[i]);
+#define BUFSIZE 1024
+       char buf[BUFSIZE];
 
-       return printed + fprintf(fp, "\n");
+       cpu_map__snprint(map, buf, sizeof(buf));
+       return fprintf(fp, "%s\n", buf);
+#undef BUFSIZE
 }
 
 struct cpu_map *cpu_map__dummy_new(void)
@@ -599,3 +598,46 @@ bool cpu_map__has(struct cpu_map *cpus, int cpu)
 
        return false;
 }
+
+size_t cpu_map__snprint(struct cpu_map *map, char *buf, size_t size)
+{
+       int i, cpu, start = -1;
+       bool first = true;
+       size_t ret = 0;
+
+#define COMMA first ? "" : ","
+
+       for (i = 0; i < map->nr + 1; i++) {
+               bool last = i == map->nr;
+
+               cpu = last ? INT_MAX : map->map[i];
+
+               if (start == -1) {
+                       start = i;
+                       if (last) {
+                               ret += snprintf(buf + ret, size - ret,
+                                               "%s%d", COMMA,
+                                               map->map[i]);
+                       }
+               } else if (((i - start) != (cpu - map->map[start])) || last) {
+                       int end = i - 1;
+
+                       if (start == end) {
+                               ret += snprintf(buf + ret, size - ret,
+                                               "%s%d", COMMA,
+                                               map->map[start]);
+                       } else {
+                               ret += snprintf(buf + ret, size - ret,
+                                               "%s%d-%d", COMMA,
+                                               map->map[start], map->map[end]);
+                       }
+                       first = false;
+                       start = i;
+               }
+       }
+
+#undef COMMA
+
+       pr_debug("cpumask list: %s\n", buf);
+       return ret;
+}
index 1a0a350..206dc55 100644 (file)
@@ -19,6 +19,7 @@ struct cpu_map *cpu_map__empty_new(int nr);
 struct cpu_map *cpu_map__dummy_new(void);
 struct cpu_map *cpu_map__new_data(struct cpu_map_data *data);
 struct cpu_map *cpu_map__read(FILE *file);
+size_t cpu_map__snprint(struct cpu_map *map, char *buf, size_t size);
 size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
 int cpu_map__get_socket_id(int cpu);
 int cpu_map__get_socket(struct cpu_map *map, int idx, void *data);
index 5d286f5..e1de6cc 100644 (file)
@@ -442,17 +442,27 @@ static rlim_t get_fd_limit(void)
        return limit;
 }
 
-static bool may_cache_fd(void)
+static rlim_t fd_limit;
+
+/*
+ * Used only by tests/dso-data.c to reset the environment
+ * for tests. I dont expect we should change this during
+ * standard runtime.
+ */
+void reset_fd_limit(void)
 {
-       static rlim_t limit;
+       fd_limit = 0;
+}
 
-       if (!limit)
-               limit = get_fd_limit();
+static bool may_cache_fd(void)
+{
+       if (!fd_limit)
+               fd_limit = get_fd_limit();
 
-       if (limit == RLIM_INFINITY)
+       if (fd_limit == RLIM_INFINITY)
                return true;
 
-       return limit > (rlim_t) dso__data_open_cnt;
+       return fd_limit > (rlim_t) dso__data_open_cnt;
 }
 
 /*
index 76d79d0..a571f24 100644 (file)
@@ -360,4 +360,6 @@ enum dso_type dso__type(struct dso *dso, struct machine *machine);
 
 int dso__strerror_load(struct dso *dso, char *buf, size_t buflen);
 
+void reset_fd_limit(void);
+
 #endif /* __PERF_DSO */
index 9b141f1..e20438b 100644 (file)
@@ -1092,7 +1092,7 @@ size_t perf_event__fprintf_cpu_map(union perf_event *event, FILE *fp)
        struct cpu_map *cpus = cpu_map__new_data(&event->cpu_map.data);
        size_t ret;
 
-       ret = fprintf(fp, " nr: ");
+       ret = fprintf(fp, ": ");
 
        if (cpus)
                ret += cpu_map__fprintf(cpus, fp);
index 1d8f2bb..0fea724 100644 (file)
@@ -2422,3 +2422,10 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target,
                         err, strerror_r(err, sbuf, sizeof(sbuf)),
                         perf_evsel__name(evsel));
 }
+
+char *perf_evsel__env_arch(struct perf_evsel *evsel)
+{
+       if (evsel && evsel->evlist && evsel->evlist->env)
+               return evsel->evlist->env->arch;
+       return NULL;
+}
index 828ddd1..86fed7a 100644 (file)
@@ -435,4 +435,6 @@ typedef int (*attr__fprintf_f)(FILE *, const char *, const char *, void *);
 int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr,
                             attr__fprintf_f attr__fprintf, void *priv);
 
+char *perf_evsel__env_arch(struct perf_evsel *evsel);
+
 #endif /* __PERF_EVSEL_H */