Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 338909
b: refs/heads/master
c: 26a031e
h: refs/heads/master
i:
  338907: cda8058
v: v3
  • Loading branch information
Andrew Vagin authored and Arnaldo Carvalho de Melo committed Oct 26, 2012
1 parent 021ab29 commit d307481
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 4 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: e558a5bd8b74aff4690a8c55b08a1dc91ef50d7c
refs/heads/master: 26a031e136f4f8dc82c64df48cca0eb3b5d3eb4f
5 changes: 5 additions & 0 deletions trunk/tools/perf/Documentation/perf-inject.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ OPTIONS
-o::
--output=::
Output file name. (default: stdout)
-s::
--sched-stat::
Merge sched_stat and sched_switch for getting events where and how long
tasks slept. sched_switch contains a callchain where a task slept and
sched_stat contains a timeslice how long a task slept.

SEE ALSO
--------
Expand Down
142 changes: 139 additions & 3 deletions trunk/tools/perf/builtin-inject.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,32 @@
#include "builtin.h"

#include "perf.h"
#include "util/color.h"
#include "util/evlist.h"
#include "util/evsel.h"
#include "util/session.h"
#include "util/tool.h"
#include "util/debug.h"

#include "util/parse-options.h"

#include <linux/list.h>

struct perf_inject {
struct perf_tool tool;
bool build_ids;
bool sched_stat;
const char *input_name;
int pipe_output,
output;
u64 bytes_written;
struct list_head samples;
};

struct event_entry {
struct list_head node;
u32 tid;
union perf_event event[0];
};

static int perf_event__repipe_synth(struct perf_tool *tool,
Expand Down Expand Up @@ -86,12 +99,23 @@ static int perf_event__repipe(struct perf_tool *tool,
return perf_event__repipe_synth(tool, event, machine);
}

typedef int (*inject_handler)(struct perf_tool *tool,
union perf_event *event,
struct perf_sample *sample,
struct perf_evsel *evsel,
struct machine *machine);

static int perf_event__repipe_sample(struct perf_tool *tool,
union perf_event *event,
struct perf_sample *sample __maybe_unused,
struct perf_evsel *evsel __maybe_unused,
struct machine *machine)
struct perf_sample *sample,
struct perf_evsel *evsel,
struct machine *machine)
{
if (evsel->handler.func) {
inject_handler f = evsel->handler.func;
return f(tool, event, sample, evsel, machine);
}

return perf_event__repipe_synth(tool, event, machine);
}

Expand Down Expand Up @@ -216,13 +240,101 @@ static int perf_event__inject_buildid(struct perf_tool *tool,
return 0;
}

static int perf_inject__sched_process_exit(struct perf_tool *tool,
union perf_event *event __maybe_unused,
struct perf_sample *sample,
struct perf_evsel *evsel __maybe_unused,
struct machine *machine __maybe_unused)
{
struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
struct event_entry *ent;

list_for_each_entry(ent, &inject->samples, node) {
if (sample->tid == ent->tid) {
list_del_init(&ent->node);
free(ent);
break;
}
}

return 0;
}

static int perf_inject__sched_switch(struct perf_tool *tool,
union perf_event *event,
struct perf_sample *sample,
struct perf_evsel *evsel,
struct machine *machine)
{
struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
struct event_entry *ent;

perf_inject__sched_process_exit(tool, event, sample, evsel, machine);

ent = malloc(event->header.size + sizeof(struct event_entry));
if (ent == NULL) {
color_fprintf(stderr, PERF_COLOR_RED,
"Not enough memory to process sched switch event!");
return -1;
}

ent->tid = sample->tid;
memcpy(&ent->event, event, event->header.size);
list_add(&ent->node, &inject->samples);
return 0;
}

static int perf_inject__sched_stat(struct perf_tool *tool,
union perf_event *event __maybe_unused,
struct perf_sample *sample,
struct perf_evsel *evsel,
struct machine *machine)
{
struct event_entry *ent;
union perf_event *event_sw;
struct perf_sample sample_sw;
struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
u32 pid = perf_evsel__intval(evsel, sample, "pid");

list_for_each_entry(ent, &inject->samples, node) {
if (pid == ent->tid)
goto found;
}

return 0;
found:
event_sw = &ent->event[0];
perf_evsel__parse_sample(evsel, event_sw, &sample_sw);

sample_sw.period = sample->period;
sample_sw.time = sample->time;
perf_event__synthesize_sample(event_sw, evsel->attr.sample_type,
&sample_sw, false);
return perf_event__repipe(tool, event_sw, &sample_sw, machine);
}

extern volatile int session_done;

static void sig_handler(int sig __maybe_unused)
{
session_done = 1;
}

static int perf_evsel__check_stype(struct perf_evsel *evsel,
u64 sample_type, const char *sample_msg)
{
struct perf_event_attr *attr = &evsel->attr;
const char *name = perf_evsel__name(evsel);

if (!(attr->sample_type & sample_type)) {
pr_err("Samples for %s event do not have %s attribute set.",
name, sample_msg);
return -EINVAL;
}

return 0;
}

static int __cmd_inject(struct perf_inject *inject)
{
struct perf_session *session;
Expand All @@ -241,6 +353,26 @@ static int __cmd_inject(struct perf_inject *inject)
if (session == NULL)
return -ENOMEM;

if (inject->sched_stat) {
struct perf_evsel *evsel;

inject->tool.ordered_samples = true;

list_for_each_entry(evsel, &session->evlist->entries, node) {
const char *name = perf_evsel__name(evsel);

if (!strcmp(name, "sched:sched_switch")) {
if (perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID"))
return -EINVAL;

evsel->handler.func = perf_inject__sched_switch;
} else if (!strcmp(name, "sched:sched_process_exit"))
evsel->handler.func = perf_inject__sched_process_exit;
else if (!strncmp(name, "sched:sched_stat_", 17))
evsel->handler.func = perf_inject__sched_stat;
}
}

if (!inject->pipe_output)
lseek(inject->output, session->header.data_offset, SEEK_SET);

Expand Down Expand Up @@ -275,6 +407,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
.build_id = perf_event__repipe_op2_synth,
},
.input_name = "-",
.samples = LIST_HEAD_INIT(inject.samples),
};
const char *output_name = "-";
const struct option options[] = {
Expand All @@ -284,6 +417,9 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
"input file name"),
OPT_STRING('o', "output", &output_name, "file",
"output file name"),
OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat,
"Merge sched-stat and sched-switch for getting events "
"where and how long tasks slept"),
OPT_INCR('v', "verbose", &verbose,
"be more verbose (show build ids, etc)"),
OPT_END()
Expand Down

0 comments on commit d307481

Please sign in to comment.