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