1 // SPDX-License-Identifier: GPL-2.0-only 2 3 #include "util/debug.h" 4 #include "util/evlist.h" 5 #include "util/evsel.h" 6 #include "util/mmap.h" 7 #include "util/perf_api_probe.h" 8 #include <perf/mmap.h> 9 #include <linux/perf_event.h> 10 #include <limits.h> 11 #include <pthread.h> 12 #include <sched.h> 13 #include <stdbool.h> 14 15 int perf_evlist__add_sb_event(struct evlist *evlist, struct perf_event_attr *attr, 16 evsel__sb_cb_t cb, void *data) 17 { 18 struct evsel *evsel; 19 20 if (!attr->sample_id_all) { 21 pr_warning("enabling sample_id_all for all side band events\n"); 22 attr->sample_id_all = 1; 23 } 24 25 evsel = evsel__new_idx(attr, evlist->core.nr_entries); 26 if (!evsel) 27 return -1; 28 29 evsel->side_band.cb = cb; 30 evsel->side_band.data = data; 31 evlist__add(evlist, evsel); 32 return 0; 33 } 34 35 static void *perf_evlist__poll_thread(void *arg) 36 { 37 struct evlist *evlist = arg; 38 bool draining = false; 39 int i, done = 0; 40 /* 41 * In order to read symbols from other namespaces perf to needs to call 42 * setns(2). This isn't permitted if the struct_fs has multiple users. 43 * unshare(2) the fs so that we may continue to setns into namespaces 44 * that we're observing when, for instance, reading the build-ids at 45 * the end of a 'perf record' session. 46 */ 47 unshare(CLONE_FS); 48 49 while (!done) { 50 bool got_data = false; 51 52 if (evlist->thread.done) 53 draining = true; 54 55 if (!draining) 56 evlist__poll(evlist, 1000); 57 58 for (i = 0; i < evlist->core.nr_mmaps; i++) { 59 struct mmap *map = &evlist->mmap[i]; 60 union perf_event *event; 61 62 if (perf_mmap__read_init(&map->core)) 63 continue; 64 while ((event = perf_mmap__read_event(&map->core)) != NULL) { 65 struct evsel *evsel = perf_evlist__event2evsel(evlist, event); 66 67 if (evsel && evsel->side_band.cb) 68 evsel->side_band.cb(event, evsel->side_band.data); 69 else 70 pr_warning("cannot locate proper evsel for the side band event\n"); 71 72 perf_mmap__consume(&map->core); 73 got_data = true; 74 } 75 perf_mmap__read_done(&map->core); 76 } 77 78 if (draining && !got_data) 79 break; 80 } 81 return NULL; 82 } 83 84 void evlist__set_cb(struct evlist *evlist, evsel__sb_cb_t cb, void *data) 85 { 86 struct evsel *evsel; 87 88 evlist__for_each_entry(evlist, evsel) { 89 evsel->core.attr.sample_id_all = 1; 90 evsel->core.attr.watermark = 1; 91 evsel->core.attr.wakeup_watermark = 1; 92 evsel->side_band.cb = cb; 93 evsel->side_band.data = data; 94 } 95 } 96 97 int perf_evlist__start_sb_thread(struct evlist *evlist, struct target *target) 98 { 99 struct evsel *counter; 100 101 if (!evlist) 102 return 0; 103 104 if (perf_evlist__create_maps(evlist, target)) 105 goto out_delete_evlist; 106 107 if (evlist->core.nr_entries > 1) { 108 bool can_sample_identifier = perf_can_sample_identifier(); 109 110 evlist__for_each_entry(evlist, counter) 111 evsel__set_sample_id(counter, can_sample_identifier); 112 113 perf_evlist__set_id_pos(evlist); 114 } 115 116 evlist__for_each_entry(evlist, counter) { 117 if (evsel__open(counter, evlist->core.cpus, evlist->core.threads) < 0) 118 goto out_delete_evlist; 119 } 120 121 if (evlist__mmap(evlist, UINT_MAX)) 122 goto out_delete_evlist; 123 124 evlist__for_each_entry(evlist, counter) { 125 if (evsel__enable(counter)) 126 goto out_delete_evlist; 127 } 128 129 evlist->thread.done = 0; 130 if (pthread_create(&evlist->thread.th, NULL, perf_evlist__poll_thread, evlist)) 131 goto out_delete_evlist; 132 133 return 0; 134 135 out_delete_evlist: 136 evlist__delete(evlist); 137 evlist = NULL; 138 return -1; 139 } 140 141 void perf_evlist__stop_sb_thread(struct evlist *evlist) 142 { 143 if (!evlist) 144 return; 145 evlist->thread.done = 1; 146 pthread_join(evlist->thread.th, NULL); 147 evlist__delete(evlist); 148 } 149