xref: /openbmc/linux/tools/perf/util/ordered-events.c (revision d10eb1eb)
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