Merge tag 'perf-core-for-mingo-20160414' of git://git.kernel.org/pub/scm/linux/kernel...
authorIngo Molnar <mingo@kernel.org>
Thu, 14 Apr 2016 13:30:59 +0000 (15:30 +0200)
committerIngo Molnar <mingo@kernel.org>
Thu, 14 Apr 2016 13:30:59 +0000 (15:30 +0200)
Pull perf/core improvements from Arnaldo Carvalho de Melo:

User visible changes:

- Introduce 'perf record --timestamp-filename', to add a timestamp
  at the end of the 'perf data' file. Will get added value when
  the patch to make 'perf.data' file snapshots gets merged (Wang Nan)

- Fix display of variables present in both --config and --user in
  'perf list' (Taeung Song)

Build fixes:

- Add seccomp and getradom beautifier related defines to fix
  the build in older systems where those definitions are not
  available (Arnaldo Carvalho de Melo)

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
12 files changed:
tools/perf/builtin-config.c
tools/perf/builtin-record.c
tools/perf/builtin-trace.c
tools/perf/trace/beauty/eventfd.c [new file with mode: 0644]
tools/perf/trace/beauty/mmap.c [new file with mode: 0644]
tools/perf/util/config.c
tools/perf/util/config.h [new file with mode: 0644]
tools/perf/util/data.c
tools/perf/util/data.h
tools/perf/util/ordered-events.c
tools/perf/util/ordered-events.h
tools/perf/util/session.c

index c42448e..fe1b77f 100644 (file)
@@ -12,6 +12,7 @@
 #include <subcmd/parse-options.h>
 #include "util/util.h"
 #include "util/debug.h"
+#include "util/config.h"
 
 static bool use_system_config, use_user_config;
 
@@ -32,13 +33,28 @@ static struct option config_options[] = {
        OPT_END()
 };
 
-static int show_config(const char *key, const char *value,
-                      void *cb __maybe_unused)
+static int show_config(struct perf_config_set *set)
 {
-       if (value)
-               printf("%s=%s\n", key, value);
-       else
-               printf("%s\n", key);
+       struct perf_config_section *section;
+       struct perf_config_item *item;
+       struct list_head *sections;
+
+       if (set == NULL)
+               return -1;
+
+       sections = &set->sections;
+       if (list_empty(sections))
+               return -1;
+
+       list_for_each_entry(section, sections, node) {
+               list_for_each_entry(item, &section->items, node) {
+                       char *value = item->value;
+
+                       if (value)
+                               printf("%s.%s=%s\n", section->name,
+                                      item->name, value);
+               }
+       }
 
        return 0;
 }
@@ -46,6 +62,7 @@ static int show_config(const char *key, const char *value,
 int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
 {
        int ret = 0;
+       struct perf_config_set *set;
        char *user_config = mkpath("%s/.perfconfig", getenv("HOME"));
 
        argc = parse_options(argc, argv, config_options, config_usage,
@@ -63,13 +80,19 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
        else if (use_user_config)
                config_exclusive_filename = user_config;
 
+       set = perf_config_set__new();
+       if (!set) {
+               ret = -1;
+               goto out_err;
+       }
+
        switch (actions) {
        case ACTION_LIST:
                if (argc) {
                        pr_err("Error: takes no arguments\n");
                        parse_options_usage(config_usage, config_options, "l", 1);
                } else {
-                       ret = perf_config(show_config, NULL);
+                       ret = show_config(set);
                        if (ret < 0) {
                                const char * config_filename = config_exclusive_filename;
                                if (!config_exclusive_filename)
@@ -83,5 +106,7 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
                usage_with_options(config_usage, config_options);
        }
 
+       perf_config_set__delete(set);
+out_err:
        return ret;
 }
index eb6a199..3239a6e 100644 (file)
@@ -56,6 +56,7 @@ struct record {
        bool                    no_buildid_cache;
        bool                    no_buildid_cache_set;
        bool                    buildid_all;
+       bool                    timestamp_filename;
        unsigned long long      samples;
 };
 
@@ -125,7 +126,43 @@ out:
 static volatile int done;
 static volatile int signr = -1;
 static volatile int child_finished;
-static volatile int auxtrace_snapshot_enabled;
+
+static volatile enum {
+       AUXTRACE_SNAPSHOT_OFF = -1,
+       AUXTRACE_SNAPSHOT_DISABLED = 0,
+       AUXTRACE_SNAPSHOT_ENABLED = 1,
+} auxtrace_snapshot_state = AUXTRACE_SNAPSHOT_OFF;
+
+static inline void
+auxtrace_snapshot_on(void)
+{
+       auxtrace_snapshot_state = AUXTRACE_SNAPSHOT_DISABLED;
+}
+
+static inline void
+auxtrace_snapshot_enable(void)
+{
+       if (auxtrace_snapshot_state == AUXTRACE_SNAPSHOT_OFF)
+               return;
+       auxtrace_snapshot_state = AUXTRACE_SNAPSHOT_ENABLED;
+}
+
+static inline void
+auxtrace_snapshot_disable(void)
+{
+       if (auxtrace_snapshot_state == AUXTRACE_SNAPSHOT_OFF)
+               return;
+       auxtrace_snapshot_state = AUXTRACE_SNAPSHOT_DISABLED;
+}
+
+static inline bool
+auxtrace_snapshot_is_enabled(void)
+{
+       if (auxtrace_snapshot_state == AUXTRACE_SNAPSHOT_OFF)
+               return false;
+       return auxtrace_snapshot_state == AUXTRACE_SNAPSHOT_ENABLED;
+}
+
 static volatile int auxtrace_snapshot_err;
 static volatile int auxtrace_record__snapshot_started;
 
@@ -249,7 +286,7 @@ static void record__read_auxtrace_snapshot(struct record *rec)
        } else {
                auxtrace_snapshot_err = auxtrace_record__snapshot_finish(rec->itr);
                if (!auxtrace_snapshot_err)
-                       auxtrace_snapshot_enabled = 1;
+                       auxtrace_snapshot_enable();
        }
 }
 
@@ -495,6 +532,37 @@ record__finish_output(struct record *rec)
        return;
 }
 
+static int
+record__switch_output(struct record *rec, bool at_exit)
+{
+       struct perf_data_file *file = &rec->file;
+       int fd, err;
+
+       /* Same Size:      "2015122520103046"*/
+       char timestamp[] = "InvalidTimestamp";
+
+       rec->samples = 0;
+       record__finish_output(rec);
+       err = fetch_current_timestamp(timestamp, sizeof(timestamp));
+       if (err) {
+               pr_err("Failed to get current timestamp\n");
+               return -EINVAL;
+       }
+
+       fd = perf_data_file__switch(file, timestamp,
+                                   rec->session->header.data_offset,
+                                   at_exit);
+       if (fd >= 0 && !at_exit) {
+               rec->bytes_written = 0;
+               rec->session->header.data_size = 0;
+       }
+
+       if (!quiet)
+               fprintf(stderr, "[ perf record: Dump %s.%s ]\n",
+                       file->path, timestamp);
+       return fd;
+}
+
 static volatile int workload_exec_errno;
 
 /*
@@ -615,10 +683,13 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
        signal(SIGCHLD, sig_handler);
        signal(SIGINT, sig_handler);
        signal(SIGTERM, sig_handler);
-       if (rec->opts.auxtrace_snapshot_mode)
+
+       if (rec->opts.auxtrace_snapshot_mode) {
                signal(SIGUSR2, snapshot_sig_handler);
-       else
+               auxtrace_snapshot_on();
+       } else {
                signal(SIGUSR2, SIG_IGN);
+       }
 
        session = perf_session__new(file, false, tool);
        if (session == NULL) {
@@ -744,12 +815,12 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
                perf_evlist__enable(rec->evlist);
        }
 
-       auxtrace_snapshot_enabled = 1;
+       auxtrace_snapshot_enable();
        for (;;) {
                unsigned long long hits = rec->samples;
 
                if (record__mmap_read_all(rec) < 0) {
-                       auxtrace_snapshot_enabled = 0;
+                       auxtrace_snapshot_disable();
                        err = -1;
                        goto out_child;
                }
@@ -787,12 +858,12 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
                 * disable events in this case.
                 */
                if (done && !disabled && !target__none(&opts->target)) {
-                       auxtrace_snapshot_enabled = 0;
+                       auxtrace_snapshot_disable();
                        perf_evlist__disable(rec->evlist);
                        disabled = true;
                }
        }
-       auxtrace_snapshot_enabled = 0;
+       auxtrace_snapshot_disable();
 
        if (forks && workload_exec_errno) {
                char msg[STRERR_BUFSIZE];
@@ -826,11 +897,22 @@ out_child:
        /* this will be recalculated during process_buildids() */
        rec->samples = 0;
 
-       if (!err)
-               record__finish_output(rec);
+       if (!err) {
+               if (!rec->timestamp_filename) {
+                       record__finish_output(rec);
+               } else {
+                       fd = record__switch_output(rec, true);
+                       if (fd < 0) {
+                               status = fd;
+                               goto out_delete_session;
+                       }
+               }
+       }
 
        if (!err && !quiet) {
                char samples[128];
+               const char *postfix = rec->timestamp_filename ?
+                                       ".<timestamp>" : "";
 
                if (rec->samples && !rec->opts.full_auxtrace)
                        scnprintf(samples, sizeof(samples),
@@ -838,9 +920,9 @@ out_child:
                else
                        samples[0] = '\0';
 
-               fprintf(stderr, "[ perf record: Captured and wrote %.3f MB %s%s ]\n",
+               fprintf(stderr, "[ perf record: Captured and wrote %.3f MB %s%s%s ]\n",
                        perf_data_file__size(file) / 1024.0 / 1024.0,
-                       file->path, samples);
+                       file->path, postfix, samples);
        }
 
 out_delete_session:
@@ -1210,6 +1292,8 @@ struct option __record_options[] = {
                   "file", "vmlinux pathname"),
        OPT_BOOLEAN(0, "buildid-all", &record.buildid_all,
                    "Record build-id of all DSOs regardless of hits"),
+       OPT_BOOLEAN(0, "timestamp-filename", &record.timestamp_filename,
+                   "append timestamp to output filename"),
        OPT_END()
 };
 
@@ -1358,9 +1442,9 @@ out_symbol_exit:
 
 static void snapshot_sig_handler(int sig __maybe_unused)
 {
-       if (!auxtrace_snapshot_enabled)
+       if (!auxtrace_snapshot_is_enabled())
                return;
-       auxtrace_snapshot_enabled = 0;
+       auxtrace_snapshot_disable();
        auxtrace_snapshot_err = auxtrace_record__snapshot_start(record.itr);
        auxtrace_record__snapshot_started = 1;
 }
index d49c131..8e090a7 100644 (file)
@@ -39,7 +39,6 @@
 
 #include <libaudit.h> /* FIXME: Still needed for audit_errno_to_name */
 #include <stdlib.h>
-#include <sys/mman.h>
 #include <linux/futex.h>
 #include <linux/err.h>
 #include <linux/seccomp.h>
 #include <sys/ptrace.h>
 #include <linux/random.h>
 
-/* For older distros: */
-#ifndef MAP_STACK
-# define MAP_STACK             0x20000
-#endif
-
-#ifndef MADV_HWPOISON
-# define MADV_HWPOISON         100
-
-#endif
-
-#ifndef MADV_MERGEABLE
-# define MADV_MERGEABLE                12
-#endif
-
-#ifndef MADV_UNMERGEABLE
-# define MADV_UNMERGEABLE      13
-#endif
-
-#ifndef EFD_SEMAPHORE
-# define EFD_SEMAPHORE         1
-#endif
-
-#ifndef EFD_NONBLOCK
-# define EFD_NONBLOCK          00004000
-#endif
-
-#ifndef EFD_CLOEXEC
-# define EFD_CLOEXEC           02000000
-#endif
-
 #ifndef O_CLOEXEC
 # define O_CLOEXEC             02000000
 #endif
@@ -429,147 +398,6 @@ static size_t syscall_arg__scnprintf_int(char *bf, size_t size,
 
 #define SCA_INT syscall_arg__scnprintf_int
 
-static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
-                                              struct syscall_arg *arg)
-{
-       int printed = 0, prot = arg->val;
-
-       if (prot == PROT_NONE)
-               return scnprintf(bf, size, "NONE");
-#define        P_MMAP_PROT(n) \
-       if (prot & PROT_##n) { \
-               printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
-               prot &= ~PROT_##n; \
-       }
-
-       P_MMAP_PROT(EXEC);
-       P_MMAP_PROT(READ);
-       P_MMAP_PROT(WRITE);
-#ifdef PROT_SEM
-       P_MMAP_PROT(SEM);
-#endif
-       P_MMAP_PROT(GROWSDOWN);
-       P_MMAP_PROT(GROWSUP);
-#undef P_MMAP_PROT
-
-       if (prot)
-               printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
-
-       return printed;
-}
-
-#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
-
-static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
-                                               struct syscall_arg *arg)
-{
-       int printed = 0, flags = arg->val;
-
-#define        P_MMAP_FLAG(n) \
-       if (flags & MAP_##n) { \
-               printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
-               flags &= ~MAP_##n; \
-       }
-
-       P_MMAP_FLAG(SHARED);
-       P_MMAP_FLAG(PRIVATE);
-#ifdef MAP_32BIT
-       P_MMAP_FLAG(32BIT);
-#endif
-       P_MMAP_FLAG(ANONYMOUS);
-       P_MMAP_FLAG(DENYWRITE);
-       P_MMAP_FLAG(EXECUTABLE);
-       P_MMAP_FLAG(FILE);
-       P_MMAP_FLAG(FIXED);
-       P_MMAP_FLAG(GROWSDOWN);
-#ifdef MAP_HUGETLB
-       P_MMAP_FLAG(HUGETLB);
-#endif
-       P_MMAP_FLAG(LOCKED);
-       P_MMAP_FLAG(NONBLOCK);
-       P_MMAP_FLAG(NORESERVE);
-       P_MMAP_FLAG(POPULATE);
-       P_MMAP_FLAG(STACK);
-#ifdef MAP_UNINITIALIZED
-       P_MMAP_FLAG(UNINITIALIZED);
-#endif
-#undef P_MMAP_FLAG
-
-       if (flags)
-               printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
-
-       return printed;
-}
-
-#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
-
-static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size,
-                                                 struct syscall_arg *arg)
-{
-       int printed = 0, flags = arg->val;
-
-#define P_MREMAP_FLAG(n) \
-       if (flags & MREMAP_##n) { \
-               printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
-               flags &= ~MREMAP_##n; \
-       }
-
-       P_MREMAP_FLAG(MAYMOVE);
-#ifdef MREMAP_FIXED
-       P_MREMAP_FLAG(FIXED);
-#endif
-#undef P_MREMAP_FLAG
-
-       if (flags)
-               printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
-
-       return printed;
-}
-
-#define SCA_MREMAP_FLAGS syscall_arg__scnprintf_mremap_flags
-
-static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
-                                                     struct syscall_arg *arg)
-{
-       int behavior = arg->val;
-
-       switch (behavior) {
-#define        P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
-       P_MADV_BHV(NORMAL);
-       P_MADV_BHV(RANDOM);
-       P_MADV_BHV(SEQUENTIAL);
-       P_MADV_BHV(WILLNEED);
-       P_MADV_BHV(DONTNEED);
-       P_MADV_BHV(REMOVE);
-       P_MADV_BHV(DONTFORK);
-       P_MADV_BHV(DOFORK);
-       P_MADV_BHV(HWPOISON);
-#ifdef MADV_SOFT_OFFLINE
-       P_MADV_BHV(SOFT_OFFLINE);
-#endif
-       P_MADV_BHV(MERGEABLE);
-       P_MADV_BHV(UNMERGEABLE);
-#ifdef MADV_HUGEPAGE
-       P_MADV_BHV(HUGEPAGE);
-#endif
-#ifdef MADV_NOHUGEPAGE
-       P_MADV_BHV(NOHUGEPAGE);
-#endif
-#ifdef MADV_DONTDUMP
-       P_MADV_BHV(DONTDUMP);
-#endif
-#ifdef MADV_DODUMP
-       P_MADV_BHV(DODUMP);
-#endif
-#undef P_MADV_PHV
-       default: break;
-       }
-
-       return scnprintf(bf, size, "%#x", behavior);
-}
-
-#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
-
 static size_t syscall_arg__scnprintf_flock(char *bf, size_t size,
                                           struct syscall_arg *arg)
 {
@@ -930,32 +758,6 @@ static size_t syscall_arg__scnprintf_perf_flags(char *bf, size_t size,
 
 #define SCA_PERF_FLAGS syscall_arg__scnprintf_perf_flags
 
-static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size,
-                                                  struct syscall_arg *arg)
-{
-       int printed = 0, flags = arg->val;
-
-       if (flags == 0)
-               return scnprintf(bf, size, "NONE");
-#define        P_FLAG(n) \
-       if (flags & EFD_##n) { \
-               printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
-               flags &= ~EFD_##n; \
-       }
-
-       P_FLAG(SEMAPHORE);
-       P_FLAG(CLOEXEC);
-       P_FLAG(NONBLOCK);
-#undef P_FLAG
-
-       if (flags)
-               printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
-
-       return printed;
-}
-
-#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
-
 static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size,
                                                struct syscall_arg *arg)
 {
@@ -1059,6 +861,13 @@ static const char *tioctls[] = {
 static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401);
 #endif /* defined(__i386__) || defined(__x86_64__) */
 
+#ifndef SECCOMP_SET_MODE_STRICT
+#define SECCOMP_SET_MODE_STRICT 0
+#endif
+#ifndef SECCOMP_SET_MODE_FILTER
+#define SECCOMP_SET_MODE_FILTER 1
+#endif
+
 static size_t syscall_arg__scnprintf_seccomp_op(char *bf, size_t size, struct syscall_arg *arg)
 {
        int op = arg->val;
@@ -1077,6 +886,10 @@ static size_t syscall_arg__scnprintf_seccomp_op(char *bf, size_t size, struct sy
 
 #define SCA_SECCOMP_OP  syscall_arg__scnprintf_seccomp_op
 
+#ifndef SECCOMP_FILTER_FLAG_TSYNC
+#define SECCOMP_FILTER_FLAG_TSYNC 1
+#endif
+
 static size_t syscall_arg__scnprintf_seccomp_flags(char *bf, size_t size,
                                                   struct syscall_arg *arg)
 {
@@ -1099,6 +912,13 @@ static size_t syscall_arg__scnprintf_seccomp_flags(char *bf, size_t size,
 
 #define SCA_SECCOMP_FLAGS syscall_arg__scnprintf_seccomp_flags
 
+#ifndef GRND_NONBLOCK
+#define GRND_NONBLOCK  0x0001
+#endif
+#ifndef GRND_RANDOM
+#define GRND_RANDOM    0x0002
+#endif
+
 static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
                                                   struct syscall_arg *arg)
 {
@@ -1126,7 +946,9 @@ static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
          .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \
          .arg_parm      = { [arg] = &strarray__##array, }
 
+#include "trace/beauty/eventfd.c"
 #include "trace/beauty/pid.c"
+#include "trace/beauty/mmap.c"
 #include "trace/beauty/mode_t.c"
 #include "trace/beauty/sched_policy.c"
 #include "trace/beauty/waitid_options.c"
diff --git a/tools/perf/trace/beauty/eventfd.c b/tools/perf/trace/beauty/eventfd.c
new file mode 100644 (file)
index 0000000..d64f4a9
--- /dev/null
@@ -0,0 +1,38 @@
+#include <sys/eventfd.h>
+
+#ifndef EFD_SEMAPHORE
+#define EFD_SEMAPHORE          1
+#endif
+
+#ifndef EFD_NONBLOCK
+#define EFD_NONBLOCK           00004000
+#endif
+
+#ifndef EFD_CLOEXEC
+#define EFD_CLOEXEC            02000000
+#endif
+
+static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size, struct syscall_arg *arg)
+{
+       int printed = 0, flags = arg->val;
+
+       if (flags == 0)
+               return scnprintf(bf, size, "NONE");
+#define        P_FLAG(n) \
+       if (flags & EFD_##n) { \
+               printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
+               flags &= ~EFD_##n; \
+       }
+
+       P_FLAG(SEMAPHORE);
+       P_FLAG(CLOEXEC);
+       P_FLAG(NONBLOCK);
+#undef P_FLAG
+
+       if (flags)
+               printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
+
+       return printed;
+}
+
+#define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags
diff --git a/tools/perf/trace/beauty/mmap.c b/tools/perf/trace/beauty/mmap.c
new file mode 100644 (file)
index 0000000..3444a4d
--- /dev/null
@@ -0,0 +1,158 @@
+#include <sys/mman.h>
+
+static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size,
+                                              struct syscall_arg *arg)
+{
+       int printed = 0, prot = arg->val;
+
+       if (prot == PROT_NONE)
+               return scnprintf(bf, size, "NONE");
+#define        P_MMAP_PROT(n) \
+       if (prot & PROT_##n) { \
+               printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
+               prot &= ~PROT_##n; \
+       }
+
+       P_MMAP_PROT(EXEC);
+       P_MMAP_PROT(READ);
+       P_MMAP_PROT(WRITE);
+#ifdef PROT_SEM
+       P_MMAP_PROT(SEM);
+#endif
+       P_MMAP_PROT(GROWSDOWN);
+       P_MMAP_PROT(GROWSUP);
+#undef P_MMAP_PROT
+
+       if (prot)
+               printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot);
+
+       return printed;
+}
+
+#define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot
+
+#ifndef MAP_STACK
+# define MAP_STACK             0x20000
+#endif
+
+static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
+                                               struct syscall_arg *arg)
+{
+       int printed = 0, flags = arg->val;
+
+#define        P_MMAP_FLAG(n) \
+       if (flags & MAP_##n) { \
+               printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
+               flags &= ~MAP_##n; \
+       }
+
+       P_MMAP_FLAG(SHARED);
+       P_MMAP_FLAG(PRIVATE);
+#ifdef MAP_32BIT
+       P_MMAP_FLAG(32BIT);
+#endif
+       P_MMAP_FLAG(ANONYMOUS);
+       P_MMAP_FLAG(DENYWRITE);
+       P_MMAP_FLAG(EXECUTABLE);
+       P_MMAP_FLAG(FILE);
+       P_MMAP_FLAG(FIXED);
+       P_MMAP_FLAG(GROWSDOWN);
+#ifdef MAP_HUGETLB
+       P_MMAP_FLAG(HUGETLB);
+#endif
+       P_MMAP_FLAG(LOCKED);
+       P_MMAP_FLAG(NONBLOCK);
+       P_MMAP_FLAG(NORESERVE);
+       P_MMAP_FLAG(POPULATE);
+       P_MMAP_FLAG(STACK);
+#ifdef MAP_UNINITIALIZED
+       P_MMAP_FLAG(UNINITIALIZED);
+#endif
+#undef P_MMAP_FLAG
+
+       if (flags)
+               printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
+
+       return printed;
+}
+
+#define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags
+
+static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size,
+                                                 struct syscall_arg *arg)
+{
+       int printed = 0, flags = arg->val;
+
+#define P_MREMAP_FLAG(n) \
+       if (flags & MREMAP_##n) { \
+               printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
+               flags &= ~MREMAP_##n; \
+       }
+
+       P_MREMAP_FLAG(MAYMOVE);
+#ifdef MREMAP_FIXED
+       P_MREMAP_FLAG(FIXED);
+#endif
+#undef P_MREMAP_FLAG
+
+       if (flags)
+               printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);
+
+       return printed;
+}
+
+#define SCA_MREMAP_FLAGS syscall_arg__scnprintf_mremap_flags
+
+#ifndef MADV_HWPOISON
+#define MADV_HWPOISON          100
+#endif
+
+#ifndef MADV_MERGEABLE
+#define MADV_MERGEABLE          12
+#endif
+
+#ifndef MADV_UNMERGEABLE
+#define MADV_UNMERGEABLE        13
+#endif
+
+static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size,
+                                                     struct syscall_arg *arg)
+{
+       int behavior = arg->val;
+
+       switch (behavior) {
+#define        P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n)
+       P_MADV_BHV(NORMAL);
+       P_MADV_BHV(RANDOM);
+       P_MADV_BHV(SEQUENTIAL);
+       P_MADV_BHV(WILLNEED);
+       P_MADV_BHV(DONTNEED);
+       P_MADV_BHV(REMOVE);
+       P_MADV_BHV(DONTFORK);
+       P_MADV_BHV(DOFORK);
+       P_MADV_BHV(HWPOISON);
+#ifdef MADV_SOFT_OFFLINE
+       P_MADV_BHV(SOFT_OFFLINE);
+#endif
+       P_MADV_BHV(MERGEABLE);
+       P_MADV_BHV(UNMERGEABLE);
+#ifdef MADV_HUGEPAGE
+       P_MADV_BHV(HUGEPAGE);
+#endif
+#ifdef MADV_NOHUGEPAGE
+       P_MADV_BHV(NOHUGEPAGE);
+#endif
+#ifdef MADV_DONTDUMP
+       P_MADV_BHV(DONTDUMP);
+#endif
+#ifdef MADV_DODUMP
+       P_MADV_BHV(DODUMP);
+#endif
+#undef P_MADV_PHV
+       default: break;
+       }
+
+       return scnprintf(bf, size, "%#x", behavior);
+}
+
+#define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior
index 664490b..dad7d82 100644 (file)
@@ -13,6 +13,7 @@
 #include <subcmd/exec-cmd.h>
 #include "util/hist.h"  /* perf_hist_config */
 #include "util/llvm-utils.h"   /* perf_llvm_config */
+#include "config.h"
 
 #define MAXNAME (256)
 
@@ -524,6 +525,178 @@ out:
        return ret;
 }
 
+static struct perf_config_section *find_section(struct list_head *sections,
+                                               const char *section_name)
+{
+       struct perf_config_section *section;
+
+       list_for_each_entry(section, sections, node)
+               if (!strcmp(section->name, section_name))
+                       return section;
+
+       return NULL;
+}
+
+static struct perf_config_item *find_config_item(const char *name,
+                                                struct perf_config_section *section)
+{
+       struct perf_config_item *item;
+
+       list_for_each_entry(item, &section->items, node)
+               if (!strcmp(item->name, name))
+                       return item;
+
+       return NULL;
+}
+
+static struct perf_config_section *add_section(struct list_head *sections,
+                                              const char *section_name)
+{
+       struct perf_config_section *section = zalloc(sizeof(*section));
+
+       if (!section)
+               return NULL;
+
+       INIT_LIST_HEAD(&section->items);
+       section->name = strdup(section_name);
+       if (!section->name) {
+               pr_debug("%s: strdup failed\n", __func__);
+               free(section);
+               return NULL;
+       }
+
+       list_add_tail(&section->node, sections);
+       return section;
+}
+
+static struct perf_config_item *add_config_item(struct perf_config_section *section,
+                                               const char *name)
+{
+       struct perf_config_item *item = zalloc(sizeof(*item));
+
+       if (!item)
+               return NULL;
+
+       item->name = strdup(name);
+       if (!item->name) {
+               pr_debug("%s: strdup failed\n", __func__);
+               free(item);
+               return NULL;
+       }
+
+       list_add_tail(&item->node, &section->items);
+       return item;
+}
+
+static int set_value(struct perf_config_item *item, const char *value)
+{
+       char *val = strdup(value);
+
+       if (!val)
+               return -1;
+
+       zfree(&item->value);
+       item->value = val;
+       return 0;
+}
+
+static int collect_config(const char *var, const char *value,
+                         void *perf_config_set)
+{
+       int ret = -1;
+       char *ptr, *key;
+       char *section_name, *name;
+       struct perf_config_section *section = NULL;
+       struct perf_config_item *item = NULL;
+       struct perf_config_set *set = perf_config_set;
+       struct list_head *sections = &set->sections;
+
+       key = ptr = strdup(var);
+       if (!key) {
+               pr_debug("%s: strdup failed\n", __func__);
+               return -1;
+       }
+
+       section_name = strsep(&ptr, ".");
+       name = ptr;
+       if (name == NULL || value == NULL)
+               goto out_free;
+
+       section = find_section(sections, section_name);
+       if (!section) {
+               section = add_section(sections, section_name);
+               if (!section)
+                       goto out_free;
+       }
+
+       item = find_config_item(name, section);
+       if (!item) {
+               item = add_config_item(section, name);
+               if (!item)
+                       goto out_free;
+       }
+
+       ret = set_value(item, value);
+       return ret;
+
+out_free:
+       free(key);
+       perf_config_set__delete(set);
+       return -1;
+}
+
+struct perf_config_set *perf_config_set__new(void)
+{
+       struct perf_config_set *set = zalloc(sizeof(*set));
+
+       if (set) {
+               INIT_LIST_HEAD(&set->sections);
+               perf_config(collect_config, set);
+       }
+
+       return set;
+}
+
+static void perf_config_item__delete(struct perf_config_item *item)
+{
+       zfree(&item->name);
+       zfree(&item->value);
+       free(item);
+}
+
+static void perf_config_section__purge(struct perf_config_section *section)
+{
+       struct perf_config_item *item, *tmp;
+
+       list_for_each_entry_safe(item, tmp, &section->items, node) {
+               list_del_init(&item->node);
+               perf_config_item__delete(item);
+       }
+}
+
+static void perf_config_section__delete(struct perf_config_section *section)
+{
+       perf_config_section__purge(section);
+       zfree(&section->name);
+       free(section);
+}
+
+static void perf_config_set__purge(struct perf_config_set *set)
+{
+       struct perf_config_section *section, *tmp;
+
+       list_for_each_entry_safe(section, tmp, &set->sections, node) {
+               list_del_init(&section->node);
+               perf_config_section__delete(section);
+       }
+}
+
+void perf_config_set__delete(struct perf_config_set *set)
+{
+       perf_config_set__purge(set);
+       free(set);
+}
+
 /*
  * Call this to report error for your variable that should not
  * get a boolean value (i.e. "[my] var" means "true").
diff --git a/tools/perf/util/config.h b/tools/perf/util/config.h
new file mode 100644 (file)
index 0000000..22ec626
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef __PERF_CONFIG_H
+#define __PERF_CONFIG_H
+
+#include <stdbool.h>
+#include <linux/list.h>
+
+struct perf_config_item {
+       char *name;
+       char *value;
+       struct list_head node;
+};
+
+struct perf_config_section {
+       char *name;
+       struct list_head items;
+       struct list_head node;
+};
+
+struct perf_config_set {
+       struct list_head sections;
+};
+
+struct perf_config_set *perf_config_set__new(void);
+void perf_config_set__delete(struct perf_config_set *set);
+
+#endif /* __PERF_CONFIG_H */
index 1921942..be83516 100644 (file)
@@ -136,3 +136,44 @@ ssize_t perf_data_file__write(struct perf_data_file *file,
 {
        return writen(file->fd, buf, size);
 }
+
+int perf_data_file__switch(struct perf_data_file *file,
+                          const char *postfix,
+                          size_t pos, bool at_exit)
+{
+       char *new_filepath;
+       int ret;
+
+       if (check_pipe(file))
+               return -EINVAL;
+       if (perf_data_file__is_read(file))
+               return -EINVAL;
+
+       if (asprintf(&new_filepath, "%s.%s", file->path, postfix) < 0)
+               return -ENOMEM;
+
+       /*
+        * Only fire a warning, don't return error, continue fill
+        * original file.
+        */
+       if (rename(file->path, new_filepath))
+               pr_warning("Failed to rename %s to %s\n", file->path, new_filepath);
+
+       if (!at_exit) {
+               close(file->fd);
+               ret = perf_data_file__open(file);
+               if (ret < 0)
+                       goto out;
+
+               if (lseek(file->fd, pos, SEEK_SET) == (off_t)-1) {
+                       ret = -errno;
+                       pr_debug("Failed to lseek to %zu: %s",
+                                pos, strerror(errno));
+                       goto out;
+               }
+       }
+       ret = file->fd;
+out:
+       free(new_filepath);
+       return ret;
+}
index 2b15d0c..ae510ce 100644 (file)
@@ -46,5 +46,14 @@ int perf_data_file__open(struct perf_data_file *file);
 void perf_data_file__close(struct perf_data_file *file);
 ssize_t perf_data_file__write(struct perf_data_file *file,
                              void *buf, size_t size);
-
+/*
+ * If at_exit is set, only rename current perf.data to
+ * perf.data.<postfix>, continue write on original file.
+ * Set at_exit when flushing the last output.
+ *
+ * Return value is fd of new output.
+ */
+int perf_data_file__switch(struct perf_data_file *file,
+                          const char *postfix,
+                          size_t pos, bool at_exit);
 #endif /* __PERF_DATA_H */
index b1b9e23..fe84df1 100644 (file)
@@ -308,3 +308,12 @@ void ordered_events__free(struct ordered_events *oe)
                free(event);
        }
 }
+
+void ordered_events__reinit(struct ordered_events *oe)
+{
+       ordered_events__deliver_t old_deliver = oe->deliver;
+
+       ordered_events__free(oe);
+       memset(oe, '\0', sizeof(*oe));
+       ordered_events__init(oe, old_deliver);
+}
index f403991..e11468a 100644 (file)
@@ -49,6 +49,7 @@ void ordered_events__delete(struct ordered_events *oe, struct ordered_event *eve
 int ordered_events__flush(struct ordered_events *oe, enum oe_flush how);
 void ordered_events__init(struct ordered_events *oe, ordered_events__deliver_t deliver);
 void ordered_events__free(struct ordered_events *oe);
+void ordered_events__reinit(struct ordered_events *oe);
 
 static inline
 void ordered_events__set_alloc_size(struct ordered_events *oe, u64 size)
index 91d4528..ca1827c 100644 (file)
@@ -1836,7 +1836,11 @@ out:
 out_err:
        ui_progress__finish();
        perf_session__warn_about_errors(session);
-       ordered_events__free(&session->ordered_events);
+       /*
+        * We may switching perf.data output, make ordered_events
+        * reusable.
+        */
+       ordered_events__reinit(&session->ordered_events);
        auxtrace__free_events(session);
        session->one_mmap = false;
        return err;