#include "builtin.h"
#include "perf.h"
+#include "util/evlist.h"
#include "util/evsel.h"
#include "util/util.h"
#include "util/cache.h"
struct rb_node rb; /* used for sorting */
/*
- * FIXME: raw_field_value() returns unsigned long long,
+ * FIXME: perf_evsel__intval() returns u64,
* so address of lockdep_map should be dealed as 64bit.
* Is there more better solution?
*/
static const char *input_name;
-struct raw_event_sample {
- u32 size;
- char data[0];
-};
-
-struct trace_acquire_event {
- void *addr;
- const char *name;
- int flag;
-};
-
-struct trace_acquired_event {
- void *addr;
- const char *name;
-};
-
-struct trace_contended_event {
- void *addr;
- const char *name;
-};
-
-struct trace_release_event {
- void *addr;
- const char *name;
-};
-
struct trace_lock_handler {
- int (*acquire_event)(struct trace_acquire_event *,
- const struct perf_sample *sample);
+ int (*acquire_event)(struct perf_evsel *evsel,
+ struct perf_sample *sample);
- int (*acquired_event)(struct trace_acquired_event *,
- const struct perf_sample *sample);
+ int (*acquired_event)(struct perf_evsel *evsel,
+ struct perf_sample *sample);
- int (*contended_event)(struct trace_contended_event *,
- const struct perf_sample *sample);
+ int (*contended_event)(struct perf_evsel *evsel,
+ struct perf_sample *sample);
- int (*release_event)(struct trace_release_event *,
- const struct perf_sample *sample);
+ int (*release_event)(struct perf_evsel *evsel,
+ struct perf_sample *sample);
};
static struct lock_seq_stat *get_seq(struct thread_stat *ts, void *addr)
READ_LOCK = 2,
};
-static int
-report_lock_acquire_event(struct trace_acquire_event *acquire_event,
- const struct perf_sample *sample)
+static int report_lock_acquire_event(struct perf_evsel *evsel,
+ struct perf_sample *sample)
{
+ void *addr;
struct lock_stat *ls;
struct thread_stat *ts;
struct lock_seq_stat *seq;
+ const char *name = perf_evsel__strval(evsel, sample, "name");
+ u64 tmp = perf_evsel__intval(evsel, sample, "lockdep_addr");
+ int flag = perf_evsel__intval(evsel, sample, "flag");
- ls = lock_stat_findnew(acquire_event->addr, acquire_event->name);
+ memcpy(&addr, &tmp, sizeof(void *));
+
+ ls = lock_stat_findnew(addr, name);
if (!ls)
return -1;
if (ls->discard)
if (!ts)
return -1;
- seq = get_seq(ts, acquire_event->addr);
+ seq = get_seq(ts, addr);
if (!seq)
return -1;
switch (seq->state) {
case SEQ_STATE_UNINITIALIZED:
case SEQ_STATE_RELEASED:
- if (!acquire_event->flag) {
+ if (!flag) {
seq->state = SEQ_STATE_ACQUIRING;
} else {
- if (acquire_event->flag & TRY_LOCK)
+ if (flag & TRY_LOCK)
ls->nr_trylock++;
- if (acquire_event->flag & READ_LOCK)
+ if (flag & READ_LOCK)
ls->nr_readlock++;
seq->state = SEQ_STATE_READ_ACQUIRED;
seq->read_count = 1;
}
break;
case SEQ_STATE_READ_ACQUIRED:
- if (acquire_event->flag & READ_LOCK) {
+ if (flag & READ_LOCK) {
seq->read_count++;
ls->nr_acquired++;
goto end;
return 0;
}
-static int
-report_lock_acquired_event(struct trace_acquired_event *acquired_event,
- const struct perf_sample *sample)
+static int report_lock_acquired_event(struct perf_evsel *evsel,
+ struct perf_sample *sample)
{
- u64 timestamp = sample->time;
+ void *addr;
struct lock_stat *ls;
struct thread_stat *ts;
struct lock_seq_stat *seq;
u64 contended_term;
+ const char *name = perf_evsel__strval(evsel, sample, "name");
+ u64 tmp = perf_evsel__intval(evsel, sample, "lockdep_addr");
+
+ memcpy(&addr, &tmp, sizeof(void *));
- ls = lock_stat_findnew(acquired_event->addr, acquired_event->name);
+ ls = lock_stat_findnew(addr, name);
if (!ls)
return -1;
if (ls->discard)
if (!ts)
return -1;
- seq = get_seq(ts, acquired_event->addr);
+ seq = get_seq(ts, addr);
if (!seq)
return -1;
case SEQ_STATE_ACQUIRING:
break;
case SEQ_STATE_CONTENDED:
- contended_term = timestamp - seq->prev_event_time;
+ contended_term = sample->time - seq->prev_event_time;
ls->wait_time_total += contended_term;
if (contended_term < ls->wait_time_min)
ls->wait_time_min = contended_term;
seq->state = SEQ_STATE_ACQUIRED;
ls->nr_acquired++;
- seq->prev_event_time = timestamp;
+ seq->prev_event_time = sample->time;
end:
return 0;
}
-static int
-report_lock_contended_event(struct trace_contended_event *contended_event,
- const struct perf_sample *sample)
+static int report_lock_contended_event(struct perf_evsel *evsel,
+ struct perf_sample *sample)
{
+ void *addr;
struct lock_stat *ls;
struct thread_stat *ts;
struct lock_seq_stat *seq;
+ const char *name = perf_evsel__strval(evsel, sample, "name");
+ u64 tmp = perf_evsel__intval(evsel, sample, "lockdep_addr");
+
+ memcpy(&addr, &tmp, sizeof(void *));
- ls = lock_stat_findnew(contended_event->addr, contended_event->name);
+ ls = lock_stat_findnew(addr, name);
if (!ls)
return -1;
if (ls->discard)
if (!ts)
return -1;
- seq = get_seq(ts, contended_event->addr);
+ seq = get_seq(ts, addr);
if (!seq)
return -1;
return 0;
}
-static int
-report_lock_release_event(struct trace_release_event *release_event,
- const struct perf_sample *sample)
+static int report_lock_release_event(struct perf_evsel *evsel,
+ struct perf_sample *sample)
{
+ void *addr;
struct lock_stat *ls;
struct thread_stat *ts;
struct lock_seq_stat *seq;
+ const char *name = perf_evsel__strval(evsel, sample, "name");
+ u64 tmp = perf_evsel__intval(evsel, sample, "lockdep_addr");
- ls = lock_stat_findnew(release_event->addr, release_event->name);
+ memcpy(&addr, &tmp, sizeof(void *));
+
+ ls = lock_stat_findnew(addr, name);
if (!ls)
return -1;
if (ls->discard)
if (!ts)
return -1;
- seq = get_seq(ts, release_event->addr);
+ seq = get_seq(ts, addr);
if (!seq)
return -1;
static int perf_evsel__process_lock_acquire(struct perf_evsel *evsel,
struct perf_sample *sample)
{
- struct trace_acquire_event acquire_event;
- struct event_format *event = evsel->tp_format;
- void *data = sample->raw_data;
- u64 tmp; /* this is required for casting... */
- int rc = 0;
-
- tmp = raw_field_value(event, "lockdep_addr", data);
- memcpy(&acquire_event.addr, &tmp, sizeof(void *));
- acquire_event.name = (char *)raw_field_ptr(event, "name", data);
- acquire_event.flag = (int)raw_field_value(event, "flag", data);
-
if (trace_handler->acquire_event)
- rc = trace_handler->acquire_event(&acquire_event, sample);
-
- return rc;
+ return trace_handler->acquire_event(evsel, sample);
+ return 0;
}
static int perf_evsel__process_lock_acquired(struct perf_evsel *evsel,
struct perf_sample *sample)
{
- struct trace_acquired_event acquired_event;
- struct event_format *event = evsel->tp_format;
- void *data = sample->raw_data;
- u64 tmp; /* this is required for casting... */
- int rc = 0;
-
- tmp = raw_field_value(event, "lockdep_addr", data);
- memcpy(&acquired_event.addr, &tmp, sizeof(void *));
- acquired_event.name = (char *)raw_field_ptr(event, "name", data);
-
if (trace_handler->acquired_event)
- rc = trace_handler->acquired_event(&acquired_event, sample);
-
- return rc;
+ return trace_handler->acquired_event(evsel, sample);
+ return 0;
}
static int perf_evsel__process_lock_contended(struct perf_evsel *evsel,
- struct perf_sample *sample)
+ struct perf_sample *sample)
{
- struct trace_contended_event contended_event;
- struct event_format *event = evsel->tp_format;
- void *data = sample->raw_data;
- u64 tmp; /* this is required for casting... */
- int rc = 0;
-
- tmp = raw_field_value(event, "lockdep_addr", data);
- memcpy(&contended_event.addr, &tmp, sizeof(void *));
- contended_event.name = (char *)raw_field_ptr(event, "name", data);
-
if (trace_handler->contended_event)
- rc = trace_handler->contended_event(&contended_event, sample);
-
- return rc;
+ return trace_handler->contended_event(evsel, sample);
+ return 0;
}
static int perf_evsel__process_lock_release(struct perf_evsel *evsel,
- struct perf_sample *sample)
+ struct perf_sample *sample)
{
- struct trace_release_event release_event;
- struct event_format *event = evsel->tp_format;
- void *data = sample->raw_data;
- u64 tmp; /* this is required for casting... */
- int rc = 0;
-
- tmp = raw_field_value(event, "lockdep_addr", data);
- memcpy(&release_event.addr, &tmp, sizeof(void *));
- release_event.name = (char *)raw_field_ptr(event, "name", data);
-
if (trace_handler->release_event)
- rc = trace_handler->release_event(&release_event, sample);
-
- return rc;
-}
-
-static int perf_evsel__process_lock_event(struct perf_evsel *evsel,
- struct perf_sample *sample)
-{
- struct event_format *event = evsel->tp_format;
- int rc = 0;
-
- if (!strcmp(event->name, "lock_acquire"))
- rc = perf_evsel__process_lock_acquire(evsel, sample);
- if (!strcmp(event->name, "lock_acquired"))
- rc = perf_evsel__process_lock_acquired(evsel, sample);
- if (!strcmp(event->name, "lock_contended"))
- rc = perf_evsel__process_lock_contended(evsel, sample);
- if (!strcmp(event->name, "lock_release"))
- rc = perf_evsel__process_lock_release(evsel, sample);
-
- return rc;
+ return trace_handler->release_event(evsel, sample);
+ return 0;
}
static void print_bad_events(int bad, int total)
return rc;
}
+typedef int (*tracepoint_handler)(struct perf_evsel *evsel,
+ struct perf_sample *sample);
+
static int process_sample_event(struct perf_tool *tool __maybe_unused,
union perf_event *event,
struct perf_sample *sample,
return -1;
}
- return perf_evsel__process_lock_event(evsel, sample);
+ if (evsel->handler.func != NULL) {
+ tracepoint_handler f = evsel->handler.func;
+ return f(evsel, sample);
+ }
+
+ return 0;
}
static struct perf_tool eops = {
.ordered_samples = true,
};
+static const struct perf_evsel_str_handler lock_tracepoints[] = {
+ { "lock:lock_acquire", perf_evsel__process_lock_acquire, }, /* CONFIG_LOCKDEP */
+ { "lock:lock_acquired", perf_evsel__process_lock_acquired, }, /* CONFIG_LOCKDEP, CONFIG_LOCK_STAT */
+ { "lock:lock_contended", perf_evsel__process_lock_contended, }, /* CONFIG_LOCKDEP, CONFIG_LOCK_STAT */
+ { "lock:lock_release", perf_evsel__process_lock_release, }, /* CONFIG_LOCKDEP */
+};
+
static int read_events(void)
{
session = perf_session__new(input_name, O_RDONLY, 0, false, &eops);
return -1;
}
+ if (perf_session__set_tracepoints_handlers(session, lock_tracepoints)) {
+ pr_err("Initializing perf session tracepoint handlers failed\n");
+ return -1;
+ }
+
return perf_session__process_events(session, &eops);
}
OPT_END()
};
-static const char * const lock_tracepoints[] = {
- "lock:lock_acquire", /* CONFIG_LOCKDEP */
- "lock:lock_acquired", /* CONFIG_LOCKDEP, CONFIG_LOCK_STAT */
- "lock:lock_contended", /* CONFIG_LOCKDEP, CONFIG_LOCK_STAT */
- "lock:lock_release", /* CONFIG_LOCKDEP */
-};
-
static const char *record_args[] = {
"record",
"-R",
const char **rec_argv;
for (i = 0; i < ARRAY_SIZE(lock_tracepoints); i++) {
- if (!is_valid_tracepoint(lock_tracepoints[i])) {
+ if (!is_valid_tracepoint(lock_tracepoints[i].name)) {
pr_err("tracepoint %s is not enabled. "
"Are CONFIG_LOCKDEP and CONFIG_LOCK_STAT enabled?\n",
- lock_tracepoints[i]);
+ lock_tracepoints[i].name);
return 1;
}
}
for (j = 0; j < ARRAY_SIZE(lock_tracepoints); j++) {
rec_argv[i++] = "-e";
- rec_argv[i++] = strdup(lock_tracepoints[j]);
+ rec_argv[i++] = strdup(lock_tracepoints[j].name);
}
for (j = 1; j < (unsigned int)argc; j++, i++)