xref: /openbmc/linux/tools/perf/util/sideband_evlist.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
19a399944SArnaldo Carvalho de Melo // SPDX-License-Identifier: GPL-2.0-only
29a399944SArnaldo Carvalho de Melo 
39a399944SArnaldo Carvalho de Melo #include "util/debug.h"
49a399944SArnaldo Carvalho de Melo #include "util/evlist.h"
59a399944SArnaldo Carvalho de Melo #include "util/evsel.h"
69a399944SArnaldo Carvalho de Melo #include "util/mmap.h"
7976be845SArnaldo Carvalho de Melo #include "util/perf_api_probe.h"
89a399944SArnaldo Carvalho de Melo #include <perf/mmap.h>
99a399944SArnaldo Carvalho de Melo #include <linux/perf_event.h>
109a399944SArnaldo Carvalho de Melo #include <limits.h>
119a399944SArnaldo Carvalho de Melo #include <pthread.h>
129a399944SArnaldo Carvalho de Melo #include <sched.h>
139a399944SArnaldo Carvalho de Melo #include <stdbool.h>
149a399944SArnaldo Carvalho de Melo 
evlist__add_sb_event(struct evlist * evlist,struct perf_event_attr * attr,evsel__sb_cb_t cb,void * data)1508c83997SArnaldo Carvalho de Melo int evlist__add_sb_event(struct evlist *evlist, struct perf_event_attr *attr,
1665ddce3fSArnaldo Carvalho de Melo 			 evsel__sb_cb_t cb, void *data)
179a399944SArnaldo Carvalho de Melo {
189a399944SArnaldo Carvalho de Melo 	struct evsel *evsel;
199a399944SArnaldo Carvalho de Melo 
209a399944SArnaldo Carvalho de Melo 	if (!attr->sample_id_all) {
219a399944SArnaldo Carvalho de Melo 		pr_warning("enabling sample_id_all for all side band events\n");
229a399944SArnaldo Carvalho de Melo 		attr->sample_id_all = 1;
239a399944SArnaldo Carvalho de Melo 	}
249a399944SArnaldo Carvalho de Melo 
258f6725a2SArnaldo Carvalho de Melo 	evsel = evsel__new_idx(attr, evlist->core.nr_entries);
269a399944SArnaldo Carvalho de Melo 	if (!evsel)
279a399944SArnaldo Carvalho de Melo 		return -1;
289a399944SArnaldo Carvalho de Melo 
299a399944SArnaldo Carvalho de Melo 	evsel->side_band.cb = cb;
309a399944SArnaldo Carvalho de Melo 	evsel->side_band.data = data;
319a399944SArnaldo Carvalho de Melo 	evlist__add(evlist, evsel);
329a399944SArnaldo Carvalho de Melo 	return 0;
339a399944SArnaldo Carvalho de Melo }
349a399944SArnaldo Carvalho de Melo 
perf_evlist__poll_thread(void * arg)359a399944SArnaldo Carvalho de Melo static void *perf_evlist__poll_thread(void *arg)
369a399944SArnaldo Carvalho de Melo {
379a399944SArnaldo Carvalho de Melo 	struct evlist *evlist = arg;
389a399944SArnaldo Carvalho de Melo 	bool draining = false;
399a399944SArnaldo Carvalho de Melo 	int i, done = 0;
409a399944SArnaldo Carvalho de Melo 	/*
419a399944SArnaldo Carvalho de Melo 	 * In order to read symbols from other namespaces perf to needs to call
429a399944SArnaldo Carvalho de Melo 	 * setns(2).  This isn't permitted if the struct_fs has multiple users.
439a399944SArnaldo Carvalho de Melo 	 * unshare(2) the fs so that we may continue to setns into namespaces
449a399944SArnaldo Carvalho de Melo 	 * that we're observing when, for instance, reading the build-ids at
459a399944SArnaldo Carvalho de Melo 	 * the end of a 'perf record' session.
469a399944SArnaldo Carvalho de Melo 	 */
479a399944SArnaldo Carvalho de Melo 	unshare(CLONE_FS);
489a399944SArnaldo Carvalho de Melo 
499a399944SArnaldo Carvalho de Melo 	while (!done) {
509a399944SArnaldo Carvalho de Melo 		bool got_data = false;
519a399944SArnaldo Carvalho de Melo 
529a399944SArnaldo Carvalho de Melo 		if (evlist->thread.done)
539a399944SArnaldo Carvalho de Melo 			draining = true;
549a399944SArnaldo Carvalho de Melo 
559a399944SArnaldo Carvalho de Melo 		if (!draining)
569a399944SArnaldo Carvalho de Melo 			evlist__poll(evlist, 1000);
579a399944SArnaldo Carvalho de Melo 
589a399944SArnaldo Carvalho de Melo 		for (i = 0; i < evlist->core.nr_mmaps; i++) {
599a399944SArnaldo Carvalho de Melo 			struct mmap *map = &evlist->mmap[i];
609a399944SArnaldo Carvalho de Melo 			union perf_event *event;
619a399944SArnaldo Carvalho de Melo 
629a399944SArnaldo Carvalho de Melo 			if (perf_mmap__read_init(&map->core))
639a399944SArnaldo Carvalho de Melo 				continue;
649a399944SArnaldo Carvalho de Melo 			while ((event = perf_mmap__read_event(&map->core)) != NULL) {
653ccf8a7bSArnaldo Carvalho de Melo 				struct evsel *evsel = evlist__event2evsel(evlist, event);
669a399944SArnaldo Carvalho de Melo 
679a399944SArnaldo Carvalho de Melo 				if (evsel && evsel->side_band.cb)
689a399944SArnaldo Carvalho de Melo 					evsel->side_band.cb(event, evsel->side_band.data);
699a399944SArnaldo Carvalho de Melo 				else
709a399944SArnaldo Carvalho de Melo 					pr_warning("cannot locate proper evsel for the side band event\n");
719a399944SArnaldo Carvalho de Melo 
729a399944SArnaldo Carvalho de Melo 				perf_mmap__consume(&map->core);
739a399944SArnaldo Carvalho de Melo 				got_data = true;
749a399944SArnaldo Carvalho de Melo 			}
759a399944SArnaldo Carvalho de Melo 			perf_mmap__read_done(&map->core);
769a399944SArnaldo Carvalho de Melo 		}
779a399944SArnaldo Carvalho de Melo 
789a399944SArnaldo Carvalho de Melo 		if (draining && !got_data)
799a399944SArnaldo Carvalho de Melo 			break;
809a399944SArnaldo Carvalho de Melo 	}
819a399944SArnaldo Carvalho de Melo 	return NULL;
829a399944SArnaldo Carvalho de Melo }
839a399944SArnaldo Carvalho de Melo 
evlist__set_cb(struct evlist * evlist,evsel__sb_cb_t cb,void * data)8465ddce3fSArnaldo Carvalho de Melo void evlist__set_cb(struct evlist *evlist, evsel__sb_cb_t cb, void *data)
85976be845SArnaldo Carvalho de Melo {
86976be845SArnaldo Carvalho de Melo 	struct evsel *evsel;
87976be845SArnaldo Carvalho de Melo 
88976be845SArnaldo Carvalho de Melo 	evlist__for_each_entry(evlist, evsel) {
89976be845SArnaldo Carvalho de Melo 		evsel->core.attr.sample_id_all    = 1;
90976be845SArnaldo Carvalho de Melo 		evsel->core.attr.watermark        = 1;
91976be845SArnaldo Carvalho de Melo 		evsel->core.attr.wakeup_watermark = 1;
92976be845SArnaldo Carvalho de Melo 		evsel->side_band.cb   = cb;
93976be845SArnaldo Carvalho de Melo 		evsel->side_band.data = data;
94976be845SArnaldo Carvalho de Melo       }
95976be845SArnaldo Carvalho de Melo }
96976be845SArnaldo Carvalho de Melo 
evlist__start_sb_thread(struct evlist * evlist,struct target * target)9708c83997SArnaldo Carvalho de Melo int evlist__start_sb_thread(struct evlist *evlist, struct target *target)
989a399944SArnaldo Carvalho de Melo {
999a399944SArnaldo Carvalho de Melo 	struct evsel *counter;
1009a399944SArnaldo Carvalho de Melo 
1019a399944SArnaldo Carvalho de Melo 	if (!evlist)
1029a399944SArnaldo Carvalho de Melo 		return 0;
1039a399944SArnaldo Carvalho de Melo 
1047748bb71SArnaldo Carvalho de Melo 	if (evlist__create_maps(evlist, target))
1059a399944SArnaldo Carvalho de Melo 		goto out_delete_evlist;
1069a399944SArnaldo Carvalho de Melo 
107976be845SArnaldo Carvalho de Melo 	if (evlist->core.nr_entries > 1) {
108976be845SArnaldo Carvalho de Melo 		bool can_sample_identifier = perf_can_sample_identifier();
109976be845SArnaldo Carvalho de Melo 
110976be845SArnaldo Carvalho de Melo 		evlist__for_each_entry(evlist, counter)
111862b2f8fSArnaldo Carvalho de Melo 			evsel__set_sample_id(counter, can_sample_identifier);
112976be845SArnaldo Carvalho de Melo 
1130a7e7ec9SArnaldo Carvalho de Melo 		evlist__set_id_pos(evlist);
114976be845SArnaldo Carvalho de Melo 	}
115976be845SArnaldo Carvalho de Melo 
1169a399944SArnaldo Carvalho de Melo 	evlist__for_each_entry(evlist, counter) {
117*0df6ade7SIan Rogers 		if (evsel__open(counter, evlist->core.user_requested_cpus,
118*0df6ade7SIan Rogers 				evlist->core.threads) < 0)
1199a399944SArnaldo Carvalho de Melo 			goto out_delete_evlist;
1209a399944SArnaldo Carvalho de Melo 	}
1219a399944SArnaldo Carvalho de Melo 
1229a399944SArnaldo Carvalho de Melo 	if (evlist__mmap(evlist, UINT_MAX))
1239a399944SArnaldo Carvalho de Melo 		goto out_delete_evlist;
1249a399944SArnaldo Carvalho de Melo 
1259a399944SArnaldo Carvalho de Melo 	evlist__for_each_entry(evlist, counter) {
1269a399944SArnaldo Carvalho de Melo 		if (evsel__enable(counter))
1279a399944SArnaldo Carvalho de Melo 			goto out_delete_evlist;
1289a399944SArnaldo Carvalho de Melo 	}
1299a399944SArnaldo Carvalho de Melo 
1309a399944SArnaldo Carvalho de Melo 	evlist->thread.done = 0;
1319a399944SArnaldo Carvalho de Melo 	if (pthread_create(&evlist->thread.th, NULL, perf_evlist__poll_thread, evlist))
1329a399944SArnaldo Carvalho de Melo 		goto out_delete_evlist;
1339a399944SArnaldo Carvalho de Melo 
1349a399944SArnaldo Carvalho de Melo 	return 0;
1359a399944SArnaldo Carvalho de Melo 
1369a399944SArnaldo Carvalho de Melo out_delete_evlist:
1379a399944SArnaldo Carvalho de Melo 	evlist__delete(evlist);
1389a399944SArnaldo Carvalho de Melo 	evlist = NULL;
1399a399944SArnaldo Carvalho de Melo 	return -1;
1409a399944SArnaldo Carvalho de Melo }
1419a399944SArnaldo Carvalho de Melo 
evlist__stop_sb_thread(struct evlist * evlist)14208c83997SArnaldo Carvalho de Melo void evlist__stop_sb_thread(struct evlist *evlist)
1439a399944SArnaldo Carvalho de Melo {
1449a399944SArnaldo Carvalho de Melo 	if (!evlist)
1459a399944SArnaldo Carvalho de Melo 		return;
1469a399944SArnaldo Carvalho de Melo 	evlist->thread.done = 1;
1479a399944SArnaldo Carvalho de Melo 	pthread_join(evlist->thread.th, NULL);
1489a399944SArnaldo Carvalho de Melo 	evlist__delete(evlist);
1499a399944SArnaldo Carvalho de Melo }
150