perf/core improvements:
User visible: - 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> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAABCAAGBQJXD4zyAAoJENZQFvNTUqpAKK0P/1ITyqntuIXfP8pBT+hVMNQW q+2eCSqzntZxO19TvU7z2ufAc80QXbouM//iZTfTA3xM1vWIt9f2toFk6Nhlahb9 eWumb9O/W1GwLtyxxjbSwYBrnyWyZw+SYn9Itky8cJZyUXzBbxGlbEFeZRMbL0WS 9bTMYfgkwNg7N3nnCvPuuoeEb+fuM1h+m7ItN+JA0I0Qd9u3MwyTgfTsw5qmBT92 qjQFcN8/DViCBbwrp86r5snsyY3vUrRoPghp3IBC+/s01nKeU4qNeY8Qe9Wi7NVC DWdh/s56om25ecCaA9+Ni47ZCwKnehNdAjGQZXmKKJHeQw2vNFF9C/cHUGhKH61N cvHToLxcQM66lX22KLSnWJUhj9bk20VcCB1gFcs+z+i4HXCUB4Cd1dCYPVDvmddq 4IftVr5EwsDcP76eJFmUCHlehX9TPPMhA12HdKDyuQdh87aoUuvkmb8wyU+6YYly jNnd/ylQHdS3AUFf4utrX+JqLWy+lhp4kpZ4iOeLzyH5WMW8I1uJgz5OQ9nOwVLW 2TJ9em+pRUwFkJCRq7OclhXOD9Bv2lI0NKTIai9uL13drcQCnit4iuH+cCA79e7S dXoPX4qoFwEsrx2Wha+uwzMWKYSt1qMECTQNWoXyW0lPviTB8+hgnjQPEJnl06O2 fyo9rofn6/6SyBCK56O+ =hbaM -----END PGP SIGNATURE----- Merge tag 'perf-core-for-mingo-20160414' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core 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>
This commit is contained in:
commit
0b22cd276c
@ -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, §ion->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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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>
|
||||
@ -48,36 +47,6 @@
|
||||
#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"
|
||||
|
38
tools/perf/trace/beauty/eventfd.c
Normal file
38
tools/perf/trace/beauty/eventfd.c
Normal file
@ -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
|
158
tools/perf/trace/beauty/mmap.c
Normal file
158
tools/perf/trace/beauty/mmap.c
Normal file
@ -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
|
@ -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, §ion->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(§ion->items);
|
||||
section->name = strdup(section_name);
|
||||
if (!section->name) {
|
||||
pr_debug("%s: strdup failed\n", __func__);
|
||||
free(section);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_add_tail(§ion->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, §ion->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, §ion->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(§ion->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(§ion->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").
|
||||
|
26
tools/perf/util/config.h
Normal file
26
tools/perf/util/config.h
Normal file
@ -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 */
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user