diff options
Diffstat (limited to 'tools/perf/util/header.c')
-rw-r--r-- | tools/perf/util/header.c | 395 |
1 files changed, 5 insertions, 390 deletions
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index b0c34dda30a0..5722ff717777 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -42,11 +42,12 @@ | |||
42 | #include "tool.h" | 42 | #include "tool.h" |
43 | #include "time-utils.h" | 43 | #include "time-utils.h" |
44 | #include "units.h" | 44 | #include "units.h" |
45 | #include "util.h" | 45 | #include "util.h" // page_size, perf_exe() |
46 | #include "cputopo.h" | 46 | #include "cputopo.h" |
47 | #include "bpf-event.h" | 47 | #include "bpf-event.h" |
48 | 48 | ||
49 | #include <linux/ctype.h> | 49 | #include <linux/ctype.h> |
50 | #include <internal/lib.h> | ||
50 | 51 | ||
51 | /* | 52 | /* |
52 | * magic2 = "PERFILE2" | 53 | * magic2 = "PERFILE2" |
@@ -70,15 +71,6 @@ struct perf_file_attr { | |||
70 | struct perf_file_section ids; | 71 | struct perf_file_section ids; |
71 | }; | 72 | }; |
72 | 73 | ||
73 | struct feat_fd { | ||
74 | struct perf_header *ph; | ||
75 | int fd; | ||
76 | void *buf; /* Either buf != NULL or fd >= 0 */ | ||
77 | ssize_t offset; | ||
78 | size_t size; | ||
79 | struct evsel *events; | ||
80 | }; | ||
81 | |||
82 | void perf_header__set_feat(struct perf_header *header, int feat) | 74 | void perf_header__set_feat(struct perf_header *header, int feat) |
83 | { | 75 | { |
84 | set_bit(feat, header->adds_features); | 76 | set_bit(feat, header->adds_features); |
@@ -2823,15 +2815,6 @@ static int process_compressed(struct feat_fd *ff, | |||
2823 | return 0; | 2815 | return 0; |
2824 | } | 2816 | } |
2825 | 2817 | ||
2826 | struct feature_ops { | ||
2827 | int (*write)(struct feat_fd *ff, struct evlist *evlist); | ||
2828 | void (*print)(struct feat_fd *ff, FILE *fp); | ||
2829 | int (*process)(struct feat_fd *ff, void *data); | ||
2830 | const char *name; | ||
2831 | bool full_only; | ||
2832 | bool synthesize; | ||
2833 | }; | ||
2834 | |||
2835 | #define FEAT_OPR(n, func, __full_only) \ | 2818 | #define FEAT_OPR(n, func, __full_only) \ |
2836 | [HEADER_##n] = { \ | 2819 | [HEADER_##n] = { \ |
2837 | .name = __stringify(n), \ | 2820 | .name = __stringify(n), \ |
@@ -2858,8 +2841,10 @@ struct feature_ops { | |||
2858 | #define process_branch_stack NULL | 2841 | #define process_branch_stack NULL |
2859 | #define process_stat NULL | 2842 | #define process_stat NULL |
2860 | 2843 | ||
2844 | // Only used in util/synthetic-events.c | ||
2845 | const struct perf_header_feature_ops feat_ops[HEADER_LAST_FEATURE]; | ||
2861 | 2846 | ||
2862 | static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = { | 2847 | const struct perf_header_feature_ops feat_ops[HEADER_LAST_FEATURE] = { |
2863 | FEAT_OPN(TRACING_DATA, tracing_data, false), | 2848 | FEAT_OPN(TRACING_DATA, tracing_data, false), |
2864 | FEAT_OPN(BUILD_ID, build_id, false), | 2849 | FEAT_OPN(BUILD_ID, build_id, false), |
2865 | FEAT_OPR(HOSTNAME, hostname, false), | 2850 | FEAT_OPR(HOSTNAME, hostname, false), |
@@ -3656,105 +3641,6 @@ out_delete_evlist: | |||
3656 | return -ENOMEM; | 3641 | return -ENOMEM; |
3657 | } | 3642 | } |
3658 | 3643 | ||
3659 | int perf_event__synthesize_attr(struct perf_tool *tool, | ||
3660 | struct perf_event_attr *attr, u32 ids, u64 *id, | ||
3661 | perf_event__handler_t process) | ||
3662 | { | ||
3663 | union perf_event *ev; | ||
3664 | size_t size; | ||
3665 | int err; | ||
3666 | |||
3667 | size = sizeof(struct perf_event_attr); | ||
3668 | size = PERF_ALIGN(size, sizeof(u64)); | ||
3669 | size += sizeof(struct perf_event_header); | ||
3670 | size += ids * sizeof(u64); | ||
3671 | |||
3672 | ev = zalloc(size); | ||
3673 | |||
3674 | if (ev == NULL) | ||
3675 | return -ENOMEM; | ||
3676 | |||
3677 | ev->attr.attr = *attr; | ||
3678 | memcpy(ev->attr.id, id, ids * sizeof(u64)); | ||
3679 | |||
3680 | ev->attr.header.type = PERF_RECORD_HEADER_ATTR; | ||
3681 | ev->attr.header.size = (u16)size; | ||
3682 | |||
3683 | if (ev->attr.header.size == size) | ||
3684 | err = process(tool, ev, NULL, NULL); | ||
3685 | else | ||
3686 | err = -E2BIG; | ||
3687 | |||
3688 | free(ev); | ||
3689 | |||
3690 | return err; | ||
3691 | } | ||
3692 | |||
3693 | int perf_event__synthesize_features(struct perf_tool *tool, | ||
3694 | struct perf_session *session, | ||
3695 | struct evlist *evlist, | ||
3696 | perf_event__handler_t process) | ||
3697 | { | ||
3698 | struct perf_header *header = &session->header; | ||
3699 | struct feat_fd ff; | ||
3700 | struct perf_record_header_feature *fe; | ||
3701 | size_t sz, sz_hdr; | ||
3702 | int feat, ret; | ||
3703 | |||
3704 | sz_hdr = sizeof(fe->header); | ||
3705 | sz = sizeof(union perf_event); | ||
3706 | /* get a nice alignment */ | ||
3707 | sz = PERF_ALIGN(sz, page_size); | ||
3708 | |||
3709 | memset(&ff, 0, sizeof(ff)); | ||
3710 | |||
3711 | ff.buf = malloc(sz); | ||
3712 | if (!ff.buf) | ||
3713 | return -ENOMEM; | ||
3714 | |||
3715 | ff.size = sz - sz_hdr; | ||
3716 | ff.ph = &session->header; | ||
3717 | |||
3718 | for_each_set_bit(feat, header->adds_features, HEADER_FEAT_BITS) { | ||
3719 | if (!feat_ops[feat].synthesize) { | ||
3720 | pr_debug("No record header feature for header :%d\n", feat); | ||
3721 | continue; | ||
3722 | } | ||
3723 | |||
3724 | ff.offset = sizeof(*fe); | ||
3725 | |||
3726 | ret = feat_ops[feat].write(&ff, evlist); | ||
3727 | if (ret || ff.offset <= (ssize_t)sizeof(*fe)) { | ||
3728 | pr_debug("Error writing feature\n"); | ||
3729 | continue; | ||
3730 | } | ||
3731 | /* ff.buf may have changed due to realloc in do_write() */ | ||
3732 | fe = ff.buf; | ||
3733 | memset(fe, 0, sizeof(*fe)); | ||
3734 | |||
3735 | fe->feat_id = feat; | ||
3736 | fe->header.type = PERF_RECORD_HEADER_FEATURE; | ||
3737 | fe->header.size = ff.offset; | ||
3738 | |||
3739 | ret = process(tool, ff.buf, NULL, NULL); | ||
3740 | if (ret) { | ||
3741 | free(ff.buf); | ||
3742 | return ret; | ||
3743 | } | ||
3744 | } | ||
3745 | |||
3746 | /* Send HEADER_LAST_FEATURE mark. */ | ||
3747 | fe = ff.buf; | ||
3748 | fe->feat_id = HEADER_LAST_FEATURE; | ||
3749 | fe->header.type = PERF_RECORD_HEADER_FEATURE; | ||
3750 | fe->header.size = sizeof(*fe); | ||
3751 | |||
3752 | ret = process(tool, ff.buf, NULL, NULL); | ||
3753 | |||
3754 | free(ff.buf); | ||
3755 | return ret; | ||
3756 | } | ||
3757 | |||
3758 | int perf_event__process_feature(struct perf_session *session, | 3644 | int perf_event__process_feature(struct perf_session *session, |
3759 | union perf_event *event) | 3645 | union perf_event *event) |
3760 | { | 3646 | { |
@@ -3797,113 +3683,6 @@ int perf_event__process_feature(struct perf_session *session, | |||
3797 | return 0; | 3683 | return 0; |
3798 | } | 3684 | } |
3799 | 3685 | ||
3800 | static struct perf_record_event_update * | ||
3801 | event_update_event__new(size_t size, u64 type, u64 id) | ||
3802 | { | ||
3803 | struct perf_record_event_update *ev; | ||
3804 | |||
3805 | size += sizeof(*ev); | ||
3806 | size = PERF_ALIGN(size, sizeof(u64)); | ||
3807 | |||
3808 | ev = zalloc(size); | ||
3809 | if (ev) { | ||
3810 | ev->header.type = PERF_RECORD_EVENT_UPDATE; | ||
3811 | ev->header.size = (u16)size; | ||
3812 | ev->type = type; | ||
3813 | ev->id = id; | ||
3814 | } | ||
3815 | return ev; | ||
3816 | } | ||
3817 | |||
3818 | int | ||
3819 | perf_event__synthesize_event_update_unit(struct perf_tool *tool, | ||
3820 | struct evsel *evsel, | ||
3821 | perf_event__handler_t process) | ||
3822 | { | ||
3823 | struct perf_record_event_update *ev; | ||
3824 | size_t size = strlen(evsel->unit); | ||
3825 | int err; | ||
3826 | |||
3827 | ev = event_update_event__new(size + 1, PERF_EVENT_UPDATE__UNIT, evsel->id[0]); | ||
3828 | if (ev == NULL) | ||
3829 | return -ENOMEM; | ||
3830 | |||
3831 | strlcpy(ev->data, evsel->unit, size + 1); | ||
3832 | err = process(tool, (union perf_event *)ev, NULL, NULL); | ||
3833 | free(ev); | ||
3834 | return err; | ||
3835 | } | ||
3836 | |||
3837 | int | ||
3838 | perf_event__synthesize_event_update_scale(struct perf_tool *tool, | ||
3839 | struct evsel *evsel, | ||
3840 | perf_event__handler_t process) | ||
3841 | { | ||
3842 | struct perf_record_event_update *ev; | ||
3843 | struct perf_record_event_update_scale *ev_data; | ||
3844 | int err; | ||
3845 | |||
3846 | ev = event_update_event__new(sizeof(*ev_data), PERF_EVENT_UPDATE__SCALE, evsel->id[0]); | ||
3847 | if (ev == NULL) | ||
3848 | return -ENOMEM; | ||
3849 | |||
3850 | ev_data = (struct perf_record_event_update_scale *)ev->data; | ||
3851 | ev_data->scale = evsel->scale; | ||
3852 | err = process(tool, (union perf_event*) ev, NULL, NULL); | ||
3853 | free(ev); | ||
3854 | return err; | ||
3855 | } | ||
3856 | |||
3857 | int | ||
3858 | perf_event__synthesize_event_update_name(struct perf_tool *tool, | ||
3859 | struct evsel *evsel, | ||
3860 | perf_event__handler_t process) | ||
3861 | { | ||
3862 | struct perf_record_event_update *ev; | ||
3863 | size_t len = strlen(evsel->name); | ||
3864 | int err; | ||
3865 | |||
3866 | ev = event_update_event__new(len + 1, PERF_EVENT_UPDATE__NAME, evsel->id[0]); | ||
3867 | if (ev == NULL) | ||
3868 | return -ENOMEM; | ||
3869 | |||
3870 | strlcpy(ev->data, evsel->name, len + 1); | ||
3871 | err = process(tool, (union perf_event*) ev, NULL, NULL); | ||
3872 | free(ev); | ||
3873 | return err; | ||
3874 | } | ||
3875 | |||
3876 | int | ||
3877 | perf_event__synthesize_event_update_cpus(struct perf_tool *tool, | ||
3878 | struct evsel *evsel, | ||
3879 | perf_event__handler_t process) | ||
3880 | { | ||
3881 | size_t size = sizeof(struct perf_record_event_update); | ||
3882 | struct perf_record_event_update *ev; | ||
3883 | int max, err; | ||
3884 | u16 type; | ||
3885 | |||
3886 | if (!evsel->core.own_cpus) | ||
3887 | return 0; | ||
3888 | |||
3889 | ev = cpu_map_data__alloc(evsel->core.own_cpus, &size, &type, &max); | ||
3890 | if (!ev) | ||
3891 | return -ENOMEM; | ||
3892 | |||
3893 | ev->header.type = PERF_RECORD_EVENT_UPDATE; | ||
3894 | ev->header.size = (u16)size; | ||
3895 | ev->type = PERF_EVENT_UPDATE__CPUS; | ||
3896 | ev->id = evsel->id[0]; | ||
3897 | |||
3898 | cpu_map_data__synthesize((struct perf_record_cpu_map_data *)ev->data, | ||
3899 | evsel->core.own_cpus, | ||
3900 | type, max); | ||
3901 | |||
3902 | err = process(tool, (union perf_event*) ev, NULL, NULL); | ||
3903 | free(ev); | ||
3904 | return err; | ||
3905 | } | ||
3906 | |||
3907 | size_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp) | 3686 | size_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp) |
3908 | { | 3687 | { |
3909 | struct perf_record_event_update *ev = &event->event_update; | 3688 | struct perf_record_event_update *ev = &event->event_update; |
@@ -3943,93 +3722,6 @@ size_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp) | |||
3943 | return ret; | 3722 | return ret; |
3944 | } | 3723 | } |
3945 | 3724 | ||
3946 | int perf_event__synthesize_attrs(struct perf_tool *tool, | ||
3947 | struct evlist *evlist, | ||
3948 | perf_event__handler_t process) | ||
3949 | { | ||
3950 | struct evsel *evsel; | ||
3951 | int err = 0; | ||
3952 | |||
3953 | evlist__for_each_entry(evlist, evsel) { | ||
3954 | err = perf_event__synthesize_attr(tool, &evsel->core.attr, evsel->ids, | ||
3955 | evsel->id, process); | ||
3956 | if (err) { | ||
3957 | pr_debug("failed to create perf header attribute\n"); | ||
3958 | return err; | ||
3959 | } | ||
3960 | } | ||
3961 | |||
3962 | return err; | ||
3963 | } | ||
3964 | |||
3965 | static bool has_unit(struct evsel *counter) | ||
3966 | { | ||
3967 | return counter->unit && *counter->unit; | ||
3968 | } | ||
3969 | |||
3970 | static bool has_scale(struct evsel *counter) | ||
3971 | { | ||
3972 | return counter->scale != 1; | ||
3973 | } | ||
3974 | |||
3975 | int perf_event__synthesize_extra_attr(struct perf_tool *tool, | ||
3976 | struct evlist *evsel_list, | ||
3977 | perf_event__handler_t process, | ||
3978 | bool is_pipe) | ||
3979 | { | ||
3980 | struct evsel *counter; | ||
3981 | int err; | ||
3982 | |||
3983 | /* | ||
3984 | * Synthesize other events stuff not carried within | ||
3985 | * attr event - unit, scale, name | ||
3986 | */ | ||
3987 | evlist__for_each_entry(evsel_list, counter) { | ||
3988 | if (!counter->supported) | ||
3989 | continue; | ||
3990 | |||
3991 | /* | ||
3992 | * Synthesize unit and scale only if it's defined. | ||
3993 | */ | ||
3994 | if (has_unit(counter)) { | ||
3995 | err = perf_event__synthesize_event_update_unit(tool, counter, process); | ||
3996 | if (err < 0) { | ||
3997 | pr_err("Couldn't synthesize evsel unit.\n"); | ||
3998 | return err; | ||
3999 | } | ||
4000 | } | ||
4001 | |||
4002 | if (has_scale(counter)) { | ||
4003 | err = perf_event__synthesize_event_update_scale(tool, counter, process); | ||
4004 | if (err < 0) { | ||
4005 | pr_err("Couldn't synthesize evsel counter.\n"); | ||
4006 | return err; | ||
4007 | } | ||
4008 | } | ||
4009 | |||
4010 | if (counter->core.own_cpus) { | ||
4011 | err = perf_event__synthesize_event_update_cpus(tool, counter, process); | ||
4012 | if (err < 0) { | ||
4013 | pr_err("Couldn't synthesize evsel cpus.\n"); | ||
4014 | return err; | ||
4015 | } | ||
4016 | } | ||
4017 | |||
4018 | /* | ||
4019 | * Name is needed only for pipe output, | ||
4020 | * perf.data carries event names. | ||
4021 | */ | ||
4022 | if (is_pipe) { | ||
4023 | err = perf_event__synthesize_event_update_name(tool, counter, process); | ||
4024 | if (err < 0) { | ||
4025 | pr_err("Couldn't synthesize evsel name.\n"); | ||
4026 | return err; | ||
4027 | } | ||
4028 | } | ||
4029 | } | ||
4030 | return 0; | ||
4031 | } | ||
4032 | |||
4033 | int perf_event__process_attr(struct perf_tool *tool __maybe_unused, | 3725 | int perf_event__process_attr(struct perf_tool *tool __maybe_unused, |
4034 | union perf_event *event, | 3726 | union perf_event *event, |
4035 | struct evlist **pevlist) | 3727 | struct evlist **pevlist) |
@@ -4114,55 +3806,6 @@ int perf_event__process_event_update(struct perf_tool *tool __maybe_unused, | |||
4114 | return 0; | 3806 | return 0; |
4115 | } | 3807 | } |
4116 | 3808 | ||
4117 | int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, | ||
4118 | struct evlist *evlist, | ||
4119 | perf_event__handler_t process) | ||
4120 | { | ||
4121 | union perf_event ev; | ||
4122 | struct tracing_data *tdata; | ||
4123 | ssize_t size = 0, aligned_size = 0, padding; | ||
4124 | struct feat_fd ff; | ||
4125 | int err __maybe_unused = 0; | ||
4126 | |||
4127 | /* | ||
4128 | * We are going to store the size of the data followed | ||
4129 | * by the data contents. Since the fd descriptor is a pipe, | ||
4130 | * we cannot seek back to store the size of the data once | ||
4131 | * we know it. Instead we: | ||
4132 | * | ||
4133 | * - write the tracing data to the temp file | ||
4134 | * - get/write the data size to pipe | ||
4135 | * - write the tracing data from the temp file | ||
4136 | * to the pipe | ||
4137 | */ | ||
4138 | tdata = tracing_data_get(&evlist->core.entries, fd, true); | ||
4139 | if (!tdata) | ||
4140 | return -1; | ||
4141 | |||
4142 | memset(&ev, 0, sizeof(ev)); | ||
4143 | |||
4144 | ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA; | ||
4145 | size = tdata->size; | ||
4146 | aligned_size = PERF_ALIGN(size, sizeof(u64)); | ||
4147 | padding = aligned_size - size; | ||
4148 | ev.tracing_data.header.size = sizeof(ev.tracing_data); | ||
4149 | ev.tracing_data.size = aligned_size; | ||
4150 | |||
4151 | process(tool, &ev, NULL, NULL); | ||
4152 | |||
4153 | /* | ||
4154 | * The put function will copy all the tracing data | ||
4155 | * stored in temp file to the pipe. | ||
4156 | */ | ||
4157 | tracing_data_put(tdata); | ||
4158 | |||
4159 | ff = (struct feat_fd){ .fd = fd }; | ||
4160 | if (write_padded(&ff, NULL, 0, padding)) | ||
4161 | return -1; | ||
4162 | |||
4163 | return aligned_size; | ||
4164 | } | ||
4165 | |||
4166 | int perf_event__process_tracing_data(struct perf_session *session, | 3809 | int perf_event__process_tracing_data(struct perf_session *session, |
4167 | union perf_event *event) | 3810 | union perf_event *event) |
4168 | { | 3811 | { |
@@ -4202,34 +3845,6 @@ int perf_event__process_tracing_data(struct perf_session *session, | |||
4202 | return size_read + padding; | 3845 | return size_read + padding; |
4203 | } | 3846 | } |
4204 | 3847 | ||
4205 | int perf_event__synthesize_build_id(struct perf_tool *tool, | ||
4206 | struct dso *pos, u16 misc, | ||
4207 | perf_event__handler_t process, | ||
4208 | struct machine *machine) | ||
4209 | { | ||
4210 | union perf_event ev; | ||
4211 | size_t len; | ||
4212 | int err = 0; | ||
4213 | |||
4214 | if (!pos->hit) | ||
4215 | return err; | ||
4216 | |||
4217 | memset(&ev, 0, sizeof(ev)); | ||
4218 | |||
4219 | len = pos->long_name_len + 1; | ||
4220 | len = PERF_ALIGN(len, NAME_ALIGN); | ||
4221 | memcpy(&ev.build_id.build_id, pos->build_id, sizeof(pos->build_id)); | ||
4222 | ev.build_id.header.type = PERF_RECORD_HEADER_BUILD_ID; | ||
4223 | ev.build_id.header.misc = misc; | ||
4224 | ev.build_id.pid = machine->pid; | ||
4225 | ev.build_id.header.size = sizeof(ev.build_id) + len; | ||
4226 | memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len); | ||
4227 | |||
4228 | err = process(tool, &ev, NULL, machine); | ||
4229 | |||
4230 | return err; | ||
4231 | } | ||
4232 | |||
4233 | int perf_event__process_build_id(struct perf_session *session, | 3848 | int perf_event__process_build_id(struct perf_session *session, |
4234 | union perf_event *event) | 3849 | union perf_event *event) |
4235 | { | 3850 | { |