Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

perf record: Fix way of handling non-perf-event pollfds

perf record __cmd_record() does not poll evlist pollfds. Instead it polls
thread_data[0].pollfd. That happens whether or not threads are being used.

perf record duplicates evlist mmap pollfds as needed for separate threads.
The non-perf-event represented by evlist->ctl_fd has to handled separately,
which is done explicitly, duplicating it into the thread_data[0] pollfds.
That approach neglects any other non-perf-event file descriptors. Currently
there is also done_fd which needs the same handling.

Add a new generalized approach.

Add fdarray_flag__non_perf_event to identify the file descriptors that
need the special handling. For those cases, also keep a mapping of the
evlist pollfd index and thread pollfd index, so that the evlist revents
can be updated.

Although this patch adds the new handling, it does not take it into use.
There is no functional change, but it is the precursor to a fix, so is
marked as a fix.

Fixes: 415ccb58f68a6beb ("perf record: Introduce thread specific data array")
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Acked-by: Ian Rogers <irogers@google.com>
Cc: Alexey Bayduraev <alexey.v.bayduraev@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Link: https://lore.kernel.org/r/20220824072814.16422-2-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Adrian Hunter and committed by
Arnaldo Carvalho de Melo
6562c9ac bdf45725

+83 -2
+3 -2
tools/lib/api/fd/array.h
··· 31 31 }; 32 32 33 33 enum fdarray_flags { 34 - fdarray_flag__default = 0x00000000, 35 - fdarray_flag__nonfilterable = 0x00000001 34 + fdarray_flag__default = 0x00000000, 35 + fdarray_flag__nonfilterable = 0x00000001, 36 + fdarray_flag__non_perf_event = 0x00000002, 36 37 }; 37 38 38 39 void fdarray__init(struct fdarray *fda, int nr_autogrow);
+80
tools/perf/builtin-record.c
··· 143 143 "undefined", "cpu", "core", "package", "numa", "user" 144 144 }; 145 145 146 + struct pollfd_index_map { 147 + int evlist_pollfd_index; 148 + int thread_pollfd_index; 149 + }; 150 + 146 151 struct record { 147 152 struct perf_tool tool; 148 153 struct record_opts opts; ··· 176 171 int nr_threads; 177 172 struct thread_mask *thread_masks; 178 173 struct record_thread *thread_data; 174 + struct pollfd_index_map *index_map; 175 + size_t index_map_sz; 176 + size_t index_map_cnt; 179 177 }; 180 178 181 179 static volatile int done; ··· 1082 1074 zfree(&rec->thread_data); 1083 1075 } 1084 1076 1077 + static int record__map_thread_evlist_pollfd_indexes(struct record *rec, 1078 + int evlist_pollfd_index, 1079 + int thread_pollfd_index) 1080 + { 1081 + size_t x = rec->index_map_cnt; 1082 + 1083 + if (realloc_array_as_needed(rec->index_map, rec->index_map_sz, x, NULL)) 1084 + return -ENOMEM; 1085 + rec->index_map[x].evlist_pollfd_index = evlist_pollfd_index; 1086 + rec->index_map[x].thread_pollfd_index = thread_pollfd_index; 1087 + rec->index_map_cnt += 1; 1088 + return 0; 1089 + } 1090 + 1091 + static int record__update_evlist_pollfd_from_thread(struct record *rec, 1092 + struct evlist *evlist, 1093 + struct record_thread *thread_data) 1094 + { 1095 + struct pollfd *e_entries = evlist->core.pollfd.entries; 1096 + struct pollfd *t_entries = thread_data->pollfd.entries; 1097 + int err = 0; 1098 + size_t i; 1099 + 1100 + for (i = 0; i < rec->index_map_cnt; i++) { 1101 + int e_pos = rec->index_map[i].evlist_pollfd_index; 1102 + int t_pos = rec->index_map[i].thread_pollfd_index; 1103 + 1104 + if (e_entries[e_pos].fd != t_entries[t_pos].fd || 1105 + e_entries[e_pos].events != t_entries[t_pos].events) { 1106 + pr_err("Thread and evlist pollfd index mismatch\n"); 1107 + err = -EINVAL; 1108 + continue; 1109 + } 1110 + e_entries[e_pos].revents = t_entries[t_pos].revents; 1111 + } 1112 + return err; 1113 + } 1114 + 1115 + static int record__dup_non_perf_events(struct record *rec, 1116 + struct evlist *evlist, 1117 + struct record_thread *thread_data) 1118 + { 1119 + struct fdarray *fda = &evlist->core.pollfd; 1120 + int i, ret; 1121 + 1122 + for (i = 0; i < fda->nr; i++) { 1123 + if (!(fda->priv[i].flags & fdarray_flag__non_perf_event)) 1124 + continue; 1125 + ret = fdarray__dup_entry_from(&thread_data->pollfd, i, fda); 1126 + if (ret < 0) { 1127 + pr_err("Failed to duplicate descriptor in main thread pollfd\n"); 1128 + return ret; 1129 + } 1130 + pr_debug2("thread_data[%p]: pollfd[%d] <- non_perf_event fd=%d\n", 1131 + thread_data, ret, fda->entries[i].fd); 1132 + ret = record__map_thread_evlist_pollfd_indexes(rec, i, ret); 1133 + if (ret < 0) { 1134 + pr_err("Failed to map thread and evlist pollfd indexes\n"); 1135 + return ret; 1136 + } 1137 + } 1138 + return 0; 1139 + } 1140 + 1085 1141 static int record__alloc_thread_data(struct record *rec, struct evlist *evlist) 1086 1142 { 1087 1143 int t, ret; ··· 1193 1121 thread_data[t].pipes.msg[0]); 1194 1122 } else { 1195 1123 thread_data[t].tid = gettid(); 1124 + 1125 + ret = record__dup_non_perf_events(rec, evlist, &thread_data[t]); 1126 + if (ret < 0) 1127 + goto out_free; 1128 + 1196 1129 if (evlist->ctl_fd.pos == -1) 1197 1130 continue; 1198 1131 ret = fdarray__dup_entry_from(&thread_data[t].pollfd, evlist->ctl_fd.pos, ··· 2611 2534 record__thread_munmap_filtered, NULL) == 0) 2612 2535 draining = true; 2613 2536 2537 + err = record__update_evlist_pollfd_from_thread(rec, rec->evlist, thread); 2538 + if (err) 2539 + goto out_child; 2614 2540 evlist__ctlfd_update(rec->evlist, 2615 2541 &thread->pollfd.entries[thread->ctlfd_pos]); 2616 2542 }