15c581041SArnaldo Carvalho de Melo #include <poll.h> 2361c99a6SArnaldo Carvalho de Melo #include "evlist.h" 3361c99a6SArnaldo Carvalho de Melo #include "evsel.h" 4361c99a6SArnaldo Carvalho de Melo #include "util.h" 5361c99a6SArnaldo Carvalho de Melo 670db7533SArnaldo Carvalho de Melo #include <linux/bitops.h> 770db7533SArnaldo Carvalho de Melo #include <linux/hash.h> 870db7533SArnaldo Carvalho de Melo 9ef1d1af2SArnaldo Carvalho de Melo void perf_evlist__init(struct perf_evlist *evlist) 10361c99a6SArnaldo Carvalho de Melo { 1170db7533SArnaldo Carvalho de Melo int i; 1270db7533SArnaldo Carvalho de Melo 1370db7533SArnaldo Carvalho de Melo for (i = 0; i < PERF_EVLIST__HLIST_SIZE; ++i) 1470db7533SArnaldo Carvalho de Melo INIT_HLIST_HEAD(&evlist->heads[i]); 15361c99a6SArnaldo Carvalho de Melo INIT_LIST_HEAD(&evlist->entries); 16361c99a6SArnaldo Carvalho de Melo } 17361c99a6SArnaldo Carvalho de Melo 18ef1d1af2SArnaldo Carvalho de Melo struct perf_evlist *perf_evlist__new(void) 19ef1d1af2SArnaldo Carvalho de Melo { 20ef1d1af2SArnaldo Carvalho de Melo struct perf_evlist *evlist = zalloc(sizeof(*evlist)); 21ef1d1af2SArnaldo Carvalho de Melo 22ef1d1af2SArnaldo Carvalho de Melo if (evlist != NULL) 23ef1d1af2SArnaldo Carvalho de Melo perf_evlist__init(evlist); 24ef1d1af2SArnaldo Carvalho de Melo 25361c99a6SArnaldo Carvalho de Melo return evlist; 26361c99a6SArnaldo Carvalho de Melo } 27361c99a6SArnaldo Carvalho de Melo 28361c99a6SArnaldo Carvalho de Melo static void perf_evlist__purge(struct perf_evlist *evlist) 29361c99a6SArnaldo Carvalho de Melo { 30361c99a6SArnaldo Carvalho de Melo struct perf_evsel *pos, *n; 31361c99a6SArnaldo Carvalho de Melo 32361c99a6SArnaldo Carvalho de Melo list_for_each_entry_safe(pos, n, &evlist->entries, node) { 33361c99a6SArnaldo Carvalho de Melo list_del_init(&pos->node); 34361c99a6SArnaldo Carvalho de Melo perf_evsel__delete(pos); 35361c99a6SArnaldo Carvalho de Melo } 36361c99a6SArnaldo Carvalho de Melo 37361c99a6SArnaldo Carvalho de Melo evlist->nr_entries = 0; 38361c99a6SArnaldo Carvalho de Melo } 39361c99a6SArnaldo Carvalho de Melo 40ef1d1af2SArnaldo Carvalho de Melo void perf_evlist__exit(struct perf_evlist *evlist) 41ef1d1af2SArnaldo Carvalho de Melo { 42ef1d1af2SArnaldo Carvalho de Melo free(evlist->mmap); 43ef1d1af2SArnaldo Carvalho de Melo free(evlist->pollfd); 44ef1d1af2SArnaldo Carvalho de Melo evlist->mmap = NULL; 45ef1d1af2SArnaldo Carvalho de Melo evlist->pollfd = NULL; 46ef1d1af2SArnaldo Carvalho de Melo } 47ef1d1af2SArnaldo Carvalho de Melo 48361c99a6SArnaldo Carvalho de Melo void perf_evlist__delete(struct perf_evlist *evlist) 49361c99a6SArnaldo Carvalho de Melo { 50361c99a6SArnaldo Carvalho de Melo perf_evlist__purge(evlist); 51ef1d1af2SArnaldo Carvalho de Melo perf_evlist__exit(evlist); 52361c99a6SArnaldo Carvalho de Melo free(evlist); 53361c99a6SArnaldo Carvalho de Melo } 54361c99a6SArnaldo Carvalho de Melo 55361c99a6SArnaldo Carvalho de Melo void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry) 56361c99a6SArnaldo Carvalho de Melo { 57361c99a6SArnaldo Carvalho de Melo list_add_tail(&entry->node, &evlist->entries); 58361c99a6SArnaldo Carvalho de Melo ++evlist->nr_entries; 59361c99a6SArnaldo Carvalho de Melo } 60361c99a6SArnaldo Carvalho de Melo 61361c99a6SArnaldo Carvalho de Melo int perf_evlist__add_default(struct perf_evlist *evlist) 62361c99a6SArnaldo Carvalho de Melo { 63361c99a6SArnaldo Carvalho de Melo struct perf_event_attr attr = { 64361c99a6SArnaldo Carvalho de Melo .type = PERF_TYPE_HARDWARE, 65361c99a6SArnaldo Carvalho de Melo .config = PERF_COUNT_HW_CPU_CYCLES, 66361c99a6SArnaldo Carvalho de Melo }; 67361c99a6SArnaldo Carvalho de Melo struct perf_evsel *evsel = perf_evsel__new(&attr, 0); 68361c99a6SArnaldo Carvalho de Melo 69361c99a6SArnaldo Carvalho de Melo if (evsel == NULL) 70361c99a6SArnaldo Carvalho de Melo return -ENOMEM; 71361c99a6SArnaldo Carvalho de Melo 72361c99a6SArnaldo Carvalho de Melo perf_evlist__add(evlist, evsel); 73361c99a6SArnaldo Carvalho de Melo return 0; 74361c99a6SArnaldo Carvalho de Melo } 755c581041SArnaldo Carvalho de Melo 765c581041SArnaldo Carvalho de Melo int perf_evlist__alloc_pollfd(struct perf_evlist *evlist, int ncpus, int nthreads) 775c581041SArnaldo Carvalho de Melo { 785c581041SArnaldo Carvalho de Melo int nfds = ncpus * nthreads * evlist->nr_entries; 795c581041SArnaldo Carvalho de Melo evlist->pollfd = malloc(sizeof(struct pollfd) * nfds); 805c581041SArnaldo Carvalho de Melo return evlist->pollfd != NULL ? 0 : -ENOMEM; 815c581041SArnaldo Carvalho de Melo } 8270082dd9SArnaldo Carvalho de Melo 8370082dd9SArnaldo Carvalho de Melo void perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd) 8470082dd9SArnaldo Carvalho de Melo { 8570082dd9SArnaldo Carvalho de Melo fcntl(fd, F_SETFL, O_NONBLOCK); 8670082dd9SArnaldo Carvalho de Melo evlist->pollfd[evlist->nr_fds].fd = fd; 8770082dd9SArnaldo Carvalho de Melo evlist->pollfd[evlist->nr_fds].events = POLLIN; 8870082dd9SArnaldo Carvalho de Melo evlist->nr_fds++; 8970082dd9SArnaldo Carvalho de Melo } 9070db7533SArnaldo Carvalho de Melo 9170db7533SArnaldo Carvalho de Melo struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id) 9270db7533SArnaldo Carvalho de Melo { 9370db7533SArnaldo Carvalho de Melo struct hlist_head *head; 9470db7533SArnaldo Carvalho de Melo struct hlist_node *pos; 9570db7533SArnaldo Carvalho de Melo struct perf_sample_id *sid; 9670db7533SArnaldo Carvalho de Melo int hash; 9770db7533SArnaldo Carvalho de Melo 9870db7533SArnaldo Carvalho de Melo if (evlist->nr_entries == 1) 9970db7533SArnaldo Carvalho de Melo return list_entry(evlist->entries.next, struct perf_evsel, node); 10070db7533SArnaldo Carvalho de Melo 10170db7533SArnaldo Carvalho de Melo hash = hash_64(id, PERF_EVLIST__HLIST_BITS); 10270db7533SArnaldo Carvalho de Melo head = &evlist->heads[hash]; 10370db7533SArnaldo Carvalho de Melo 10470db7533SArnaldo Carvalho de Melo hlist_for_each_entry(sid, pos, head, node) 10570db7533SArnaldo Carvalho de Melo if (sid->id == id) 10670db7533SArnaldo Carvalho de Melo return sid->evsel; 10770db7533SArnaldo Carvalho de Melo return NULL; 10870db7533SArnaldo Carvalho de Melo } 10904391debSArnaldo Carvalho de Melo 1108115d60cSArnaldo Carvalho de Melo union perf_event *perf_evlist__read_on_cpu(struct perf_evlist *evlist, int cpu) 11104391debSArnaldo Carvalho de Melo { 11204391debSArnaldo Carvalho de Melo /* XXX Move this to perf.c, making it generally available */ 11304391debSArnaldo Carvalho de Melo unsigned int page_size = sysconf(_SC_PAGE_SIZE); 11404391debSArnaldo Carvalho de Melo struct perf_mmap *md = &evlist->mmap[cpu]; 11504391debSArnaldo Carvalho de Melo unsigned int head = perf_mmap__read_head(md); 11604391debSArnaldo Carvalho de Melo unsigned int old = md->prev; 11704391debSArnaldo Carvalho de Melo unsigned char *data = md->base + page_size; 1188115d60cSArnaldo Carvalho de Melo union perf_event *event = NULL; 11904391debSArnaldo Carvalho de Melo 1207bb41152SArnaldo Carvalho de Melo if (evlist->overwrite) { 12104391debSArnaldo Carvalho de Melo /* 12204391debSArnaldo Carvalho de Melo * If we're further behind than half the buffer, there's a chance 12304391debSArnaldo Carvalho de Melo * the writer will bite our tail and mess up the samples under us. 12404391debSArnaldo Carvalho de Melo * 12504391debSArnaldo Carvalho de Melo * If we somehow ended up ahead of the head, we got messed up. 12604391debSArnaldo Carvalho de Melo * 12704391debSArnaldo Carvalho de Melo * In either case, truncate and restart at head. 12804391debSArnaldo Carvalho de Melo */ 1297bb41152SArnaldo Carvalho de Melo int diff = head - old; 13004391debSArnaldo Carvalho de Melo if (diff > md->mask / 2 || diff < 0) { 13104391debSArnaldo Carvalho de Melo fprintf(stderr, "WARNING: failed to keep up with mmap data.\n"); 13204391debSArnaldo Carvalho de Melo 13304391debSArnaldo Carvalho de Melo /* 13404391debSArnaldo Carvalho de Melo * head points to a known good entry, start there. 13504391debSArnaldo Carvalho de Melo */ 13604391debSArnaldo Carvalho de Melo old = head; 13704391debSArnaldo Carvalho de Melo } 1387bb41152SArnaldo Carvalho de Melo } 13904391debSArnaldo Carvalho de Melo 14004391debSArnaldo Carvalho de Melo if (old != head) { 14104391debSArnaldo Carvalho de Melo size_t size; 14204391debSArnaldo Carvalho de Melo 1438115d60cSArnaldo Carvalho de Melo event = (union perf_event *)&data[old & md->mask]; 14404391debSArnaldo Carvalho de Melo size = event->header.size; 14504391debSArnaldo Carvalho de Melo 14604391debSArnaldo Carvalho de Melo /* 14704391debSArnaldo Carvalho de Melo * Event straddles the mmap boundary -- header should always 14804391debSArnaldo Carvalho de Melo * be inside due to u64 alignment of output. 14904391debSArnaldo Carvalho de Melo */ 15004391debSArnaldo Carvalho de Melo if ((old & md->mask) + size != ((old + size) & md->mask)) { 15104391debSArnaldo Carvalho de Melo unsigned int offset = old; 15204391debSArnaldo Carvalho de Melo unsigned int len = min(sizeof(*event), size), cpy; 15304391debSArnaldo Carvalho de Melo void *dst = &evlist->event_copy; 15404391debSArnaldo Carvalho de Melo 15504391debSArnaldo Carvalho de Melo do { 15604391debSArnaldo Carvalho de Melo cpy = min(md->mask + 1 - (offset & md->mask), len); 15704391debSArnaldo Carvalho de Melo memcpy(dst, &data[offset & md->mask], cpy); 15804391debSArnaldo Carvalho de Melo offset += cpy; 15904391debSArnaldo Carvalho de Melo dst += cpy; 16004391debSArnaldo Carvalho de Melo len -= cpy; 16104391debSArnaldo Carvalho de Melo } while (len); 16204391debSArnaldo Carvalho de Melo 16304391debSArnaldo Carvalho de Melo event = &evlist->event_copy; 16404391debSArnaldo Carvalho de Melo } 16504391debSArnaldo Carvalho de Melo 16604391debSArnaldo Carvalho de Melo old += size; 16704391debSArnaldo Carvalho de Melo } 16804391debSArnaldo Carvalho de Melo 16904391debSArnaldo Carvalho de Melo md->prev = old; 1707bb41152SArnaldo Carvalho de Melo 1717bb41152SArnaldo Carvalho de Melo if (!evlist->overwrite) 1727bb41152SArnaldo Carvalho de Melo perf_mmap__write_tail(md, old); 1737bb41152SArnaldo Carvalho de Melo 17404391debSArnaldo Carvalho de Melo return event; 17504391debSArnaldo Carvalho de Melo } 176