#include "builtin.h"
#include "perf.h"
#include "util/cache.h"
#include "util/debug.h"
#include "util/exec_cmd.h"
#include "util/header.h"
#include "util/parse-options.h"
#include "util/session.h"
#include "util/symbol.h"
#include "util/thread.h"
#include "util/trace-event.h"
#include "util/parse-options.h"
#include "util/util.h"
static char const *script_name;
static char const *generate_script_lang;
static bool debug_mode;
static u64 last_timestamp;
static u64 nr_unordered;
extern const struct option record_options[];
static int default_start_script(const char *script __unused,
int argc __unused,
const char **argv __unused)
{
return 0;
}
static int default_stop_script(void)
{
return 0;
}
static int default_generate_script(const char *outfile __unused)
{
return 0;
}
static struct scripting_ops default_scripting_ops = {
.start_script = default_start_script,
.stop_script = default_stop_script,
.process_event = print_event,
.generate_script = default_generate_script,
};
static struct scripting_ops *scripting_ops;
static void setup_scripting(void)
{
setup_perl_scripting();
setup_python_scripting();
scripting_ops = &default_scripting_ops;
}
static int cleanup_scripting(void)
{
pr_debug("\nperf script stopped\n");
return scripting_ops->stop_script();
}
static char const *input_name = "perf.data";
static int process_sample_event(event_t *event, struct perf_session *session)
{
struct sample_data data;
struct thread *thread;
memset(&data, 0, sizeof(data));
data.time = -1;
data.cpu = -1;
data.period = 1;
event__parse_sample(event, session->sample_type, &data);
dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc,
data.pid, data.tid, data.ip, data.period);
thread = perf_session__findnew(session, event->ip.pid);
if (thread == NULL) {
pr_debug("problem processing %d event, skipping it.\n",
event->header.type);
return -1;
}
if (session->sample_type & PERF_SAMPLE_RAW) {
if (debug_mode) {
if (data.time < last_timestamp) {
pr_err("Samples misordered, previous: %llu "
"this: %llu\n", last_timestamp,
data.time);
nr_unordered++;
}
last_timestamp = data.time;
return 0;
}
/*
* FIXME: better resolve from pid from the struct trace_entry
* field, although it should be the same than this perf
* event pid
*/
scripting_ops->process_event(data.cpu, data.raw_data,
data.raw_size,
data.time, thread->comm);
}
session->hists.stats.total_period += data.period;
return 0;
}
static u64 nr_lost;
static int process_lost_event(event_t *event, struct perf_session *session __used)
{
nr_lost += event->lost.lost;
return 0;
}
static struct perf_event_ops event_ops = {
.sample = process_sample_event,
.comm = event__process_comm,
.attr = event__process_attr,
.event_type = event__process_event_type,
.tracing_data = event__process_tracing_data,
.build_id = event__process_build_id,
.lost = process_lost_event,
.ordered_samples = true,
};
extern volatile int session_done;
static void sig_handler(int sig __unused)
{
session_done = 1;
}
static int __cmd_script(struct perf_session *session)
{
int ret;
signal(SIGINT, sig_handler);
ret = perf_session__process_events(session, &event_ops);
if (debug_mode) {
pr_err("Misordered timestamps: %llu\n", nr_unordered);
pr_err("Lost events: %llu\n", nr_lost);
}
return ret;
}
struct script_spec {
struct list_head node;
struct scripting_ops *ops;
char spec[0];
};
LIST_HEAD(script_specs);
static struct script_spec *script_spec__new(const char *spec,
struct scripting_ops *ops)
{
struct script_spec *s = malloc(sizeof(*s) + strlen(spec) + 1);
if (s != NULL) {
strcpy(s->spec, spec);
s->ops = ops;
}
return s;
}
static void script_spec__delete(struct script_spec *s)
{
free(s->spec);
free(s);
}
static void script_spec__add(struct script_spec *s)
{
list_add_tail(&s->node, &script_specs);
}
static struct script_spec *script_spec__find(const char *spec)
{
struct script_spec *s;
list_for_each_entry(s, &script_specs, node)
if (strcasecmp(s->spec, spec) == 0)
return s;
return