18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci
38c2ecf20Sopenharmony_ci#include "util/debug.h"
48c2ecf20Sopenharmony_ci#include "util/evlist.h"
58c2ecf20Sopenharmony_ci#include "util/evsel.h"
68c2ecf20Sopenharmony_ci#include "util/mmap.h"
78c2ecf20Sopenharmony_ci#include "util/perf_api_probe.h"
88c2ecf20Sopenharmony_ci#include <perf/mmap.h>
98c2ecf20Sopenharmony_ci#include <linux/perf_event.h>
108c2ecf20Sopenharmony_ci#include <limits.h>
118c2ecf20Sopenharmony_ci#include <pthread.h>
128c2ecf20Sopenharmony_ci#include <sched.h>
138c2ecf20Sopenharmony_ci#include <stdbool.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ciint perf_evlist__add_sb_event(struct evlist *evlist, struct perf_event_attr *attr,
168c2ecf20Sopenharmony_ci			      evsel__sb_cb_t cb, void *data)
178c2ecf20Sopenharmony_ci{
188c2ecf20Sopenharmony_ci	struct evsel *evsel;
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci	if (!attr->sample_id_all) {
218c2ecf20Sopenharmony_ci		pr_warning("enabling sample_id_all for all side band events\n");
228c2ecf20Sopenharmony_ci		attr->sample_id_all = 1;
238c2ecf20Sopenharmony_ci	}
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	evsel = evsel__new_idx(attr, evlist->core.nr_entries);
268c2ecf20Sopenharmony_ci	if (!evsel)
278c2ecf20Sopenharmony_ci		return -1;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	evsel->side_band.cb = cb;
308c2ecf20Sopenharmony_ci	evsel->side_band.data = data;
318c2ecf20Sopenharmony_ci	evlist__add(evlist, evsel);
328c2ecf20Sopenharmony_ci	return 0;
338c2ecf20Sopenharmony_ci}
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistatic void *perf_evlist__poll_thread(void *arg)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	struct evlist *evlist = arg;
388c2ecf20Sopenharmony_ci	bool draining = false;
398c2ecf20Sopenharmony_ci	int i, done = 0;
408c2ecf20Sopenharmony_ci	/*
418c2ecf20Sopenharmony_ci	 * In order to read symbols from other namespaces perf to needs to call
428c2ecf20Sopenharmony_ci	 * setns(2).  This isn't permitted if the struct_fs has multiple users.
438c2ecf20Sopenharmony_ci	 * unshare(2) the fs so that we may continue to setns into namespaces
448c2ecf20Sopenharmony_ci	 * that we're observing when, for instance, reading the build-ids at
458c2ecf20Sopenharmony_ci	 * the end of a 'perf record' session.
468c2ecf20Sopenharmony_ci	 */
478c2ecf20Sopenharmony_ci	unshare(CLONE_FS);
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	while (!done) {
508c2ecf20Sopenharmony_ci		bool got_data = false;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci		if (evlist->thread.done)
538c2ecf20Sopenharmony_ci			draining = true;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci		if (!draining)
568c2ecf20Sopenharmony_ci			evlist__poll(evlist, 1000);
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci		for (i = 0; i < evlist->core.nr_mmaps; i++) {
598c2ecf20Sopenharmony_ci			struct mmap *map = &evlist->mmap[i];
608c2ecf20Sopenharmony_ci			union perf_event *event;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci			if (perf_mmap__read_init(&map->core))
638c2ecf20Sopenharmony_ci				continue;
648c2ecf20Sopenharmony_ci			while ((event = perf_mmap__read_event(&map->core)) != NULL) {
658c2ecf20Sopenharmony_ci				struct evsel *evsel = perf_evlist__event2evsel(evlist, event);
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci				if (evsel && evsel->side_band.cb)
688c2ecf20Sopenharmony_ci					evsel->side_band.cb(event, evsel->side_band.data);
698c2ecf20Sopenharmony_ci				else
708c2ecf20Sopenharmony_ci					pr_warning("cannot locate proper evsel for the side band event\n");
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci				perf_mmap__consume(&map->core);
738c2ecf20Sopenharmony_ci				got_data = true;
748c2ecf20Sopenharmony_ci			}
758c2ecf20Sopenharmony_ci			perf_mmap__read_done(&map->core);
768c2ecf20Sopenharmony_ci		}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci		if (draining && !got_data)
798c2ecf20Sopenharmony_ci			break;
808c2ecf20Sopenharmony_ci	}
818c2ecf20Sopenharmony_ci	return NULL;
828c2ecf20Sopenharmony_ci}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_civoid evlist__set_cb(struct evlist *evlist, evsel__sb_cb_t cb, void *data)
858c2ecf20Sopenharmony_ci{
868c2ecf20Sopenharmony_ci	struct evsel *evsel;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
898c2ecf20Sopenharmony_ci		evsel->core.attr.sample_id_all    = 1;
908c2ecf20Sopenharmony_ci		evsel->core.attr.watermark        = 1;
918c2ecf20Sopenharmony_ci		evsel->core.attr.wakeup_watermark = 1;
928c2ecf20Sopenharmony_ci		evsel->side_band.cb   = cb;
938c2ecf20Sopenharmony_ci		evsel->side_band.data = data;
948c2ecf20Sopenharmony_ci      }
958c2ecf20Sopenharmony_ci}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ciint perf_evlist__start_sb_thread(struct evlist *evlist, struct target *target)
988c2ecf20Sopenharmony_ci{
998c2ecf20Sopenharmony_ci	struct evsel *counter;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	if (!evlist)
1028c2ecf20Sopenharmony_ci		return 0;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	if (perf_evlist__create_maps(evlist, target))
1058c2ecf20Sopenharmony_ci		goto out_delete_evlist;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	if (evlist->core.nr_entries > 1) {
1088c2ecf20Sopenharmony_ci		bool can_sample_identifier = perf_can_sample_identifier();
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci		evlist__for_each_entry(evlist, counter)
1118c2ecf20Sopenharmony_ci			evsel__set_sample_id(counter, can_sample_identifier);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci		perf_evlist__set_id_pos(evlist);
1148c2ecf20Sopenharmony_ci	}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	evlist__for_each_entry(evlist, counter) {
1178c2ecf20Sopenharmony_ci		if (evsel__open(counter, evlist->core.cpus, evlist->core.threads) < 0)
1188c2ecf20Sopenharmony_ci			goto out_delete_evlist;
1198c2ecf20Sopenharmony_ci	}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	if (evlist__mmap(evlist, UINT_MAX))
1228c2ecf20Sopenharmony_ci		goto out_delete_evlist;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	evlist__for_each_entry(evlist, counter) {
1258c2ecf20Sopenharmony_ci		if (evsel__enable(counter))
1268c2ecf20Sopenharmony_ci			goto out_delete_evlist;
1278c2ecf20Sopenharmony_ci	}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	evlist->thread.done = 0;
1308c2ecf20Sopenharmony_ci	if (pthread_create(&evlist->thread.th, NULL, perf_evlist__poll_thread, evlist))
1318c2ecf20Sopenharmony_ci		goto out_delete_evlist;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	return 0;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ciout_delete_evlist:
1368c2ecf20Sopenharmony_ci	evlist__delete(evlist);
1378c2ecf20Sopenharmony_ci	evlist = NULL;
1388c2ecf20Sopenharmony_ci	return -1;
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_civoid perf_evlist__stop_sb_thread(struct evlist *evlist)
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	if (!evlist)
1448c2ecf20Sopenharmony_ci		return;
1458c2ecf20Sopenharmony_ci	evlist->thread.done = 1;
1468c2ecf20Sopenharmony_ci	pthread_join(evlist->thread.th, NULL);
1478c2ecf20Sopenharmony_ci	evlist__delete(evlist);
1488c2ecf20Sopenharmony_ci}
149