diff --git a/scripts/package/Makefile b/scripts/package/Makefile index a4f31c900fa6..c5d473393816 100644 --- a/scripts/package/Makefile +++ b/scripts/package/Makefile @@ -115,7 +115,9 @@ git --git-dir=$(srctree)/.git archive --prefix=$(perf-tar)/ \ -o $(perf-tar).tar; \ mkdir -p $(perf-tar); \ git --git-dir=$(srctree)/.git rev-parse HEAD > $(perf-tar)/HEAD; \ -tar rf $(perf-tar).tar $(perf-tar)/HEAD; \ +(cd $(srctree)/tools/perf; \ +util/PERF-VERSION-GEN ../../$(perf-tar)/ 2>/dev/null); \ +tar rf $(perf-tar).tar $(perf-tar)/HEAD $(perf-tar)/PERF-VERSION-FILE; \ rm -r $(perf-tar); \ $(if $(findstring tar-src,$@),, \ $(if $(findstring bz2,$@),bzip2, \ diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 409ceaf3b9b9..6a2508589460 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -106,8 +106,8 @@ static int perf_event__repipe_sample(struct perf_tool *tool, struct perf_evsel *evsel, struct machine *machine) { - if (evsel->handler.func) { - inject_handler f = evsel->handler.func; + if (evsel->handler) { + inject_handler f = evsel->handler; return f(tool, event, sample, evsel, machine); } @@ -383,11 +383,11 @@ static int __cmd_inject(struct perf_inject *inject) if (perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID")) return -EINVAL; - evsel->handler.func = perf_inject__sched_switch; + evsel->handler = perf_inject__sched_switch; } else if (!strcmp(name, "sched:sched_process_exit")) - evsel->handler.func = perf_inject__sched_process_exit; + evsel->handler = perf_inject__sched_process_exit; else if (!strncmp(name, "sched:sched_stat_", 17)) - evsel->handler.func = perf_inject__sched_stat; + evsel->handler = perf_inject__sched_stat; } } diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index a28970f7ddfb..929462aa4943 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -317,8 +317,8 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, dump_printf(" ... thread: %s:%d\n", thread__comm_str(thread), thread->tid); - if (evsel->handler.func != NULL) { - tracepoint_handler f = evsel->handler.func; + if (evsel->handler != NULL) { + tracepoint_handler f = evsel->handler; return f(evsel, sample); } diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index 35f9aaa565cc..c852c7a85d32 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c @@ -819,8 +819,8 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, return -1; } - if (evsel->handler.func != NULL) { - tracepoint_handler f = evsel->handler.func; + if (evsel->handler != NULL) { + tracepoint_handler f = evsel->handler; return f(evsel, sample); } diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index ea4c04f7437e..15280b5e5574 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -74,14 +74,8 @@ struct perf_record { bool no_buildid; bool no_buildid_cache; long samples; - off_t post_processing_offset; }; -static void advance_output(struct perf_record *rec, size_t size) -{ - rec->bytes_written += size; -} - static int write_output(struct perf_record *rec, void *buf, size_t size) { struct perf_data_file *file = &rec->file; @@ -252,13 +246,14 @@ static int process_buildids(struct perf_record *rec) { struct perf_data_file *file = &rec->file; struct perf_session *session = rec->session; + u64 start = session->header.data_offset; u64 size = lseek(file->fd, 0, SEEK_CUR); if (size == 0) return 0; - return __perf_session__process_events(session, rec->post_processing_offset, - size - rec->post_processing_offset, + return __perf_session__process_events(session, start, + size - start, size, &build_id__mark_dso_hit_ops); } @@ -342,9 +337,28 @@ out: return rc; } +static void perf_record__init_features(struct perf_record *rec) +{ + struct perf_evlist *evsel_list = rec->evlist; + struct perf_session *session = rec->session; + int feat; + + for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++) + perf_header__set_feat(&session->header, feat); + + if (rec->no_buildid) + perf_header__clear_feat(&session->header, HEADER_BUILD_ID); + + if (!have_tracepoints(&evsel_list->entries)) + perf_header__clear_feat(&session->header, HEADER_TRACING_DATA); + + if (!rec->opts.branch_stack) + perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK); +} + static int __cmd_record(struct perf_record *rec, int argc, const char **argv) { - int err, feat; + int err; unsigned long waking = 0; const bool forks = argc > 0; struct machine *machine; @@ -371,17 +385,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) rec->session = session; - for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++) - perf_header__set_feat(&session->header, feat); - - if (rec->no_buildid) - perf_header__clear_feat(&session->header, HEADER_BUILD_ID); - - if (!have_tracepoints(&evsel_list->entries)) - perf_header__clear_feat(&session->header, HEADER_TRACING_DATA); - - if (!rec->opts.branch_stack) - perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK); + perf_record__init_features(rec); if (forks) { err = perf_evlist__prepare_workload(evsel_list, &opts->target, @@ -425,8 +429,6 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) goto out_delete_session; } - rec->post_processing_offset = lseek(file->fd, 0, SEEK_CUR); - machine = &session->machines.host; if (file->is_pipe) { @@ -452,7 +454,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) pr_err("Couldn't record tracing data.\n"); goto out_delete_session; } - advance_output(rec, err); + rec->bytes_written += err; } } diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index a81ab1828aa5..0f3c65518a2c 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -1427,8 +1427,8 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool __maybe_ evsel->hists.stats.total_period += sample->period; hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); - if (evsel->handler.func != NULL) { - tracepoint_handler f = evsel->handler.func; + if (evsel->handler != NULL) { + tracepoint_handler f = evsel->handler; err = f(tool, evsel, sample, machine); } diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index e11c61d9bda4..41c9bde2fb67 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -483,8 +483,8 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, if (sample->cpu > numcpus) numcpus = sample->cpu; - if (evsel->handler.func != NULL) { - tracepoint_handler f = evsel->handler.func; + if (evsel->handler != NULL) { + tracepoint_handler f = evsel->handler; return f(evsel, sample); } diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index b3e57dc64546..329b7832b5da 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -35,6 +35,189 @@ # define MADV_UNMERGEABLE 13 #endif +struct tp_field { + int offset; + union { + u64 (*integer)(struct tp_field *field, struct perf_sample *sample); + void *(*pointer)(struct tp_field *field, struct perf_sample *sample); + }; +}; + +#define TP_UINT_FIELD(bits) \ +static u64 tp_field__u##bits(struct tp_field *field, struct perf_sample *sample) \ +{ \ + return *(u##bits *)(sample->raw_data + field->offset); \ +} + +TP_UINT_FIELD(8); +TP_UINT_FIELD(16); +TP_UINT_FIELD(32); +TP_UINT_FIELD(64); + +#define TP_UINT_FIELD__SWAPPED(bits) \ +static u64 tp_field__swapped_u##bits(struct tp_field *field, struct perf_sample *sample) \ +{ \ + u##bits value = *(u##bits *)(sample->raw_data + field->offset); \ + return bswap_##bits(value);\ +} + +TP_UINT_FIELD__SWAPPED(16); +TP_UINT_FIELD__SWAPPED(32); +TP_UINT_FIELD__SWAPPED(64); + +static int tp_field__init_uint(struct tp_field *field, + struct format_field *format_field, + bool needs_swap) +{ + field->offset = format_field->offset; + + switch (format_field->size) { + case 1: + field->integer = tp_field__u8; + break; + case 2: + field->integer = needs_swap ? tp_field__swapped_u16 : tp_field__u16; + break; + case 4: + field->integer = needs_swap ? tp_field__swapped_u32 : tp_field__u32; + break; + case 8: + field->integer = needs_swap ? tp_field__swapped_u64 : tp_field__u64; + break; + default: + return -1; + } + + return 0; +} + +static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample) +{ + return sample->raw_data + field->offset; +} + +static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field) +{ + field->offset = format_field->offset; + field->pointer = tp_field__ptr; + return 0; +} + +struct syscall_tp { + struct tp_field id; + union { + struct tp_field args, ret; + }; +}; + +static int perf_evsel__init_tp_uint_field(struct perf_evsel *evsel, + struct tp_field *field, + const char *name) +{ + struct format_field *format_field = perf_evsel__field(evsel, name); + + if (format_field == NULL) + return -1; + + return tp_field__init_uint(field, format_field, evsel->needs_swap); +} + +#define perf_evsel__init_sc_tp_uint_field(evsel, name) \ + ({ struct syscall_tp *sc = evsel->priv;\ + perf_evsel__init_tp_uint_field(evsel, &sc->name, #name); }) + +static int perf_evsel__init_tp_ptr_field(struct perf_evsel *evsel, + struct tp_field *field, + const char *name) +{ + struct format_field *format_field = perf_evsel__field(evsel, name); + + if (format_field == NULL) + return -1; + + return tp_field__init_ptr(field, format_field); +} + +#define perf_evsel__init_sc_tp_ptr_field(evsel, name) \ + ({ struct syscall_tp *sc = evsel->priv;\ + perf_evsel__init_tp_ptr_field(evsel, &sc->name, #name); }) + +static void perf_evsel__delete_priv(struct perf_evsel *evsel) +{ + free(evsel->priv); + evsel->priv = NULL; + perf_evsel__delete(evsel); +} + +static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, + void *handler, int idx) +{ + struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction, idx); + + if (evsel) { + evsel->priv = malloc(sizeof(struct syscall_tp)); + + if (evsel->priv == NULL) + goto out_delete; + + if (perf_evsel__init_sc_tp_uint_field(evsel, id)) + goto out_delete; + + evsel->handler = handler; + } + + return evsel; + +out_delete: + perf_evsel__delete_priv(evsel); + return NULL; +} + +#define perf_evsel__sc_tp_uint(evsel, name, sample) \ + ({ struct syscall_tp *fields = evsel->priv; \ + fields->name.integer(&fields->name, sample); }) + +#define perf_evsel__sc_tp_ptr(evsel, name, sample) \ + ({ struct syscall_tp *fields = evsel->priv; \ + fields->name.pointer(&fields->name, sample); }) + +static int perf_evlist__add_syscall_newtp(struct perf_evlist *evlist, + void *sys_enter_handler, + void *sys_exit_handler) +{ + int ret = -1; + int idx = evlist->nr_entries; + struct perf_evsel *sys_enter, *sys_exit; + + sys_enter = perf_evsel__syscall_newtp("sys_enter", sys_enter_handler, idx++); + if (sys_enter == NULL) + goto out; + + if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args)) + goto out_delete_sys_enter; + + sys_exit = perf_evsel__syscall_newtp("sys_exit", sys_exit_handler, idx++); + if (sys_exit == NULL) + goto out_delete_sys_enter; + + if (perf_evsel__init_sc_tp_uint_field(sys_exit, ret)) + goto out_delete_sys_exit; + + perf_evlist__add(evlist, sys_enter); + perf_evlist__add(evlist, sys_exit); + + ret = 0; +out: + return ret; + +out_delete_sys_exit: + perf_evsel__delete_priv(sys_exit); +out_delete_sys_enter: + perf_evsel__delete_priv(sys_enter); + goto out; +} + + struct syscall_arg { unsigned long val; struct thread *thread; @@ -1392,7 +1575,7 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, void *args; size_t printed = 0; struct thread *thread; - int id = perf_evsel__intval(evsel, sample, "id"); + int id = perf_evsel__sc_tp_uint(evsel, id, sample); struct syscall *sc = trace__syscall_info(trace, evsel, id); struct thread_trace *ttrace; @@ -1407,12 +1590,7 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, if (ttrace == NULL) return -1; - args = perf_evsel__rawptr(evsel, sample, "args"); - if (args == NULL) { - fprintf(trace->output, "Problems reading syscall arguments\n"); - return -1; - } - + args = perf_evsel__sc_tp_ptr(evsel, args, sample); ttrace = thread->priv; if (ttrace->entry_str == NULL) { @@ -1445,7 +1623,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, int ret; u64 duration = 0; struct thread *thread; - int id = perf_evsel__intval(evsel, sample, "id"); + int id = perf_evsel__sc_tp_uint(evsel, id, sample); struct syscall *sc = trace__syscall_info(trace, evsel, id); struct thread_trace *ttrace; @@ -1463,7 +1641,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, if (trace->summary) thread__update_stats(ttrace, id, sample); - ret = perf_evsel__intval(evsel, sample, "ret"); + ret = perf_evsel__sc_tp_uint(evsel, ret, sample); if (id == trace->audit.open_id && ret >= 0 && trace->last_vfs_getname) { trace__set_fd_pathname(thread, ret, trace->last_vfs_getname); @@ -1570,7 +1748,7 @@ static int trace__process_sample(struct perf_tool *tool, struct trace *trace = container_of(tool, struct trace, tool); int err = 0; - tracepoint_handler handler = evsel->handler.func; + tracepoint_handler handler = evsel->handler; if (skip_sample(trace, sample)) return 0; @@ -1656,7 +1834,7 @@ static void perf_evlist__add_vfs_getname(struct perf_evlist *evlist) return; } - evsel->handler.func = trace__vfs_getname; + evsel->handler = trace__vfs_getname; perf_evlist__add(evlist, evsel); } @@ -1675,8 +1853,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv) goto out; } - if (perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_enter", trace__sys_enter) || - perf_evlist__add_newtp(evlist, "raw_syscalls", "sys_exit", trace__sys_exit)) + if (perf_evlist__add_syscall_newtp(evlist, trace__sys_enter, trace__sys_exit)) goto out_error_tp; perf_evlist__add_vfs_getname(evlist); @@ -1768,7 +1945,7 @@ again: goto next_event; } - handler = evsel->handler.func; + handler = evsel->handler; handler(trace, evsel, &sample); next_event: perf_evlist__mmap_consume(evlist, i); diff --git a/tools/perf/util/PERF-VERSION-GEN b/tools/perf/util/PERF-VERSION-GEN index ce7a804b2951..39f17507578d 100755 --- a/tools/perf/util/PERF-VERSION-GEN +++ b/tools/perf/util/PERF-VERSION-GEN @@ -19,6 +19,9 @@ if test -d ../../.git -o -f ../../.git then TAG=$(git describe --abbrev=0 --match "v[0-9].[0-9]*" 2>/dev/null ) CID=$(git log -1 --abbrev=4 --pretty=format:"%h" 2>/dev/null) && CID="-g$CID" +elif test -f ../../PERF-VERSION-FILE +then + TAG=$(cut -d' ' -f3 ../../PERF-VERSION-FILE | sed -e 's/\"//g') fi if test -z "$TAG" then diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 1c173ccb0ef2..b939221efd8d 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -255,7 +255,7 @@ int perf_evlist__add_newtp(struct perf_evlist *evlist, if (evsel == NULL) return -1; - evsel->handler.func = handler; + evsel->handler = handler; perf_evlist__add(evlist, evsel); return 0; } diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 5aa68cddc7d9..64ec8e1a7a28 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -74,10 +74,7 @@ struct perf_evsel { off_t id_offset; }; struct cgroup_sel *cgrp; - struct { - void *func; - void *data; - } handler; + void *handler; struct cpu_map *cpus; unsigned int sample_size; int id_pos; diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 0ce46943d627..f36d24a02445 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1650,9 +1650,9 @@ int __perf_session__set_tracepoints_handlers(struct perf_session *session, continue; err = -EEXIST; - if (evsel->handler.func != NULL) + if (evsel->handler != NULL) goto out; - evsel->handler.func = assocs[i].handler; + evsel->handler = assocs[i].handler; } err = 0; diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index f4cc147e0220..43e5ff42a609 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -22,7 +22,6 @@ #include "parse-events.h" #include "thread.h" -#include "sort.h" extern regex_t parent_regex; extern const char *sort_order;