1 // SPDX-License-Identifier: GPL-2.0-only
3 #include "util/debug.h"
4 #include "util/evlist.h"
5 #include "util/evsel.h"
7 #include "util/perf_api_probe.h"
9 #include <linux/perf_event.h>
15 int perf_evlist__add_sb_event(struct evlist
*evlist
, struct perf_event_attr
*attr
,
16 evsel__sb_cb_t cb
, void *data
)
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;
25 evsel
= evsel__new_idx(attr
, evlist
->core
.nr_entries
);
29 evsel
->side_band
.cb
= cb
;
30 evsel
->side_band
.data
= data
;
31 evlist__add(evlist
, evsel
);
35 static void *perf_evlist__poll_thread(void *arg
)
37 struct evlist
*evlist
= arg
;
38 bool draining
= false;
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.
50 bool got_data
= false;
52 if (evlist
->thread
.done
)
56 evlist__poll(evlist
, 1000);
58 for (i
= 0; i
< evlist
->core
.nr_mmaps
; i
++) {
59 struct mmap
*map
= &evlist
->mmap
[i
];
60 union perf_event
*event
;
62 if (perf_mmap__read_init(&map
->core
))
64 while ((event
= perf_mmap__read_event(&map
->core
)) != NULL
) {
65 struct evsel
*evsel
= perf_evlist__event2evsel(evlist
, event
);
67 if (evsel
&& evsel
->side_band
.cb
)
68 evsel
->side_band
.cb(event
, evsel
->side_band
.data
);
70 pr_warning("cannot locate proper evsel for the side band event\n");
72 perf_mmap__consume(&map
->core
);
75 perf_mmap__read_done(&map
->core
);
78 if (draining
&& !got_data
)
84 void evlist__set_cb(struct evlist
*evlist
, evsel__sb_cb_t cb
, void *data
)
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
;
97 int perf_evlist__start_sb_thread(struct evlist
*evlist
, struct target
*target
)
99 struct evsel
*counter
;
104 if (perf_evlist__create_maps(evlist
, target
))
105 goto out_delete_evlist
;
107 if (evlist
->core
.nr_entries
> 1) {
108 bool can_sample_identifier
= perf_can_sample_identifier();
110 evlist__for_each_entry(evlist
, counter
)
111 evsel__set_sample_id(counter
, can_sample_identifier
);
113 perf_evlist__set_id_pos(evlist
);
116 evlist__for_each_entry(evlist
, counter
) {
117 if (evsel__open(counter
, evlist
->core
.cpus
, evlist
->core
.threads
) < 0)
118 goto out_delete_evlist
;
121 if (evlist__mmap(evlist
, UINT_MAX
))
122 goto out_delete_evlist
;
124 evlist__for_each_entry(evlist
, counter
) {
125 if (evsel__enable(counter
))
126 goto out_delete_evlist
;
129 evlist
->thread
.done
= 0;
130 if (pthread_create(&evlist
->thread
.th
, NULL
, perf_evlist__poll_thread
, evlist
))
131 goto out_delete_evlist
;
136 evlist__delete(evlist
);
141 void perf_evlist__stop_sb_thread(struct evlist
*evlist
)
145 evlist
->thread
.done
= 1;
146 pthread_join(evlist
->thread
.th
, NULL
);
147 evlist__delete(evlist
);