提交 03d85a63 编写于 作者: I Ingo Molnar

Merge tag 'perf-core-for-mingo-20160429' of...

Merge tag 'perf-core-for-mingo-20160429' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core

Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:

User visible changes:

 - Allow generate timestamped suffixed multiple perf.data files upon receiving
   SIGUSR2 in 'perf record', to slice a long running monitoring session, allowing
   to dump uninteresting sessions (Wang Nan)

 - Handle ENOMEM for perf_event_max_stack + PERF_SAMPLE_CALLCHAIN
   in perf_evsel__open_strerror(), showing a more informative
   message when the request call stack depth can't be allocated by
   the kernel (Arnaldo Carvalho de Melo)

Infrastructure changes:

 - Use strbuf for making strings in 'perf probe' (Masami Hiramatsu)

 - Do not use sizeof on pointer type, not a problem since its a pointer to
   pointer, fix none the less. Found by Coccinelle (Vaishali Thakkar)

Cleanups:

 - Fix for Coverity found issues in the bpf feature build test (Florian Fainelli)
Signed-off-by: NArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: NIngo Molnar <mingo@kernel.org>
上级 3521ba1c ca7ce82a
master alk-4.19.24 alk-4.19.30 alk-4.19.34 alk-4.19.36 alk-4.19.43 alk-4.19.48 alk-4.19.57 ck-4.19.67 ck-4.19.81 ck-4.19.91 github/fork/deepanshu1422/fix-typo-in-comment github/fork/haosdent/fix-typo linux-next v4.19.91 v4.19.90 v4.19.89 v4.19.88 v4.19.87 v4.19.86 v4.19.85 v4.19.84 v4.19.83 v4.19.82 v4.19.81 v4.19.80 v4.19.79 v4.19.78 v4.19.77 v4.19.76 v4.19.75 v4.19.74 v4.19.73 v4.19.72 v4.19.71 v4.19.70 v4.19.69 v4.19.68 v4.19.67 v4.19.66 v4.19.65 v4.19.64 v4.19.63 v4.19.62 v4.19.61 v4.19.60 v4.19.59 v4.19.58 v4.19.57 v4.19.56 v4.19.55 v4.19.54 v4.19.53 v4.19.52 v4.19.51 v4.19.50 v4.19.49 v4.19.48 v4.19.47 v4.19.46 v4.19.45 v4.19.44 v4.19.43 v4.19.42 v4.19.41 v4.19.40 v4.19.39 v4.19.38 v4.19.37 v4.19.36 v4.19.35 v4.19.34 v4.19.33 v4.19.32 v4.19.31 v4.19.30 v4.19.29 v4.19.28 v4.19.27 v4.19.26 v4.19.25 v4.19.24 v4.19.23 v4.19.22 v4.19.21 v4.19.20 v4.19.19 v4.19.18 v4.19.17 v4.19.16 v4.19.15 v4.19.14 v4.19.13 v4.19.12 v4.19.11 v4.19.10 v4.19.9 v4.19.8 v4.19.7 v4.19.6 v4.19.5 v4.19.4 v4.19.3 v4.19.2 v4.19.1 v4.19 v4.19-rc8 v4.19-rc7 v4.19-rc6 v4.19-rc5 v4.19-rc4 v4.19-rc3 v4.19-rc2 v4.19-rc1 ck-release-21 ck-release-20 ck-release-19.2 ck-release-19.1 ck-release-19 ck-release-18 ck-release-17.2 ck-release-17.1 ck-release-17 ck-release-16 ck-release-15.1 ck-release-15 ck-release-14 ck-release-13.2 ck-release-13 ck-release-12 ck-release-11 ck-release-10 ck-release-9 ck-release-7 alk-release-15 alk-release-14 alk-release-13.2 alk-release-13 alk-release-12 alk-release-11 alk-release-10 alk-release-9 alk-release-7
无相关合并请求
......@@ -27,10 +27,9 @@ 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.
*/
return syscall(__NR_bpf, BPF_PROG_LOAD, attr, sizeof(attr));
return syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
}
......@@ -347,6 +347,19 @@ 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.
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, --no-buildid and --no-buildid-cache.
SEE ALSO
--------
linkperf:perf-stat[1], linkperf:perf-list[1]
......@@ -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 <unistd.h>
......@@ -57,6 +58,7 @@ struct record {
bool no_buildid_cache_set;
bool buildid_all;
bool timestamp_filename;
bool switch_output;
unsigned long long samples;
};
......@@ -127,44 +129,9 @@ 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 DEFINE_TRIGGER(switch_output_trigger);
static void sig_handler(int sig)
{
......@@ -282,11 +249,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);
}
}
......@@ -532,6 +500,25 @@ 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
record__switch_output(struct record *rec, bool at_exit)
{
......@@ -560,6 +547,23 @@ 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);
/*
* 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;
}
......@@ -684,9 +688,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);
auxtrace_snapshot_on();
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);
}
......@@ -815,27 +822,45 @@ 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);
trigger_ready(&switch_output_trigger);
for (;;) {
unsigned long long hits = rec->samples;
if (record__mmap_read_all(rec) < 0) {
auxtrace_snapshot_disable();
trigger_error(&auxtrace_snapshot_trigger);
trigger_error(&switch_output_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;
}
}
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;
......@@ -858,12 +883,13 @@ 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);
trigger_off(&switch_output_trigger);
if (forks && workload_exec_errno) {
char msg[STRERR_BUFSIZE];
......@@ -1297,6 +1323,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()
};
......@@ -1352,6 +1380,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)
......@@ -1385,8 +1416,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) {
......@@ -1445,9 +1504,13 @@ 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);
}
if (trigger_is_ready(&switch_output_trigger))
trigger_hit(&switch_output_trigger);
}
......@@ -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"
......
......@@ -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++) {
......
#include <sys/types.h>
#include <sys/socket.h>
#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
......@@ -2325,10 +2325,18 @@ 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 <limit>'");
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",
"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)
......@@ -2360,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));
}
......@@ -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 */
......
......@@ -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);
......
......@@ -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);
}
}
......
#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
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册
反馈
建议
客服 返回
顶部