From a431d67934dfe9ffbe65972b0dbe576331595186 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Sun, 24 Apr 2016 19:34:53 -0700 Subject: [PATCH 01/13] bpf tools: Remove expression with no effect Assigning "attr" to "attr" does not have any effect, but was caught by Coverity, so let's remove this. Reported-by: coverity (CID 1354720) Signed-off-by: Florian Fainelli Tested-by: Wang Nan Acked-by: Alexei Starovoitov Cc: Jiri Olsa Fixes: 1b76c13e4b36 ("bpf tools: Introduce 'bpf' library and add bpf feature check") Link: http://lkml.kernel.org/r/1461551694-5512-2-git-send-email-f.fainelli@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/build/feature/test-bpf.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/build/feature/test-bpf.c b/tools/build/feature/test-bpf.c index b389026839b97..8236df9a46ca7 100644 --- a/tools/build/feature/test-bpf.c +++ b/tools/build/feature/test-bpf.c @@ -27,7 +27,6 @@ int main(void) attr.log_level = 0; attr.kern_version = 0; - attr = attr; /* * Test existence of __NR_bpf and BPF_PROG_LOAD. * This call should fail if we run the testcase. From 1a71476e4f2693ed93523c80ff1e2d4a8634717c Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Sun, 24 Apr 2016 19:34:54 -0700 Subject: [PATCH 02/13] bpf tools: Fix syscall argument Coverity flagged this under CID 1354884 as a sizeof mismatch, it turns out that the argument "attr" passed to syscall should have been a pointer to attr in the first place. Reported-by: coverity (CID 1354884) Signed-off-by: Florian Fainelli Acked-by: Alexei Starovoitov Acked-by: Wang Nan Cc: Jiri Olsa Fixes: 8f9e05fb298f ("perf tools: Fix PowerPC native building") Link: http://lkml.kernel.org/r/1461551694-5512-3-git-send-email-f.fainelli@gmail.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/build/feature/test-bpf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/build/feature/test-bpf.c b/tools/build/feature/test-bpf.c index 8236df9a46ca7..e04ab89a1013b 100644 --- a/tools/build/feature/test-bpf.c +++ b/tools/build/feature/test-bpf.c @@ -31,5 +31,5 @@ int main(void) * Test existence of __NR_bpf and BPF_PROG_LOAD. * This call should fail if we run the testcase. */ - return syscall(__NR_bpf, BPF_PROG_LOAD, attr, sizeof(attr)); + return syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr)); } From de46d5268c4ec5c5b473c96fbf56ece188a6ba85 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 27 Apr 2016 17:51:45 -0300 Subject: [PATCH 03/13] perf evsel: Handle ENOMEM for perf_event_max_stack + PERF_SAMPLE_CALLCHAIN When the kernel allows tweaking perf_event_max_stack and the event being setup has PERF_SAMPLE_CALLCHAIN in its perf_event_attr.sample_type, tell the user that tweaking /proc/sys/kernel/perf_event_max_stack may solve the problem. Before: # echo 32000 > /proc/sys/kernel/perf_event_max_stack # perf record -g usleep 1 Error: The sys_perf_event_open() syscall returned with 12 (Cannot allocate memory) for event (cycles:ppp). /bin/dmesg may provide additional information. No CONFIG_PERF_EVENTS=y kernel support configured? # After: # echo 64000 > /proc/sys/kernel/perf_event_max_stack # perf record -g usleep 1 Error: Not enough memory to setup event with callchain. Hint: Try tweaking /proc/sys/kernel/perf_event_max_stack Hint: Current value: 64000 # Suggested-by: David Ahern Cc: Adrian Hunter Cc: Brendan Gregg Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Milian Wolff Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-ebv0orelj1s1ye857vhb82ov@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evsel.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 334364e25bbe8..9bed7f4419d8d 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -2325,6 +2325,14 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, "Probably the maximum number of open file descriptors has been reached.\n" "Hint: Try again after reducing the number of events.\n" "Hint: Try increasing the limit with 'ulimit -n '"); + case ENOMEM: + if ((evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN) != 0 && + access("/proc/sys/kernel/perf_event_max_stack", F_OK) == 0) + return scnprintf(msg, size, + "Not enough memory to setup event with callchain.\n" + "Hint: Try tweaking /proc/sys/kernel/perf_event_max_stack\n" + "Hint: Current value: %d", sysctl_perf_event_max_stack); + break; case ENODEV: if (target->cpu_list) return scnprintf(msg, size, "%s", From 81d64f46d41c428474c64e5c59e5458b7f50d9fd Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 27 Apr 2016 17:56:53 -0300 Subject: [PATCH 04/13] perf evsel: Remove two extraneous ending newlines in open_strerror() The error messages returned by this method should not have an ending newline, fix the two cases where it was. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Milian Wolff Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-8af0pazzhzl3dluuh8p7ar7p@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evsel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 9bed7f4419d8d..3371721a05f2f 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -2336,7 +2336,7 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, case ENODEV: if (target->cpu_list) return scnprintf(msg, size, "%s", - "No such device - did you specify an out-of-range profile CPU?\n"); + "No such device - did you specify an out-of-range profile CPU?"); break; case EOPNOTSUPP: if (evsel->attr.precise_ip) @@ -2368,7 +2368,7 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, return scnprintf(msg, size, "The sys_perf_event_open() syscall returned with %d (%s) for event (%s).\n" "/bin/dmesg may provide additional information.\n" - "No CONFIG_PERF_EVENTS=y kernel support configured?\n", + "No CONFIG_PERF_EVENTS=y kernel support configured?", err, strerror_r(err, sbuf, sizeof(sbuf)), perf_evsel__name(evsel)); } From 909b0360ae358f212f526e171ea4ef433b1b4103 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Thu, 28 Apr 2016 03:37:14 +0900 Subject: [PATCH 05/13] perf probe: Use strbuf for making strings Replace many fixed-length char array with strbuf to stringify perf_probe_event and probe_trace_event etc. Signed-off-by: Masami Hiramatsu Signed-off-by: Masami Hiramatsu Cc: Ananth N Mavinakayanahalli Cc: Hemant Kumar Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20160427183713.23446.97377.stgit@devbox Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-event.c | 246 ++++++++++++--------------------- tools/perf/util/probe-event.h | 2 +- tools/perf/util/probe-finder.c | 14 +- 3 files changed, 93 insertions(+), 169 deletions(-) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index a9774628c6f6a..85d82f4dc5e9e 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -1673,69 +1673,51 @@ int parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev) } /* Compose only probe arg */ -int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len) +char *synthesize_perf_probe_arg(struct perf_probe_arg *pa) { struct perf_probe_arg_field *field = pa->field; - int ret; - char *tmp = buf; + struct strbuf buf; + char *ret; + strbuf_init(&buf, 64); if (pa->name && pa->var) - ret = e_snprintf(tmp, len, "%s=%s", pa->name, pa->var); + strbuf_addf(&buf, "%s=%s", pa->name, pa->var); else - ret = e_snprintf(tmp, len, "%s", pa->name ? pa->name : pa->var); - if (ret <= 0) - goto error; - tmp += ret; - len -= ret; + strbuf_addstr(&buf, pa->name ?: pa->var); while (field) { if (field->name[0] == '[') - ret = e_snprintf(tmp, len, "%s", field->name); + strbuf_addstr(&buf, field->name); else - ret = e_snprintf(tmp, len, "%s%s", - field->ref ? "->" : ".", field->name); - if (ret <= 0) - goto error; - tmp += ret; - len -= ret; + strbuf_addf(&buf, "%s%s", field->ref ? "->" : ".", + field->name); field = field->next; } - if (pa->type) { - ret = e_snprintf(tmp, len, ":%s", pa->type); - if (ret <= 0) - goto error; - tmp += ret; - len -= ret; - } + if (pa->type) + strbuf_addf(&buf, ":%s", pa->type); + + ret = strbuf_detach(&buf, NULL); - return tmp - buf; -error: - pr_debug("Failed to synthesize perf probe argument: %d\n", ret); return ret; } /* Compose only probe point (not argument) */ static char *synthesize_perf_probe_point(struct perf_probe_point *pp) { - char *buf, *tmp; - char offs[32] = "", line[32] = "", file[32] = ""; - int ret, len; - - buf = zalloc(MAX_CMDLEN); - if (buf == NULL) { - ret = -ENOMEM; - goto error; - } - if (pp->offset) { - ret = e_snprintf(offs, 32, "+%lu", pp->offset); - if (ret <= 0) - goto error; - } - if (pp->line) { - ret = e_snprintf(line, 32, ":%d", pp->line); - if (ret <= 0) - goto error; + struct strbuf buf; + char *tmp; + int len; + + strbuf_init(&buf, 64); + if (pp->function) { + strbuf_addstr(&buf, pp->function); + if (pp->offset) + strbuf_addf(&buf, "+%lu", pp->offset); + else if (pp->line) + strbuf_addf(&buf, ":%d", pp->line); + else if (pp->retprobe) + strbuf_addstr(&buf, "%return"); } if (pp->file) { tmp = pp->file; @@ -1744,25 +1726,12 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp) tmp = strchr(pp->file + len - 30, '/'); tmp = tmp ? tmp + 1 : pp->file + len - 30; } - ret = e_snprintf(file, 32, "@%s", tmp); - if (ret <= 0) - goto error; + strbuf_addf(&buf, "@%s", tmp); + if (!pp->function && pp->line) + strbuf_addf(&buf, ":%d", pp->line); } - if (pp->function) - ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s%s", pp->function, - offs, pp->retprobe ? "%return" : "", line, - file); - else - ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", file, line); - if (ret <= 0) - goto error; - - return buf; -error: - pr_debug("Failed to synthesize perf probe point: %d\n", ret); - free(buf); - return NULL; + return strbuf_detach(&buf, NULL); } #if 0 @@ -1791,45 +1760,30 @@ char *synthesize_perf_probe_command(struct perf_probe_event *pev) #endif static int __synthesize_probe_trace_arg_ref(struct probe_trace_arg_ref *ref, - char **buf, size_t *buflen, - int depth) + struct strbuf *buf, int depth) { - int ret; if (ref->next) { depth = __synthesize_probe_trace_arg_ref(ref->next, buf, - buflen, depth + 1); + depth + 1); if (depth < 0) goto out; } - - ret = e_snprintf(*buf, *buflen, "%+ld(", ref->offset); - if (ret < 0) - depth = ret; - else { - *buf += ret; - *buflen -= ret; - } + strbuf_addf(buf, "%+ld(", ref->offset); out: return depth; - } static int synthesize_probe_trace_arg(struct probe_trace_arg *arg, - char *buf, size_t buflen) + struct strbuf *buf) { struct probe_trace_arg_ref *ref = arg->ref; - int ret, depth = 0; - char *tmp = buf; + int depth = 0; /* Argument name or separator */ if (arg->name) - ret = e_snprintf(buf, buflen, " %s=", arg->name); + strbuf_addf(buf, " %s=", arg->name); else - ret = e_snprintf(buf, buflen, " "); - if (ret < 0) - return ret; - buf += ret; - buflen -= ret; + strbuf_addch(buf, ' '); /* Special case: @XXX */ if (arg->value[0] == '@' && arg->ref) @@ -1837,60 +1791,41 @@ static int synthesize_probe_trace_arg(struct probe_trace_arg *arg, /* Dereferencing arguments */ if (ref) { - depth = __synthesize_probe_trace_arg_ref(ref, &buf, - &buflen, 1); + depth = __synthesize_probe_trace_arg_ref(ref, buf, 1); if (depth < 0) return depth; } /* Print argument value */ if (arg->value[0] == '@' && arg->ref) - ret = e_snprintf(buf, buflen, "%s%+ld", arg->value, - arg->ref->offset); + strbuf_addf(buf, "%s%+ld", arg->value, arg->ref->offset); else - ret = e_snprintf(buf, buflen, "%s", arg->value); - if (ret < 0) - return ret; - buf += ret; - buflen -= ret; + strbuf_addstr(buf, arg->value); /* Closing */ - while (depth--) { - ret = e_snprintf(buf, buflen, ")"); - if (ret < 0) - return ret; - buf += ret; - buflen -= ret; - } + while (depth--) + strbuf_addch(buf, ')'); /* Print argument type */ - if (arg->type) { - ret = e_snprintf(buf, buflen, ":%s", arg->type); - if (ret <= 0) - return ret; - buf += ret; - } + if (arg->type) + strbuf_addf(buf, ":%s", arg->type); - return buf - tmp; + return 0; } char *synthesize_probe_trace_command(struct probe_trace_event *tev) { struct probe_trace_point *tp = &tev->point; - char *buf; - int i, len, ret; - - buf = zalloc(MAX_CMDLEN); - if (buf == NULL) - return NULL; - - len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s ", tp->retprobe ? 'r' : 'p', - tev->group, tev->event); - if (len <= 0) - goto error; + struct strbuf buf; + char *ret = NULL; + int i; /* Uprobes must have tp->module */ if (tev->uprobes && !tp->module) - goto error; + return NULL; + + strbuf_init(&buf, 32); + strbuf_addf(&buf, "%c:%s/%s ", tp->retprobe ? 'r' : 'p', + tev->group, tev->event); /* * If tp->address == 0, then this point must be a * absolute address uprobe. @@ -1904,34 +1839,23 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev) /* Use the tp->address for uprobes */ if (tev->uprobes) - ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s:0x%lx", - tp->module, tp->address); + strbuf_addf(&buf, "%s:0x%lx", tp->module, tp->address); else if (!strncmp(tp->symbol, "0x", 2)) /* Absolute address. See try_to_find_absolute_address() */ - ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s%s0x%lx", - tp->module ?: "", tp->module ? ":" : "", - tp->address); + strbuf_addf(&buf, "%s%s0x%lx", tp->module ?: "", + tp->module ? ":" : "", tp->address); else - ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s%s%s+%lu", - tp->module ?: "", tp->module ? ":" : "", - tp->symbol, tp->offset); - - if (ret <= 0) - goto error; - len += ret; + strbuf_addf(&buf, "%s%s%s+%lu", tp->module ?: "", + tp->module ? ":" : "", tp->symbol, tp->offset); - for (i = 0; i < tev->nargs; i++) { - ret = synthesize_probe_trace_arg(&tev->args[i], buf + len, - MAX_CMDLEN - len); - if (ret <= 0) + for (i = 0; i < tev->nargs; i++) + if (synthesize_probe_trace_arg(&tev->args[i], &buf) < 0) goto error; - len += ret; - } - return buf; + ret = strbuf_detach(&buf, NULL); error: - free(buf); - return NULL; + strbuf_release(&buf); + return ret; } static int find_perf_probe_point_from_map(struct probe_trace_point *tp, @@ -2013,7 +1937,7 @@ static int convert_to_perf_probe_point(struct probe_trace_point *tp, static int convert_to_perf_probe_event(struct probe_trace_event *tev, struct perf_probe_event *pev, bool is_kprobe) { - char buf[64] = ""; + struct strbuf buf = STRBUF_INIT; int i, ret; /* Convert event/group name */ @@ -2036,9 +1960,9 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev, if (tev->args[i].name) pev->args[i].name = strdup(tev->args[i].name); else { - ret = synthesize_probe_trace_arg(&tev->args[i], - buf, 64); - pev->args[i].name = strdup(buf); + strbuf_init(&buf, 32); + ret = synthesize_probe_trace_arg(&tev->args[i], &buf); + pev->args[i].name = strbuf_detach(&buf, NULL); } if (pev->args[i].name == NULL && ret >= 0) ret = -ENOMEM; @@ -2216,37 +2140,37 @@ static int perf_probe_event__sprintf(const char *group, const char *event, const char *module, struct strbuf *result) { - int i, ret; - char buf[128]; - char *place; + int i; + char *buf; - /* Synthesize only event probe point */ - place = synthesize_perf_probe_point(&pev->point); - if (!place) - return -EINVAL; + if (asprintf(&buf, "%s:%s", group, event) < 0) + return -errno; + strbuf_addf(result, " %-20s (on ", buf); + free(buf); - ret = e_snprintf(buf, 128, "%s:%s", group, event); - if (ret < 0) - goto out; + /* Synthesize only event probe point */ + buf = synthesize_perf_probe_point(&pev->point); + if (!buf) + return -ENOMEM; + strbuf_addstr(result, buf); + free(buf); - strbuf_addf(result, " %-20s (on %s", buf, place); if (module) strbuf_addf(result, " in %s", module); if (pev->nargs > 0) { strbuf_add(result, " with", 5); for (i = 0; i < pev->nargs; i++) { - ret = synthesize_perf_probe_arg(&pev->args[i], - buf, 128); - if (ret < 0) - goto out; + buf = synthesize_perf_probe_arg(&pev->args[i]); + if (!buf) + return -ENOMEM; strbuf_addf(result, " %s", buf); + free(buf); } } strbuf_addch(result, ')'); -out: - free(place); - return ret; + + return 0; } /* Show an event */ diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index e54e7b011577e..e2209623f981b 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h @@ -120,7 +120,7 @@ int parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev); /* Events to command string */ char *synthesize_perf_probe_command(struct perf_probe_event *pev); char *synthesize_probe_trace_command(struct probe_trace_event *tev); -int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len); +char *synthesize_perf_probe_arg(struct perf_probe_arg *pa); /* Check the perf_probe_event needs debuginfo */ bool perf_probe_event_need_dwarf(struct perf_probe_event *pev); diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index b3bd0fba02379..9f688758b000c 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -553,7 +553,7 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf) { Dwarf_Die vr_die; - char buf[32], *ptr; + char *buf, *ptr; int ret = 0; /* Copy raw parameters */ @@ -563,13 +563,13 @@ static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf) if (pf->pvar->name) pf->tvar->name = strdup(pf->pvar->name); else { - ret = synthesize_perf_probe_arg(pf->pvar, buf, 32); - if (ret < 0) - return ret; + buf = synthesize_perf_probe_arg(pf->pvar); + if (!buf) + return -ENOMEM; ptr = strchr(buf, ':'); /* Change type separator to _ */ if (ptr) *ptr = '_'; - pf->tvar->name = strdup(buf); + pf->tvar->name = buf; } if (pf->tvar->name == NULL) return -ENOMEM; @@ -1334,8 +1334,8 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data) if (ret2 == 0) { strlist__add(vl->vars, strbuf_detach(&buf, NULL)); - } - strbuf_release(&buf); + } else + strbuf_release(&buf); } } From 3dcc4436fa6f09ce093ff59bf8477c3059dc46df Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Wed, 20 Apr 2016 18:59:48 +0000 Subject: [PATCH 06/13] perf tools: Introduce trigger class Use 'trigger' to model operations which need to be executed when an event (a signal, for example) is observed. States and transits: OFF--(on)--> READY --(hit)--> HIT ^ | | (ready) | | \_____________/ is_hit and is_ready are two key functions to query the state of a trigger. is_hit means the event already happen; is_ready means the trigger is waiting for the event. Signed-off-by: Wang Nan Acked-by: Adrian Hunter Cc: He Kuang Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1461178794-40467-2-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/trigger.h | 94 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 tools/perf/util/trigger.h diff --git a/tools/perf/util/trigger.h b/tools/perf/util/trigger.h new file mode 100644 index 0000000000000..e97d7016d771c --- /dev/null +++ b/tools/perf/util/trigger.h @@ -0,0 +1,94 @@ +#ifndef __TRIGGER_H_ +#define __TRIGGER_H_ 1 + +#include "util/debug.h" +#include "asm/bug.h" + +/* + * Use trigger to model operations which need to be executed when + * an event (a signal, for example) is observed. + * + * States and transits: + * + * + * OFF--(on)--> READY --(hit)--> HIT + * ^ | + * | (ready) + * | | + * \_____________/ + * + * is_hit and is_ready are two key functions to query the state of + * a trigger. is_hit means the event already happen; is_ready means the + * trigger is waiting for the event. + */ + +struct trigger { + volatile enum { + TRIGGER_ERROR = -2, + TRIGGER_OFF = -1, + TRIGGER_READY = 0, + TRIGGER_HIT = 1, + } state; + const char *name; +}; + +#define TRIGGER_WARN_ONCE(t, exp) \ + WARN_ONCE(t->state != exp, "trigger '%s' state transist error: %d in %s()\n", \ + t->name, t->state, __func__) + +static inline bool trigger_is_available(struct trigger *t) +{ + return t->state >= 0; +} + +static inline bool trigger_is_error(struct trigger *t) +{ + return t->state <= TRIGGER_ERROR; +} + +static inline void trigger_on(struct trigger *t) +{ + TRIGGER_WARN_ONCE(t, TRIGGER_OFF); + t->state = TRIGGER_READY; +} + +static inline void trigger_ready(struct trigger *t) +{ + if (!trigger_is_available(t)) + return; + t->state = TRIGGER_READY; +} + +static inline void trigger_hit(struct trigger *t) +{ + if (!trigger_is_available(t)) + return; + TRIGGER_WARN_ONCE(t, TRIGGER_READY); + t->state = TRIGGER_HIT; +} + +static inline void trigger_off(struct trigger *t) +{ + if (!trigger_is_available(t)) + return; + t->state = TRIGGER_OFF; +} + +static inline void trigger_error(struct trigger *t) +{ + t->state = TRIGGER_ERROR; +} + +static inline bool trigger_is_ready(struct trigger *t) +{ + return t->state == TRIGGER_READY; +} + +static inline bool trigger_is_hit(struct trigger *t) +{ + return t->state == TRIGGER_HIT; +} + +#define DEFINE_TRIGGER(n) \ +struct trigger n = {.state = TRIGGER_OFF, .name = #n} +#endif From 5f9cf5992cfb9d9763fb92f755642dda8f9e844f Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Wed, 20 Apr 2016 18:59:49 +0000 Subject: [PATCH 07/13] perf tools: Derive trigger class from auxtrace_snapshot auxtrace_snapshot_state matches the trigger model. Use trigger to implement it. auxtrace_snapshot_state and auxtrace_snapshot_err are absorbed. Signed-off-by: Wang Nan Acked-by: Adrian Hunter Cc: He Kuang Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1461178794-40467-3-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 73 ++++++++++--------------------------- 1 file changed, 20 insertions(+), 53 deletions(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index bd9593346bb2f..f4710c82980f6 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -34,6 +34,7 @@ #include "util/parse-regs-options.h" #include "util/llvm-utils.h" #include "util/bpf-loader.h" +#include "util/trigger.h" #include "asm/bug.h" #include @@ -127,44 +128,8 @@ static volatile int done; static volatile int signr = -1; static volatile int child_finished; -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; +static DEFINE_TRIGGER(auxtrace_snapshot_trigger); static void sig_handler(int sig) { @@ -282,11 +247,12 @@ static void record__read_auxtrace_snapshot(struct record *rec) { pr_debug("Recording AUX area tracing snapshot\n"); if (record__auxtrace_read_snapshot_all(rec) < 0) { - auxtrace_snapshot_err = -1; + trigger_error(&auxtrace_snapshot_trigger); } else { - auxtrace_snapshot_err = auxtrace_record__snapshot_finish(rec->itr); - if (!auxtrace_snapshot_err) - auxtrace_snapshot_enable(); + if (auxtrace_record__snapshot_finish(rec->itr)) + trigger_error(&auxtrace_snapshot_trigger); + else + trigger_ready(&auxtrace_snapshot_trigger); } } @@ -686,7 +652,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) if (rec->opts.auxtrace_snapshot_mode) { signal(SIGUSR2, snapshot_sig_handler); - auxtrace_snapshot_on(); + trigger_on(&auxtrace_snapshot_trigger); } else { signal(SIGUSR2, SIG_IGN); } @@ -815,21 +781,21 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) perf_evlist__enable(rec->evlist); } - auxtrace_snapshot_enable(); + trigger_ready(&auxtrace_snapshot_trigger); for (;;) { unsigned long long hits = rec->samples; if (record__mmap_read_all(rec) < 0) { - auxtrace_snapshot_disable(); + trigger_error(&auxtrace_snapshot_trigger); err = -1; goto out_child; } if (auxtrace_record__snapshot_started) { auxtrace_record__snapshot_started = 0; - if (!auxtrace_snapshot_err) + if (!trigger_is_error(&auxtrace_snapshot_trigger)) record__read_auxtrace_snapshot(rec); - if (auxtrace_snapshot_err) { + if (trigger_is_error(&auxtrace_snapshot_trigger)) { pr_err("AUX area tracing snapshot failed\n"); err = -1; goto out_child; @@ -858,12 +824,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_disable(); + trigger_off(&auxtrace_snapshot_trigger); perf_evlist__disable(rec->evlist); disabled = true; } } - auxtrace_snapshot_disable(); + trigger_off(&auxtrace_snapshot_trigger); if (forks && workload_exec_errno) { char msg[STRERR_BUFSIZE]; @@ -1445,9 +1411,10 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) static void snapshot_sig_handler(int sig __maybe_unused) { - if (!auxtrace_snapshot_is_enabled()) - return; - auxtrace_snapshot_disable(); - auxtrace_snapshot_err = auxtrace_record__snapshot_start(record.itr); - auxtrace_record__snapshot_started = 1; + if (trigger_is_ready(&auxtrace_snapshot_trigger)) { + trigger_hit(&auxtrace_snapshot_trigger); + auxtrace_record__snapshot_started = 1; + if (auxtrace_record__snapshot_start(record.itr)) + trigger_error(&auxtrace_snapshot_trigger); + } } From 3c1cb7e3723caad9b4c1b2f816d86d8605296a4b Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Wed, 20 Apr 2016 18:59:50 +0000 Subject: [PATCH 08/13] perf record: Split output into multiple files via '--switch-output' Allow 'perf record' to split its output into multiple files. For example: # ~/perf record -a --timestamp-filename --switch-output & [1] 10763 # kill -s SIGUSR2 10763 [ perf record: dump data: Woken up 1 times ] # [ perf record: Dump perf.data.2015122622314468 ] # kill -s SIGUSR2 10763 [ perf record: dump data: Woken up 1 times ] # [ perf record: Dump perf.data.2015122622314762 ] # kill -s SIGUSR2 10763 [ perf record: dump data: Woken up 1 times ] #[ perf record: Dump perf.data.2015122622315171 ] # fg perf record -a --timestamp-filename --switch-output ^C[ perf record: Woken up 1 times to write data ] [ perf record: Dump perf.data.2015122622315513 ] [ perf record: Captured and wrote 0.014 MB perf.data. (296 samples) ] # ls -l total 920 -rw------- 1 root root 797692 Dec 26 22:31 perf.data.2015122622314468 -rw------- 1 root root 59960 Dec 26 22:31 perf.data.2015122622314762 -rw------- 1 root root 59912 Dec 26 22:31 perf.data.2015122622315171 -rw------- 1 root root 19220 Dec 26 22:31 perf.data.2015122622315513 Signed-off-by: Wang Nan Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1461178794-40467-4-git-send-email-wangnan0@huawei.com Signed-off-by: He Kuang [ Added man page entry, used the re-synthesize patch in this series as a fixup ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-record.txt | 8 +++++ tools/perf/builtin-record.c | 40 ++++++++++++++++++++++-- 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 19aa17532a167..a77a431ca4ef1 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -347,6 +347,14 @@ Configure all used events to run in kernel space. --all-user:: Configure all used events to run in user space. +--switch-output:: +Generate multiple perf.data files, timestamp prefixed, switching to a new one +when receiving a SIGUSR2. + +A possible use case is to, given an external event, slice the perf.data file +that gets then processed, possibly via a perf script, to decide if that +particular perf.data snapshot should be kept or not. + SEE ALSO -------- linkperf:perf-stat[1], linkperf:perf-list[1] diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index f4710c82980f6..8ebe953c7af0e 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -58,6 +58,7 @@ struct record { bool no_buildid_cache_set; bool buildid_all; bool timestamp_filename; + bool switch_output; unsigned long long samples; }; @@ -130,6 +131,7 @@ static volatile int child_finished; static volatile int auxtrace_record__snapshot_started; static DEFINE_TRIGGER(auxtrace_snapshot_trigger); +static DEFINE_TRIGGER(switch_output_trigger); static void sig_handler(int sig) { @@ -498,6 +500,8 @@ record__finish_output(struct record *rec) return; } +static int record__synthesize(struct record *rec); + static int record__switch_output(struct record *rec, bool at_exit) { @@ -526,6 +530,11 @@ record__switch_output(struct record *rec, bool at_exit) if (!quiet) fprintf(stderr, "[ perf record: Dump %s.%s ]\n", file->path, timestamp); + + /* Output tracking events */ + if (!at_exit) + record__synthesize(rec); + return fd; } @@ -650,9 +659,12 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) signal(SIGINT, sig_handler); signal(SIGTERM, sig_handler); - if (rec->opts.auxtrace_snapshot_mode) { + if (rec->opts.auxtrace_snapshot_mode || rec->switch_output) { signal(SIGUSR2, snapshot_sig_handler); - trigger_on(&auxtrace_snapshot_trigger); + if (rec->opts.auxtrace_snapshot_mode) + trigger_on(&auxtrace_snapshot_trigger); + if (rec->switch_output) + trigger_on(&switch_output_trigger); } else { signal(SIGUSR2, SIG_IGN); } @@ -782,11 +794,13 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) } trigger_ready(&auxtrace_snapshot_trigger); + trigger_ready(&switch_output_trigger); for (;;) { unsigned long long hits = rec->samples; if (record__mmap_read_all(rec) < 0) { trigger_error(&auxtrace_snapshot_trigger); + trigger_error(&switch_output_trigger); err = -1; goto out_child; } @@ -802,6 +816,22 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) } } + if (trigger_is_hit(&switch_output_trigger)) { + trigger_ready(&switch_output_trigger); + + if (!quiet) + fprintf(stderr, "[ perf record: dump data: Woken up %ld times ]\n", + waking); + waking = 0; + fd = record__switch_output(rec, false); + if (fd < 0) { + pr_err("Failed to switch to new file\n"); + trigger_error(&switch_output_trigger); + err = fd; + goto out_child; + } + } + if (hits == rec->samples) { if (done || draining) break; @@ -830,6 +860,7 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) } } trigger_off(&auxtrace_snapshot_trigger); + trigger_off(&switch_output_trigger); if (forks && workload_exec_errno) { char msg[STRERR_BUFSIZE]; @@ -1263,6 +1294,8 @@ struct option __record_options[] = { "Record build-id of all DSOs regardless of hits"), OPT_BOOLEAN(0, "timestamp-filename", &record.timestamp_filename, "append timestamp to output filename"), + OPT_BOOLEAN(0, "switch-output", &record.switch_output, + "Switch output when receive SIGUSR2"), OPT_END() }; @@ -1417,4 +1450,7 @@ static void snapshot_sig_handler(int sig __maybe_unused) if (auxtrace_record__snapshot_start(record.itr)) trigger_error(&auxtrace_snapshot_trigger); } + + if (trigger_is_ready(&switch_output_trigger)) + trigger_hit(&switch_output_trigger); } From eca857ab381858450ec2f91f5aaae7f2f7a7a180 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Wed, 20 Apr 2016 18:59:51 +0000 Subject: [PATCH 09/13] perf record: Force enable --timestamp-filename when --switch-output is provided Without this patch, the last output doesn't have timestamp appended if --timestamp-filename is not explicitly provided. For example: # perf record -a --switch-output & [1] 11224 # kill -s SIGUSR2 11224 [ perf record: dump data: Woken up 1 times ] # [ perf record: Dump perf.data.2015122622372823 ] # fg perf record -a --switch-output ^C[ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.027 MB perf.data (540 samples) ] # ls -l total 836 -rw------- 1 root root 33256 Dec 26 22:37 perf.data <---- *Odd* -rw------- 1 root root 817156 Dec 26 22:37 perf.data.2015122622372823 Signed-off-by: Wang Nan Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1461178794-40467-5-git-send-email-wangnan0@huawei.com Signed-off-by: He Kuang [ Updated man page, that also got an entry for --timestamp-filename ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-record.txt | 5 +++++ tools/perf/builtin-record.c | 3 +++ 2 files changed, 8 insertions(+) diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index a77a431ca4ef1..79a8a14f37b1f 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -347,6 +347,9 @@ Configure all used events to run in kernel space. --all-user:: Configure all used events to run in user space. +--timestamp-filename +Append timestamp to output file name. + --switch-output:: Generate multiple perf.data files, timestamp prefixed, switching to a new one when receiving a SIGUSR2. @@ -355,6 +358,8 @@ A possible use case is to, given an external event, slice the perf.data file that gets then processed, possibly via a perf script, to decide if that particular perf.data snapshot should be kept or not. +Implies --timestamp-filename. + SEE ALSO -------- linkperf:perf-stat[1], linkperf:perf-list[1] diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 8ebe953c7af0e..80b805b7f5c77 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -1351,6 +1351,9 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) return -EINVAL; } + if (rec->switch_output) + rec->timestamp_filename = true; + if (!rec->itr) { rec->itr = auxtrace_record__init(rec->evlist, &err); if (err) From 0c1d46a8796e8309f1ca693e5cad6f318e4b8159 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Wed, 20 Apr 2016 18:59:52 +0000 Subject: [PATCH 10/13] perf record: Disable buildid cache options by default in switch output mode The cost of buildid cache processing is high: reading all events in output perf.data, opening each elf file to read buildids then copying them into ~/.debug directory. In switch output mode, these heavy works block perf from receiving perf events for too long. Enable no-buildid and no-buildid-cache by default if --switch-output is provided. Still allow user use --no-no-buildid to explicitly enable buildid in this case. Signed-off-by: Wang Nan Cc: Adrian Hunter Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1461178794-40467-6-git-send-email-wangnan0@huawei.com Signed-off-by: He Kuang [ Updated man page ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-record.txt | 2 +- tools/perf/builtin-record.c | 30 +++++++++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 79a8a14f37b1f..8dbee832abd9e 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -358,7 +358,7 @@ A possible use case is to, given an external event, slice the perf.data file that gets then processed, possibly via a perf script, to decide if that particular perf.data snapshot should be kept or not. -Implies --timestamp-filename. +Implies --timestamp-filename, --no-buildid and --no-buildid-cache. SEE ALSO -------- diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 80b805b7f5c77..178b49ecd05ff 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -1387,8 +1387,36 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) "If some relocation was applied (e.g. kexec) symbols may be misresolved\n" "even with a suitable vmlinux or kallsyms file.\n\n"); - if (rec->no_buildid_cache || rec->no_buildid) + if (rec->no_buildid_cache || rec->no_buildid) { disable_buildid_cache(); + } else if (rec->switch_output) { + /* + * In 'perf record --switch-output', disable buildid + * generation by default to reduce data file switching + * overhead. Still generate buildid if they are required + * explicitly using + * + * perf record --signal-trigger --no-no-buildid \ + * --no-no-buildid-cache + * + * Following code equals to: + * + * if ((rec->no_buildid || !rec->no_buildid_set) && + * (rec->no_buildid_cache || !rec->no_buildid_cache_set)) + * disable_buildid_cache(); + */ + bool disable = true; + + if (rec->no_buildid_set && !rec->no_buildid) + disable = false; + if (rec->no_buildid_cache_set && !rec->no_buildid_cache) + disable = false; + if (disable) { + rec->no_buildid = true; + rec->no_buildid_cache = true; + disable_buildid_cache(); + } + } if (rec->evlist->nr_entries == 0 && perf_evlist__add_default(rec->evlist) < 0) { From be7b0c9e376e93a00b6c8631e2721e9dc7c6a1fa Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Wed, 20 Apr 2016 18:59:54 +0000 Subject: [PATCH 11/13] perf record: Generate tracking events for process forked by perf With 'perf record --switch-output' without -a, record__synthesize() in record__switch_output() won't generate tracking events because there's no thread_map in evlist. Which causes newly created perf.data doesn't contain map and comm information. This patch creates a fake thread_map and directly call perf_event__synthesize_thread_map() for those events. Signed-off-by: Wang Nan Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1461178794-40467-8-git-send-email-wangnan0@huawei.com Signed-off-by: He Kuang Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 178b49ecd05ff..f3679c44d3f3d 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -500,6 +500,23 @@ record__finish_output(struct record *rec) return; } +static int record__synthesize_workload(struct record *rec) +{ + struct { + struct thread_map map; + struct thread_map_data map_data; + } thread_map; + + thread_map.map.nr = 1; + thread_map.map.map[0].pid = rec->evlist->workload.pid; + thread_map.map.map[0].comm = NULL; + return perf_event__synthesize_thread_map(&rec->tool, &thread_map.map, + process_synthesized_event, + &rec->session->machines.host, + rec->opts.sample_address, + rec->opts.proc_map_timeout); +} + static int record__synthesize(struct record *rec); static int @@ -532,9 +549,21 @@ record__switch_output(struct record *rec, bool at_exit) file->path, timestamp); /* Output tracking events */ - if (!at_exit) + if (!at_exit) { record__synthesize(rec); + /* + * In 'perf record --switch-output' without -a, + * record__synthesize() in record__switch_output() won't + * generate tracking events because there's no thread_map + * in evlist. Which causes newly created perf.data doesn't + * contain map and comm information. + * Create a fake thread_map and directly call + * perf_event__synthesize_thread_map() for those events. + */ + if (target__none(&rec->opts.target)) + record__synthesize_workload(rec); + } return fd; } From a30e6259b5e31e8d2b40f3b0099d98a6ebe0e360 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 27 Apr 2016 19:01:52 -0300 Subject: [PATCH 12/13] perf trace: Move msg_flags beautifier to tools/perf/trace/beauty/ To reduce the size of builtin-trace.c. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-11zxg3qitk6bw2x30135k9z4@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-trace.c | 62 +---------------------------- tools/perf/trace/beauty/msg_flags.c | 62 +++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 61 deletions(-) create mode 100644 tools/perf/trace/beauty/msg_flags.c diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index f4f3389c92c7b..9e38fe973f0c1 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -52,10 +52,6 @@ # define O_CLOEXEC 02000000 #endif -#ifndef MSG_CMSG_CLOEXEC -# define MSG_CMSG_CLOEXEC 0x40000000 -#endif - struct trace { struct perf_tool tool; struct syscalltbl *sctbl; @@ -513,63 +509,6 @@ static const char *socket_families[] = { }; static DEFINE_STRARRAY(socket_families); -#ifndef MSG_PROBE -#define MSG_PROBE 0x10 -#endif -#ifndef MSG_WAITFORONE -#define MSG_WAITFORONE 0x10000 -#endif -#ifndef MSG_SENDPAGE_NOTLAST -#define MSG_SENDPAGE_NOTLAST 0x20000 -#endif -#ifndef MSG_FASTOPEN -#define MSG_FASTOPEN 0x20000000 -#endif - -static size_t syscall_arg__scnprintf_msg_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_MSG_FLAG(n) \ - if (flags & MSG_##n) { \ - printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ - flags &= ~MSG_##n; \ - } - - P_MSG_FLAG(OOB); - P_MSG_FLAG(PEEK); - P_MSG_FLAG(DONTROUTE); - P_MSG_FLAG(TRYHARD); - P_MSG_FLAG(CTRUNC); - P_MSG_FLAG(PROBE); - P_MSG_FLAG(TRUNC); - P_MSG_FLAG(DONTWAIT); - P_MSG_FLAG(EOR); - P_MSG_FLAG(WAITALL); - P_MSG_FLAG(FIN); - P_MSG_FLAG(SYN); - P_MSG_FLAG(CONFIRM); - P_MSG_FLAG(RST); - P_MSG_FLAG(ERRQUEUE); - P_MSG_FLAG(NOSIGNAL); - P_MSG_FLAG(MORE); - P_MSG_FLAG(WAITFORONE); - P_MSG_FLAG(SENDPAGE_NOTLAST); - P_MSG_FLAG(FASTOPEN); - P_MSG_FLAG(CMSG_CLOEXEC); -#undef P_MSG_FLAG - - if (flags) - printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); - - return printed; -} - -#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags - static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size, struct syscall_arg *arg) { @@ -850,6 +789,7 @@ static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size, #include "trace/beauty/pid.c" #include "trace/beauty/mmap.c" #include "trace/beauty/mode_t.c" +#include "trace/beauty/msg_flags.c" #include "trace/beauty/perf_event_open.c" #include "trace/beauty/sched_policy.c" #include "trace/beauty/socket_type.c" diff --git a/tools/perf/trace/beauty/msg_flags.c b/tools/perf/trace/beauty/msg_flags.c new file mode 100644 index 0000000000000..07fa8a0acad6a --- /dev/null +++ b/tools/perf/trace/beauty/msg_flags.c @@ -0,0 +1,62 @@ +#include +#include + +#ifndef MSG_PROBE +#define MSG_PROBE 0x10 +#endif +#ifndef MSG_WAITFORONE +#define MSG_WAITFORONE 0x10000 +#endif +#ifndef MSG_SENDPAGE_NOTLAST +#define MSG_SENDPAGE_NOTLAST 0x20000 +#endif +#ifndef MSG_FASTOPEN +#define MSG_FASTOPEN 0x20000000 +#endif +#ifndef MSG_CMSG_CLOEXEC +# define MSG_CMSG_CLOEXEC 0x40000000 +#endif + +static size_t syscall_arg__scnprintf_msg_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_MSG_FLAG(n) \ + if (flags & MSG_##n) { \ + printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ + flags &= ~MSG_##n; \ + } + + P_MSG_FLAG(OOB); + P_MSG_FLAG(PEEK); + P_MSG_FLAG(DONTROUTE); + P_MSG_FLAG(TRYHARD); + P_MSG_FLAG(CTRUNC); + P_MSG_FLAG(PROBE); + P_MSG_FLAG(TRUNC); + P_MSG_FLAG(DONTWAIT); + P_MSG_FLAG(EOR); + P_MSG_FLAG(WAITALL); + P_MSG_FLAG(FIN); + P_MSG_FLAG(SYN); + P_MSG_FLAG(CONFIRM); + P_MSG_FLAG(RST); + P_MSG_FLAG(ERRQUEUE); + P_MSG_FLAG(NOSIGNAL); + P_MSG_FLAG(MORE); + P_MSG_FLAG(WAITFORONE); + P_MSG_FLAG(SENDPAGE_NOTLAST); + P_MSG_FLAG(FASTOPEN); + P_MSG_FLAG(CMSG_CLOEXEC); +#undef P_MSG_FLAG + + if (flags) + printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); + + return printed; +} + +#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags From ca7ce82a280a65c377c24c95c29b1dec6e80b428 Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Thu, 28 Apr 2016 22:16:57 +0530 Subject: [PATCH 13/13] perf tests: Do not use sizeof on pointer type Using sizeof on a malloced pointer type will return the wordsize which can often cause one to allocate a buffer much smaller than it is needed. So, here do not use sizeof on pointer type. Note that this has no effect on runtime because 'dsos' is a pointer to a pointer. Problem found using Coccinelle. Signed-off-by: Vaishali Thakkar Cc: Alexander Shishkin Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1461862017-23358-1-git-send-email-vaishali.thakkar@oracle.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/dso-data.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/tests/dso-data.c b/tools/perf/tests/dso-data.c index dc673ff7c4375..8cf0d9e189a8b 100644 --- a/tools/perf/tests/dso-data.c +++ b/tools/perf/tests/dso-data.c @@ -202,7 +202,7 @@ static int dsos__create(int cnt, int size) { int i; - dsos = malloc(sizeof(dsos) * cnt); + dsos = malloc(sizeof(*dsos) * cnt); TEST_ASSERT_VAL("failed to alloc dsos array", dsos); for (i = 0; i < cnt; i++) {