xref: /openbmc/linux/tools/perf/util/ordered-events.c (revision fa4e5c67)
15f86b80bSJiri Olsa #include <linux/list.h>
25f86b80bSJiri Olsa #include "ordered-events.h"
35f86b80bSJiri Olsa #include "evlist.h"
45f86b80bSJiri Olsa #include "session.h"
55f86b80bSJiri Olsa #include "asm/bug.h"
65f86b80bSJiri Olsa #include "debug.h"
75f86b80bSJiri Olsa 
85f86b80bSJiri Olsa static void queue_event(struct ordered_events *oe, struct ordered_event *new)
95f86b80bSJiri Olsa {
105f86b80bSJiri Olsa 	struct ordered_event *last = oe->last;
115f86b80bSJiri Olsa 	u64 timestamp = new->timestamp;
125f86b80bSJiri Olsa 	struct list_head *p;
135f86b80bSJiri Olsa 
145f86b80bSJiri Olsa 	++oe->nr_events;
155f86b80bSJiri Olsa 	oe->last = new;
165f86b80bSJiri Olsa 
175f86b80bSJiri Olsa 	if (!last) {
185f86b80bSJiri Olsa 		list_add(&new->list, &oe->events);
195f86b80bSJiri Olsa 		oe->max_timestamp = timestamp;
205f86b80bSJiri Olsa 		return;
215f86b80bSJiri Olsa 	}
225f86b80bSJiri Olsa 
235f86b80bSJiri Olsa 	/*
245f86b80bSJiri Olsa 	 * last event might point to some random place in the list as it's
255f86b80bSJiri Olsa 	 * the last queued event. We expect that the new event is close to
265f86b80bSJiri Olsa 	 * this.
275f86b80bSJiri Olsa 	 */
285f86b80bSJiri Olsa 	if (last->timestamp <= timestamp) {
295f86b80bSJiri Olsa 		while (last->timestamp <= timestamp) {
305f86b80bSJiri Olsa 			p = last->list.next;
315f86b80bSJiri Olsa 			if (p == &oe->events) {
325f86b80bSJiri Olsa 				list_add_tail(&new->list, &oe->events);
335f86b80bSJiri Olsa 				oe->max_timestamp = timestamp;
345f86b80bSJiri Olsa 				return;
355f86b80bSJiri Olsa 			}
365f86b80bSJiri Olsa 			last = list_entry(p, struct ordered_event, list);
375f86b80bSJiri Olsa 		}
385f86b80bSJiri Olsa 		list_add_tail(&new->list, &last->list);
395f86b80bSJiri Olsa 	} else {
405f86b80bSJiri Olsa 		while (last->timestamp > timestamp) {
415f86b80bSJiri Olsa 			p = last->list.prev;
425f86b80bSJiri Olsa 			if (p == &oe->events) {
435f86b80bSJiri Olsa 				list_add(&new->list, &oe->events);
445f86b80bSJiri Olsa 				return;
455f86b80bSJiri Olsa 			}
465f86b80bSJiri Olsa 			last = list_entry(p, struct ordered_event, list);
475f86b80bSJiri Olsa 		}
485f86b80bSJiri Olsa 		list_add(&new->list, &last->list);
495f86b80bSJiri Olsa 	}
505f86b80bSJiri Olsa }
515f86b80bSJiri Olsa 
525f86b80bSJiri Olsa #define MAX_SAMPLE_BUFFER	(64 * 1024 / sizeof(struct ordered_event))
535f86b80bSJiri Olsa static struct ordered_event *alloc_event(struct ordered_events *oe)
545f86b80bSJiri Olsa {
555f86b80bSJiri Olsa 	struct list_head *cache = &oe->cache;
565f86b80bSJiri Olsa 	struct ordered_event *new = NULL;
575f86b80bSJiri Olsa 
585f86b80bSJiri Olsa 	if (!list_empty(cache)) {
595f86b80bSJiri Olsa 		new = list_entry(cache->next, struct ordered_event, list);
605f86b80bSJiri Olsa 		list_del(&new->list);
615f86b80bSJiri Olsa 	} else if (oe->buffer) {
625f86b80bSJiri Olsa 		new = oe->buffer + oe->buffer_idx;
635f86b80bSJiri Olsa 		if (++oe->buffer_idx == MAX_SAMPLE_BUFFER)
645f86b80bSJiri Olsa 			oe->buffer = NULL;
655f86b80bSJiri Olsa 	} else if (oe->cur_alloc_size < oe->max_alloc_size) {
665f86b80bSJiri Olsa 		size_t size = MAX_SAMPLE_BUFFER * sizeof(*new);
675f86b80bSJiri Olsa 
685f86b80bSJiri Olsa 		oe->buffer = malloc(size);
695f86b80bSJiri Olsa 		if (!oe->buffer)
705f86b80bSJiri Olsa 			return NULL;
715f86b80bSJiri Olsa 
725f86b80bSJiri Olsa 		oe->cur_alloc_size += size;
735f86b80bSJiri Olsa 		list_add(&oe->buffer->list, &oe->to_free);
745f86b80bSJiri Olsa 
755f86b80bSJiri Olsa 		/* First entry is abused to maintain the to_free list. */
765f86b80bSJiri Olsa 		oe->buffer_idx = 2;
775f86b80bSJiri Olsa 		new = oe->buffer + 1;
785f86b80bSJiri Olsa 	}
795f86b80bSJiri Olsa 
805f86b80bSJiri Olsa 	return new;
815f86b80bSJiri Olsa }
825f86b80bSJiri Olsa 
835f86b80bSJiri Olsa struct ordered_event *
845f86b80bSJiri Olsa ordered_events__new(struct ordered_events *oe, u64 timestamp)
855f86b80bSJiri Olsa {
865f86b80bSJiri Olsa 	struct ordered_event *new;
875f86b80bSJiri Olsa 
885f86b80bSJiri Olsa 	new = alloc_event(oe);
895f86b80bSJiri Olsa 	if (new) {
905f86b80bSJiri Olsa 		new->timestamp = timestamp;
915f86b80bSJiri Olsa 		queue_event(oe, new);
925f86b80bSJiri Olsa 	}
935f86b80bSJiri Olsa 
945f86b80bSJiri Olsa 	return new;
955f86b80bSJiri Olsa }
965f86b80bSJiri Olsa 
975f86b80bSJiri Olsa void ordered_events__delete(struct ordered_events *oe, struct ordered_event *event)
985f86b80bSJiri Olsa {
99fa4e5c67SJiri Olsa 	list_move(&event->list, &oe->cache);
1005f86b80bSJiri Olsa 	oe->nr_events--;
1015f86b80bSJiri Olsa }
1025f86b80bSJiri Olsa 
1035f86b80bSJiri Olsa static int __ordered_events__flush(struct perf_session *s,
1045f86b80bSJiri Olsa 				   struct perf_tool *tool)
1055f86b80bSJiri Olsa {
1065f86b80bSJiri Olsa 	struct ordered_events *oe = &s->ordered_events;
1075f86b80bSJiri Olsa 	struct list_head *head = &oe->events;
1085f86b80bSJiri Olsa 	struct ordered_event *tmp, *iter;
1095f86b80bSJiri Olsa 	struct perf_sample sample;
1105f86b80bSJiri Olsa 	u64 limit = oe->next_flush;
1115f86b80bSJiri Olsa 	u64 last_ts = oe->last ? oe->last->timestamp : 0ULL;
1125f86b80bSJiri Olsa 	bool show_progress = limit == ULLONG_MAX;
1135f86b80bSJiri Olsa 	struct ui_progress prog;
1145f86b80bSJiri Olsa 	int ret;
1155f86b80bSJiri Olsa 
1165f86b80bSJiri Olsa 	if (!tool->ordered_events || !limit)
1175f86b80bSJiri Olsa 		return 0;
1185f86b80bSJiri Olsa 
1195f86b80bSJiri Olsa 	if (show_progress)
1205f86b80bSJiri Olsa 		ui_progress__init(&prog, oe->nr_events, "Processing time ordered events...");
1215f86b80bSJiri Olsa 
1225f86b80bSJiri Olsa 	list_for_each_entry_safe(iter, tmp, head, list) {
1235f86b80bSJiri Olsa 		if (session_done())
1245f86b80bSJiri Olsa 			return 0;
1255f86b80bSJiri Olsa 
1265f86b80bSJiri Olsa 		if (iter->timestamp > limit)
1275f86b80bSJiri Olsa 			break;
1285f86b80bSJiri Olsa 
1295f86b80bSJiri Olsa 		ret = perf_evlist__parse_sample(s->evlist, iter->event, &sample);
1305f86b80bSJiri Olsa 		if (ret)
1315f86b80bSJiri Olsa 			pr_err("Can't parse sample, err = %d\n", ret);
1325f86b80bSJiri Olsa 		else {
1335f86b80bSJiri Olsa 			ret = perf_session__deliver_event(s, iter->event, &sample, tool,
1345f86b80bSJiri Olsa 							  iter->file_offset);
1355f86b80bSJiri Olsa 			if (ret)
1365f86b80bSJiri Olsa 				return ret;
1375f86b80bSJiri Olsa 		}
1385f86b80bSJiri Olsa 
1395f86b80bSJiri Olsa 		ordered_events__delete(oe, iter);
1405f86b80bSJiri Olsa 		oe->last_flush = iter->timestamp;
1415f86b80bSJiri Olsa 
1425f86b80bSJiri Olsa 		if (show_progress)
1435f86b80bSJiri Olsa 			ui_progress__update(&prog, 1);
1445f86b80bSJiri Olsa 	}
1455f86b80bSJiri Olsa 
1465f86b80bSJiri Olsa 	if (list_empty(head))
1475f86b80bSJiri Olsa 		oe->last = NULL;
1485f86b80bSJiri Olsa 	else if (last_ts <= limit)
1495f86b80bSJiri Olsa 		oe->last = list_entry(head->prev, struct ordered_event, list);
1505f86b80bSJiri Olsa 
1515f86b80bSJiri Olsa 	return 0;
1525f86b80bSJiri Olsa }
1535f86b80bSJiri Olsa 
1545f86b80bSJiri Olsa int ordered_events__flush(struct perf_session *s, struct perf_tool *tool,
1555f86b80bSJiri Olsa 			  enum oe_flush how)
1565f86b80bSJiri Olsa {
1575f86b80bSJiri Olsa 	struct ordered_events *oe = &s->ordered_events;
1585f86b80bSJiri Olsa 	int err;
1595f86b80bSJiri Olsa 
1605f86b80bSJiri Olsa 	switch (how) {
1615f86b80bSJiri Olsa 	case OE_FLUSH__FINAL:
1625f86b80bSJiri Olsa 		oe->next_flush = ULLONG_MAX;
1635f86b80bSJiri Olsa 		break;
1645f86b80bSJiri Olsa 
1655f86b80bSJiri Olsa 	case OE_FLUSH__HALF:
1665f86b80bSJiri Olsa 	{
1675f86b80bSJiri Olsa 		struct ordered_event *first, *last;
1685f86b80bSJiri Olsa 		struct list_head *head = &oe->events;
1695f86b80bSJiri Olsa 
1705f86b80bSJiri Olsa 		first = list_entry(head->next, struct ordered_event, list);
1715f86b80bSJiri Olsa 		last = oe->last;
1725f86b80bSJiri Olsa 
1735f86b80bSJiri Olsa 		/* Warn if we are called before any event got allocated. */
1745f86b80bSJiri Olsa 		if (WARN_ONCE(!last || list_empty(head), "empty queue"))
1755f86b80bSJiri Olsa 			return 0;
1765f86b80bSJiri Olsa 
1775f86b80bSJiri Olsa 		oe->next_flush  = first->timestamp;
1785f86b80bSJiri Olsa 		oe->next_flush += (last->timestamp - first->timestamp) / 2;
1795f86b80bSJiri Olsa 		break;
1805f86b80bSJiri Olsa 	}
1815f86b80bSJiri Olsa 
1825f86b80bSJiri Olsa 	case OE_FLUSH__ROUND:
1835f86b80bSJiri Olsa 	default:
1845f86b80bSJiri Olsa 		break;
1855f86b80bSJiri Olsa 	};
1865f86b80bSJiri Olsa 
1875f86b80bSJiri Olsa 	err = __ordered_events__flush(s, tool);
1885f86b80bSJiri Olsa 
1895f86b80bSJiri Olsa 	if (!err) {
1905f86b80bSJiri Olsa 		if (how == OE_FLUSH__ROUND)
1915f86b80bSJiri Olsa 			oe->next_flush = oe->max_timestamp;
1925f86b80bSJiri Olsa 	}
1935f86b80bSJiri Olsa 
1945f86b80bSJiri Olsa 	return err;
1955f86b80bSJiri Olsa }
196