// SPDX-License-Identifier: GPL-2.0-only/* * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> * * Parts came from builtin-{top,stat,record}.c, see those files for further * copyright notes. */#include "evlist.h" #include <errno.h>#include <inttypes.h>#include <signal.h>#include <stdlib.h>#include <string.h> #include <fcntl.h>#include <linux/bitops.h>#include <linux/err.h>#include <linux/hash.h>#include <linux/log2.h>#include <linux/string.h>#include <linux/time64.h>#include <linux/zalloc.h>#include <poll.h>#include <sched.h>#include <sys/ioctl.h>#include <sys/mman.h>#include <sys/prctl.h>#include <sys/timerfd.h>#include <sys/wait.h>#include <unistd.h> #include <api/fs/fs.h>#include <internal/lib.h> // page_size#include <internal/rc_check.h>#include <internal/xyarray.h>#include <perf/cpumap.h>#include <perf/evlist.h>#include <perf/evsel.h>#include <perf/mmap.h>#include <subcmd/parse-options.h> #include "../perf.h"#include "affinity.h"#include "asm/bug.h"#include "bpf-event.h"#include "bpf-filter.h"#include "bpf_counter.h"#include "cpumap.h"#include "debug.h"#include "dwarf-regs.h"#include "env.h"#include "event.h"#include "evsel.h"#include "evsel_fprintf.h"#include "intel-tpebs.h"#include "metricgroup.h"#include "mmap.h"#include "parse-events.h"#include "perf_api_probe.h"#include "pmu.h"#include "pmus.h"#include "record.h"#include "sample.h"#include "stat.h"#include "strbuf.h"#include "string2.h"#include "target.h"#include "thread_map.h"#include "units.h"#include "util.h" #ifdef LACKS_SIGQUEUE_PROTOTYPEint sigqueue(pid_t pid, int sig, const union sigval value);#endif #define FD(e, x, y) (*(int *)xyarray__entry(e->core.fd, x, y))#define SID(e, x, y) xyarray__entry(e->core.sample_id, x, y) static void event_enable_timer__exit(struct event_enable_timer **ep); struct evlist *evlist__new(void){ struct evlist *result; RC_STRUCT(evlist) *evlist; evlist = zalloc(sizeof(*evlist)); if (ADD_RC_CHK(result, evlist)) { perf_evlist__init(evlist__core(result)); perf_evlist__set_maps(evlist__core(result), /*cpus=*/NULL, /*threads=*/NULL); evlist__set_workload_pid(result, -1); evlist__set_bkw_mmap_state(result, BKW_MMAP_NOTREADY); evlist__set_ctl_fd_fd(result, -1); evlist__set_ctl_fd_ack(result, -1); evlist__set_ctl_fd_pos(result, -1); evlist__set_nr_br_cntr(result, -1); metricgroup__rblist_init(evlist__metric_events(result)); INIT_LIST_HEAD(&evlist->deferred_samples); refcount_set(evlist__refcnt(result), 1); } else { free(evlist); result = NULL; } return result;} struct evlist *evlist__new_default(const struct target *target, bool sample_callchains){ struct evlist *evlist = evlist__new(); bool can_profile_kernel; struct perf_pmu *pmu = NULL; char buf[256]; int err; if (!evlist) return NULL; can_profile_kernel = perf_event_paranoid_check(1); if (EM_HOST == EM_S390 && sample_callchains) { snprintf(buf, sizeof(buf), "software/%s/%s", target__has_cpu(target) ? "cpu-clock" : "task-clock", can_profile_kernel ? "P" : "Pu"); err = parse_event(evlist, buf); if (err) goto out_err; } else { while ((pmu = perf_pmus__scan_core(pmu)) != NULL) { snprintf(buf, sizeof(buf), "%s/cycles/%s", pmu->name, can_profile_kernel ? "P" : "Pu"); err = parse_event(evlist, buf); if (err) goto out_err; } } /* If there is only 1 event a sample identifier isn't necessary. */ if (evlist__nr_entries(evlist) > 1) { struct evsel *evsel; evlist__for_each_entry(evlist, evsel) evsel__set_sample_id(evsel, /*can_sample_identifier=*/false); } return evlist;out_err: evlist__put(evlist); return NULL;} struct evlist *evlist__new_dummy(void){ struct evlist *evlist = evlist__new(); if (evlist && evlist__add_dummy(evlist)) { evlist__put(evlist); evlist = NULL; } return evlist;} struct evlist *evlist__get(struct evlist *evlist){ struct evlist *result; if (RC_CHK_GET(result, evlist)) refcount_inc(evlist__refcnt(evlist)); return result;} /** * evlist__set_id_pos - set the positions of event ids. * @evlist: selected event list * * Events with compatible sample types all have the same id_pos * and is_pos. For convenience, put a copy on evlist. */void evlist__set_id_pos(struct evlist *evlist){ struct evsel *first = evlist__first(evlist); RC_CHK_ACCESS(evlist)->id_pos = first->id_pos; RC_CHK_ACCESS(evlist)->is_pos = first->is_pos;} static void evlist__update_id_pos(struct evlist *evlist){ struct evsel *evsel; evlist__for_each_entry(evlist, evsel) evsel__calc_id_pos(evsel); evlist__set_id_pos(evlist);} static void evlist__purge(struct evlist *evlist){ struct evsel *pos, *n; evlist__for_each_entry_safe(evlist, n, pos) { list_del_init(&pos->core.node); if (pos->evlist) { if (!RC_CHK_EQUAL(pos->evlist, evlist)) { evlist__put(pos->evlist); } else { refcount_dec_and_test(evlist__refcnt(pos->evlist)); RC_CHK_PUT(pos->evlist); } } pos->evlist = NULL; evsel__put(pos); } evlist__core(evlist)->nr_entries = 0;} static void evlist__exit(struct evlist *evlist){ metricgroup__rblist_exit(evlist__metric_events(evlist)); event_enable_timer__exit(&RC_CHK_ACCESS(evlist)->eet); free(evlist__mmap(evlist)); free(evlist__overwrite_mmap(evlist)); perf_evlist__exit(evlist__core(evlist));} void evlist__put(struct evlist *evlist){ struct evsel *evsel; unsigned int count, ref_cnt; if (evlist == NULL) return; if (refcount_dec_and_test(evlist__refcnt(evlist))) goto out_delete; retry: count = refcount_read(evlist__refcnt(evlist)); ref_cnt = count; evlist__for_each_entry(evlist, evsel) { if (RC_CHK_EQUAL(evsel->evlist, evlist) && count && refcount_read(&evsel->refcnt) == 1) count--; } if (refcount_read(evlist__refcnt(evlist)) != ref_cnt) goto retry; if (count != 0) { /* * Not the last reference except for back references from * evsels. */ RC_CHK_PUT(evlist); return; }out_delete: evlist__free_stats(evlist); evlist__do_munmap(evlist); evlist__close(evlist); evlist__purge(evlist); evlist__exit(evlist); RC_CHK_FREE(evlist);} void evlist__add(struct evlist *evlist, struct evsel *entry){ perf_evlist__add(evlist__core(evlist), &entry->core); evlist__put(entry->evlist); entry->evlist = evlist__get(evlist); entry->tracking = !entry->core.idx; if (evlist__nr_entries(evlist) == 1) evlist__set_id_pos(evlist);} void evlist__remove(struct evlist *evlist, struct evsel *evsel){ perf_evlist__remove(evlist__core(evlist), &evsel->core); evlist__put(evsel->evlist); evsel->evlist = NULL;} void evlist__splice_list_tail(struct evlist *evlist, struct list_head *list){ while (!list_empty(list)) { struct evsel *evsel, *temp, *leader = NULL; __evlist__for_each_entry_safe(list, temp, evsel) { list_del_init(&evsel->core.node); evlist__add(evlist, evsel); leader = evsel; break; } __evlist__for_each_entry_safe(list, temp, evsel) { if (evsel__has_leader(evsel, leader)) { list_del_init(&evsel->core.node); evlist__add(evlist, evsel); } } }} int __evlist__set_tracepoints_handlers(struct evlist *evlist, const struct evsel_str_handler *assocs, size_t nr_assocs){ size_t i; int err; for (i = 0; i < nr_assocs; i++) { // Adding a handler for an event not in this evlist, just ignore it. struct evsel *evsel = evlist__find_tracepoint_by_name(evlist, assocs[i].name); if (evsel == NULL) continue; err = -EEXIST; if (evsel->handler != NULL) goto out; evsel->handler = assocs[i].handler; } err = 0;out: return err;} static void evlist__set_leader(struct evlist *evlist){ perf_evlist__set_leader(evlist__core(evlist));} static struct evsel *evlist__dummy_event(struct evlist *evlist){ struct perf_event_attr attr = { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_DUMMY, .size = sizeof(attr), /* to capture ABI version */ /* Avoid frequency mode for dummy events to avoid associated timers. */ .freq = 0, .sample_period = 1, }; return evsel__new_idx(&attr, evlist__nr_entries(evlist));} int evlist__add_dummy(struct evlist *evlist){ struct evsel *evsel = evlist__dummy_event(evlist); if (evsel == NULL) return -ENOMEM; evlist__add(evlist, evsel); return 0;} struct evsel *evlist__add_aux_dummy(struct evlist *evlist, bool system_wide){ struct evsel *evsel = evlist__dummy_event(evlist); if (!evsel) return NULL; evsel->core.attr.exclude_kernel = 1; evsel->core.attr.exclude_guest = 1; evsel->core.attr.exclude_hv = 1; evsel->core.system_wide = system_wide; evsel->no_aux_samples = true; evsel->name = strdup("dummy:u"); evlist__add(evlist, evsel); return evsel;} #ifdef HAVE_LIBTRACEEVENTstruct evsel *evlist__add_sched_switch(struct evlist *evlist, bool system_wide){ struct evsel *evsel = evsel__newtp_idx("sched", "sched_switch", 0, /*format=*/true); if (IS_ERR(evsel)) return evsel; evsel__set_sample_bit(evsel, CPU); evsel__set_sample_bit(evsel, TIME); evsel->core.system_wide = system_wide; evsel->no_aux_samples = true; evlist__add(evlist, evsel); return evsel;}#endif struct evsel *evlist__find_tracepoint_by_name(struct evlist *evlist, const char *name){ struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { if ((evsel->core.attr.type == PERF_TYPE_TRACEPOINT) && (strcmp(evsel->name, name) == 0)) return evsel; } return NULL;} #ifdef HAVE_LIBTRACEEVENTint evlist__add_newtp(struct evlist *evlist, const char *sys, const char *name, void *handler){ struct evsel *evsel = evsel__newtp(sys, name); if (IS_ERR(evsel)) return -1; evsel->handler = handler; evlist__add(evlist, evsel); return 0;}#endif /* * Should sched_setaffinity be used with evlist__for_each_cpu? Determine if * migrating the thread will avoid possibly numerous IPIs. */static bool evlist__use_affinity(struct evlist *evlist){ struct evsel *pos; struct perf_cpu_map *used_cpus = NULL; bool ret = false; if (evlist__no_affinity(evlist) || !evlist__core(evlist)->user_requested_cpus || cpu_map__is_dummy(evlist__core(evlist)->user_requested_cpus)) return false; evlist__for_each_entry(evlist, pos) { struct perf_cpu_map *intersect; if (!perf_pmu__benefits_from_affinity(pos->pmu)) continue; if (evsel__is_dummy_event(pos)) { /* * The dummy event is opened on all CPUs so assume >1 * event with shared CPUs. */ ret = true; break; } if (evsel__is_retire_lat(pos)) { /* * Retirement latency events are similar to tool ones in * their implementation, and so don't require affinity. */ continue; } if (perf_cpu_map__is_empty(used_cpus)) { /* First benefitting event, we want >1 on a common CPU. */ used_cpus = perf_cpu_map__get(pos->core.cpus); continue; } if ((pos->core.attr.read_format & PERF_FORMAT_GROUP) && evsel__leader(pos) != pos) { /* Skip members of the same sample group. */ continue; } intersect = perf_cpu_map__intersect(used_cpus, pos->core.cpus); if (!perf_cpu_map__is_empty(intersect)) { /* >1 event with shared CPUs. */ perf_cpu_map__put(intersect); ret = true; break; } perf_cpu_map__put(intersect); perf_cpu_map__merge(&used_cpus, pos->core.cpus); } perf_cpu_map__put(used_cpus); return ret;} void evlist_cpu_iterator__init(struct evlist_cpu_iterator *itr, struct evlist *evlist){ *itr = (struct evlist_cpu_iterator){ .container = evlist, .evsel = NULL, .cpu_map_idx = 0, .evlist_cpu_map_idx = 0, .evlist_cpu_map_nr = perf_cpu_map__nr(evlist__core(evlist)->all_cpus), .cpu = (struct perf_cpu){ .cpu = -1}, .affinity = NULL, }; if (evlist__empty(evlist)) { /* Ensure the empty list doesn't iterate. */ itr->evlist_cpu_map_idx = itr->evlist_cpu_map_nr; return; } Lines 1–500 of 2798. Load more
// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> * * Parts came from builtin-{top,stat,record}.c, see those files for further * copyright notes. */ #include "evlist.h" #include <errno.h> #include <inttypes.h> #include <signal.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <linux/bitops.h> #include <linux/err.h> #include <linux/hash.h> #include <linux/log2.h> #include <linux/string.h> #include <linux/time64.h> #include <linux/zalloc.h> #include <poll.h> #include <sched.h> #include <sys/ioctl.h> #include <sys/mman.h> #include <sys/prctl.h> #include <sys/timerfd.h> #include <sys/wait.h> #include <unistd.h> #include <api/fs/fs.h> #include <internal/lib.h> // page_size #include <internal/rc_check.h> #include <internal/xyarray.h> #include <perf/cpumap.h> #include <perf/evlist.h> #include <perf/evsel.h> #include <perf/mmap.h> #include <subcmd/parse-options.h> #include "../perf.h" #include "affinity.h" #include "asm/bug.h" #include "bpf-event.h" #include "bpf-filter.h" #include "bpf_counter.h" #include "cpumap.h" #include "debug.h" #include "dwarf-regs.h" #include "env.h" #include "event.h" #include "evsel.h" #include "evsel_fprintf.h" #include "intel-tpebs.h" #include "metricgroup.h" #include "mmap.h" #include "parse-events.h" #include "perf_api_probe.h" #include "pmu.h" #include "pmus.h" #include "record.h" #include "sample.h" #include "stat.h" #include "strbuf.h" #include "string2.h" #include "target.h" #include "thread_map.h" #include "units.h" #include "util.h" #ifdef LACKS_SIGQUEUE_PROTOTYPE int sigqueue(pid_t pid, int sig, const union sigval value); #endif #define FD(e, x, y) (*(int *)xyarray__entry(e->core.fd, x, y)) #define SID(e, x, y) xyarray__entry(e->core.sample_id, x, y) static void event_enable_timer__exit(struct event_enable_timer **ep); struct evlist *evlist__new(void) { struct evlist *result; RC_STRUCT(evlist) *evlist; evlist = zalloc(sizeof(*evlist)); if (ADD_RC_CHK(result, evlist)) { perf_evlist__init(evlist__core(result)); perf_evlist__set_maps(evlist__core(result), /*cpus=*/NULL, /*threads=*/NULL); evlist__set_workload_pid(result, -1); evlist__set_bkw_mmap_state(result, BKW_MMAP_NOTREADY); evlist__set_ctl_fd_fd(result, -1); evlist__set_ctl_fd_ack(result, -1); evlist__set_ctl_fd_pos(result, -1); evlist__set_nr_br_cntr(result, -1); metricgroup__rblist_init(evlist__metric_events(result)); INIT_LIST_HEAD(&evlist->deferred_samples); refcount_set(evlist__refcnt(result), 1); } else { free(evlist); result = NULL; } return result; } struct evlist *evlist__new_default(const struct target *target, bool sample_callchains) { struct evlist *evlist = evlist__new(); bool can_profile_kernel; struct perf_pmu *pmu = NULL; char buf[256]; int err; if (!evlist) return NULL; can_profile_kernel = perf_event_paranoid_check(1); if (EM_HOST == EM_S390 && sample_callchains) { snprintf(buf, sizeof(buf), "software/%s/%s", target__has_cpu(target) ? "cpu-clock" : "task-clock", can_profile_kernel ? "P" : "Pu"); err = parse_event(evlist, buf); if (err) goto out_err; } else { while ((pmu = perf_pmus__scan_core(pmu)) != NULL) { snprintf(buf, sizeof(buf), "%s/cycles/%s", pmu->name, can_profile_kernel ? "P" : "Pu"); err = parse_event(evlist, buf); if (err) goto out_err; } } /* If there is only 1 event a sample identifier isn't necessary. */ if (evlist__nr_entries(evlist) > 1) { struct evsel *evsel; evlist__for_each_entry(evlist, evsel) evsel__set_sample_id(evsel, /*can_sample_identifier=*/false); } return evlist; out_err: evlist__put(evlist); return NULL; } struct evlist *evlist__new_dummy(void) { struct evlist *evlist = evlist__new(); if (evlist && evlist__add_dummy(evlist)) { evlist__put(evlist); evlist = NULL; } return evlist; } struct evlist *evlist__get(struct evlist *evlist) { struct evlist *result; if (RC_CHK_GET(result, evlist)) refcount_inc(evlist__refcnt(evlist)); return result; } /** * evlist__set_id_pos - set the positions of event ids. * @evlist: selected event list * * Events with compatible sample types all have the same id_pos * and is_pos. For convenience, put a copy on evlist. */ void evlist__set_id_pos(struct evlist *evlist) { struct evsel *first = evlist__first(evlist); RC_CHK_ACCESS(evlist)->id_pos = first->id_pos; RC_CHK_ACCESS(evlist)->is_pos = first->is_pos; } static void evlist__update_id_pos(struct evlist *evlist) { struct evsel *evsel; evlist__for_each_entry(evlist, evsel) evsel__calc_id_pos(evsel); evlist__set_id_pos(evlist); } static void evlist__purge(struct evlist *evlist) { struct evsel *pos, *n; evlist__for_each_entry_safe(evlist, n, pos) { list_del_init(&pos->core.node); if (pos->evlist) { if (!RC_CHK_EQUAL(pos->evlist, evlist)) { evlist__put(pos->evlist); } else { refcount_dec_and_test(evlist__refcnt(pos->evlist)); RC_CHK_PUT(pos->evlist); } } pos->evlist = NULL; evsel__put(pos); } evlist__core(evlist)->nr_entries = 0; } static void evlist__exit(struct evlist *evlist) { metricgroup__rblist_exit(evlist__metric_events(evlist)); event_enable_timer__exit(&RC_CHK_ACCESS(evlist)->eet); free(evlist__mmap(evlist)); free(evlist__overwrite_mmap(evlist)); perf_evlist__exit(evlist__core(evlist)); } void evlist__put(struct evlist *evlist) { struct evsel *evsel; unsigned int count, ref_cnt; if (evlist == NULL) return; if (refcount_dec_and_test(evlist__refcnt(evlist))) goto out_delete; retry: count = refcount_read(evlist__refcnt(evlist)); ref_cnt = count; evlist__for_each_entry(evlist, evsel) { if (RC_CHK_EQUAL(evsel->evlist, evlist) && count && refcount_read(&evsel->refcnt) == 1) count--; } if (refcount_read(evlist__refcnt(evlist)) != ref_cnt) goto retry; if (count != 0) { /* * Not the last reference except for back references from * evsels. */ RC_CHK_PUT(evlist); return; } out_delete: evlist__free_stats(evlist); evlist__do_munmap(evlist); evlist__close(evlist); evlist__purge(evlist); evlist__exit(evlist); RC_CHK_FREE(evlist); } void evlist__add(struct evlist *evlist, struct evsel *entry) { perf_evlist__add(evlist__core(evlist), &entry->core); evlist__put(entry->evlist); entry->evlist = evlist__get(evlist); entry->tracking = !entry->core.idx; if (evlist__nr_entries(evlist) == 1) evlist__set_id_pos(evlist); } void evlist__remove(struct evlist *evlist, struct evsel *evsel) { perf_evlist__remove(evlist__core(evlist), &evsel->core); evlist__put(evsel->evlist); evsel->evlist = NULL; } void evlist__splice_list_tail(struct evlist *evlist, struct list_head *list) { while (!list_empty(list)) { struct evsel *evsel, *temp, *leader = NULL; __evlist__for_each_entry_safe(list, temp, evsel) { list_del_init(&evsel->core.node); evlist__add(evlist, evsel); leader = evsel; break; } __evlist__for_each_entry_safe(list, temp, evsel) { if (evsel__has_leader(evsel, leader)) { list_del_init(&evsel->core.node); evlist__add(evlist, evsel); } } } } int __evlist__set_tracepoints_handlers(struct evlist *evlist, const struct evsel_str_handler *assocs, size_t nr_assocs) { size_t i; int err; for (i = 0; i < nr_assocs; i++) { // Adding a handler for an event not in this evlist, just ignore it. struct evsel *evsel = evlist__find_tracepoint_by_name(evlist, assocs[i].name); if (evsel == NULL) continue; err = -EEXIST; if (evsel->handler != NULL) goto out; evsel->handler = assocs[i].handler; } err = 0; out: return err; } static void evlist__set_leader(struct evlist *evlist) { perf_evlist__set_leader(evlist__core(evlist)); } static struct evsel *evlist__dummy_event(struct evlist *evlist) { struct perf_event_attr attr = { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_DUMMY, .size = sizeof(attr), /* to capture ABI version */ /* Avoid frequency mode for dummy events to avoid associated timers. */ .freq = 0, .sample_period = 1, }; return evsel__new_idx(&attr, evlist__nr_entries(evlist)); } int evlist__add_dummy(struct evlist *evlist) { struct evsel *evsel = evlist__dummy_event(evlist); if (evsel == NULL) return -ENOMEM; evlist__add(evlist, evsel); return 0; } struct evsel *evlist__add_aux_dummy(struct evlist *evlist, bool system_wide) { struct evsel *evsel = evlist__dummy_event(evlist); if (!evsel) return NULL; evsel->core.attr.exclude_kernel = 1; evsel->core.attr.exclude_guest = 1; evsel->core.attr.exclude_hv = 1; evsel->core.system_wide = system_wide; evsel->no_aux_samples = true; evsel->name = strdup("dummy:u"); evlist__add(evlist, evsel); return evsel; } #ifdef HAVE_LIBTRACEEVENT struct evsel *evlist__add_sched_switch(struct evlist *evlist, bool system_wide) { struct evsel *evsel = evsel__newtp_idx("sched", "sched_switch", 0, /*format=*/true); if (IS_ERR(evsel)) return evsel; evsel__set_sample_bit(evsel, CPU); evsel__set_sample_bit(evsel, TIME); evsel->core.system_wide = system_wide; evsel->no_aux_samples = true; evlist__add(evlist, evsel); return evsel; } #endif struct evsel *evlist__find_tracepoint_by_name(struct evlist *evlist, const char *name) { struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { if ((evsel->core.attr.type == PERF_TYPE_TRACEPOINT) && (strcmp(evsel->name, name) == 0)) return evsel; } return NULL; } #ifdef HAVE_LIBTRACEEVENT int evlist__add_newtp(struct evlist *evlist, const char *sys, const char *name, void *handler) { struct evsel *evsel = evsel__newtp(sys, name); if (IS_ERR(evsel)) return -1; evsel->handler = handler; evlist__add(evlist, evsel); return 0; } #endif /* * Should sched_setaffinity be used with evlist__for_each_cpu? Determine if * migrating the thread will avoid possibly numerous IPIs. */ static bool evlist__use_affinity(struct evlist *evlist) { struct evsel *pos; struct perf_cpu_map *used_cpus = NULL; bool ret = false; if (evlist__no_affinity(evlist) || !evlist__core(evlist)->user_requested_cpus || cpu_map__is_dummy(evlist__core(evlist)->user_requested_cpus)) return false; evlist__for_each_entry(evlist, pos) { struct perf_cpu_map *intersect; if (!perf_pmu__benefits_from_affinity(pos->pmu)) continue; if (evsel__is_dummy_event(pos)) { /* * The dummy event is opened on all CPUs so assume >1 * event with shared CPUs. */ ret = true; break; } if (evsel__is_retire_lat(pos)) { /* * Retirement latency events are similar to tool ones in * their implementation, and so don't require affinity. */ continue; } if (perf_cpu_map__is_empty(used_cpus)) { /* First benefitting event, we want >1 on a common CPU. */ used_cpus = perf_cpu_map__get(pos->core.cpus); continue; } if ((pos->core.attr.read_format & PERF_FORMAT_GROUP) && evsel__leader(pos) != pos) { /* Skip members of the same sample group. */ continue; } intersect = perf_cpu_map__intersect(used_cpus, pos->core.cpus); if (!perf_cpu_map__is_empty(intersect)) { /* >1 event with shared CPUs. */ perf_cpu_map__put(intersect); ret = true; break; } perf_cpu_map__put(intersect); perf_cpu_map__merge(&used_cpus, pos->core.cpus); } perf_cpu_map__put(used_cpus); return ret; } void evlist_cpu_iterator__init(struct evlist_cpu_iterator *itr, struct evlist *evlist) { *itr = (struct evlist_cpu_iterator){ .container = evlist, .evsel = NULL, .cpu_map_idx = 0, .evlist_cpu_map_idx = 0, .evlist_cpu_map_nr = perf_cpu_map__nr(evlist__core(evlist)->all_cpus), .cpu = (struct perf_cpu){ .cpu = -1}, .affinity = NULL, }; if (evlist__empty(evlist)) { /* Ensure the empty list doesn't iterate. */ itr->evlist_cpu_map_idx = itr->evlist_cpu_map_nr; return; }