15f86b80bSJiri Olsa #include <linux/list.h> 2cee3ab9cSJiri Olsa #include <linux/compiler.h> 354bf53b1SAlexander Yarygin #include <linux/string.h> 45f86b80bSJiri Olsa #include "ordered-events.h" 55f86b80bSJiri Olsa #include "evlist.h" 65f86b80bSJiri Olsa #include "session.h" 75f86b80bSJiri Olsa #include "asm/bug.h" 85f86b80bSJiri Olsa #include "debug.h" 95f86b80bSJiri Olsa 10cee3ab9cSJiri Olsa #define pr_N(n, fmt, ...) \ 11cee3ab9cSJiri Olsa eprintf(n, debug_ordered_events, fmt, ##__VA_ARGS__) 12cee3ab9cSJiri Olsa 13cee3ab9cSJiri Olsa #define pr(fmt, ...) pr_N(1, pr_fmt(fmt), ##__VA_ARGS__) 14cee3ab9cSJiri Olsa 155f86b80bSJiri Olsa static void queue_event(struct ordered_events *oe, struct ordered_event *new) 165f86b80bSJiri Olsa { 175f86b80bSJiri Olsa struct ordered_event *last = oe->last; 185f86b80bSJiri Olsa u64 timestamp = new->timestamp; 195f86b80bSJiri Olsa struct list_head *p; 205f86b80bSJiri Olsa 215f86b80bSJiri Olsa ++oe->nr_events; 225f86b80bSJiri Olsa oe->last = new; 235f86b80bSJiri Olsa 24cee3ab9cSJiri Olsa pr_oe_time2(timestamp, "queue_event nr_events %u\n", oe->nr_events); 25cee3ab9cSJiri Olsa 265f86b80bSJiri Olsa if (!last) { 275f86b80bSJiri Olsa list_add(&new->list, &oe->events); 285f86b80bSJiri Olsa oe->max_timestamp = timestamp; 295f86b80bSJiri Olsa return; 305f86b80bSJiri Olsa } 315f86b80bSJiri Olsa 325f86b80bSJiri Olsa /* 335f86b80bSJiri Olsa * last event might point to some random place in the list as it's 345f86b80bSJiri Olsa * the last queued event. We expect that the new event is close to 355f86b80bSJiri Olsa * this. 365f86b80bSJiri Olsa */ 375f86b80bSJiri Olsa if (last->timestamp <= timestamp) { 385f86b80bSJiri Olsa while (last->timestamp <= timestamp) { 395f86b80bSJiri Olsa p = last->list.next; 405f86b80bSJiri Olsa if (p == &oe->events) { 415f86b80bSJiri Olsa list_add_tail(&new->list, &oe->events); 425f86b80bSJiri Olsa oe->max_timestamp = timestamp; 435f86b80bSJiri Olsa return; 445f86b80bSJiri Olsa } 455f86b80bSJiri Olsa last = list_entry(p, struct ordered_event, list); 465f86b80bSJiri Olsa } 475f86b80bSJiri Olsa list_add_tail(&new->list, &last->list); 485f86b80bSJiri Olsa } else { 495f86b80bSJiri Olsa while (last->timestamp > timestamp) { 505f86b80bSJiri Olsa p = last->list.prev; 515f86b80bSJiri Olsa if (p == &oe->events) { 525f86b80bSJiri Olsa list_add(&new->list, &oe->events); 535f86b80bSJiri Olsa return; 545f86b80bSJiri Olsa } 555f86b80bSJiri Olsa last = list_entry(p, struct ordered_event, list); 565f86b80bSJiri Olsa } 575f86b80bSJiri Olsa list_add(&new->list, &last->list); 585f86b80bSJiri Olsa } 595f86b80bSJiri Olsa } 605f86b80bSJiri Olsa 6154bf53b1SAlexander Yarygin static union perf_event *__dup_event(struct ordered_events *oe, 6254bf53b1SAlexander Yarygin union perf_event *event) 6354bf53b1SAlexander Yarygin { 6454bf53b1SAlexander Yarygin union perf_event *new_event = NULL; 6554bf53b1SAlexander Yarygin 6654bf53b1SAlexander Yarygin if (oe->cur_alloc_size < oe->max_alloc_size) { 6754bf53b1SAlexander Yarygin new_event = memdup(event, event->header.size); 6854bf53b1SAlexander Yarygin if (new_event) 6954bf53b1SAlexander Yarygin oe->cur_alloc_size += event->header.size; 7054bf53b1SAlexander Yarygin } 7154bf53b1SAlexander Yarygin 7254bf53b1SAlexander Yarygin return new_event; 7354bf53b1SAlexander Yarygin } 7454bf53b1SAlexander Yarygin 7554bf53b1SAlexander Yarygin static union perf_event *dup_event(struct ordered_events *oe, 7654bf53b1SAlexander Yarygin union perf_event *event) 7754bf53b1SAlexander Yarygin { 7854bf53b1SAlexander Yarygin return oe->copy_on_queue ? __dup_event(oe, event) : event; 7954bf53b1SAlexander Yarygin } 8054bf53b1SAlexander Yarygin 8154bf53b1SAlexander Yarygin static void free_dup_event(struct ordered_events *oe, union perf_event *event) 8254bf53b1SAlexander Yarygin { 8354bf53b1SAlexander Yarygin if (oe->copy_on_queue) { 8454bf53b1SAlexander Yarygin oe->cur_alloc_size -= event->header.size; 8554bf53b1SAlexander Yarygin free(event); 8654bf53b1SAlexander Yarygin } 8754bf53b1SAlexander Yarygin } 8854bf53b1SAlexander Yarygin 895f86b80bSJiri Olsa #define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct ordered_event)) 9054bf53b1SAlexander Yarygin static struct ordered_event *alloc_event(struct ordered_events *oe, 9154bf53b1SAlexander Yarygin union perf_event *event) 925f86b80bSJiri Olsa { 935f86b80bSJiri Olsa struct list_head *cache = &oe->cache; 945f86b80bSJiri Olsa struct ordered_event *new = NULL; 9554bf53b1SAlexander Yarygin union perf_event *new_event; 9654bf53b1SAlexander Yarygin 9754bf53b1SAlexander Yarygin new_event = dup_event(oe, event); 9854bf53b1SAlexander Yarygin if (!new_event) 9954bf53b1SAlexander Yarygin return NULL; 1005f86b80bSJiri Olsa 1015f86b80bSJiri Olsa if (!list_empty(cache)) { 1025f86b80bSJiri Olsa new = list_entry(cache->next, struct ordered_event, list); 1035f86b80bSJiri Olsa list_del(&new->list); 1045f86b80bSJiri Olsa } else if (oe->buffer) { 1055f86b80bSJiri Olsa new = oe->buffer + oe->buffer_idx; 1065f86b80bSJiri Olsa if (++oe->buffer_idx == MAX_SAMPLE_BUFFER) 1075f86b80bSJiri Olsa oe->buffer = NULL; 1085f86b80bSJiri Olsa } else if (oe->cur_alloc_size < oe->max_alloc_size) { 1095f86b80bSJiri Olsa size_t size = MAX_SAMPLE_BUFFER * sizeof(*new); 1105f86b80bSJiri Olsa 1115f86b80bSJiri Olsa oe->buffer = malloc(size); 11254bf53b1SAlexander Yarygin if (!oe->buffer) { 11354bf53b1SAlexander Yarygin free_dup_event(oe, new_event); 1145f86b80bSJiri Olsa return NULL; 11554bf53b1SAlexander Yarygin } 1165f86b80bSJiri Olsa 117cee3ab9cSJiri Olsa pr("alloc size %" PRIu64 "B (+%zu), max %" PRIu64 "B\n", 118cee3ab9cSJiri Olsa oe->cur_alloc_size, size, oe->max_alloc_size); 119cee3ab9cSJiri Olsa 1205f86b80bSJiri Olsa oe->cur_alloc_size += size; 1215f86b80bSJiri Olsa list_add(&oe->buffer->list, &oe->to_free); 1225f86b80bSJiri Olsa 1235f86b80bSJiri Olsa /* First entry is abused to maintain the to_free list. */ 1245f86b80bSJiri Olsa oe->buffer_idx = 2; 1255f86b80bSJiri Olsa new = oe->buffer + 1; 126cee3ab9cSJiri Olsa } else { 127cee3ab9cSJiri Olsa pr("allocation limit reached %" PRIu64 "B\n", oe->max_alloc_size); 1285f86b80bSJiri Olsa } 1295f86b80bSJiri Olsa 13054bf53b1SAlexander Yarygin new->event = new_event; 1315f86b80bSJiri Olsa return new; 1325f86b80bSJiri Olsa } 1335f86b80bSJiri Olsa 1345f86b80bSJiri Olsa struct ordered_event * 13554bf53b1SAlexander Yarygin ordered_events__new(struct ordered_events *oe, u64 timestamp, 13654bf53b1SAlexander Yarygin union perf_event *event) 1375f86b80bSJiri Olsa { 1385f86b80bSJiri Olsa struct ordered_event *new; 1395f86b80bSJiri Olsa 14054bf53b1SAlexander Yarygin new = alloc_event(oe, event); 1415f86b80bSJiri Olsa if (new) { 1425f86b80bSJiri Olsa new->timestamp = timestamp; 1435f86b80bSJiri Olsa queue_event(oe, new); 1445f86b80bSJiri Olsa } 1455f86b80bSJiri Olsa 1465f86b80bSJiri Olsa return new; 1475f86b80bSJiri Olsa } 1485f86b80bSJiri Olsa 1495f86b80bSJiri Olsa void ordered_events__delete(struct ordered_events *oe, struct ordered_event *event) 1505f86b80bSJiri Olsa { 151fa4e5c67SJiri Olsa list_move(&event->list, &oe->cache); 1525f86b80bSJiri Olsa oe->nr_events--; 15354bf53b1SAlexander Yarygin free_dup_event(oe, event->event); 1545f86b80bSJiri Olsa } 1555f86b80bSJiri Olsa 156b7b61cbeSArnaldo Carvalho de Melo static int __ordered_events__flush(struct ordered_events *oe) 1575f86b80bSJiri Olsa { 1585f86b80bSJiri Olsa struct list_head *head = &oe->events; 1595f86b80bSJiri Olsa struct ordered_event *tmp, *iter; 1605f86b80bSJiri Olsa struct perf_sample sample; 1615f86b80bSJiri Olsa u64 limit = oe->next_flush; 1625f86b80bSJiri Olsa u64 last_ts = oe->last ? oe->last->timestamp : 0ULL; 1635f86b80bSJiri Olsa bool show_progress = limit == ULLONG_MAX; 1645f86b80bSJiri Olsa struct ui_progress prog; 1655f86b80bSJiri Olsa int ret; 1665f86b80bSJiri Olsa 16728083681SArnaldo Carvalho de Melo if (!limit) 1685f86b80bSJiri Olsa return 0; 1695f86b80bSJiri Olsa 1705f86b80bSJiri Olsa if (show_progress) 1715f86b80bSJiri Olsa ui_progress__init(&prog, oe->nr_events, "Processing time ordered events..."); 1725f86b80bSJiri Olsa 1735f86b80bSJiri Olsa list_for_each_entry_safe(iter, tmp, head, list) { 1745f86b80bSJiri Olsa if (session_done()) 1755f86b80bSJiri Olsa return 0; 1765f86b80bSJiri Olsa 1775f86b80bSJiri Olsa if (iter->timestamp > limit) 1785f86b80bSJiri Olsa break; 1795f86b80bSJiri Olsa 180b7b61cbeSArnaldo Carvalho de Melo ret = perf_evlist__parse_sample(oe->evlist, iter->event, &sample); 1815f86b80bSJiri Olsa if (ret) 1825f86b80bSJiri Olsa pr_err("Can't parse sample, err = %d\n", ret); 1835f86b80bSJiri Olsa else { 184d10eb1ebSArnaldo Carvalho de Melo ret = oe->deliver(oe, iter, &sample); 1855f86b80bSJiri Olsa if (ret) 1865f86b80bSJiri Olsa return ret; 1875f86b80bSJiri Olsa } 1885f86b80bSJiri Olsa 1895f86b80bSJiri Olsa ordered_events__delete(oe, iter); 1905f86b80bSJiri Olsa oe->last_flush = iter->timestamp; 1915f86b80bSJiri Olsa 1925f86b80bSJiri Olsa if (show_progress) 1935f86b80bSJiri Olsa ui_progress__update(&prog, 1); 1945f86b80bSJiri Olsa } 1955f86b80bSJiri Olsa 1965f86b80bSJiri Olsa if (list_empty(head)) 1975f86b80bSJiri Olsa oe->last = NULL; 1985f86b80bSJiri Olsa else if (last_ts <= limit) 1995f86b80bSJiri Olsa oe->last = list_entry(head->prev, struct ordered_event, list); 2005f86b80bSJiri Olsa 2015f86b80bSJiri Olsa return 0; 2025f86b80bSJiri Olsa } 2035f86b80bSJiri Olsa 204b7b61cbeSArnaldo Carvalho de Melo int ordered_events__flush(struct ordered_events *oe, enum oe_flush how) 2055f86b80bSJiri Olsa { 206cee3ab9cSJiri Olsa static const char * const str[] = { 207b0a45203SJiri Olsa "NONE", 208cee3ab9cSJiri Olsa "FINAL", 209cee3ab9cSJiri Olsa "ROUND", 210cee3ab9cSJiri Olsa "HALF ", 211cee3ab9cSJiri Olsa }; 2125f86b80bSJiri Olsa int err; 2135f86b80bSJiri Olsa 21428083681SArnaldo Carvalho de Melo if (oe->nr_events == 0) 21528083681SArnaldo Carvalho de Melo return 0; 21628083681SArnaldo Carvalho de Melo 2175f86b80bSJiri Olsa switch (how) { 2185f86b80bSJiri Olsa case OE_FLUSH__FINAL: 2195f86b80bSJiri Olsa oe->next_flush = ULLONG_MAX; 2205f86b80bSJiri Olsa break; 2215f86b80bSJiri Olsa 2225f86b80bSJiri Olsa case OE_FLUSH__HALF: 2235f86b80bSJiri Olsa { 2245f86b80bSJiri Olsa struct ordered_event *first, *last; 2255f86b80bSJiri Olsa struct list_head *head = &oe->events; 2265f86b80bSJiri Olsa 2275f86b80bSJiri Olsa first = list_entry(head->next, struct ordered_event, list); 2285f86b80bSJiri Olsa last = oe->last; 2295f86b80bSJiri Olsa 2305f86b80bSJiri Olsa /* Warn if we are called before any event got allocated. */ 2315f86b80bSJiri Olsa if (WARN_ONCE(!last || list_empty(head), "empty queue")) 2325f86b80bSJiri Olsa return 0; 2335f86b80bSJiri Olsa 2345f86b80bSJiri Olsa oe->next_flush = first->timestamp; 2355f86b80bSJiri Olsa oe->next_flush += (last->timestamp - first->timestamp) / 2; 2365f86b80bSJiri Olsa break; 2375f86b80bSJiri Olsa } 2385f86b80bSJiri Olsa 2395f86b80bSJiri Olsa case OE_FLUSH__ROUND: 240b0a45203SJiri Olsa case OE_FLUSH__NONE: 2415f86b80bSJiri Olsa default: 2425f86b80bSJiri Olsa break; 2435f86b80bSJiri Olsa }; 2445f86b80bSJiri Olsa 245cee3ab9cSJiri Olsa pr_oe_time(oe->next_flush, "next_flush - ordered_events__flush PRE %s, nr_events %u\n", 246cee3ab9cSJiri Olsa str[how], oe->nr_events); 247cee3ab9cSJiri Olsa pr_oe_time(oe->max_timestamp, "max_timestamp\n"); 248cee3ab9cSJiri Olsa 249b7b61cbeSArnaldo Carvalho de Melo err = __ordered_events__flush(oe); 2505f86b80bSJiri Olsa 2515f86b80bSJiri Olsa if (!err) { 2525f86b80bSJiri Olsa if (how == OE_FLUSH__ROUND) 2535f86b80bSJiri Olsa oe->next_flush = oe->max_timestamp; 254b0a45203SJiri Olsa 255b0a45203SJiri Olsa oe->last_flush_type = how; 2565f86b80bSJiri Olsa } 2575f86b80bSJiri Olsa 258cee3ab9cSJiri Olsa pr_oe_time(oe->next_flush, "next_flush - ordered_events__flush POST %s, nr_events %u\n", 259cee3ab9cSJiri Olsa str[how], oe->nr_events); 260cee3ab9cSJiri Olsa pr_oe_time(oe->last_flush, "last_flush\n"); 261cee3ab9cSJiri Olsa 2625f86b80bSJiri Olsa return err; 2635f86b80bSJiri Olsa } 26436522f5cSJiri Olsa 265b7b61cbeSArnaldo Carvalho de Melo void ordered_events__init(struct ordered_events *oe, struct machines *machines, 266d10eb1ebSArnaldo Carvalho de Melo struct perf_evlist *evlist, struct perf_tool *tool, 267d10eb1ebSArnaldo Carvalho de Melo ordered_events__deliver_t deliver) 26836522f5cSJiri Olsa { 26936522f5cSJiri Olsa INIT_LIST_HEAD(&oe->events); 27036522f5cSJiri Olsa INIT_LIST_HEAD(&oe->cache); 27136522f5cSJiri Olsa INIT_LIST_HEAD(&oe->to_free); 27236522f5cSJiri Olsa oe->max_alloc_size = (u64) -1; 27336522f5cSJiri Olsa oe->cur_alloc_size = 0; 274b7b61cbeSArnaldo Carvalho de Melo oe->evlist = evlist; 275b7b61cbeSArnaldo Carvalho de Melo oe->machines = machines; 276b7b61cbeSArnaldo Carvalho de Melo oe->tool = tool; 277d10eb1ebSArnaldo Carvalho de Melo oe->deliver = deliver; 27836522f5cSJiri Olsa } 279adc56ed1SJiri Olsa 280adc56ed1SJiri Olsa void ordered_events__free(struct ordered_events *oe) 281adc56ed1SJiri Olsa { 282adc56ed1SJiri Olsa while (!list_empty(&oe->to_free)) { 283adc56ed1SJiri Olsa struct ordered_event *event; 284adc56ed1SJiri Olsa 285adc56ed1SJiri Olsa event = list_entry(oe->to_free.next, struct ordered_event, list); 286adc56ed1SJiri Olsa list_del(&event->list); 28754bf53b1SAlexander Yarygin free_dup_event(oe, event->event); 288adc56ed1SJiri Olsa free(event); 289adc56ed1SJiri Olsa } 290adc56ed1SJiri Olsa } 291