162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Parts came from builtin-{top,stat,record}.c, see those files for further
662306a36Sopenharmony_ci * copyright notes.
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci#include <api/fs/fs.h>
962306a36Sopenharmony_ci#include <errno.h>
1062306a36Sopenharmony_ci#include <inttypes.h>
1162306a36Sopenharmony_ci#include <poll.h>
1262306a36Sopenharmony_ci#include "cpumap.h"
1362306a36Sopenharmony_ci#include "util/mmap.h"
1462306a36Sopenharmony_ci#include "thread_map.h"
1562306a36Sopenharmony_ci#include "target.h"
1662306a36Sopenharmony_ci#include "evlist.h"
1762306a36Sopenharmony_ci#include "evsel.h"
1862306a36Sopenharmony_ci#include "record.h"
1962306a36Sopenharmony_ci#include "debug.h"
2062306a36Sopenharmony_ci#include "units.h"
2162306a36Sopenharmony_ci#include "bpf_counter.h"
2262306a36Sopenharmony_ci#include <internal/lib.h> // page_size
2362306a36Sopenharmony_ci#include "affinity.h"
2462306a36Sopenharmony_ci#include "../perf.h"
2562306a36Sopenharmony_ci#include "asm/bug.h"
2662306a36Sopenharmony_ci#include "bpf-event.h"
2762306a36Sopenharmony_ci#include "util/event.h"
2862306a36Sopenharmony_ci#include "util/string2.h"
2962306a36Sopenharmony_ci#include "util/perf_api_probe.h"
3062306a36Sopenharmony_ci#include "util/evsel_fprintf.h"
3162306a36Sopenharmony_ci#include "util/pmu.h"
3262306a36Sopenharmony_ci#include "util/sample.h"
3362306a36Sopenharmony_ci#include "util/bpf-filter.h"
3462306a36Sopenharmony_ci#include "util/stat.h"
3562306a36Sopenharmony_ci#include "util/util.h"
3662306a36Sopenharmony_ci#include <signal.h>
3762306a36Sopenharmony_ci#include <unistd.h>
3862306a36Sopenharmony_ci#include <sched.h>
3962306a36Sopenharmony_ci#include <stdlib.h>
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#include "parse-events.h"
4262306a36Sopenharmony_ci#include <subcmd/parse-options.h>
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#include <fcntl.h>
4562306a36Sopenharmony_ci#include <sys/ioctl.h>
4662306a36Sopenharmony_ci#include <sys/mman.h>
4762306a36Sopenharmony_ci#include <sys/prctl.h>
4862306a36Sopenharmony_ci#include <sys/timerfd.h>
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci#include <linux/bitops.h>
5162306a36Sopenharmony_ci#include <linux/hash.h>
5262306a36Sopenharmony_ci#include <linux/log2.h>
5362306a36Sopenharmony_ci#include <linux/err.h>
5462306a36Sopenharmony_ci#include <linux/string.h>
5562306a36Sopenharmony_ci#include <linux/time64.h>
5662306a36Sopenharmony_ci#include <linux/zalloc.h>
5762306a36Sopenharmony_ci#include <perf/evlist.h>
5862306a36Sopenharmony_ci#include <perf/evsel.h>
5962306a36Sopenharmony_ci#include <perf/cpumap.h>
6062306a36Sopenharmony_ci#include <perf/mmap.h>
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci#include <internal/xyarray.h>
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci#ifdef LACKS_SIGQUEUE_PROTOTYPE
6562306a36Sopenharmony_ciint sigqueue(pid_t pid, int sig, const union sigval value);
6662306a36Sopenharmony_ci#endif
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci#define FD(e, x, y) (*(int *)xyarray__entry(e->core.fd, x, y))
6962306a36Sopenharmony_ci#define SID(e, x, y) xyarray__entry(e->core.sample_id, x, y)
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_civoid evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus,
7262306a36Sopenharmony_ci		  struct perf_thread_map *threads)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	perf_evlist__init(&evlist->core);
7562306a36Sopenharmony_ci	perf_evlist__set_maps(&evlist->core, cpus, threads);
7662306a36Sopenharmony_ci	evlist->workload.pid = -1;
7762306a36Sopenharmony_ci	evlist->bkw_mmap_state = BKW_MMAP_NOTREADY;
7862306a36Sopenharmony_ci	evlist->ctl_fd.fd = -1;
7962306a36Sopenharmony_ci	evlist->ctl_fd.ack = -1;
8062306a36Sopenharmony_ci	evlist->ctl_fd.pos = -1;
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistruct evlist *evlist__new(void)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	struct evlist *evlist = zalloc(sizeof(*evlist));
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	if (evlist != NULL)
8862306a36Sopenharmony_ci		evlist__init(evlist, NULL, NULL);
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	return evlist;
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistruct evlist *evlist__new_default(void)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	struct evlist *evlist = evlist__new();
9662306a36Sopenharmony_ci	bool can_profile_kernel;
9762306a36Sopenharmony_ci	int err;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	if (!evlist)
10062306a36Sopenharmony_ci		return NULL;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	can_profile_kernel = perf_event_paranoid_check(1);
10362306a36Sopenharmony_ci	err = parse_event(evlist, can_profile_kernel ? "cycles:P" : "cycles:Pu");
10462306a36Sopenharmony_ci	if (err) {
10562306a36Sopenharmony_ci		evlist__delete(evlist);
10662306a36Sopenharmony_ci		return NULL;
10762306a36Sopenharmony_ci	}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	if (evlist->core.nr_entries > 1) {
11062306a36Sopenharmony_ci		struct evsel *evsel;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci		evlist__for_each_entry(evlist, evsel)
11362306a36Sopenharmony_ci			evsel__set_sample_id(evsel, /*can_sample_identifier=*/false);
11462306a36Sopenharmony_ci	}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	return evlist;
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistruct evlist *evlist__new_dummy(void)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	struct evlist *evlist = evlist__new();
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	if (evlist && evlist__add_dummy(evlist)) {
12462306a36Sopenharmony_ci		evlist__delete(evlist);
12562306a36Sopenharmony_ci		evlist = NULL;
12662306a36Sopenharmony_ci	}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	return evlist;
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci/**
13262306a36Sopenharmony_ci * evlist__set_id_pos - set the positions of event ids.
13362306a36Sopenharmony_ci * @evlist: selected event list
13462306a36Sopenharmony_ci *
13562306a36Sopenharmony_ci * Events with compatible sample types all have the same id_pos
13662306a36Sopenharmony_ci * and is_pos.  For convenience, put a copy on evlist.
13762306a36Sopenharmony_ci */
13862306a36Sopenharmony_civoid evlist__set_id_pos(struct evlist *evlist)
13962306a36Sopenharmony_ci{
14062306a36Sopenharmony_ci	struct evsel *first = evlist__first(evlist);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	evlist->id_pos = first->id_pos;
14362306a36Sopenharmony_ci	evlist->is_pos = first->is_pos;
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_cistatic void evlist__update_id_pos(struct evlist *evlist)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	struct evsel *evsel;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	evlist__for_each_entry(evlist, evsel)
15162306a36Sopenharmony_ci		evsel__calc_id_pos(evsel);
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	evlist__set_id_pos(evlist);
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic void evlist__purge(struct evlist *evlist)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	struct evsel *pos, *n;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	evlist__for_each_entry_safe(evlist, n, pos) {
16162306a36Sopenharmony_ci		list_del_init(&pos->core.node);
16262306a36Sopenharmony_ci		pos->evlist = NULL;
16362306a36Sopenharmony_ci		evsel__delete(pos);
16462306a36Sopenharmony_ci	}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	evlist->core.nr_entries = 0;
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_civoid evlist__exit(struct evlist *evlist)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	event_enable_timer__exit(&evlist->eet);
17262306a36Sopenharmony_ci	zfree(&evlist->mmap);
17362306a36Sopenharmony_ci	zfree(&evlist->overwrite_mmap);
17462306a36Sopenharmony_ci	perf_evlist__exit(&evlist->core);
17562306a36Sopenharmony_ci}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_civoid evlist__delete(struct evlist *evlist)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	if (evlist == NULL)
18062306a36Sopenharmony_ci		return;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	evlist__free_stats(evlist);
18362306a36Sopenharmony_ci	evlist__munmap(evlist);
18462306a36Sopenharmony_ci	evlist__close(evlist);
18562306a36Sopenharmony_ci	evlist__purge(evlist);
18662306a36Sopenharmony_ci	evlist__exit(evlist);
18762306a36Sopenharmony_ci	free(evlist);
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_civoid evlist__add(struct evlist *evlist, struct evsel *entry)
19162306a36Sopenharmony_ci{
19262306a36Sopenharmony_ci	perf_evlist__add(&evlist->core, &entry->core);
19362306a36Sopenharmony_ci	entry->evlist = evlist;
19462306a36Sopenharmony_ci	entry->tracking = !entry->core.idx;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	if (evlist->core.nr_entries == 1)
19762306a36Sopenharmony_ci		evlist__set_id_pos(evlist);
19862306a36Sopenharmony_ci}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_civoid evlist__remove(struct evlist *evlist, struct evsel *evsel)
20162306a36Sopenharmony_ci{
20262306a36Sopenharmony_ci	evsel->evlist = NULL;
20362306a36Sopenharmony_ci	perf_evlist__remove(&evlist->core, &evsel->core);
20462306a36Sopenharmony_ci}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_civoid evlist__splice_list_tail(struct evlist *evlist, struct list_head *list)
20762306a36Sopenharmony_ci{
20862306a36Sopenharmony_ci	while (!list_empty(list)) {
20962306a36Sopenharmony_ci		struct evsel *evsel, *temp, *leader = NULL;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci		__evlist__for_each_entry_safe(list, temp, evsel) {
21262306a36Sopenharmony_ci			list_del_init(&evsel->core.node);
21362306a36Sopenharmony_ci			evlist__add(evlist, evsel);
21462306a36Sopenharmony_ci			leader = evsel;
21562306a36Sopenharmony_ci			break;
21662306a36Sopenharmony_ci		}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci		__evlist__for_each_entry_safe(list, temp, evsel) {
21962306a36Sopenharmony_ci			if (evsel__has_leader(evsel, leader)) {
22062306a36Sopenharmony_ci				list_del_init(&evsel->core.node);
22162306a36Sopenharmony_ci				evlist__add(evlist, evsel);
22262306a36Sopenharmony_ci			}
22362306a36Sopenharmony_ci		}
22462306a36Sopenharmony_ci	}
22562306a36Sopenharmony_ci}
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ciint __evlist__set_tracepoints_handlers(struct evlist *evlist,
22862306a36Sopenharmony_ci				       const struct evsel_str_handler *assocs, size_t nr_assocs)
22962306a36Sopenharmony_ci{
23062306a36Sopenharmony_ci	size_t i;
23162306a36Sopenharmony_ci	int err;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	for (i = 0; i < nr_assocs; i++) {
23462306a36Sopenharmony_ci		// Adding a handler for an event not in this evlist, just ignore it.
23562306a36Sopenharmony_ci		struct evsel *evsel = evlist__find_tracepoint_by_name(evlist, assocs[i].name);
23662306a36Sopenharmony_ci		if (evsel == NULL)
23762306a36Sopenharmony_ci			continue;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci		err = -EEXIST;
24062306a36Sopenharmony_ci		if (evsel->handler != NULL)
24162306a36Sopenharmony_ci			goto out;
24262306a36Sopenharmony_ci		evsel->handler = assocs[i].handler;
24362306a36Sopenharmony_ci	}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	err = 0;
24662306a36Sopenharmony_ciout:
24762306a36Sopenharmony_ci	return err;
24862306a36Sopenharmony_ci}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_cistatic void evlist__set_leader(struct evlist *evlist)
25162306a36Sopenharmony_ci{
25262306a36Sopenharmony_ci	perf_evlist__set_leader(&evlist->core);
25362306a36Sopenharmony_ci}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_cistatic struct evsel *evlist__dummy_event(struct evlist *evlist)
25662306a36Sopenharmony_ci{
25762306a36Sopenharmony_ci	struct perf_event_attr attr = {
25862306a36Sopenharmony_ci		.type	= PERF_TYPE_SOFTWARE,
25962306a36Sopenharmony_ci		.config = PERF_COUNT_SW_DUMMY,
26062306a36Sopenharmony_ci		.size	= sizeof(attr), /* to capture ABI version */
26162306a36Sopenharmony_ci		/* Avoid frequency mode for dummy events to avoid associated timers. */
26262306a36Sopenharmony_ci		.freq = 0,
26362306a36Sopenharmony_ci		.sample_period = 1,
26462306a36Sopenharmony_ci	};
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	return evsel__new_idx(&attr, evlist->core.nr_entries);
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ciint evlist__add_dummy(struct evlist *evlist)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci	struct evsel *evsel = evlist__dummy_event(evlist);
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	if (evsel == NULL)
27462306a36Sopenharmony_ci		return -ENOMEM;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	evlist__add(evlist, evsel);
27762306a36Sopenharmony_ci	return 0;
27862306a36Sopenharmony_ci}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_cistruct evsel *evlist__add_aux_dummy(struct evlist *evlist, bool system_wide)
28162306a36Sopenharmony_ci{
28262306a36Sopenharmony_ci	struct evsel *evsel = evlist__dummy_event(evlist);
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	if (!evsel)
28562306a36Sopenharmony_ci		return NULL;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	evsel->core.attr.exclude_kernel = 1;
28862306a36Sopenharmony_ci	evsel->core.attr.exclude_guest = 1;
28962306a36Sopenharmony_ci	evsel->core.attr.exclude_hv = 1;
29062306a36Sopenharmony_ci	evsel->core.system_wide = system_wide;
29162306a36Sopenharmony_ci	evsel->no_aux_samples = true;
29262306a36Sopenharmony_ci	evsel->name = strdup("dummy:u");
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	evlist__add(evlist, evsel);
29562306a36Sopenharmony_ci	return evsel;
29662306a36Sopenharmony_ci}
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci#ifdef HAVE_LIBTRACEEVENT
29962306a36Sopenharmony_cistruct evsel *evlist__add_sched_switch(struct evlist *evlist, bool system_wide)
30062306a36Sopenharmony_ci{
30162306a36Sopenharmony_ci	struct evsel *evsel = evsel__newtp_idx("sched", "sched_switch", 0);
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	if (IS_ERR(evsel))
30462306a36Sopenharmony_ci		return evsel;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	evsel__set_sample_bit(evsel, CPU);
30762306a36Sopenharmony_ci	evsel__set_sample_bit(evsel, TIME);
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	evsel->core.system_wide = system_wide;
31062306a36Sopenharmony_ci	evsel->no_aux_samples = true;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	evlist__add(evlist, evsel);
31362306a36Sopenharmony_ci	return evsel;
31462306a36Sopenharmony_ci}
31562306a36Sopenharmony_ci#endif
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ciint evlist__add_attrs(struct evlist *evlist, struct perf_event_attr *attrs, size_t nr_attrs)
31862306a36Sopenharmony_ci{
31962306a36Sopenharmony_ci	struct evsel *evsel, *n;
32062306a36Sopenharmony_ci	LIST_HEAD(head);
32162306a36Sopenharmony_ci	size_t i;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	for (i = 0; i < nr_attrs; i++) {
32462306a36Sopenharmony_ci		evsel = evsel__new_idx(attrs + i, evlist->core.nr_entries + i);
32562306a36Sopenharmony_ci		if (evsel == NULL)
32662306a36Sopenharmony_ci			goto out_delete_partial_list;
32762306a36Sopenharmony_ci		list_add_tail(&evsel->core.node, &head);
32862306a36Sopenharmony_ci	}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	evlist__splice_list_tail(evlist, &head);
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	return 0;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ciout_delete_partial_list:
33562306a36Sopenharmony_ci	__evlist__for_each_entry_safe(&head, n, evsel)
33662306a36Sopenharmony_ci		evsel__delete(evsel);
33762306a36Sopenharmony_ci	return -1;
33862306a36Sopenharmony_ci}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ciint __evlist__add_default_attrs(struct evlist *evlist, struct perf_event_attr *attrs, size_t nr_attrs)
34162306a36Sopenharmony_ci{
34262306a36Sopenharmony_ci	size_t i;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	for (i = 0; i < nr_attrs; i++)
34562306a36Sopenharmony_ci		event_attr_init(attrs + i);
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	return evlist__add_attrs(evlist, attrs, nr_attrs);
34862306a36Sopenharmony_ci}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci__weak int arch_evlist__add_default_attrs(struct evlist *evlist,
35162306a36Sopenharmony_ci					  struct perf_event_attr *attrs,
35262306a36Sopenharmony_ci					  size_t nr_attrs)
35362306a36Sopenharmony_ci{
35462306a36Sopenharmony_ci	if (!nr_attrs)
35562306a36Sopenharmony_ci		return 0;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	return __evlist__add_default_attrs(evlist, attrs, nr_attrs);
35862306a36Sopenharmony_ci}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_cistruct evsel *evlist__find_tracepoint_by_id(struct evlist *evlist, int id)
36162306a36Sopenharmony_ci{
36262306a36Sopenharmony_ci	struct evsel *evsel;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
36562306a36Sopenharmony_ci		if (evsel->core.attr.type   == PERF_TYPE_TRACEPOINT &&
36662306a36Sopenharmony_ci		    (int)evsel->core.attr.config == id)
36762306a36Sopenharmony_ci			return evsel;
36862306a36Sopenharmony_ci	}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	return NULL;
37162306a36Sopenharmony_ci}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_cistruct evsel *evlist__find_tracepoint_by_name(struct evlist *evlist, const char *name)
37462306a36Sopenharmony_ci{
37562306a36Sopenharmony_ci	struct evsel *evsel;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
37862306a36Sopenharmony_ci		if ((evsel->core.attr.type == PERF_TYPE_TRACEPOINT) &&
37962306a36Sopenharmony_ci		    (strcmp(evsel->name, name) == 0))
38062306a36Sopenharmony_ci			return evsel;
38162306a36Sopenharmony_ci	}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	return NULL;
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci#ifdef HAVE_LIBTRACEEVENT
38762306a36Sopenharmony_ciint evlist__add_newtp(struct evlist *evlist, const char *sys, const char *name, void *handler)
38862306a36Sopenharmony_ci{
38962306a36Sopenharmony_ci	struct evsel *evsel = evsel__newtp(sys, name);
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	if (IS_ERR(evsel))
39262306a36Sopenharmony_ci		return -1;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	evsel->handler = handler;
39562306a36Sopenharmony_ci	evlist__add(evlist, evsel);
39662306a36Sopenharmony_ci	return 0;
39762306a36Sopenharmony_ci}
39862306a36Sopenharmony_ci#endif
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_cistruct evlist_cpu_iterator evlist__cpu_begin(struct evlist *evlist, struct affinity *affinity)
40162306a36Sopenharmony_ci{
40262306a36Sopenharmony_ci	struct evlist_cpu_iterator itr = {
40362306a36Sopenharmony_ci		.container = evlist,
40462306a36Sopenharmony_ci		.evsel = NULL,
40562306a36Sopenharmony_ci		.cpu_map_idx = 0,
40662306a36Sopenharmony_ci		.evlist_cpu_map_idx = 0,
40762306a36Sopenharmony_ci		.evlist_cpu_map_nr = perf_cpu_map__nr(evlist->core.all_cpus),
40862306a36Sopenharmony_ci		.cpu = (struct perf_cpu){ .cpu = -1},
40962306a36Sopenharmony_ci		.affinity = affinity,
41062306a36Sopenharmony_ci	};
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	if (evlist__empty(evlist)) {
41362306a36Sopenharmony_ci		/* Ensure the empty list doesn't iterate. */
41462306a36Sopenharmony_ci		itr.evlist_cpu_map_idx = itr.evlist_cpu_map_nr;
41562306a36Sopenharmony_ci	} else {
41662306a36Sopenharmony_ci		itr.evsel = evlist__first(evlist);
41762306a36Sopenharmony_ci		if (itr.affinity) {
41862306a36Sopenharmony_ci			itr.cpu = perf_cpu_map__cpu(evlist->core.all_cpus, 0);
41962306a36Sopenharmony_ci			affinity__set(itr.affinity, itr.cpu.cpu);
42062306a36Sopenharmony_ci			itr.cpu_map_idx = perf_cpu_map__idx(itr.evsel->core.cpus, itr.cpu);
42162306a36Sopenharmony_ci			/*
42262306a36Sopenharmony_ci			 * If this CPU isn't in the evsel's cpu map then advance
42362306a36Sopenharmony_ci			 * through the list.
42462306a36Sopenharmony_ci			 */
42562306a36Sopenharmony_ci			if (itr.cpu_map_idx == -1)
42662306a36Sopenharmony_ci				evlist_cpu_iterator__next(&itr);
42762306a36Sopenharmony_ci		}
42862306a36Sopenharmony_ci	}
42962306a36Sopenharmony_ci	return itr;
43062306a36Sopenharmony_ci}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_civoid evlist_cpu_iterator__next(struct evlist_cpu_iterator *evlist_cpu_itr)
43362306a36Sopenharmony_ci{
43462306a36Sopenharmony_ci	while (evlist_cpu_itr->evsel != evlist__last(evlist_cpu_itr->container)) {
43562306a36Sopenharmony_ci		evlist_cpu_itr->evsel = evsel__next(evlist_cpu_itr->evsel);
43662306a36Sopenharmony_ci		evlist_cpu_itr->cpu_map_idx =
43762306a36Sopenharmony_ci			perf_cpu_map__idx(evlist_cpu_itr->evsel->core.cpus,
43862306a36Sopenharmony_ci					  evlist_cpu_itr->cpu);
43962306a36Sopenharmony_ci		if (evlist_cpu_itr->cpu_map_idx != -1)
44062306a36Sopenharmony_ci			return;
44162306a36Sopenharmony_ci	}
44262306a36Sopenharmony_ci	evlist_cpu_itr->evlist_cpu_map_idx++;
44362306a36Sopenharmony_ci	if (evlist_cpu_itr->evlist_cpu_map_idx < evlist_cpu_itr->evlist_cpu_map_nr) {
44462306a36Sopenharmony_ci		evlist_cpu_itr->evsel = evlist__first(evlist_cpu_itr->container);
44562306a36Sopenharmony_ci		evlist_cpu_itr->cpu =
44662306a36Sopenharmony_ci			perf_cpu_map__cpu(evlist_cpu_itr->container->core.all_cpus,
44762306a36Sopenharmony_ci					  evlist_cpu_itr->evlist_cpu_map_idx);
44862306a36Sopenharmony_ci		if (evlist_cpu_itr->affinity)
44962306a36Sopenharmony_ci			affinity__set(evlist_cpu_itr->affinity, evlist_cpu_itr->cpu.cpu);
45062306a36Sopenharmony_ci		evlist_cpu_itr->cpu_map_idx =
45162306a36Sopenharmony_ci			perf_cpu_map__idx(evlist_cpu_itr->evsel->core.cpus,
45262306a36Sopenharmony_ci					  evlist_cpu_itr->cpu);
45362306a36Sopenharmony_ci		/*
45462306a36Sopenharmony_ci		 * If this CPU isn't in the evsel's cpu map then advance through
45562306a36Sopenharmony_ci		 * the list.
45662306a36Sopenharmony_ci		 */
45762306a36Sopenharmony_ci		if (evlist_cpu_itr->cpu_map_idx == -1)
45862306a36Sopenharmony_ci			evlist_cpu_iterator__next(evlist_cpu_itr);
45962306a36Sopenharmony_ci	}
46062306a36Sopenharmony_ci}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_cibool evlist_cpu_iterator__end(const struct evlist_cpu_iterator *evlist_cpu_itr)
46362306a36Sopenharmony_ci{
46462306a36Sopenharmony_ci	return evlist_cpu_itr->evlist_cpu_map_idx >= evlist_cpu_itr->evlist_cpu_map_nr;
46562306a36Sopenharmony_ci}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_cistatic int evsel__strcmp(struct evsel *pos, char *evsel_name)
46862306a36Sopenharmony_ci{
46962306a36Sopenharmony_ci	if (!evsel_name)
47062306a36Sopenharmony_ci		return 0;
47162306a36Sopenharmony_ci	if (evsel__is_dummy_event(pos))
47262306a36Sopenharmony_ci		return 1;
47362306a36Sopenharmony_ci	return !evsel__name_is(pos, evsel_name);
47462306a36Sopenharmony_ci}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_cistatic int evlist__is_enabled(struct evlist *evlist)
47762306a36Sopenharmony_ci{
47862306a36Sopenharmony_ci	struct evsel *pos;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	evlist__for_each_entry(evlist, pos) {
48162306a36Sopenharmony_ci		if (!evsel__is_group_leader(pos) || !pos->core.fd)
48262306a36Sopenharmony_ci			continue;
48362306a36Sopenharmony_ci		/* If at least one event is enabled, evlist is enabled. */
48462306a36Sopenharmony_ci		if (!pos->disabled)
48562306a36Sopenharmony_ci			return true;
48662306a36Sopenharmony_ci	}
48762306a36Sopenharmony_ci	return false;
48862306a36Sopenharmony_ci}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_cistatic void __evlist__disable(struct evlist *evlist, char *evsel_name, bool excl_dummy)
49162306a36Sopenharmony_ci{
49262306a36Sopenharmony_ci	struct evsel *pos;
49362306a36Sopenharmony_ci	struct evlist_cpu_iterator evlist_cpu_itr;
49462306a36Sopenharmony_ci	struct affinity saved_affinity, *affinity = NULL;
49562306a36Sopenharmony_ci	bool has_imm = false;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	// See explanation in evlist__close()
49862306a36Sopenharmony_ci	if (!cpu_map__is_dummy(evlist->core.user_requested_cpus)) {
49962306a36Sopenharmony_ci		if (affinity__setup(&saved_affinity) < 0)
50062306a36Sopenharmony_ci			return;
50162306a36Sopenharmony_ci		affinity = &saved_affinity;
50262306a36Sopenharmony_ci	}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	/* Disable 'immediate' events last */
50562306a36Sopenharmony_ci	for (int imm = 0; imm <= 1; imm++) {
50662306a36Sopenharmony_ci		evlist__for_each_cpu(evlist_cpu_itr, evlist, affinity) {
50762306a36Sopenharmony_ci			pos = evlist_cpu_itr.evsel;
50862306a36Sopenharmony_ci			if (evsel__strcmp(pos, evsel_name))
50962306a36Sopenharmony_ci				continue;
51062306a36Sopenharmony_ci			if (pos->disabled || !evsel__is_group_leader(pos) || !pos->core.fd)
51162306a36Sopenharmony_ci				continue;
51262306a36Sopenharmony_ci			if (excl_dummy && evsel__is_dummy_event(pos))
51362306a36Sopenharmony_ci				continue;
51462306a36Sopenharmony_ci			if (pos->immediate)
51562306a36Sopenharmony_ci				has_imm = true;
51662306a36Sopenharmony_ci			if (pos->immediate != imm)
51762306a36Sopenharmony_ci				continue;
51862306a36Sopenharmony_ci			evsel__disable_cpu(pos, evlist_cpu_itr.cpu_map_idx);
51962306a36Sopenharmony_ci		}
52062306a36Sopenharmony_ci		if (!has_imm)
52162306a36Sopenharmony_ci			break;
52262306a36Sopenharmony_ci	}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	affinity__cleanup(affinity);
52562306a36Sopenharmony_ci	evlist__for_each_entry(evlist, pos) {
52662306a36Sopenharmony_ci		if (evsel__strcmp(pos, evsel_name))
52762306a36Sopenharmony_ci			continue;
52862306a36Sopenharmony_ci		if (!evsel__is_group_leader(pos) || !pos->core.fd)
52962306a36Sopenharmony_ci			continue;
53062306a36Sopenharmony_ci		if (excl_dummy && evsel__is_dummy_event(pos))
53162306a36Sopenharmony_ci			continue;
53262306a36Sopenharmony_ci		pos->disabled = true;
53362306a36Sopenharmony_ci	}
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	/*
53662306a36Sopenharmony_ci	 * If we disabled only single event, we need to check
53762306a36Sopenharmony_ci	 * the enabled state of the evlist manually.
53862306a36Sopenharmony_ci	 */
53962306a36Sopenharmony_ci	if (evsel_name)
54062306a36Sopenharmony_ci		evlist->enabled = evlist__is_enabled(evlist);
54162306a36Sopenharmony_ci	else
54262306a36Sopenharmony_ci		evlist->enabled = false;
54362306a36Sopenharmony_ci}
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_civoid evlist__disable(struct evlist *evlist)
54662306a36Sopenharmony_ci{
54762306a36Sopenharmony_ci	__evlist__disable(evlist, NULL, false);
54862306a36Sopenharmony_ci}
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_civoid evlist__disable_non_dummy(struct evlist *evlist)
55162306a36Sopenharmony_ci{
55262306a36Sopenharmony_ci	__evlist__disable(evlist, NULL, true);
55362306a36Sopenharmony_ci}
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_civoid evlist__disable_evsel(struct evlist *evlist, char *evsel_name)
55662306a36Sopenharmony_ci{
55762306a36Sopenharmony_ci	__evlist__disable(evlist, evsel_name, false);
55862306a36Sopenharmony_ci}
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_cistatic void __evlist__enable(struct evlist *evlist, char *evsel_name, bool excl_dummy)
56162306a36Sopenharmony_ci{
56262306a36Sopenharmony_ci	struct evsel *pos;
56362306a36Sopenharmony_ci	struct evlist_cpu_iterator evlist_cpu_itr;
56462306a36Sopenharmony_ci	struct affinity saved_affinity, *affinity = NULL;
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	// See explanation in evlist__close()
56762306a36Sopenharmony_ci	if (!cpu_map__is_dummy(evlist->core.user_requested_cpus)) {
56862306a36Sopenharmony_ci		if (affinity__setup(&saved_affinity) < 0)
56962306a36Sopenharmony_ci			return;
57062306a36Sopenharmony_ci		affinity = &saved_affinity;
57162306a36Sopenharmony_ci	}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	evlist__for_each_cpu(evlist_cpu_itr, evlist, affinity) {
57462306a36Sopenharmony_ci		pos = evlist_cpu_itr.evsel;
57562306a36Sopenharmony_ci		if (evsel__strcmp(pos, evsel_name))
57662306a36Sopenharmony_ci			continue;
57762306a36Sopenharmony_ci		if (!evsel__is_group_leader(pos) || !pos->core.fd)
57862306a36Sopenharmony_ci			continue;
57962306a36Sopenharmony_ci		if (excl_dummy && evsel__is_dummy_event(pos))
58062306a36Sopenharmony_ci			continue;
58162306a36Sopenharmony_ci		evsel__enable_cpu(pos, evlist_cpu_itr.cpu_map_idx);
58262306a36Sopenharmony_ci	}
58362306a36Sopenharmony_ci	affinity__cleanup(affinity);
58462306a36Sopenharmony_ci	evlist__for_each_entry(evlist, pos) {
58562306a36Sopenharmony_ci		if (evsel__strcmp(pos, evsel_name))
58662306a36Sopenharmony_ci			continue;
58762306a36Sopenharmony_ci		if (!evsel__is_group_leader(pos) || !pos->core.fd)
58862306a36Sopenharmony_ci			continue;
58962306a36Sopenharmony_ci		if (excl_dummy && evsel__is_dummy_event(pos))
59062306a36Sopenharmony_ci			continue;
59162306a36Sopenharmony_ci		pos->disabled = false;
59262306a36Sopenharmony_ci	}
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	/*
59562306a36Sopenharmony_ci	 * Even single event sets the 'enabled' for evlist,
59662306a36Sopenharmony_ci	 * so the toggle can work properly and toggle to
59762306a36Sopenharmony_ci	 * 'disabled' state.
59862306a36Sopenharmony_ci	 */
59962306a36Sopenharmony_ci	evlist->enabled = true;
60062306a36Sopenharmony_ci}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_civoid evlist__enable(struct evlist *evlist)
60362306a36Sopenharmony_ci{
60462306a36Sopenharmony_ci	__evlist__enable(evlist, NULL, false);
60562306a36Sopenharmony_ci}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_civoid evlist__enable_non_dummy(struct evlist *evlist)
60862306a36Sopenharmony_ci{
60962306a36Sopenharmony_ci	__evlist__enable(evlist, NULL, true);
61062306a36Sopenharmony_ci}
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_civoid evlist__enable_evsel(struct evlist *evlist, char *evsel_name)
61362306a36Sopenharmony_ci{
61462306a36Sopenharmony_ci	__evlist__enable(evlist, evsel_name, false);
61562306a36Sopenharmony_ci}
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_civoid evlist__toggle_enable(struct evlist *evlist)
61862306a36Sopenharmony_ci{
61962306a36Sopenharmony_ci	(evlist->enabled ? evlist__disable : evlist__enable)(evlist);
62062306a36Sopenharmony_ci}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ciint evlist__add_pollfd(struct evlist *evlist, int fd)
62362306a36Sopenharmony_ci{
62462306a36Sopenharmony_ci	return perf_evlist__add_pollfd(&evlist->core, fd, NULL, POLLIN, fdarray_flag__default);
62562306a36Sopenharmony_ci}
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ciint evlist__filter_pollfd(struct evlist *evlist, short revents_and_mask)
62862306a36Sopenharmony_ci{
62962306a36Sopenharmony_ci	return perf_evlist__filter_pollfd(&evlist->core, revents_and_mask);
63062306a36Sopenharmony_ci}
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci#ifdef HAVE_EVENTFD_SUPPORT
63362306a36Sopenharmony_ciint evlist__add_wakeup_eventfd(struct evlist *evlist, int fd)
63462306a36Sopenharmony_ci{
63562306a36Sopenharmony_ci	return perf_evlist__add_pollfd(&evlist->core, fd, NULL, POLLIN,
63662306a36Sopenharmony_ci				       fdarray_flag__nonfilterable |
63762306a36Sopenharmony_ci				       fdarray_flag__non_perf_event);
63862306a36Sopenharmony_ci}
63962306a36Sopenharmony_ci#endif
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ciint evlist__poll(struct evlist *evlist, int timeout)
64262306a36Sopenharmony_ci{
64362306a36Sopenharmony_ci	return perf_evlist__poll(&evlist->core, timeout);
64462306a36Sopenharmony_ci}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_cistruct perf_sample_id *evlist__id2sid(struct evlist *evlist, u64 id)
64762306a36Sopenharmony_ci{
64862306a36Sopenharmony_ci	struct hlist_head *head;
64962306a36Sopenharmony_ci	struct perf_sample_id *sid;
65062306a36Sopenharmony_ci	int hash;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	hash = hash_64(id, PERF_EVLIST__HLIST_BITS);
65362306a36Sopenharmony_ci	head = &evlist->core.heads[hash];
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	hlist_for_each_entry(sid, head, node)
65662306a36Sopenharmony_ci		if (sid->id == id)
65762306a36Sopenharmony_ci			return sid;
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	return NULL;
66062306a36Sopenharmony_ci}
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_cistruct evsel *evlist__id2evsel(struct evlist *evlist, u64 id)
66362306a36Sopenharmony_ci{
66462306a36Sopenharmony_ci	struct perf_sample_id *sid;
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	if (evlist->core.nr_entries == 1 || !id)
66762306a36Sopenharmony_ci		return evlist__first(evlist);
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	sid = evlist__id2sid(evlist, id);
67062306a36Sopenharmony_ci	if (sid)
67162306a36Sopenharmony_ci		return container_of(sid->evsel, struct evsel, core);
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	if (!evlist__sample_id_all(evlist))
67462306a36Sopenharmony_ci		return evlist__first(evlist);
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	return NULL;
67762306a36Sopenharmony_ci}
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_cistruct evsel *evlist__id2evsel_strict(struct evlist *evlist, u64 id)
68062306a36Sopenharmony_ci{
68162306a36Sopenharmony_ci	struct perf_sample_id *sid;
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	if (!id)
68462306a36Sopenharmony_ci		return NULL;
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	sid = evlist__id2sid(evlist, id);
68762306a36Sopenharmony_ci	if (sid)
68862306a36Sopenharmony_ci		return container_of(sid->evsel, struct evsel, core);
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	return NULL;
69162306a36Sopenharmony_ci}
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_cistatic int evlist__event2id(struct evlist *evlist, union perf_event *event, u64 *id)
69462306a36Sopenharmony_ci{
69562306a36Sopenharmony_ci	const __u64 *array = event->sample.array;
69662306a36Sopenharmony_ci	ssize_t n;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	n = (event->header.size - sizeof(event->header)) >> 3;
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	if (event->header.type == PERF_RECORD_SAMPLE) {
70162306a36Sopenharmony_ci		if (evlist->id_pos >= n)
70262306a36Sopenharmony_ci			return -1;
70362306a36Sopenharmony_ci		*id = array[evlist->id_pos];
70462306a36Sopenharmony_ci	} else {
70562306a36Sopenharmony_ci		if (evlist->is_pos > n)
70662306a36Sopenharmony_ci			return -1;
70762306a36Sopenharmony_ci		n -= evlist->is_pos;
70862306a36Sopenharmony_ci		*id = array[n];
70962306a36Sopenharmony_ci	}
71062306a36Sopenharmony_ci	return 0;
71162306a36Sopenharmony_ci}
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_cistruct evsel *evlist__event2evsel(struct evlist *evlist, union perf_event *event)
71462306a36Sopenharmony_ci{
71562306a36Sopenharmony_ci	struct evsel *first = evlist__first(evlist);
71662306a36Sopenharmony_ci	struct hlist_head *head;
71762306a36Sopenharmony_ci	struct perf_sample_id *sid;
71862306a36Sopenharmony_ci	int hash;
71962306a36Sopenharmony_ci	u64 id;
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	if (evlist->core.nr_entries == 1)
72262306a36Sopenharmony_ci		return first;
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	if (!first->core.attr.sample_id_all &&
72562306a36Sopenharmony_ci	    event->header.type != PERF_RECORD_SAMPLE)
72662306a36Sopenharmony_ci		return first;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	if (evlist__event2id(evlist, event, &id))
72962306a36Sopenharmony_ci		return NULL;
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	/* Synthesized events have an id of zero */
73262306a36Sopenharmony_ci	if (!id)
73362306a36Sopenharmony_ci		return first;
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	hash = hash_64(id, PERF_EVLIST__HLIST_BITS);
73662306a36Sopenharmony_ci	head = &evlist->core.heads[hash];
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	hlist_for_each_entry(sid, head, node) {
73962306a36Sopenharmony_ci		if (sid->id == id)
74062306a36Sopenharmony_ci			return container_of(sid->evsel, struct evsel, core);
74162306a36Sopenharmony_ci	}
74262306a36Sopenharmony_ci	return NULL;
74362306a36Sopenharmony_ci}
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_cistatic int evlist__set_paused(struct evlist *evlist, bool value)
74662306a36Sopenharmony_ci{
74762306a36Sopenharmony_ci	int i;
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	if (!evlist->overwrite_mmap)
75062306a36Sopenharmony_ci		return 0;
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	for (i = 0; i < evlist->core.nr_mmaps; i++) {
75362306a36Sopenharmony_ci		int fd = evlist->overwrite_mmap[i].core.fd;
75462306a36Sopenharmony_ci		int err;
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci		if (fd < 0)
75762306a36Sopenharmony_ci			continue;
75862306a36Sopenharmony_ci		err = ioctl(fd, PERF_EVENT_IOC_PAUSE_OUTPUT, value ? 1 : 0);
75962306a36Sopenharmony_ci		if (err)
76062306a36Sopenharmony_ci			return err;
76162306a36Sopenharmony_ci	}
76262306a36Sopenharmony_ci	return 0;
76362306a36Sopenharmony_ci}
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_cistatic int evlist__pause(struct evlist *evlist)
76662306a36Sopenharmony_ci{
76762306a36Sopenharmony_ci	return evlist__set_paused(evlist, true);
76862306a36Sopenharmony_ci}
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_cistatic int evlist__resume(struct evlist *evlist)
77162306a36Sopenharmony_ci{
77262306a36Sopenharmony_ci	return evlist__set_paused(evlist, false);
77362306a36Sopenharmony_ci}
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_cistatic void evlist__munmap_nofree(struct evlist *evlist)
77662306a36Sopenharmony_ci{
77762306a36Sopenharmony_ci	int i;
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	if (evlist->mmap)
78062306a36Sopenharmony_ci		for (i = 0; i < evlist->core.nr_mmaps; i++)
78162306a36Sopenharmony_ci			perf_mmap__munmap(&evlist->mmap[i].core);
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	if (evlist->overwrite_mmap)
78462306a36Sopenharmony_ci		for (i = 0; i < evlist->core.nr_mmaps; i++)
78562306a36Sopenharmony_ci			perf_mmap__munmap(&evlist->overwrite_mmap[i].core);
78662306a36Sopenharmony_ci}
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_civoid evlist__munmap(struct evlist *evlist)
78962306a36Sopenharmony_ci{
79062306a36Sopenharmony_ci	evlist__munmap_nofree(evlist);
79162306a36Sopenharmony_ci	zfree(&evlist->mmap);
79262306a36Sopenharmony_ci	zfree(&evlist->overwrite_mmap);
79362306a36Sopenharmony_ci}
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_cistatic void perf_mmap__unmap_cb(struct perf_mmap *map)
79662306a36Sopenharmony_ci{
79762306a36Sopenharmony_ci	struct mmap *m = container_of(map, struct mmap, core);
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	mmap__munmap(m);
80062306a36Sopenharmony_ci}
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_cistatic struct mmap *evlist__alloc_mmap(struct evlist *evlist,
80362306a36Sopenharmony_ci				       bool overwrite)
80462306a36Sopenharmony_ci{
80562306a36Sopenharmony_ci	int i;
80662306a36Sopenharmony_ci	struct mmap *map;
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	map = zalloc(evlist->core.nr_mmaps * sizeof(struct mmap));
80962306a36Sopenharmony_ci	if (!map)
81062306a36Sopenharmony_ci		return NULL;
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	for (i = 0; i < evlist->core.nr_mmaps; i++) {
81362306a36Sopenharmony_ci		struct perf_mmap *prev = i ? &map[i - 1].core : NULL;
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci		/*
81662306a36Sopenharmony_ci		 * When the perf_mmap() call is made we grab one refcount, plus
81762306a36Sopenharmony_ci		 * one extra to let perf_mmap__consume() get the last
81862306a36Sopenharmony_ci		 * events after all real references (perf_mmap__get()) are
81962306a36Sopenharmony_ci		 * dropped.
82062306a36Sopenharmony_ci		 *
82162306a36Sopenharmony_ci		 * Each PERF_EVENT_IOC_SET_OUTPUT points to this mmap and
82262306a36Sopenharmony_ci		 * thus does perf_mmap__get() on it.
82362306a36Sopenharmony_ci		 */
82462306a36Sopenharmony_ci		perf_mmap__init(&map[i].core, prev, overwrite, perf_mmap__unmap_cb);
82562306a36Sopenharmony_ci	}
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	return map;
82862306a36Sopenharmony_ci}
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_cistatic void
83162306a36Sopenharmony_ciperf_evlist__mmap_cb_idx(struct perf_evlist *_evlist,
83262306a36Sopenharmony_ci			 struct perf_evsel *_evsel,
83362306a36Sopenharmony_ci			 struct perf_mmap_param *_mp,
83462306a36Sopenharmony_ci			 int idx)
83562306a36Sopenharmony_ci{
83662306a36Sopenharmony_ci	struct evlist *evlist = container_of(_evlist, struct evlist, core);
83762306a36Sopenharmony_ci	struct mmap_params *mp = container_of(_mp, struct mmap_params, core);
83862306a36Sopenharmony_ci	struct evsel *evsel = container_of(_evsel, struct evsel, core);
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	auxtrace_mmap_params__set_idx(&mp->auxtrace_mp, evlist, evsel, idx);
84162306a36Sopenharmony_ci}
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_cistatic struct perf_mmap*
84462306a36Sopenharmony_ciperf_evlist__mmap_cb_get(struct perf_evlist *_evlist, bool overwrite, int idx)
84562306a36Sopenharmony_ci{
84662306a36Sopenharmony_ci	struct evlist *evlist = container_of(_evlist, struct evlist, core);
84762306a36Sopenharmony_ci	struct mmap *maps;
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	maps = overwrite ? evlist->overwrite_mmap : evlist->mmap;
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	if (!maps) {
85262306a36Sopenharmony_ci		maps = evlist__alloc_mmap(evlist, overwrite);
85362306a36Sopenharmony_ci		if (!maps)
85462306a36Sopenharmony_ci			return NULL;
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci		if (overwrite) {
85762306a36Sopenharmony_ci			evlist->overwrite_mmap = maps;
85862306a36Sopenharmony_ci			if (evlist->bkw_mmap_state == BKW_MMAP_NOTREADY)
85962306a36Sopenharmony_ci				evlist__toggle_bkw_mmap(evlist, BKW_MMAP_RUNNING);
86062306a36Sopenharmony_ci		} else {
86162306a36Sopenharmony_ci			evlist->mmap = maps;
86262306a36Sopenharmony_ci		}
86362306a36Sopenharmony_ci	}
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	return &maps[idx].core;
86662306a36Sopenharmony_ci}
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_cistatic int
86962306a36Sopenharmony_ciperf_evlist__mmap_cb_mmap(struct perf_mmap *_map, struct perf_mmap_param *_mp,
87062306a36Sopenharmony_ci			  int output, struct perf_cpu cpu)
87162306a36Sopenharmony_ci{
87262306a36Sopenharmony_ci	struct mmap *map = container_of(_map, struct mmap, core);
87362306a36Sopenharmony_ci	struct mmap_params *mp = container_of(_mp, struct mmap_params, core);
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	return mmap__mmap(map, mp, output, cpu);
87662306a36Sopenharmony_ci}
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ciunsigned long perf_event_mlock_kb_in_pages(void)
87962306a36Sopenharmony_ci{
88062306a36Sopenharmony_ci	unsigned long pages;
88162306a36Sopenharmony_ci	int max;
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	if (sysctl__read_int("kernel/perf_event_mlock_kb", &max) < 0) {
88462306a36Sopenharmony_ci		/*
88562306a36Sopenharmony_ci		 * Pick a once upon a time good value, i.e. things look
88662306a36Sopenharmony_ci		 * strange since we can't read a sysctl value, but lets not
88762306a36Sopenharmony_ci		 * die yet...
88862306a36Sopenharmony_ci		 */
88962306a36Sopenharmony_ci		max = 512;
89062306a36Sopenharmony_ci	} else {
89162306a36Sopenharmony_ci		max -= (page_size / 1024);
89262306a36Sopenharmony_ci	}
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	pages = (max * 1024) / page_size;
89562306a36Sopenharmony_ci	if (!is_power_of_2(pages))
89662306a36Sopenharmony_ci		pages = rounddown_pow_of_two(pages);
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	return pages;
89962306a36Sopenharmony_ci}
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_cisize_t evlist__mmap_size(unsigned long pages)
90262306a36Sopenharmony_ci{
90362306a36Sopenharmony_ci	if (pages == UINT_MAX)
90462306a36Sopenharmony_ci		pages = perf_event_mlock_kb_in_pages();
90562306a36Sopenharmony_ci	else if (!is_power_of_2(pages))
90662306a36Sopenharmony_ci		return 0;
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	return (pages + 1) * page_size;
90962306a36Sopenharmony_ci}
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_cistatic long parse_pages_arg(const char *str, unsigned long min,
91262306a36Sopenharmony_ci			    unsigned long max)
91362306a36Sopenharmony_ci{
91462306a36Sopenharmony_ci	unsigned long pages, val;
91562306a36Sopenharmony_ci	static struct parse_tag tags[] = {
91662306a36Sopenharmony_ci		{ .tag  = 'B', .mult = 1       },
91762306a36Sopenharmony_ci		{ .tag  = 'K', .mult = 1 << 10 },
91862306a36Sopenharmony_ci		{ .tag  = 'M', .mult = 1 << 20 },
91962306a36Sopenharmony_ci		{ .tag  = 'G', .mult = 1 << 30 },
92062306a36Sopenharmony_ci		{ .tag  = 0 },
92162306a36Sopenharmony_ci	};
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	if (str == NULL)
92462306a36Sopenharmony_ci		return -EINVAL;
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	val = parse_tag_value(str, tags);
92762306a36Sopenharmony_ci	if (val != (unsigned long) -1) {
92862306a36Sopenharmony_ci		/* we got file size value */
92962306a36Sopenharmony_ci		pages = PERF_ALIGN(val, page_size) / page_size;
93062306a36Sopenharmony_ci	} else {
93162306a36Sopenharmony_ci		/* we got pages count value */
93262306a36Sopenharmony_ci		char *eptr;
93362306a36Sopenharmony_ci		pages = strtoul(str, &eptr, 10);
93462306a36Sopenharmony_ci		if (*eptr != '\0')
93562306a36Sopenharmony_ci			return -EINVAL;
93662306a36Sopenharmony_ci	}
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci	if (pages == 0 && min == 0) {
93962306a36Sopenharmony_ci		/* leave number of pages at 0 */
94062306a36Sopenharmony_ci	} else if (!is_power_of_2(pages)) {
94162306a36Sopenharmony_ci		char buf[100];
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci		/* round pages up to next power of 2 */
94462306a36Sopenharmony_ci		pages = roundup_pow_of_two(pages);
94562306a36Sopenharmony_ci		if (!pages)
94662306a36Sopenharmony_ci			return -EINVAL;
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci		unit_number__scnprintf(buf, sizeof(buf), pages * page_size);
94962306a36Sopenharmony_ci		pr_info("rounding mmap pages size to %s (%lu pages)\n",
95062306a36Sopenharmony_ci			buf, pages);
95162306a36Sopenharmony_ci	}
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	if (pages > max)
95462306a36Sopenharmony_ci		return -EINVAL;
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	return pages;
95762306a36Sopenharmony_ci}
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ciint __evlist__parse_mmap_pages(unsigned int *mmap_pages, const char *str)
96062306a36Sopenharmony_ci{
96162306a36Sopenharmony_ci	unsigned long max = UINT_MAX;
96262306a36Sopenharmony_ci	long pages;
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	if (max > SIZE_MAX / page_size)
96562306a36Sopenharmony_ci		max = SIZE_MAX / page_size;
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci	pages = parse_pages_arg(str, 1, max);
96862306a36Sopenharmony_ci	if (pages < 0) {
96962306a36Sopenharmony_ci		pr_err("Invalid argument for --mmap_pages/-m\n");
97062306a36Sopenharmony_ci		return -1;
97162306a36Sopenharmony_ci	}
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	*mmap_pages = pages;
97462306a36Sopenharmony_ci	return 0;
97562306a36Sopenharmony_ci}
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ciint evlist__parse_mmap_pages(const struct option *opt, const char *str, int unset __maybe_unused)
97862306a36Sopenharmony_ci{
97962306a36Sopenharmony_ci	return __evlist__parse_mmap_pages(opt->value, str);
98062306a36Sopenharmony_ci}
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci/**
98362306a36Sopenharmony_ci * evlist__mmap_ex - Create mmaps to receive events.
98462306a36Sopenharmony_ci * @evlist: list of events
98562306a36Sopenharmony_ci * @pages: map length in pages
98662306a36Sopenharmony_ci * @overwrite: overwrite older events?
98762306a36Sopenharmony_ci * @auxtrace_pages - auxtrace map length in pages
98862306a36Sopenharmony_ci * @auxtrace_overwrite - overwrite older auxtrace data?
98962306a36Sopenharmony_ci *
99062306a36Sopenharmony_ci * If @overwrite is %false the user needs to signal event consumption using
99162306a36Sopenharmony_ci * perf_mmap__write_tail().  Using evlist__mmap_read() does this
99262306a36Sopenharmony_ci * automatically.
99362306a36Sopenharmony_ci *
99462306a36Sopenharmony_ci * Similarly, if @auxtrace_overwrite is %false the user needs to signal data
99562306a36Sopenharmony_ci * consumption using auxtrace_mmap__write_tail().
99662306a36Sopenharmony_ci *
99762306a36Sopenharmony_ci * Return: %0 on success, negative error code otherwise.
99862306a36Sopenharmony_ci */
99962306a36Sopenharmony_ciint evlist__mmap_ex(struct evlist *evlist, unsigned int pages,
100062306a36Sopenharmony_ci			 unsigned int auxtrace_pages,
100162306a36Sopenharmony_ci			 bool auxtrace_overwrite, int nr_cblocks, int affinity, int flush,
100262306a36Sopenharmony_ci			 int comp_level)
100362306a36Sopenharmony_ci{
100462306a36Sopenharmony_ci	/*
100562306a36Sopenharmony_ci	 * Delay setting mp.prot: set it before calling perf_mmap__mmap.
100662306a36Sopenharmony_ci	 * Its value is decided by evsel's write_backward.
100762306a36Sopenharmony_ci	 * So &mp should not be passed through const pointer.
100862306a36Sopenharmony_ci	 */
100962306a36Sopenharmony_ci	struct mmap_params mp = {
101062306a36Sopenharmony_ci		.nr_cblocks	= nr_cblocks,
101162306a36Sopenharmony_ci		.affinity	= affinity,
101262306a36Sopenharmony_ci		.flush		= flush,
101362306a36Sopenharmony_ci		.comp_level	= comp_level
101462306a36Sopenharmony_ci	};
101562306a36Sopenharmony_ci	struct perf_evlist_mmap_ops ops = {
101662306a36Sopenharmony_ci		.idx  = perf_evlist__mmap_cb_idx,
101762306a36Sopenharmony_ci		.get  = perf_evlist__mmap_cb_get,
101862306a36Sopenharmony_ci		.mmap = perf_evlist__mmap_cb_mmap,
101962306a36Sopenharmony_ci	};
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	evlist->core.mmap_len = evlist__mmap_size(pages);
102262306a36Sopenharmony_ci	pr_debug("mmap size %zuB\n", evlist->core.mmap_len);
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	auxtrace_mmap_params__init(&mp.auxtrace_mp, evlist->core.mmap_len,
102562306a36Sopenharmony_ci				   auxtrace_pages, auxtrace_overwrite);
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	return perf_evlist__mmap_ops(&evlist->core, &ops, &mp.core);
102862306a36Sopenharmony_ci}
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ciint evlist__mmap(struct evlist *evlist, unsigned int pages)
103162306a36Sopenharmony_ci{
103262306a36Sopenharmony_ci	return evlist__mmap_ex(evlist, pages, 0, false, 0, PERF_AFFINITY_SYS, 1, 0);
103362306a36Sopenharmony_ci}
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ciint evlist__create_maps(struct evlist *evlist, struct target *target)
103662306a36Sopenharmony_ci{
103762306a36Sopenharmony_ci	bool all_threads = (target->per_thread && target->system_wide);
103862306a36Sopenharmony_ci	struct perf_cpu_map *cpus;
103962306a36Sopenharmony_ci	struct perf_thread_map *threads;
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	/*
104262306a36Sopenharmony_ci	 * If specify '-a' and '--per-thread' to perf record, perf record
104362306a36Sopenharmony_ci	 * will override '--per-thread'. target->per_thread = false and
104462306a36Sopenharmony_ci	 * target->system_wide = true.
104562306a36Sopenharmony_ci	 *
104662306a36Sopenharmony_ci	 * If specify '--per-thread' only to perf record,
104762306a36Sopenharmony_ci	 * target->per_thread = true and target->system_wide = false.
104862306a36Sopenharmony_ci	 *
104962306a36Sopenharmony_ci	 * So target->per_thread && target->system_wide is false.
105062306a36Sopenharmony_ci	 * For perf record, thread_map__new_str doesn't call
105162306a36Sopenharmony_ci	 * thread_map__new_all_cpus. That will keep perf record's
105262306a36Sopenharmony_ci	 * current behavior.
105362306a36Sopenharmony_ci	 *
105462306a36Sopenharmony_ci	 * For perf stat, it allows the case that target->per_thread and
105562306a36Sopenharmony_ci	 * target->system_wide are all true. It means to collect system-wide
105662306a36Sopenharmony_ci	 * per-thread data. thread_map__new_str will call
105762306a36Sopenharmony_ci	 * thread_map__new_all_cpus to enumerate all threads.
105862306a36Sopenharmony_ci	 */
105962306a36Sopenharmony_ci	threads = thread_map__new_str(target->pid, target->tid, target->uid,
106062306a36Sopenharmony_ci				      all_threads);
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	if (!threads)
106362306a36Sopenharmony_ci		return -1;
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	if (target__uses_dummy_map(target))
106662306a36Sopenharmony_ci		cpus = perf_cpu_map__dummy_new();
106762306a36Sopenharmony_ci	else
106862306a36Sopenharmony_ci		cpus = perf_cpu_map__new(target->cpu_list);
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	if (!cpus)
107162306a36Sopenharmony_ci		goto out_delete_threads;
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	evlist->core.has_user_cpus = !!target->cpu_list;
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	perf_evlist__set_maps(&evlist->core, cpus, threads);
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	/* as evlist now has references, put count here */
107862306a36Sopenharmony_ci	perf_cpu_map__put(cpus);
107962306a36Sopenharmony_ci	perf_thread_map__put(threads);
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci	return 0;
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ciout_delete_threads:
108462306a36Sopenharmony_ci	perf_thread_map__put(threads);
108562306a36Sopenharmony_ci	return -1;
108662306a36Sopenharmony_ci}
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ciint evlist__apply_filters(struct evlist *evlist, struct evsel **err_evsel)
108962306a36Sopenharmony_ci{
109062306a36Sopenharmony_ci	struct evsel *evsel;
109162306a36Sopenharmony_ci	int err = 0;
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
109462306a36Sopenharmony_ci		/*
109562306a36Sopenharmony_ci		 * filters only work for tracepoint event, which doesn't have cpu limit.
109662306a36Sopenharmony_ci		 * So evlist and evsel should always be same.
109762306a36Sopenharmony_ci		 */
109862306a36Sopenharmony_ci		if (evsel->filter) {
109962306a36Sopenharmony_ci			err = perf_evsel__apply_filter(&evsel->core, evsel->filter);
110062306a36Sopenharmony_ci			if (err) {
110162306a36Sopenharmony_ci				*err_evsel = evsel;
110262306a36Sopenharmony_ci				break;
110362306a36Sopenharmony_ci			}
110462306a36Sopenharmony_ci		}
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci		/*
110762306a36Sopenharmony_ci		 * non-tracepoint events can have BPF filters.
110862306a36Sopenharmony_ci		 */
110962306a36Sopenharmony_ci		if (!list_empty(&evsel->bpf_filters)) {
111062306a36Sopenharmony_ci			err = perf_bpf_filter__prepare(evsel);
111162306a36Sopenharmony_ci			if (err) {
111262306a36Sopenharmony_ci				*err_evsel = evsel;
111362306a36Sopenharmony_ci				break;
111462306a36Sopenharmony_ci			}
111562306a36Sopenharmony_ci		}
111662306a36Sopenharmony_ci	}
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci	return err;
111962306a36Sopenharmony_ci}
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ciint evlist__set_tp_filter(struct evlist *evlist, const char *filter)
112262306a36Sopenharmony_ci{
112362306a36Sopenharmony_ci	struct evsel *evsel;
112462306a36Sopenharmony_ci	int err = 0;
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci	if (filter == NULL)
112762306a36Sopenharmony_ci		return -1;
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
113062306a36Sopenharmony_ci		if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT)
113162306a36Sopenharmony_ci			continue;
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci		err = evsel__set_filter(evsel, filter);
113462306a36Sopenharmony_ci		if (err)
113562306a36Sopenharmony_ci			break;
113662306a36Sopenharmony_ci	}
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	return err;
113962306a36Sopenharmony_ci}
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ciint evlist__append_tp_filter(struct evlist *evlist, const char *filter)
114262306a36Sopenharmony_ci{
114362306a36Sopenharmony_ci	struct evsel *evsel;
114462306a36Sopenharmony_ci	int err = 0;
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci	if (filter == NULL)
114762306a36Sopenharmony_ci		return -1;
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
115062306a36Sopenharmony_ci		if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT)
115162306a36Sopenharmony_ci			continue;
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci		err = evsel__append_tp_filter(evsel, filter);
115462306a36Sopenharmony_ci		if (err)
115562306a36Sopenharmony_ci			break;
115662306a36Sopenharmony_ci	}
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	return err;
115962306a36Sopenharmony_ci}
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_cichar *asprintf__tp_filter_pids(size_t npids, pid_t *pids)
116262306a36Sopenharmony_ci{
116362306a36Sopenharmony_ci	char *filter;
116462306a36Sopenharmony_ci	size_t i;
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci	for (i = 0; i < npids; ++i) {
116762306a36Sopenharmony_ci		if (i == 0) {
116862306a36Sopenharmony_ci			if (asprintf(&filter, "common_pid != %d", pids[i]) < 0)
116962306a36Sopenharmony_ci				return NULL;
117062306a36Sopenharmony_ci		} else {
117162306a36Sopenharmony_ci			char *tmp;
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci			if (asprintf(&tmp, "%s && common_pid != %d", filter, pids[i]) < 0)
117462306a36Sopenharmony_ci				goto out_free;
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci			free(filter);
117762306a36Sopenharmony_ci			filter = tmp;
117862306a36Sopenharmony_ci		}
117962306a36Sopenharmony_ci	}
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci	return filter;
118262306a36Sopenharmony_ciout_free:
118362306a36Sopenharmony_ci	free(filter);
118462306a36Sopenharmony_ci	return NULL;
118562306a36Sopenharmony_ci}
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ciint evlist__set_tp_filter_pids(struct evlist *evlist, size_t npids, pid_t *pids)
118862306a36Sopenharmony_ci{
118962306a36Sopenharmony_ci	char *filter = asprintf__tp_filter_pids(npids, pids);
119062306a36Sopenharmony_ci	int ret = evlist__set_tp_filter(evlist, filter);
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci	free(filter);
119362306a36Sopenharmony_ci	return ret;
119462306a36Sopenharmony_ci}
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ciint evlist__set_tp_filter_pid(struct evlist *evlist, pid_t pid)
119762306a36Sopenharmony_ci{
119862306a36Sopenharmony_ci	return evlist__set_tp_filter_pids(evlist, 1, &pid);
119962306a36Sopenharmony_ci}
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ciint evlist__append_tp_filter_pids(struct evlist *evlist, size_t npids, pid_t *pids)
120262306a36Sopenharmony_ci{
120362306a36Sopenharmony_ci	char *filter = asprintf__tp_filter_pids(npids, pids);
120462306a36Sopenharmony_ci	int ret = evlist__append_tp_filter(evlist, filter);
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	free(filter);
120762306a36Sopenharmony_ci	return ret;
120862306a36Sopenharmony_ci}
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ciint evlist__append_tp_filter_pid(struct evlist *evlist, pid_t pid)
121162306a36Sopenharmony_ci{
121262306a36Sopenharmony_ci	return evlist__append_tp_filter_pids(evlist, 1, &pid);
121362306a36Sopenharmony_ci}
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_cibool evlist__valid_sample_type(struct evlist *evlist)
121662306a36Sopenharmony_ci{
121762306a36Sopenharmony_ci	struct evsel *pos;
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	if (evlist->core.nr_entries == 1)
122062306a36Sopenharmony_ci		return true;
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci	if (evlist->id_pos < 0 || evlist->is_pos < 0)
122362306a36Sopenharmony_ci		return false;
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	evlist__for_each_entry(evlist, pos) {
122662306a36Sopenharmony_ci		if (pos->id_pos != evlist->id_pos ||
122762306a36Sopenharmony_ci		    pos->is_pos != evlist->is_pos)
122862306a36Sopenharmony_ci			return false;
122962306a36Sopenharmony_ci	}
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci	return true;
123262306a36Sopenharmony_ci}
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ciu64 __evlist__combined_sample_type(struct evlist *evlist)
123562306a36Sopenharmony_ci{
123662306a36Sopenharmony_ci	struct evsel *evsel;
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	if (evlist->combined_sample_type)
123962306a36Sopenharmony_ci		return evlist->combined_sample_type;
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	evlist__for_each_entry(evlist, evsel)
124262306a36Sopenharmony_ci		evlist->combined_sample_type |= evsel->core.attr.sample_type;
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	return evlist->combined_sample_type;
124562306a36Sopenharmony_ci}
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ciu64 evlist__combined_sample_type(struct evlist *evlist)
124862306a36Sopenharmony_ci{
124962306a36Sopenharmony_ci	evlist->combined_sample_type = 0;
125062306a36Sopenharmony_ci	return __evlist__combined_sample_type(evlist);
125162306a36Sopenharmony_ci}
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ciu64 evlist__combined_branch_type(struct evlist *evlist)
125462306a36Sopenharmony_ci{
125562306a36Sopenharmony_ci	struct evsel *evsel;
125662306a36Sopenharmony_ci	u64 branch_type = 0;
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci	evlist__for_each_entry(evlist, evsel)
125962306a36Sopenharmony_ci		branch_type |= evsel->core.attr.branch_sample_type;
126062306a36Sopenharmony_ci	return branch_type;
126162306a36Sopenharmony_ci}
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_cibool evlist__valid_read_format(struct evlist *evlist)
126462306a36Sopenharmony_ci{
126562306a36Sopenharmony_ci	struct evsel *first = evlist__first(evlist), *pos = first;
126662306a36Sopenharmony_ci	u64 read_format = first->core.attr.read_format;
126762306a36Sopenharmony_ci	u64 sample_type = first->core.attr.sample_type;
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci	evlist__for_each_entry(evlist, pos) {
127062306a36Sopenharmony_ci		if (read_format != pos->core.attr.read_format) {
127162306a36Sopenharmony_ci			pr_debug("Read format differs %#" PRIx64 " vs %#" PRIx64 "\n",
127262306a36Sopenharmony_ci				 read_format, (u64)pos->core.attr.read_format);
127362306a36Sopenharmony_ci		}
127462306a36Sopenharmony_ci	}
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci	/* PERF_SAMPLE_READ implies PERF_FORMAT_ID. */
127762306a36Sopenharmony_ci	if ((sample_type & PERF_SAMPLE_READ) &&
127862306a36Sopenharmony_ci	    !(read_format & PERF_FORMAT_ID)) {
127962306a36Sopenharmony_ci		return false;
128062306a36Sopenharmony_ci	}
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci	return true;
128362306a36Sopenharmony_ci}
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ciu16 evlist__id_hdr_size(struct evlist *evlist)
128662306a36Sopenharmony_ci{
128762306a36Sopenharmony_ci	struct evsel *first = evlist__first(evlist);
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci	return first->core.attr.sample_id_all ? evsel__id_hdr_size(first) : 0;
129062306a36Sopenharmony_ci}
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_cibool evlist__valid_sample_id_all(struct evlist *evlist)
129362306a36Sopenharmony_ci{
129462306a36Sopenharmony_ci	struct evsel *first = evlist__first(evlist), *pos = first;
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci	evlist__for_each_entry_continue(evlist, pos) {
129762306a36Sopenharmony_ci		if (first->core.attr.sample_id_all != pos->core.attr.sample_id_all)
129862306a36Sopenharmony_ci			return false;
129962306a36Sopenharmony_ci	}
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	return true;
130262306a36Sopenharmony_ci}
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_cibool evlist__sample_id_all(struct evlist *evlist)
130562306a36Sopenharmony_ci{
130662306a36Sopenharmony_ci	struct evsel *first = evlist__first(evlist);
130762306a36Sopenharmony_ci	return first->core.attr.sample_id_all;
130862306a36Sopenharmony_ci}
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_civoid evlist__set_selected(struct evlist *evlist, struct evsel *evsel)
131162306a36Sopenharmony_ci{
131262306a36Sopenharmony_ci	evlist->selected = evsel;
131362306a36Sopenharmony_ci}
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_civoid evlist__close(struct evlist *evlist)
131662306a36Sopenharmony_ci{
131762306a36Sopenharmony_ci	struct evsel *evsel;
131862306a36Sopenharmony_ci	struct evlist_cpu_iterator evlist_cpu_itr;
131962306a36Sopenharmony_ci	struct affinity affinity;
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci	/*
132262306a36Sopenharmony_ci	 * With perf record core.user_requested_cpus is usually NULL.
132362306a36Sopenharmony_ci	 * Use the old method to handle this for now.
132462306a36Sopenharmony_ci	 */
132562306a36Sopenharmony_ci	if (!evlist->core.user_requested_cpus ||
132662306a36Sopenharmony_ci	    cpu_map__is_dummy(evlist->core.user_requested_cpus)) {
132762306a36Sopenharmony_ci		evlist__for_each_entry_reverse(evlist, evsel)
132862306a36Sopenharmony_ci			evsel__close(evsel);
132962306a36Sopenharmony_ci		return;
133062306a36Sopenharmony_ci	}
133162306a36Sopenharmony_ci
133262306a36Sopenharmony_ci	if (affinity__setup(&affinity) < 0)
133362306a36Sopenharmony_ci		return;
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci	evlist__for_each_cpu(evlist_cpu_itr, evlist, &affinity) {
133662306a36Sopenharmony_ci		perf_evsel__close_cpu(&evlist_cpu_itr.evsel->core,
133762306a36Sopenharmony_ci				      evlist_cpu_itr.cpu_map_idx);
133862306a36Sopenharmony_ci	}
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ci	affinity__cleanup(&affinity);
134162306a36Sopenharmony_ci	evlist__for_each_entry_reverse(evlist, evsel) {
134262306a36Sopenharmony_ci		perf_evsel__free_fd(&evsel->core);
134362306a36Sopenharmony_ci		perf_evsel__free_id(&evsel->core);
134462306a36Sopenharmony_ci	}
134562306a36Sopenharmony_ci	perf_evlist__reset_id_hash(&evlist->core);
134662306a36Sopenharmony_ci}
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_cistatic int evlist__create_syswide_maps(struct evlist *evlist)
134962306a36Sopenharmony_ci{
135062306a36Sopenharmony_ci	struct perf_cpu_map *cpus;
135162306a36Sopenharmony_ci	struct perf_thread_map *threads;
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci	/*
135462306a36Sopenharmony_ci	 * Try reading /sys/devices/system/cpu/online to get
135562306a36Sopenharmony_ci	 * an all cpus map.
135662306a36Sopenharmony_ci	 *
135762306a36Sopenharmony_ci	 * FIXME: -ENOMEM is the best we can do here, the cpu_map
135862306a36Sopenharmony_ci	 * code needs an overhaul to properly forward the
135962306a36Sopenharmony_ci	 * error, and we may not want to do that fallback to a
136062306a36Sopenharmony_ci	 * default cpu identity map :-\
136162306a36Sopenharmony_ci	 */
136262306a36Sopenharmony_ci	cpus = perf_cpu_map__new(NULL);
136362306a36Sopenharmony_ci	if (!cpus)
136462306a36Sopenharmony_ci		goto out;
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_ci	threads = perf_thread_map__new_dummy();
136762306a36Sopenharmony_ci	if (!threads)
136862306a36Sopenharmony_ci		goto out_put;
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci	perf_evlist__set_maps(&evlist->core, cpus, threads);
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	perf_thread_map__put(threads);
137362306a36Sopenharmony_ciout_put:
137462306a36Sopenharmony_ci	perf_cpu_map__put(cpus);
137562306a36Sopenharmony_ciout:
137662306a36Sopenharmony_ci	return -ENOMEM;
137762306a36Sopenharmony_ci}
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ciint evlist__open(struct evlist *evlist)
138062306a36Sopenharmony_ci{
138162306a36Sopenharmony_ci	struct evsel *evsel;
138262306a36Sopenharmony_ci	int err;
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci	/*
138562306a36Sopenharmony_ci	 * Default: one fd per CPU, all threads, aka systemwide
138662306a36Sopenharmony_ci	 * as sys_perf_event_open(cpu = -1, thread = -1) is EINVAL
138762306a36Sopenharmony_ci	 */
138862306a36Sopenharmony_ci	if (evlist->core.threads == NULL && evlist->core.user_requested_cpus == NULL) {
138962306a36Sopenharmony_ci		err = evlist__create_syswide_maps(evlist);
139062306a36Sopenharmony_ci		if (err < 0)
139162306a36Sopenharmony_ci			goto out_err;
139262306a36Sopenharmony_ci	}
139362306a36Sopenharmony_ci
139462306a36Sopenharmony_ci	evlist__update_id_pos(evlist);
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
139762306a36Sopenharmony_ci		err = evsel__open(evsel, evsel->core.cpus, evsel->core.threads);
139862306a36Sopenharmony_ci		if (err < 0)
139962306a36Sopenharmony_ci			goto out_err;
140062306a36Sopenharmony_ci	}
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci	return 0;
140362306a36Sopenharmony_ciout_err:
140462306a36Sopenharmony_ci	evlist__close(evlist);
140562306a36Sopenharmony_ci	errno = -err;
140662306a36Sopenharmony_ci	return err;
140762306a36Sopenharmony_ci}
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ciint evlist__prepare_workload(struct evlist *evlist, struct target *target, const char *argv[],
141062306a36Sopenharmony_ci			     bool pipe_output, void (*exec_error)(int signo, siginfo_t *info, void *ucontext))
141162306a36Sopenharmony_ci{
141262306a36Sopenharmony_ci	int child_ready_pipe[2], go_pipe[2];
141362306a36Sopenharmony_ci	char bf;
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci	if (pipe(child_ready_pipe) < 0) {
141662306a36Sopenharmony_ci		perror("failed to create 'ready' pipe");
141762306a36Sopenharmony_ci		return -1;
141862306a36Sopenharmony_ci	}
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ci	if (pipe(go_pipe) < 0) {
142162306a36Sopenharmony_ci		perror("failed to create 'go' pipe");
142262306a36Sopenharmony_ci		goto out_close_ready_pipe;
142362306a36Sopenharmony_ci	}
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci	evlist->workload.pid = fork();
142662306a36Sopenharmony_ci	if (evlist->workload.pid < 0) {
142762306a36Sopenharmony_ci		perror("failed to fork");
142862306a36Sopenharmony_ci		goto out_close_pipes;
142962306a36Sopenharmony_ci	}
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci	if (!evlist->workload.pid) {
143262306a36Sopenharmony_ci		int ret;
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_ci		if (pipe_output)
143562306a36Sopenharmony_ci			dup2(2, 1);
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci		signal(SIGTERM, SIG_DFL);
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci		close(child_ready_pipe[0]);
144062306a36Sopenharmony_ci		close(go_pipe[1]);
144162306a36Sopenharmony_ci		fcntl(go_pipe[0], F_SETFD, FD_CLOEXEC);
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci		/*
144462306a36Sopenharmony_ci		 * Change the name of this process not to confuse --exclude-perf users
144562306a36Sopenharmony_ci		 * that sees 'perf' in the window up to the execvp() and thinks that
144662306a36Sopenharmony_ci		 * perf samples are not being excluded.
144762306a36Sopenharmony_ci		 */
144862306a36Sopenharmony_ci		prctl(PR_SET_NAME, "perf-exec");
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_ci		/*
145162306a36Sopenharmony_ci		 * Tell the parent we're ready to go
145262306a36Sopenharmony_ci		 */
145362306a36Sopenharmony_ci		close(child_ready_pipe[1]);
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci		/*
145662306a36Sopenharmony_ci		 * Wait until the parent tells us to go.
145762306a36Sopenharmony_ci		 */
145862306a36Sopenharmony_ci		ret = read(go_pipe[0], &bf, 1);
145962306a36Sopenharmony_ci		/*
146062306a36Sopenharmony_ci		 * The parent will ask for the execvp() to be performed by
146162306a36Sopenharmony_ci		 * writing exactly one byte, in workload.cork_fd, usually via
146262306a36Sopenharmony_ci		 * evlist__start_workload().
146362306a36Sopenharmony_ci		 *
146462306a36Sopenharmony_ci		 * For cancelling the workload without actually running it,
146562306a36Sopenharmony_ci		 * the parent will just close workload.cork_fd, without writing
146662306a36Sopenharmony_ci		 * anything, i.e. read will return zero and we just exit()
146762306a36Sopenharmony_ci		 * here.
146862306a36Sopenharmony_ci		 */
146962306a36Sopenharmony_ci		if (ret != 1) {
147062306a36Sopenharmony_ci			if (ret == -1)
147162306a36Sopenharmony_ci				perror("unable to read pipe");
147262306a36Sopenharmony_ci			exit(ret);
147362306a36Sopenharmony_ci		}
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci		execvp(argv[0], (char **)argv);
147662306a36Sopenharmony_ci
147762306a36Sopenharmony_ci		if (exec_error) {
147862306a36Sopenharmony_ci			union sigval val;
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_ci			val.sival_int = errno;
148162306a36Sopenharmony_ci			if (sigqueue(getppid(), SIGUSR1, val))
148262306a36Sopenharmony_ci				perror(argv[0]);
148362306a36Sopenharmony_ci		} else
148462306a36Sopenharmony_ci			perror(argv[0]);
148562306a36Sopenharmony_ci		exit(-1);
148662306a36Sopenharmony_ci	}
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci	if (exec_error) {
148962306a36Sopenharmony_ci		struct sigaction act = {
149062306a36Sopenharmony_ci			.sa_flags     = SA_SIGINFO,
149162306a36Sopenharmony_ci			.sa_sigaction = exec_error,
149262306a36Sopenharmony_ci		};
149362306a36Sopenharmony_ci		sigaction(SIGUSR1, &act, NULL);
149462306a36Sopenharmony_ci	}
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci	if (target__none(target)) {
149762306a36Sopenharmony_ci		if (evlist->core.threads == NULL) {
149862306a36Sopenharmony_ci			fprintf(stderr, "FATAL: evlist->threads need to be set at this point (%s:%d).\n",
149962306a36Sopenharmony_ci				__func__, __LINE__);
150062306a36Sopenharmony_ci			goto out_close_pipes;
150162306a36Sopenharmony_ci		}
150262306a36Sopenharmony_ci		perf_thread_map__set_pid(evlist->core.threads, 0, evlist->workload.pid);
150362306a36Sopenharmony_ci	}
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci	close(child_ready_pipe[1]);
150662306a36Sopenharmony_ci	close(go_pipe[0]);
150762306a36Sopenharmony_ci	/*
150862306a36Sopenharmony_ci	 * wait for child to settle
150962306a36Sopenharmony_ci	 */
151062306a36Sopenharmony_ci	if (read(child_ready_pipe[0], &bf, 1) == -1) {
151162306a36Sopenharmony_ci		perror("unable to read pipe");
151262306a36Sopenharmony_ci		goto out_close_pipes;
151362306a36Sopenharmony_ci	}
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci	fcntl(go_pipe[1], F_SETFD, FD_CLOEXEC);
151662306a36Sopenharmony_ci	evlist->workload.cork_fd = go_pipe[1];
151762306a36Sopenharmony_ci	close(child_ready_pipe[0]);
151862306a36Sopenharmony_ci	return 0;
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ciout_close_pipes:
152162306a36Sopenharmony_ci	close(go_pipe[0]);
152262306a36Sopenharmony_ci	close(go_pipe[1]);
152362306a36Sopenharmony_ciout_close_ready_pipe:
152462306a36Sopenharmony_ci	close(child_ready_pipe[0]);
152562306a36Sopenharmony_ci	close(child_ready_pipe[1]);
152662306a36Sopenharmony_ci	return -1;
152762306a36Sopenharmony_ci}
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ciint evlist__start_workload(struct evlist *evlist)
153062306a36Sopenharmony_ci{
153162306a36Sopenharmony_ci	if (evlist->workload.cork_fd > 0) {
153262306a36Sopenharmony_ci		char bf = 0;
153362306a36Sopenharmony_ci		int ret;
153462306a36Sopenharmony_ci		/*
153562306a36Sopenharmony_ci		 * Remove the cork, let it rip!
153662306a36Sopenharmony_ci		 */
153762306a36Sopenharmony_ci		ret = write(evlist->workload.cork_fd, &bf, 1);
153862306a36Sopenharmony_ci		if (ret < 0)
153962306a36Sopenharmony_ci			perror("unable to write to pipe");
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_ci		close(evlist->workload.cork_fd);
154262306a36Sopenharmony_ci		return ret;
154362306a36Sopenharmony_ci	}
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ci	return 0;
154662306a36Sopenharmony_ci}
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_ciint evlist__parse_sample(struct evlist *evlist, union perf_event *event, struct perf_sample *sample)
154962306a36Sopenharmony_ci{
155062306a36Sopenharmony_ci	struct evsel *evsel = evlist__event2evsel(evlist, event);
155162306a36Sopenharmony_ci	int ret;
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_ci	if (!evsel)
155462306a36Sopenharmony_ci		return -EFAULT;
155562306a36Sopenharmony_ci	ret = evsel__parse_sample(evsel, event, sample);
155662306a36Sopenharmony_ci	if (ret)
155762306a36Sopenharmony_ci		return ret;
155862306a36Sopenharmony_ci	if (perf_guest && sample->id) {
155962306a36Sopenharmony_ci		struct perf_sample_id *sid = evlist__id2sid(evlist, sample->id);
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ci		if (sid) {
156262306a36Sopenharmony_ci			sample->machine_pid = sid->machine_pid;
156362306a36Sopenharmony_ci			sample->vcpu = sid->vcpu.cpu;
156462306a36Sopenharmony_ci		}
156562306a36Sopenharmony_ci	}
156662306a36Sopenharmony_ci	return 0;
156762306a36Sopenharmony_ci}
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_ciint evlist__parse_sample_timestamp(struct evlist *evlist, union perf_event *event, u64 *timestamp)
157062306a36Sopenharmony_ci{
157162306a36Sopenharmony_ci	struct evsel *evsel = evlist__event2evsel(evlist, event);
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ci	if (!evsel)
157462306a36Sopenharmony_ci		return -EFAULT;
157562306a36Sopenharmony_ci	return evsel__parse_sample_timestamp(evsel, event, timestamp);
157662306a36Sopenharmony_ci}
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ciint evlist__strerror_open(struct evlist *evlist, int err, char *buf, size_t size)
157962306a36Sopenharmony_ci{
158062306a36Sopenharmony_ci	int printed, value;
158162306a36Sopenharmony_ci	char sbuf[STRERR_BUFSIZE], *emsg = str_error_r(err, sbuf, sizeof(sbuf));
158262306a36Sopenharmony_ci
158362306a36Sopenharmony_ci	switch (err) {
158462306a36Sopenharmony_ci	case EACCES:
158562306a36Sopenharmony_ci	case EPERM:
158662306a36Sopenharmony_ci		printed = scnprintf(buf, size,
158762306a36Sopenharmony_ci				    "Error:\t%s.\n"
158862306a36Sopenharmony_ci				    "Hint:\tCheck /proc/sys/kernel/perf_event_paranoid setting.", emsg);
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci		value = perf_event_paranoid();
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci		printed += scnprintf(buf + printed, size - printed, "\nHint:\t");
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci		if (value >= 2) {
159562306a36Sopenharmony_ci			printed += scnprintf(buf + printed, size - printed,
159662306a36Sopenharmony_ci					     "For your workloads it needs to be <= 1\nHint:\t");
159762306a36Sopenharmony_ci		}
159862306a36Sopenharmony_ci		printed += scnprintf(buf + printed, size - printed,
159962306a36Sopenharmony_ci				     "For system wide tracing it needs to be set to -1.\n");
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_ci		printed += scnprintf(buf + printed, size - printed,
160262306a36Sopenharmony_ci				    "Hint:\tTry: 'sudo sh -c \"echo -1 > /proc/sys/kernel/perf_event_paranoid\"'\n"
160362306a36Sopenharmony_ci				    "Hint:\tThe current value is %d.", value);
160462306a36Sopenharmony_ci		break;
160562306a36Sopenharmony_ci	case EINVAL: {
160662306a36Sopenharmony_ci		struct evsel *first = evlist__first(evlist);
160762306a36Sopenharmony_ci		int max_freq;
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ci		if (sysctl__read_int("kernel/perf_event_max_sample_rate", &max_freq) < 0)
161062306a36Sopenharmony_ci			goto out_default;
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_ci		if (first->core.attr.sample_freq < (u64)max_freq)
161362306a36Sopenharmony_ci			goto out_default;
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_ci		printed = scnprintf(buf, size,
161662306a36Sopenharmony_ci				    "Error:\t%s.\n"
161762306a36Sopenharmony_ci				    "Hint:\tCheck /proc/sys/kernel/perf_event_max_sample_rate.\n"
161862306a36Sopenharmony_ci				    "Hint:\tThe current value is %d and %" PRIu64 " is being requested.",
161962306a36Sopenharmony_ci				    emsg, max_freq, first->core.attr.sample_freq);
162062306a36Sopenharmony_ci		break;
162162306a36Sopenharmony_ci	}
162262306a36Sopenharmony_ci	default:
162362306a36Sopenharmony_ciout_default:
162462306a36Sopenharmony_ci		scnprintf(buf, size, "%s", emsg);
162562306a36Sopenharmony_ci		break;
162662306a36Sopenharmony_ci	}
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci	return 0;
162962306a36Sopenharmony_ci}
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ciint evlist__strerror_mmap(struct evlist *evlist, int err, char *buf, size_t size)
163262306a36Sopenharmony_ci{
163362306a36Sopenharmony_ci	char sbuf[STRERR_BUFSIZE], *emsg = str_error_r(err, sbuf, sizeof(sbuf));
163462306a36Sopenharmony_ci	int pages_attempted = evlist->core.mmap_len / 1024, pages_max_per_user, printed = 0;
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_ci	switch (err) {
163762306a36Sopenharmony_ci	case EPERM:
163862306a36Sopenharmony_ci		sysctl__read_int("kernel/perf_event_mlock_kb", &pages_max_per_user);
163962306a36Sopenharmony_ci		printed += scnprintf(buf + printed, size - printed,
164062306a36Sopenharmony_ci				     "Error:\t%s.\n"
164162306a36Sopenharmony_ci				     "Hint:\tCheck /proc/sys/kernel/perf_event_mlock_kb (%d kB) setting.\n"
164262306a36Sopenharmony_ci				     "Hint:\tTried using %zd kB.\n",
164362306a36Sopenharmony_ci				     emsg, pages_max_per_user, pages_attempted);
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_ci		if (pages_attempted >= pages_max_per_user) {
164662306a36Sopenharmony_ci			printed += scnprintf(buf + printed, size - printed,
164762306a36Sopenharmony_ci					     "Hint:\tTry 'sudo sh -c \"echo %d > /proc/sys/kernel/perf_event_mlock_kb\"', or\n",
164862306a36Sopenharmony_ci					     pages_max_per_user + pages_attempted);
164962306a36Sopenharmony_ci		}
165062306a36Sopenharmony_ci
165162306a36Sopenharmony_ci		printed += scnprintf(buf + printed, size - printed,
165262306a36Sopenharmony_ci				     "Hint:\tTry using a smaller -m/--mmap-pages value.");
165362306a36Sopenharmony_ci		break;
165462306a36Sopenharmony_ci	default:
165562306a36Sopenharmony_ci		scnprintf(buf, size, "%s", emsg);
165662306a36Sopenharmony_ci		break;
165762306a36Sopenharmony_ci	}
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci	return 0;
166062306a36Sopenharmony_ci}
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_civoid evlist__to_front(struct evlist *evlist, struct evsel *move_evsel)
166362306a36Sopenharmony_ci{
166462306a36Sopenharmony_ci	struct evsel *evsel, *n;
166562306a36Sopenharmony_ci	LIST_HEAD(move);
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_ci	if (move_evsel == evlist__first(evlist))
166862306a36Sopenharmony_ci		return;
166962306a36Sopenharmony_ci
167062306a36Sopenharmony_ci	evlist__for_each_entry_safe(evlist, n, evsel) {
167162306a36Sopenharmony_ci		if (evsel__leader(evsel) == evsel__leader(move_evsel))
167262306a36Sopenharmony_ci			list_move_tail(&evsel->core.node, &move);
167362306a36Sopenharmony_ci	}
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci	list_splice(&move, &evlist->core.entries);
167662306a36Sopenharmony_ci}
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_cistruct evsel *evlist__get_tracking_event(struct evlist *evlist)
167962306a36Sopenharmony_ci{
168062306a36Sopenharmony_ci	struct evsel *evsel;
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
168362306a36Sopenharmony_ci		if (evsel->tracking)
168462306a36Sopenharmony_ci			return evsel;
168562306a36Sopenharmony_ci	}
168662306a36Sopenharmony_ci
168762306a36Sopenharmony_ci	return evlist__first(evlist);
168862306a36Sopenharmony_ci}
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_civoid evlist__set_tracking_event(struct evlist *evlist, struct evsel *tracking_evsel)
169162306a36Sopenharmony_ci{
169262306a36Sopenharmony_ci	struct evsel *evsel;
169362306a36Sopenharmony_ci
169462306a36Sopenharmony_ci	if (tracking_evsel->tracking)
169562306a36Sopenharmony_ci		return;
169662306a36Sopenharmony_ci
169762306a36Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
169862306a36Sopenharmony_ci		if (evsel != tracking_evsel)
169962306a36Sopenharmony_ci			evsel->tracking = false;
170062306a36Sopenharmony_ci	}
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_ci	tracking_evsel->tracking = true;
170362306a36Sopenharmony_ci}
170462306a36Sopenharmony_ci
170562306a36Sopenharmony_cistruct evsel *evlist__find_evsel_by_str(struct evlist *evlist, const char *str)
170662306a36Sopenharmony_ci{
170762306a36Sopenharmony_ci	struct evsel *evsel;
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
171062306a36Sopenharmony_ci		if (!evsel->name)
171162306a36Sopenharmony_ci			continue;
171262306a36Sopenharmony_ci		if (evsel__name_is(evsel, str))
171362306a36Sopenharmony_ci			return evsel;
171462306a36Sopenharmony_ci	}
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_ci	return NULL;
171762306a36Sopenharmony_ci}
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_civoid evlist__toggle_bkw_mmap(struct evlist *evlist, enum bkw_mmap_state state)
172062306a36Sopenharmony_ci{
172162306a36Sopenharmony_ci	enum bkw_mmap_state old_state = evlist->bkw_mmap_state;
172262306a36Sopenharmony_ci	enum action {
172362306a36Sopenharmony_ci		NONE,
172462306a36Sopenharmony_ci		PAUSE,
172562306a36Sopenharmony_ci		RESUME,
172662306a36Sopenharmony_ci	} action = NONE;
172762306a36Sopenharmony_ci
172862306a36Sopenharmony_ci	if (!evlist->overwrite_mmap)
172962306a36Sopenharmony_ci		return;
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_ci	switch (old_state) {
173262306a36Sopenharmony_ci	case BKW_MMAP_NOTREADY: {
173362306a36Sopenharmony_ci		if (state != BKW_MMAP_RUNNING)
173462306a36Sopenharmony_ci			goto state_err;
173562306a36Sopenharmony_ci		break;
173662306a36Sopenharmony_ci	}
173762306a36Sopenharmony_ci	case BKW_MMAP_RUNNING: {
173862306a36Sopenharmony_ci		if (state != BKW_MMAP_DATA_PENDING)
173962306a36Sopenharmony_ci			goto state_err;
174062306a36Sopenharmony_ci		action = PAUSE;
174162306a36Sopenharmony_ci		break;
174262306a36Sopenharmony_ci	}
174362306a36Sopenharmony_ci	case BKW_MMAP_DATA_PENDING: {
174462306a36Sopenharmony_ci		if (state != BKW_MMAP_EMPTY)
174562306a36Sopenharmony_ci			goto state_err;
174662306a36Sopenharmony_ci		break;
174762306a36Sopenharmony_ci	}
174862306a36Sopenharmony_ci	case BKW_MMAP_EMPTY: {
174962306a36Sopenharmony_ci		if (state != BKW_MMAP_RUNNING)
175062306a36Sopenharmony_ci			goto state_err;
175162306a36Sopenharmony_ci		action = RESUME;
175262306a36Sopenharmony_ci		break;
175362306a36Sopenharmony_ci	}
175462306a36Sopenharmony_ci	default:
175562306a36Sopenharmony_ci		WARN_ONCE(1, "Shouldn't get there\n");
175662306a36Sopenharmony_ci	}
175762306a36Sopenharmony_ci
175862306a36Sopenharmony_ci	evlist->bkw_mmap_state = state;
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_ci	switch (action) {
176162306a36Sopenharmony_ci	case PAUSE:
176262306a36Sopenharmony_ci		evlist__pause(evlist);
176362306a36Sopenharmony_ci		break;
176462306a36Sopenharmony_ci	case RESUME:
176562306a36Sopenharmony_ci		evlist__resume(evlist);
176662306a36Sopenharmony_ci		break;
176762306a36Sopenharmony_ci	case NONE:
176862306a36Sopenharmony_ci	default:
176962306a36Sopenharmony_ci		break;
177062306a36Sopenharmony_ci	}
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_cistate_err:
177362306a36Sopenharmony_ci	return;
177462306a36Sopenharmony_ci}
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_cibool evlist__exclude_kernel(struct evlist *evlist)
177762306a36Sopenharmony_ci{
177862306a36Sopenharmony_ci	struct evsel *evsel;
177962306a36Sopenharmony_ci
178062306a36Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
178162306a36Sopenharmony_ci		if (!evsel->core.attr.exclude_kernel)
178262306a36Sopenharmony_ci			return false;
178362306a36Sopenharmony_ci	}
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_ci	return true;
178662306a36Sopenharmony_ci}
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_ci/*
178962306a36Sopenharmony_ci * Events in data file are not collect in groups, but we still want
179062306a36Sopenharmony_ci * the group display. Set the artificial group and set the leader's
179162306a36Sopenharmony_ci * forced_leader flag to notify the display code.
179262306a36Sopenharmony_ci */
179362306a36Sopenharmony_civoid evlist__force_leader(struct evlist *evlist)
179462306a36Sopenharmony_ci{
179562306a36Sopenharmony_ci	if (evlist__nr_groups(evlist) == 0) {
179662306a36Sopenharmony_ci		struct evsel *leader = evlist__first(evlist);
179762306a36Sopenharmony_ci
179862306a36Sopenharmony_ci		evlist__set_leader(evlist);
179962306a36Sopenharmony_ci		leader->forced_leader = true;
180062306a36Sopenharmony_ci	}
180162306a36Sopenharmony_ci}
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_cistruct evsel *evlist__reset_weak_group(struct evlist *evsel_list, struct evsel *evsel, bool close)
180462306a36Sopenharmony_ci{
180562306a36Sopenharmony_ci	struct evsel *c2, *leader;
180662306a36Sopenharmony_ci	bool is_open = true;
180762306a36Sopenharmony_ci
180862306a36Sopenharmony_ci	leader = evsel__leader(evsel);
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_ci	pr_debug("Weak group for %s/%d failed\n",
181162306a36Sopenharmony_ci			leader->name, leader->core.nr_members);
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_ci	/*
181462306a36Sopenharmony_ci	 * for_each_group_member doesn't work here because it doesn't
181562306a36Sopenharmony_ci	 * include the first entry.
181662306a36Sopenharmony_ci	 */
181762306a36Sopenharmony_ci	evlist__for_each_entry(evsel_list, c2) {
181862306a36Sopenharmony_ci		if (c2 == evsel)
181962306a36Sopenharmony_ci			is_open = false;
182062306a36Sopenharmony_ci		if (evsel__has_leader(c2, leader)) {
182162306a36Sopenharmony_ci			if (is_open && close)
182262306a36Sopenharmony_ci				perf_evsel__close(&c2->core);
182362306a36Sopenharmony_ci			/*
182462306a36Sopenharmony_ci			 * We want to close all members of the group and reopen
182562306a36Sopenharmony_ci			 * them. Some events, like Intel topdown, require being
182662306a36Sopenharmony_ci			 * in a group and so keep these in the group.
182762306a36Sopenharmony_ci			 */
182862306a36Sopenharmony_ci			evsel__remove_from_group(c2, leader);
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_ci			/*
183162306a36Sopenharmony_ci			 * Set this for all former members of the group
183262306a36Sopenharmony_ci			 * to indicate they get reopened.
183362306a36Sopenharmony_ci			 */
183462306a36Sopenharmony_ci			c2->reset_group = true;
183562306a36Sopenharmony_ci		}
183662306a36Sopenharmony_ci	}
183762306a36Sopenharmony_ci	/* Reset the leader count if all entries were removed. */
183862306a36Sopenharmony_ci	if (leader->core.nr_members == 1)
183962306a36Sopenharmony_ci		leader->core.nr_members = 0;
184062306a36Sopenharmony_ci	return leader;
184162306a36Sopenharmony_ci}
184262306a36Sopenharmony_ci
184362306a36Sopenharmony_cistatic int evlist__parse_control_fifo(const char *str, int *ctl_fd, int *ctl_fd_ack, bool *ctl_fd_close)
184462306a36Sopenharmony_ci{
184562306a36Sopenharmony_ci	char *s, *p;
184662306a36Sopenharmony_ci	int ret = 0, fd;
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_ci	if (strncmp(str, "fifo:", 5))
184962306a36Sopenharmony_ci		return -EINVAL;
185062306a36Sopenharmony_ci
185162306a36Sopenharmony_ci	str += 5;
185262306a36Sopenharmony_ci	if (!*str || *str == ',')
185362306a36Sopenharmony_ci		return -EINVAL;
185462306a36Sopenharmony_ci
185562306a36Sopenharmony_ci	s = strdup(str);
185662306a36Sopenharmony_ci	if (!s)
185762306a36Sopenharmony_ci		return -ENOMEM;
185862306a36Sopenharmony_ci
185962306a36Sopenharmony_ci	p = strchr(s, ',');
186062306a36Sopenharmony_ci	if (p)
186162306a36Sopenharmony_ci		*p = '\0';
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_ci	/*
186462306a36Sopenharmony_ci	 * O_RDWR avoids POLLHUPs which is necessary to allow the other
186562306a36Sopenharmony_ci	 * end of a FIFO to be repeatedly opened and closed.
186662306a36Sopenharmony_ci	 */
186762306a36Sopenharmony_ci	fd = open(s, O_RDWR | O_NONBLOCK | O_CLOEXEC);
186862306a36Sopenharmony_ci	if (fd < 0) {
186962306a36Sopenharmony_ci		pr_err("Failed to open '%s'\n", s);
187062306a36Sopenharmony_ci		ret = -errno;
187162306a36Sopenharmony_ci		goto out_free;
187262306a36Sopenharmony_ci	}
187362306a36Sopenharmony_ci	*ctl_fd = fd;
187462306a36Sopenharmony_ci	*ctl_fd_close = true;
187562306a36Sopenharmony_ci
187662306a36Sopenharmony_ci	if (p && *++p) {
187762306a36Sopenharmony_ci		/* O_RDWR | O_NONBLOCK means the other end need not be open */
187862306a36Sopenharmony_ci		fd = open(p, O_RDWR | O_NONBLOCK | O_CLOEXEC);
187962306a36Sopenharmony_ci		if (fd < 0) {
188062306a36Sopenharmony_ci			pr_err("Failed to open '%s'\n", p);
188162306a36Sopenharmony_ci			ret = -errno;
188262306a36Sopenharmony_ci			goto out_free;
188362306a36Sopenharmony_ci		}
188462306a36Sopenharmony_ci		*ctl_fd_ack = fd;
188562306a36Sopenharmony_ci	}
188662306a36Sopenharmony_ci
188762306a36Sopenharmony_ciout_free:
188862306a36Sopenharmony_ci	free(s);
188962306a36Sopenharmony_ci	return ret;
189062306a36Sopenharmony_ci}
189162306a36Sopenharmony_ci
189262306a36Sopenharmony_ciint evlist__parse_control(const char *str, int *ctl_fd, int *ctl_fd_ack, bool *ctl_fd_close)
189362306a36Sopenharmony_ci{
189462306a36Sopenharmony_ci	char *comma = NULL, *endptr = NULL;
189562306a36Sopenharmony_ci
189662306a36Sopenharmony_ci	*ctl_fd_close = false;
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_ci	if (strncmp(str, "fd:", 3))
189962306a36Sopenharmony_ci		return evlist__parse_control_fifo(str, ctl_fd, ctl_fd_ack, ctl_fd_close);
190062306a36Sopenharmony_ci
190162306a36Sopenharmony_ci	*ctl_fd = strtoul(&str[3], &endptr, 0);
190262306a36Sopenharmony_ci	if (endptr == &str[3])
190362306a36Sopenharmony_ci		return -EINVAL;
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_ci	comma = strchr(str, ',');
190662306a36Sopenharmony_ci	if (comma) {
190762306a36Sopenharmony_ci		if (endptr != comma)
190862306a36Sopenharmony_ci			return -EINVAL;
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_ci		*ctl_fd_ack = strtoul(comma + 1, &endptr, 0);
191162306a36Sopenharmony_ci		if (endptr == comma + 1 || *endptr != '\0')
191262306a36Sopenharmony_ci			return -EINVAL;
191362306a36Sopenharmony_ci	}
191462306a36Sopenharmony_ci
191562306a36Sopenharmony_ci	return 0;
191662306a36Sopenharmony_ci}
191762306a36Sopenharmony_ci
191862306a36Sopenharmony_civoid evlist__close_control(int ctl_fd, int ctl_fd_ack, bool *ctl_fd_close)
191962306a36Sopenharmony_ci{
192062306a36Sopenharmony_ci	if (*ctl_fd_close) {
192162306a36Sopenharmony_ci		*ctl_fd_close = false;
192262306a36Sopenharmony_ci		close(ctl_fd);
192362306a36Sopenharmony_ci		if (ctl_fd_ack >= 0)
192462306a36Sopenharmony_ci			close(ctl_fd_ack);
192562306a36Sopenharmony_ci	}
192662306a36Sopenharmony_ci}
192762306a36Sopenharmony_ci
192862306a36Sopenharmony_ciint evlist__initialize_ctlfd(struct evlist *evlist, int fd, int ack)
192962306a36Sopenharmony_ci{
193062306a36Sopenharmony_ci	if (fd == -1) {
193162306a36Sopenharmony_ci		pr_debug("Control descriptor is not initialized\n");
193262306a36Sopenharmony_ci		return 0;
193362306a36Sopenharmony_ci	}
193462306a36Sopenharmony_ci
193562306a36Sopenharmony_ci	evlist->ctl_fd.pos = perf_evlist__add_pollfd(&evlist->core, fd, NULL, POLLIN,
193662306a36Sopenharmony_ci						     fdarray_flag__nonfilterable |
193762306a36Sopenharmony_ci						     fdarray_flag__non_perf_event);
193862306a36Sopenharmony_ci	if (evlist->ctl_fd.pos < 0) {
193962306a36Sopenharmony_ci		evlist->ctl_fd.pos = -1;
194062306a36Sopenharmony_ci		pr_err("Failed to add ctl fd entry: %m\n");
194162306a36Sopenharmony_ci		return -1;
194262306a36Sopenharmony_ci	}
194362306a36Sopenharmony_ci
194462306a36Sopenharmony_ci	evlist->ctl_fd.fd = fd;
194562306a36Sopenharmony_ci	evlist->ctl_fd.ack = ack;
194662306a36Sopenharmony_ci
194762306a36Sopenharmony_ci	return 0;
194862306a36Sopenharmony_ci}
194962306a36Sopenharmony_ci
195062306a36Sopenharmony_cibool evlist__ctlfd_initialized(struct evlist *evlist)
195162306a36Sopenharmony_ci{
195262306a36Sopenharmony_ci	return evlist->ctl_fd.pos >= 0;
195362306a36Sopenharmony_ci}
195462306a36Sopenharmony_ci
195562306a36Sopenharmony_ciint evlist__finalize_ctlfd(struct evlist *evlist)
195662306a36Sopenharmony_ci{
195762306a36Sopenharmony_ci	struct pollfd *entries = evlist->core.pollfd.entries;
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_ci	if (!evlist__ctlfd_initialized(evlist))
196062306a36Sopenharmony_ci		return 0;
196162306a36Sopenharmony_ci
196262306a36Sopenharmony_ci	entries[evlist->ctl_fd.pos].fd = -1;
196362306a36Sopenharmony_ci	entries[evlist->ctl_fd.pos].events = 0;
196462306a36Sopenharmony_ci	entries[evlist->ctl_fd.pos].revents = 0;
196562306a36Sopenharmony_ci
196662306a36Sopenharmony_ci	evlist->ctl_fd.pos = -1;
196762306a36Sopenharmony_ci	evlist->ctl_fd.ack = -1;
196862306a36Sopenharmony_ci	evlist->ctl_fd.fd = -1;
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ci	return 0;
197162306a36Sopenharmony_ci}
197262306a36Sopenharmony_ci
197362306a36Sopenharmony_cistatic int evlist__ctlfd_recv(struct evlist *evlist, enum evlist_ctl_cmd *cmd,
197462306a36Sopenharmony_ci			      char *cmd_data, size_t data_size)
197562306a36Sopenharmony_ci{
197662306a36Sopenharmony_ci	int err;
197762306a36Sopenharmony_ci	char c;
197862306a36Sopenharmony_ci	size_t bytes_read = 0;
197962306a36Sopenharmony_ci
198062306a36Sopenharmony_ci	*cmd = EVLIST_CTL_CMD_UNSUPPORTED;
198162306a36Sopenharmony_ci	memset(cmd_data, 0, data_size);
198262306a36Sopenharmony_ci	data_size--;
198362306a36Sopenharmony_ci
198462306a36Sopenharmony_ci	do {
198562306a36Sopenharmony_ci		err = read(evlist->ctl_fd.fd, &c, 1);
198662306a36Sopenharmony_ci		if (err > 0) {
198762306a36Sopenharmony_ci			if (c == '\n' || c == '\0')
198862306a36Sopenharmony_ci				break;
198962306a36Sopenharmony_ci			cmd_data[bytes_read++] = c;
199062306a36Sopenharmony_ci			if (bytes_read == data_size)
199162306a36Sopenharmony_ci				break;
199262306a36Sopenharmony_ci			continue;
199362306a36Sopenharmony_ci		} else if (err == -1) {
199462306a36Sopenharmony_ci			if (errno == EINTR)
199562306a36Sopenharmony_ci				continue;
199662306a36Sopenharmony_ci			if (errno == EAGAIN || errno == EWOULDBLOCK)
199762306a36Sopenharmony_ci				err = 0;
199862306a36Sopenharmony_ci			else
199962306a36Sopenharmony_ci				pr_err("Failed to read from ctlfd %d: %m\n", evlist->ctl_fd.fd);
200062306a36Sopenharmony_ci		}
200162306a36Sopenharmony_ci		break;
200262306a36Sopenharmony_ci	} while (1);
200362306a36Sopenharmony_ci
200462306a36Sopenharmony_ci	pr_debug("Message from ctl_fd: \"%s%s\"\n", cmd_data,
200562306a36Sopenharmony_ci		 bytes_read == data_size ? "" : c == '\n' ? "\\n" : "\\0");
200662306a36Sopenharmony_ci
200762306a36Sopenharmony_ci	if (bytes_read > 0) {
200862306a36Sopenharmony_ci		if (!strncmp(cmd_data, EVLIST_CTL_CMD_ENABLE_TAG,
200962306a36Sopenharmony_ci			     (sizeof(EVLIST_CTL_CMD_ENABLE_TAG)-1))) {
201062306a36Sopenharmony_ci			*cmd = EVLIST_CTL_CMD_ENABLE;
201162306a36Sopenharmony_ci		} else if (!strncmp(cmd_data, EVLIST_CTL_CMD_DISABLE_TAG,
201262306a36Sopenharmony_ci				    (sizeof(EVLIST_CTL_CMD_DISABLE_TAG)-1))) {
201362306a36Sopenharmony_ci			*cmd = EVLIST_CTL_CMD_DISABLE;
201462306a36Sopenharmony_ci		} else if (!strncmp(cmd_data, EVLIST_CTL_CMD_SNAPSHOT_TAG,
201562306a36Sopenharmony_ci				    (sizeof(EVLIST_CTL_CMD_SNAPSHOT_TAG)-1))) {
201662306a36Sopenharmony_ci			*cmd = EVLIST_CTL_CMD_SNAPSHOT;
201762306a36Sopenharmony_ci			pr_debug("is snapshot\n");
201862306a36Sopenharmony_ci		} else if (!strncmp(cmd_data, EVLIST_CTL_CMD_EVLIST_TAG,
201962306a36Sopenharmony_ci				    (sizeof(EVLIST_CTL_CMD_EVLIST_TAG)-1))) {
202062306a36Sopenharmony_ci			*cmd = EVLIST_CTL_CMD_EVLIST;
202162306a36Sopenharmony_ci		} else if (!strncmp(cmd_data, EVLIST_CTL_CMD_STOP_TAG,
202262306a36Sopenharmony_ci				    (sizeof(EVLIST_CTL_CMD_STOP_TAG)-1))) {
202362306a36Sopenharmony_ci			*cmd = EVLIST_CTL_CMD_STOP;
202462306a36Sopenharmony_ci		} else if (!strncmp(cmd_data, EVLIST_CTL_CMD_PING_TAG,
202562306a36Sopenharmony_ci				    (sizeof(EVLIST_CTL_CMD_PING_TAG)-1))) {
202662306a36Sopenharmony_ci			*cmd = EVLIST_CTL_CMD_PING;
202762306a36Sopenharmony_ci		}
202862306a36Sopenharmony_ci	}
202962306a36Sopenharmony_ci
203062306a36Sopenharmony_ci	return bytes_read ? (int)bytes_read : err;
203162306a36Sopenharmony_ci}
203262306a36Sopenharmony_ci
203362306a36Sopenharmony_ciint evlist__ctlfd_ack(struct evlist *evlist)
203462306a36Sopenharmony_ci{
203562306a36Sopenharmony_ci	int err;
203662306a36Sopenharmony_ci
203762306a36Sopenharmony_ci	if (evlist->ctl_fd.ack == -1)
203862306a36Sopenharmony_ci		return 0;
203962306a36Sopenharmony_ci
204062306a36Sopenharmony_ci	err = write(evlist->ctl_fd.ack, EVLIST_CTL_CMD_ACK_TAG,
204162306a36Sopenharmony_ci		    sizeof(EVLIST_CTL_CMD_ACK_TAG));
204262306a36Sopenharmony_ci	if (err == -1)
204362306a36Sopenharmony_ci		pr_err("failed to write to ctl_ack_fd %d: %m\n", evlist->ctl_fd.ack);
204462306a36Sopenharmony_ci
204562306a36Sopenharmony_ci	return err;
204662306a36Sopenharmony_ci}
204762306a36Sopenharmony_ci
204862306a36Sopenharmony_cistatic int get_cmd_arg(char *cmd_data, size_t cmd_size, char **arg)
204962306a36Sopenharmony_ci{
205062306a36Sopenharmony_ci	char *data = cmd_data + cmd_size;
205162306a36Sopenharmony_ci
205262306a36Sopenharmony_ci	/* no argument */
205362306a36Sopenharmony_ci	if (!*data)
205462306a36Sopenharmony_ci		return 0;
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ci	/* there's argument */
205762306a36Sopenharmony_ci	if (*data == ' ') {
205862306a36Sopenharmony_ci		*arg = data + 1;
205962306a36Sopenharmony_ci		return 1;
206062306a36Sopenharmony_ci	}
206162306a36Sopenharmony_ci
206262306a36Sopenharmony_ci	/* malformed */
206362306a36Sopenharmony_ci	return -1;
206462306a36Sopenharmony_ci}
206562306a36Sopenharmony_ci
206662306a36Sopenharmony_cistatic int evlist__ctlfd_enable(struct evlist *evlist, char *cmd_data, bool enable)
206762306a36Sopenharmony_ci{
206862306a36Sopenharmony_ci	struct evsel *evsel;
206962306a36Sopenharmony_ci	char *name;
207062306a36Sopenharmony_ci	int err;
207162306a36Sopenharmony_ci
207262306a36Sopenharmony_ci	err = get_cmd_arg(cmd_data,
207362306a36Sopenharmony_ci			  enable ? sizeof(EVLIST_CTL_CMD_ENABLE_TAG) - 1 :
207462306a36Sopenharmony_ci				   sizeof(EVLIST_CTL_CMD_DISABLE_TAG) - 1,
207562306a36Sopenharmony_ci			  &name);
207662306a36Sopenharmony_ci	if (err < 0) {
207762306a36Sopenharmony_ci		pr_info("failed: wrong command\n");
207862306a36Sopenharmony_ci		return -1;
207962306a36Sopenharmony_ci	}
208062306a36Sopenharmony_ci
208162306a36Sopenharmony_ci	if (err) {
208262306a36Sopenharmony_ci		evsel = evlist__find_evsel_by_str(evlist, name);
208362306a36Sopenharmony_ci		if (evsel) {
208462306a36Sopenharmony_ci			if (enable)
208562306a36Sopenharmony_ci				evlist__enable_evsel(evlist, name);
208662306a36Sopenharmony_ci			else
208762306a36Sopenharmony_ci				evlist__disable_evsel(evlist, name);
208862306a36Sopenharmony_ci			pr_info("Event %s %s\n", evsel->name,
208962306a36Sopenharmony_ci				enable ? "enabled" : "disabled");
209062306a36Sopenharmony_ci		} else {
209162306a36Sopenharmony_ci			pr_info("failed: can't find '%s' event\n", name);
209262306a36Sopenharmony_ci		}
209362306a36Sopenharmony_ci	} else {
209462306a36Sopenharmony_ci		if (enable) {
209562306a36Sopenharmony_ci			evlist__enable(evlist);
209662306a36Sopenharmony_ci			pr_info(EVLIST_ENABLED_MSG);
209762306a36Sopenharmony_ci		} else {
209862306a36Sopenharmony_ci			evlist__disable(evlist);
209962306a36Sopenharmony_ci			pr_info(EVLIST_DISABLED_MSG);
210062306a36Sopenharmony_ci		}
210162306a36Sopenharmony_ci	}
210262306a36Sopenharmony_ci
210362306a36Sopenharmony_ci	return 0;
210462306a36Sopenharmony_ci}
210562306a36Sopenharmony_ci
210662306a36Sopenharmony_cistatic int evlist__ctlfd_list(struct evlist *evlist, char *cmd_data)
210762306a36Sopenharmony_ci{
210862306a36Sopenharmony_ci	struct perf_attr_details details = { .verbose = false, };
210962306a36Sopenharmony_ci	struct evsel *evsel;
211062306a36Sopenharmony_ci	char *arg;
211162306a36Sopenharmony_ci	int err;
211262306a36Sopenharmony_ci
211362306a36Sopenharmony_ci	err = get_cmd_arg(cmd_data,
211462306a36Sopenharmony_ci			  sizeof(EVLIST_CTL_CMD_EVLIST_TAG) - 1,
211562306a36Sopenharmony_ci			  &arg);
211662306a36Sopenharmony_ci	if (err < 0) {
211762306a36Sopenharmony_ci		pr_info("failed: wrong command\n");
211862306a36Sopenharmony_ci		return -1;
211962306a36Sopenharmony_ci	}
212062306a36Sopenharmony_ci
212162306a36Sopenharmony_ci	if (err) {
212262306a36Sopenharmony_ci		if (!strcmp(arg, "-v")) {
212362306a36Sopenharmony_ci			details.verbose = true;
212462306a36Sopenharmony_ci		} else if (!strcmp(arg, "-g")) {
212562306a36Sopenharmony_ci			details.event_group = true;
212662306a36Sopenharmony_ci		} else if (!strcmp(arg, "-F")) {
212762306a36Sopenharmony_ci			details.freq = true;
212862306a36Sopenharmony_ci		} else {
212962306a36Sopenharmony_ci			pr_info("failed: wrong command\n");
213062306a36Sopenharmony_ci			return -1;
213162306a36Sopenharmony_ci		}
213262306a36Sopenharmony_ci	}
213362306a36Sopenharmony_ci
213462306a36Sopenharmony_ci	evlist__for_each_entry(evlist, evsel)
213562306a36Sopenharmony_ci		evsel__fprintf(evsel, &details, stderr);
213662306a36Sopenharmony_ci
213762306a36Sopenharmony_ci	return 0;
213862306a36Sopenharmony_ci}
213962306a36Sopenharmony_ci
214062306a36Sopenharmony_ciint evlist__ctlfd_process(struct evlist *evlist, enum evlist_ctl_cmd *cmd)
214162306a36Sopenharmony_ci{
214262306a36Sopenharmony_ci	int err = 0;
214362306a36Sopenharmony_ci	char cmd_data[EVLIST_CTL_CMD_MAX_LEN];
214462306a36Sopenharmony_ci	int ctlfd_pos = evlist->ctl_fd.pos;
214562306a36Sopenharmony_ci	struct pollfd *entries = evlist->core.pollfd.entries;
214662306a36Sopenharmony_ci
214762306a36Sopenharmony_ci	if (!evlist__ctlfd_initialized(evlist) || !entries[ctlfd_pos].revents)
214862306a36Sopenharmony_ci		return 0;
214962306a36Sopenharmony_ci
215062306a36Sopenharmony_ci	if (entries[ctlfd_pos].revents & POLLIN) {
215162306a36Sopenharmony_ci		err = evlist__ctlfd_recv(evlist, cmd, cmd_data,
215262306a36Sopenharmony_ci					 EVLIST_CTL_CMD_MAX_LEN);
215362306a36Sopenharmony_ci		if (err > 0) {
215462306a36Sopenharmony_ci			switch (*cmd) {
215562306a36Sopenharmony_ci			case EVLIST_CTL_CMD_ENABLE:
215662306a36Sopenharmony_ci			case EVLIST_CTL_CMD_DISABLE:
215762306a36Sopenharmony_ci				err = evlist__ctlfd_enable(evlist, cmd_data,
215862306a36Sopenharmony_ci							   *cmd == EVLIST_CTL_CMD_ENABLE);
215962306a36Sopenharmony_ci				break;
216062306a36Sopenharmony_ci			case EVLIST_CTL_CMD_EVLIST:
216162306a36Sopenharmony_ci				err = evlist__ctlfd_list(evlist, cmd_data);
216262306a36Sopenharmony_ci				break;
216362306a36Sopenharmony_ci			case EVLIST_CTL_CMD_SNAPSHOT:
216462306a36Sopenharmony_ci			case EVLIST_CTL_CMD_STOP:
216562306a36Sopenharmony_ci			case EVLIST_CTL_CMD_PING:
216662306a36Sopenharmony_ci				break;
216762306a36Sopenharmony_ci			case EVLIST_CTL_CMD_ACK:
216862306a36Sopenharmony_ci			case EVLIST_CTL_CMD_UNSUPPORTED:
216962306a36Sopenharmony_ci			default:
217062306a36Sopenharmony_ci				pr_debug("ctlfd: unsupported %d\n", *cmd);
217162306a36Sopenharmony_ci				break;
217262306a36Sopenharmony_ci			}
217362306a36Sopenharmony_ci			if (!(*cmd == EVLIST_CTL_CMD_ACK || *cmd == EVLIST_CTL_CMD_UNSUPPORTED ||
217462306a36Sopenharmony_ci			      *cmd == EVLIST_CTL_CMD_SNAPSHOT))
217562306a36Sopenharmony_ci				evlist__ctlfd_ack(evlist);
217662306a36Sopenharmony_ci		}
217762306a36Sopenharmony_ci	}
217862306a36Sopenharmony_ci
217962306a36Sopenharmony_ci	if (entries[ctlfd_pos].revents & (POLLHUP | POLLERR))
218062306a36Sopenharmony_ci		evlist__finalize_ctlfd(evlist);
218162306a36Sopenharmony_ci	else
218262306a36Sopenharmony_ci		entries[ctlfd_pos].revents = 0;
218362306a36Sopenharmony_ci
218462306a36Sopenharmony_ci	return err;
218562306a36Sopenharmony_ci}
218662306a36Sopenharmony_ci
218762306a36Sopenharmony_ci/**
218862306a36Sopenharmony_ci * struct event_enable_time - perf record -D/--delay single time range.
218962306a36Sopenharmony_ci * @start: start of time range to enable events in milliseconds
219062306a36Sopenharmony_ci * @end: end of time range to enable events in milliseconds
219162306a36Sopenharmony_ci *
219262306a36Sopenharmony_ci * N.B. this structure is also accessed as an array of int.
219362306a36Sopenharmony_ci */
219462306a36Sopenharmony_cistruct event_enable_time {
219562306a36Sopenharmony_ci	int	start;
219662306a36Sopenharmony_ci	int	end;
219762306a36Sopenharmony_ci};
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_cistatic int parse_event_enable_time(const char *str, struct event_enable_time *range, bool first)
220062306a36Sopenharmony_ci{
220162306a36Sopenharmony_ci	const char *fmt = first ? "%u - %u %n" : " , %u - %u %n";
220262306a36Sopenharmony_ci	int ret, start, end, n;
220362306a36Sopenharmony_ci
220462306a36Sopenharmony_ci	ret = sscanf(str, fmt, &start, &end, &n);
220562306a36Sopenharmony_ci	if (ret != 2 || end <= start)
220662306a36Sopenharmony_ci		return -EINVAL;
220762306a36Sopenharmony_ci	if (range) {
220862306a36Sopenharmony_ci		range->start = start;
220962306a36Sopenharmony_ci		range->end = end;
221062306a36Sopenharmony_ci	}
221162306a36Sopenharmony_ci	return n;
221262306a36Sopenharmony_ci}
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_cistatic ssize_t parse_event_enable_times(const char *str, struct event_enable_time *range)
221562306a36Sopenharmony_ci{
221662306a36Sopenharmony_ci	int incr = !!range;
221762306a36Sopenharmony_ci	bool first = true;
221862306a36Sopenharmony_ci	ssize_t ret, cnt;
221962306a36Sopenharmony_ci
222062306a36Sopenharmony_ci	for (cnt = 0; *str; cnt++) {
222162306a36Sopenharmony_ci		ret = parse_event_enable_time(str, range, first);
222262306a36Sopenharmony_ci		if (ret < 0)
222362306a36Sopenharmony_ci			return ret;
222462306a36Sopenharmony_ci		/* Check no overlap */
222562306a36Sopenharmony_ci		if (!first && range && range->start <= range[-1].end)
222662306a36Sopenharmony_ci			return -EINVAL;
222762306a36Sopenharmony_ci		str += ret;
222862306a36Sopenharmony_ci		range += incr;
222962306a36Sopenharmony_ci		first = false;
223062306a36Sopenharmony_ci	}
223162306a36Sopenharmony_ci	return cnt;
223262306a36Sopenharmony_ci}
223362306a36Sopenharmony_ci
223462306a36Sopenharmony_ci/**
223562306a36Sopenharmony_ci * struct event_enable_timer - control structure for perf record -D/--delay.
223662306a36Sopenharmony_ci * @evlist: event list
223762306a36Sopenharmony_ci * @times: time ranges that events are enabled (N.B. this is also accessed as an
223862306a36Sopenharmony_ci *         array of int)
223962306a36Sopenharmony_ci * @times_cnt: number of time ranges
224062306a36Sopenharmony_ci * @timerfd: timer file descriptor
224162306a36Sopenharmony_ci * @pollfd_pos: position in @evlist array of file descriptors to poll (fdarray)
224262306a36Sopenharmony_ci * @times_step: current position in (int *)@times)[],
224362306a36Sopenharmony_ci *              refer event_enable_timer__process()
224462306a36Sopenharmony_ci *
224562306a36Sopenharmony_ci * Note, this structure is only used when there are time ranges, not when there
224662306a36Sopenharmony_ci * is only an initial delay.
224762306a36Sopenharmony_ci */
224862306a36Sopenharmony_cistruct event_enable_timer {
224962306a36Sopenharmony_ci	struct evlist *evlist;
225062306a36Sopenharmony_ci	struct event_enable_time *times;
225162306a36Sopenharmony_ci	size_t	times_cnt;
225262306a36Sopenharmony_ci	int	timerfd;
225362306a36Sopenharmony_ci	int	pollfd_pos;
225462306a36Sopenharmony_ci	size_t	times_step;
225562306a36Sopenharmony_ci};
225662306a36Sopenharmony_ci
225762306a36Sopenharmony_cistatic int str_to_delay(const char *str)
225862306a36Sopenharmony_ci{
225962306a36Sopenharmony_ci	char *endptr;
226062306a36Sopenharmony_ci	long d;
226162306a36Sopenharmony_ci
226262306a36Sopenharmony_ci	d = strtol(str, &endptr, 10);
226362306a36Sopenharmony_ci	if (*endptr || d > INT_MAX || d < -1)
226462306a36Sopenharmony_ci		return 0;
226562306a36Sopenharmony_ci	return d;
226662306a36Sopenharmony_ci}
226762306a36Sopenharmony_ci
226862306a36Sopenharmony_ciint evlist__parse_event_enable_time(struct evlist *evlist, struct record_opts *opts,
226962306a36Sopenharmony_ci				    const char *str, int unset)
227062306a36Sopenharmony_ci{
227162306a36Sopenharmony_ci	enum fdarray_flags flags = fdarray_flag__nonfilterable | fdarray_flag__non_perf_event;
227262306a36Sopenharmony_ci	struct event_enable_timer *eet;
227362306a36Sopenharmony_ci	ssize_t times_cnt;
227462306a36Sopenharmony_ci	ssize_t ret;
227562306a36Sopenharmony_ci	int err;
227662306a36Sopenharmony_ci
227762306a36Sopenharmony_ci	if (unset)
227862306a36Sopenharmony_ci		return 0;
227962306a36Sopenharmony_ci
228062306a36Sopenharmony_ci	opts->target.initial_delay = str_to_delay(str);
228162306a36Sopenharmony_ci	if (opts->target.initial_delay)
228262306a36Sopenharmony_ci		return 0;
228362306a36Sopenharmony_ci
228462306a36Sopenharmony_ci	ret = parse_event_enable_times(str, NULL);
228562306a36Sopenharmony_ci	if (ret < 0)
228662306a36Sopenharmony_ci		return ret;
228762306a36Sopenharmony_ci
228862306a36Sopenharmony_ci	times_cnt = ret;
228962306a36Sopenharmony_ci	if (times_cnt == 0)
229062306a36Sopenharmony_ci		return -EINVAL;
229162306a36Sopenharmony_ci
229262306a36Sopenharmony_ci	eet = zalloc(sizeof(*eet));
229362306a36Sopenharmony_ci	if (!eet)
229462306a36Sopenharmony_ci		return -ENOMEM;
229562306a36Sopenharmony_ci
229662306a36Sopenharmony_ci	eet->times = calloc(times_cnt, sizeof(*eet->times));
229762306a36Sopenharmony_ci	if (!eet->times) {
229862306a36Sopenharmony_ci		err = -ENOMEM;
229962306a36Sopenharmony_ci		goto free_eet;
230062306a36Sopenharmony_ci	}
230162306a36Sopenharmony_ci
230262306a36Sopenharmony_ci	if (parse_event_enable_times(str, eet->times) != times_cnt) {
230362306a36Sopenharmony_ci		err = -EINVAL;
230462306a36Sopenharmony_ci		goto free_eet_times;
230562306a36Sopenharmony_ci	}
230662306a36Sopenharmony_ci
230762306a36Sopenharmony_ci	eet->times_cnt = times_cnt;
230862306a36Sopenharmony_ci
230962306a36Sopenharmony_ci	eet->timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
231062306a36Sopenharmony_ci	if (eet->timerfd == -1) {
231162306a36Sopenharmony_ci		err = -errno;
231262306a36Sopenharmony_ci		pr_err("timerfd_create failed: %s\n", strerror(errno));
231362306a36Sopenharmony_ci		goto free_eet_times;
231462306a36Sopenharmony_ci	}
231562306a36Sopenharmony_ci
231662306a36Sopenharmony_ci	eet->pollfd_pos = perf_evlist__add_pollfd(&evlist->core, eet->timerfd, NULL, POLLIN, flags);
231762306a36Sopenharmony_ci	if (eet->pollfd_pos < 0) {
231862306a36Sopenharmony_ci		err = eet->pollfd_pos;
231962306a36Sopenharmony_ci		goto close_timerfd;
232062306a36Sopenharmony_ci	}
232162306a36Sopenharmony_ci
232262306a36Sopenharmony_ci	eet->evlist = evlist;
232362306a36Sopenharmony_ci	evlist->eet = eet;
232462306a36Sopenharmony_ci	opts->target.initial_delay = eet->times[0].start;
232562306a36Sopenharmony_ci
232662306a36Sopenharmony_ci	return 0;
232762306a36Sopenharmony_ci
232862306a36Sopenharmony_ciclose_timerfd:
232962306a36Sopenharmony_ci	close(eet->timerfd);
233062306a36Sopenharmony_cifree_eet_times:
233162306a36Sopenharmony_ci	zfree(&eet->times);
233262306a36Sopenharmony_cifree_eet:
233362306a36Sopenharmony_ci	free(eet);
233462306a36Sopenharmony_ci	return err;
233562306a36Sopenharmony_ci}
233662306a36Sopenharmony_ci
233762306a36Sopenharmony_cistatic int event_enable_timer__set_timer(struct event_enable_timer *eet, int ms)
233862306a36Sopenharmony_ci{
233962306a36Sopenharmony_ci	struct itimerspec its = {
234062306a36Sopenharmony_ci		.it_value.tv_sec = ms / MSEC_PER_SEC,
234162306a36Sopenharmony_ci		.it_value.tv_nsec = (ms % MSEC_PER_SEC) * NSEC_PER_MSEC,
234262306a36Sopenharmony_ci	};
234362306a36Sopenharmony_ci	int err = 0;
234462306a36Sopenharmony_ci
234562306a36Sopenharmony_ci	if (timerfd_settime(eet->timerfd, 0, &its, NULL) < 0) {
234662306a36Sopenharmony_ci		err = -errno;
234762306a36Sopenharmony_ci		pr_err("timerfd_settime failed: %s\n", strerror(errno));
234862306a36Sopenharmony_ci	}
234962306a36Sopenharmony_ci	return err;
235062306a36Sopenharmony_ci}
235162306a36Sopenharmony_ci
235262306a36Sopenharmony_ciint event_enable_timer__start(struct event_enable_timer *eet)
235362306a36Sopenharmony_ci{
235462306a36Sopenharmony_ci	int ms;
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_ci	if (!eet)
235762306a36Sopenharmony_ci		return 0;
235862306a36Sopenharmony_ci
235962306a36Sopenharmony_ci	ms = eet->times[0].end - eet->times[0].start;
236062306a36Sopenharmony_ci	eet->times_step = 1;
236162306a36Sopenharmony_ci
236262306a36Sopenharmony_ci	return event_enable_timer__set_timer(eet, ms);
236362306a36Sopenharmony_ci}
236462306a36Sopenharmony_ci
236562306a36Sopenharmony_ciint event_enable_timer__process(struct event_enable_timer *eet)
236662306a36Sopenharmony_ci{
236762306a36Sopenharmony_ci	struct pollfd *entries;
236862306a36Sopenharmony_ci	short revents;
236962306a36Sopenharmony_ci
237062306a36Sopenharmony_ci	if (!eet)
237162306a36Sopenharmony_ci		return 0;
237262306a36Sopenharmony_ci
237362306a36Sopenharmony_ci	entries = eet->evlist->core.pollfd.entries;
237462306a36Sopenharmony_ci	revents = entries[eet->pollfd_pos].revents;
237562306a36Sopenharmony_ci	entries[eet->pollfd_pos].revents = 0;
237662306a36Sopenharmony_ci
237762306a36Sopenharmony_ci	if (revents & POLLIN) {
237862306a36Sopenharmony_ci		size_t step = eet->times_step;
237962306a36Sopenharmony_ci		size_t pos = step / 2;
238062306a36Sopenharmony_ci
238162306a36Sopenharmony_ci		if (step & 1) {
238262306a36Sopenharmony_ci			evlist__disable_non_dummy(eet->evlist);
238362306a36Sopenharmony_ci			pr_info(EVLIST_DISABLED_MSG);
238462306a36Sopenharmony_ci			if (pos >= eet->times_cnt - 1) {
238562306a36Sopenharmony_ci				/* Disarm timer */
238662306a36Sopenharmony_ci				event_enable_timer__set_timer(eet, 0);
238762306a36Sopenharmony_ci				return 1; /* Stop */
238862306a36Sopenharmony_ci			}
238962306a36Sopenharmony_ci		} else {
239062306a36Sopenharmony_ci			evlist__enable_non_dummy(eet->evlist);
239162306a36Sopenharmony_ci			pr_info(EVLIST_ENABLED_MSG);
239262306a36Sopenharmony_ci		}
239362306a36Sopenharmony_ci
239462306a36Sopenharmony_ci		step += 1;
239562306a36Sopenharmony_ci		pos = step / 2;
239662306a36Sopenharmony_ci
239762306a36Sopenharmony_ci		if (pos < eet->times_cnt) {
239862306a36Sopenharmony_ci			int *times = (int *)eet->times; /* Accessing 'times' as array of int */
239962306a36Sopenharmony_ci			int ms = times[step] - times[step - 1];
240062306a36Sopenharmony_ci
240162306a36Sopenharmony_ci			eet->times_step = step;
240262306a36Sopenharmony_ci			return event_enable_timer__set_timer(eet, ms);
240362306a36Sopenharmony_ci		}
240462306a36Sopenharmony_ci	}
240562306a36Sopenharmony_ci
240662306a36Sopenharmony_ci	return 0;
240762306a36Sopenharmony_ci}
240862306a36Sopenharmony_ci
240962306a36Sopenharmony_civoid event_enable_timer__exit(struct event_enable_timer **ep)
241062306a36Sopenharmony_ci{
241162306a36Sopenharmony_ci	if (!ep || !*ep)
241262306a36Sopenharmony_ci		return;
241362306a36Sopenharmony_ci	zfree(&(*ep)->times);
241462306a36Sopenharmony_ci	zfree(ep);
241562306a36Sopenharmony_ci}
241662306a36Sopenharmony_ci
241762306a36Sopenharmony_cistruct evsel *evlist__find_evsel(struct evlist *evlist, int idx)
241862306a36Sopenharmony_ci{
241962306a36Sopenharmony_ci	struct evsel *evsel;
242062306a36Sopenharmony_ci
242162306a36Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
242262306a36Sopenharmony_ci		if (evsel->core.idx == idx)
242362306a36Sopenharmony_ci			return evsel;
242462306a36Sopenharmony_ci	}
242562306a36Sopenharmony_ci	return NULL;
242662306a36Sopenharmony_ci}
242762306a36Sopenharmony_ci
242862306a36Sopenharmony_ciint evlist__scnprintf_evsels(struct evlist *evlist, size_t size, char *bf)
242962306a36Sopenharmony_ci{
243062306a36Sopenharmony_ci	struct evsel *evsel;
243162306a36Sopenharmony_ci	int printed = 0;
243262306a36Sopenharmony_ci
243362306a36Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
243462306a36Sopenharmony_ci		if (evsel__is_dummy_event(evsel))
243562306a36Sopenharmony_ci			continue;
243662306a36Sopenharmony_ci		if (size > (strlen(evsel__name(evsel)) + (printed ? 2 : 1))) {
243762306a36Sopenharmony_ci			printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "," : "", evsel__name(evsel));
243862306a36Sopenharmony_ci		} else {
243962306a36Sopenharmony_ci			printed += scnprintf(bf + printed, size - printed, "%s...", printed ? "," : "");
244062306a36Sopenharmony_ci			break;
244162306a36Sopenharmony_ci		}
244262306a36Sopenharmony_ci	}
244362306a36Sopenharmony_ci
244462306a36Sopenharmony_ci	return printed;
244562306a36Sopenharmony_ci}
244662306a36Sopenharmony_ci
244762306a36Sopenharmony_civoid evlist__check_mem_load_aux(struct evlist *evlist)
244862306a36Sopenharmony_ci{
244962306a36Sopenharmony_ci	struct evsel *leader, *evsel, *pos;
245062306a36Sopenharmony_ci
245162306a36Sopenharmony_ci	/*
245262306a36Sopenharmony_ci	 * For some platforms, the 'mem-loads' event is required to use
245362306a36Sopenharmony_ci	 * together with 'mem-loads-aux' within a group and 'mem-loads-aux'
245462306a36Sopenharmony_ci	 * must be the group leader. Now we disable this group before reporting
245562306a36Sopenharmony_ci	 * because 'mem-loads-aux' is just an auxiliary event. It doesn't carry
245662306a36Sopenharmony_ci	 * any valid memory load information.
245762306a36Sopenharmony_ci	 */
245862306a36Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
245962306a36Sopenharmony_ci		leader = evsel__leader(evsel);
246062306a36Sopenharmony_ci		if (leader == evsel)
246162306a36Sopenharmony_ci			continue;
246262306a36Sopenharmony_ci
246362306a36Sopenharmony_ci		if (leader->name && strstr(leader->name, "mem-loads-aux")) {
246462306a36Sopenharmony_ci			for_each_group_evsel(pos, leader) {
246562306a36Sopenharmony_ci				evsel__set_leader(pos, pos);
246662306a36Sopenharmony_ci				pos->core.nr_members = 0;
246762306a36Sopenharmony_ci			}
246862306a36Sopenharmony_ci		}
246962306a36Sopenharmony_ci	}
247062306a36Sopenharmony_ci}
247162306a36Sopenharmony_ci
247262306a36Sopenharmony_ci/**
247362306a36Sopenharmony_ci * evlist__warn_user_requested_cpus() - Check each evsel against requested CPUs
247462306a36Sopenharmony_ci *     and warn if the user CPU list is inapplicable for the event's PMU's
247562306a36Sopenharmony_ci *     CPUs. Not core PMUs list a CPU in sysfs, but this may be overwritten by a
247662306a36Sopenharmony_ci *     user requested CPU and so any online CPU is applicable. Core PMUs handle
247762306a36Sopenharmony_ci *     events on the CPUs in their list and otherwise the event isn't supported.
247862306a36Sopenharmony_ci * @evlist: The list of events being checked.
247962306a36Sopenharmony_ci * @cpu_list: The user provided list of CPUs.
248062306a36Sopenharmony_ci */
248162306a36Sopenharmony_civoid evlist__warn_user_requested_cpus(struct evlist *evlist, const char *cpu_list)
248262306a36Sopenharmony_ci{
248362306a36Sopenharmony_ci	struct perf_cpu_map *user_requested_cpus;
248462306a36Sopenharmony_ci	struct evsel *pos;
248562306a36Sopenharmony_ci
248662306a36Sopenharmony_ci	if (!cpu_list)
248762306a36Sopenharmony_ci		return;
248862306a36Sopenharmony_ci
248962306a36Sopenharmony_ci	user_requested_cpus = perf_cpu_map__new(cpu_list);
249062306a36Sopenharmony_ci	if (!user_requested_cpus)
249162306a36Sopenharmony_ci		return;
249262306a36Sopenharmony_ci
249362306a36Sopenharmony_ci	evlist__for_each_entry(evlist, pos) {
249462306a36Sopenharmony_ci		struct perf_cpu_map *intersect, *to_test;
249562306a36Sopenharmony_ci		const struct perf_pmu *pmu = evsel__find_pmu(pos);
249662306a36Sopenharmony_ci
249762306a36Sopenharmony_ci		to_test = pmu && pmu->is_core ? pmu->cpus : cpu_map__online();
249862306a36Sopenharmony_ci		intersect = perf_cpu_map__intersect(to_test, user_requested_cpus);
249962306a36Sopenharmony_ci		if (!perf_cpu_map__equal(intersect, user_requested_cpus)) {
250062306a36Sopenharmony_ci			char buf[128];
250162306a36Sopenharmony_ci
250262306a36Sopenharmony_ci			cpu_map__snprint(to_test, buf, sizeof(buf));
250362306a36Sopenharmony_ci			pr_warning("WARNING: A requested CPU in '%s' is not supported by PMU '%s' (CPUs %s) for event '%s'\n",
250462306a36Sopenharmony_ci				cpu_list, pmu ? pmu->name : "cpu", buf, evsel__name(pos));
250562306a36Sopenharmony_ci		}
250662306a36Sopenharmony_ci		perf_cpu_map__put(intersect);
250762306a36Sopenharmony_ci	}
250862306a36Sopenharmony_ci	perf_cpu_map__put(user_requested_cpus);
250962306a36Sopenharmony_ci}
251062306a36Sopenharmony_ci
251162306a36Sopenharmony_civoid evlist__uniquify_name(struct evlist *evlist)
251262306a36Sopenharmony_ci{
251362306a36Sopenharmony_ci	struct evsel *pos;
251462306a36Sopenharmony_ci	char *new_name;
251562306a36Sopenharmony_ci	int ret;
251662306a36Sopenharmony_ci
251762306a36Sopenharmony_ci	if (perf_pmus__num_core_pmus() == 1)
251862306a36Sopenharmony_ci		return;
251962306a36Sopenharmony_ci
252062306a36Sopenharmony_ci	evlist__for_each_entry(evlist, pos) {
252162306a36Sopenharmony_ci		if (!evsel__is_hybrid(pos))
252262306a36Sopenharmony_ci			continue;
252362306a36Sopenharmony_ci
252462306a36Sopenharmony_ci		if (strchr(pos->name, '/'))
252562306a36Sopenharmony_ci			continue;
252662306a36Sopenharmony_ci
252762306a36Sopenharmony_ci		ret = asprintf(&new_name, "%s/%s/",
252862306a36Sopenharmony_ci			       pos->pmu_name, pos->name);
252962306a36Sopenharmony_ci		if (ret) {
253062306a36Sopenharmony_ci			free(pos->name);
253162306a36Sopenharmony_ci			pos->name = new_name;
253262306a36Sopenharmony_ci		}
253362306a36Sopenharmony_ci	}
253462306a36Sopenharmony_ci}
2535