perf tools: Add debug prints for ordered events queue
[linux-2.6-block.git] / tools / perf / util / ordered-events.c
CommitLineData
5f86b80b 1#include <linux/list.h>
cee3ab9c 2#include <linux/compiler.h>
5f86b80b
JO
3#include "ordered-events.h"
4#include "evlist.h"
5#include "session.h"
6#include "asm/bug.h"
7#include "debug.h"
8
cee3ab9c
JO
9#define pr_N(n, fmt, ...) \
10 eprintf(n, debug_ordered_events, fmt, ##__VA_ARGS__)
11
12#define pr(fmt, ...) pr_N(1, pr_fmt(fmt), ##__VA_ARGS__)
13
5f86b80b
JO
14static void queue_event(struct ordered_events *oe, struct ordered_event *new)
15{
16 struct ordered_event *last = oe->last;
17 u64 timestamp = new->timestamp;
18 struct list_head *p;
19
20 ++oe->nr_events;
21 oe->last = new;
22
cee3ab9c
JO
23 pr_oe_time2(timestamp, "queue_event nr_events %u\n", oe->nr_events);
24
5f86b80b
JO
25 if (!last) {
26 list_add(&new->list, &oe->events);
27 oe->max_timestamp = timestamp;
28 return;
29 }
30
31 /*
32 * last event might point to some random place in the list as it's
33 * the last queued event. We expect that the new event is close to
34 * this.
35 */
36 if (last->timestamp <= timestamp) {
37 while (last->timestamp <= timestamp) {
38 p = last->list.next;
39 if (p == &oe->events) {
40 list_add_tail(&new->list, &oe->events);
41 oe->max_timestamp = timestamp;
42 return;
43 }
44 last = list_entry(p, struct ordered_event, list);
45 }
46 list_add_tail(&new->list, &last->list);
47 } else {
48 while (last->timestamp > timestamp) {
49 p = last->list.prev;
50 if (p == &oe->events) {
51 list_add(&new->list, &oe->events);
52 return;
53 }
54 last = list_entry(p, struct ordered_event, list);
55 }
56 list_add(&new->list, &last->list);
57 }
58}
59
60#define MAX_SAMPLE_BUFFER (64 * 1024 / sizeof(struct ordered_event))
61static struct ordered_event *alloc_event(struct ordered_events *oe)
62{
63 struct list_head *cache = &oe->cache;
64 struct ordered_event *new = NULL;
65
66 if (!list_empty(cache)) {
67 new = list_entry(cache->next, struct ordered_event, list);
68 list_del(&new->list);
69 } else if (oe->buffer) {
70 new = oe->buffer + oe->buffer_idx;
71 if (++oe->buffer_idx == MAX_SAMPLE_BUFFER)
72 oe->buffer = NULL;
73 } else if (oe->cur_alloc_size < oe->max_alloc_size) {
74 size_t size = MAX_SAMPLE_BUFFER * sizeof(*new);
75
76 oe->buffer = malloc(size);
77 if (!oe->buffer)
78 return NULL;
79
cee3ab9c
JO
80 pr("alloc size %" PRIu64 "B (+%zu), max %" PRIu64 "B\n",
81 oe->cur_alloc_size, size, oe->max_alloc_size);
82
5f86b80b
JO
83 oe->cur_alloc_size += size;
84 list_add(&oe->buffer->list, &oe->to_free);
85
86 /* First entry is abused to maintain the to_free list. */
87 oe->buffer_idx = 2;
88 new = oe->buffer + 1;
cee3ab9c
JO
89 } else {
90 pr("allocation limit reached %" PRIu64 "B\n", oe->max_alloc_size);
5f86b80b
JO
91 }
92
93 return new;
94}
95
96struct ordered_event *
97ordered_events__new(struct ordered_events *oe, u64 timestamp)
98{
99 struct ordered_event *new;
100
101 new = alloc_event(oe);
102 if (new) {
103 new->timestamp = timestamp;
104 queue_event(oe, new);
105 }
106
107 return new;
108}
109
110void ordered_events__delete(struct ordered_events *oe, struct ordered_event *event)
111{
fa4e5c67 112 list_move(&event->list, &oe->cache);
5f86b80b
JO
113 oe->nr_events--;
114}
115
116static int __ordered_events__flush(struct perf_session *s,
117 struct perf_tool *tool)
118{
119 struct ordered_events *oe = &s->ordered_events;
120 struct list_head *head = &oe->events;
121 struct ordered_event *tmp, *iter;
122 struct perf_sample sample;
123 u64 limit = oe->next_flush;
124 u64 last_ts = oe->last ? oe->last->timestamp : 0ULL;
125 bool show_progress = limit == ULLONG_MAX;
126 struct ui_progress prog;
127 int ret;
128
129 if (!tool->ordered_events || !limit)
130 return 0;
131
132 if (show_progress)
133 ui_progress__init(&prog, oe->nr_events, "Processing time ordered events...");
134
135 list_for_each_entry_safe(iter, tmp, head, list) {
136 if (session_done())
137 return 0;
138
139 if (iter->timestamp > limit)
140 break;
141
142 ret = perf_evlist__parse_sample(s->evlist, iter->event, &sample);
143 if (ret)
144 pr_err("Can't parse sample, err = %d\n", ret);
145 else {
146 ret = perf_session__deliver_event(s, iter->event, &sample, tool,
147 iter->file_offset);
148 if (ret)
149 return ret;
150 }
151
152 ordered_events__delete(oe, iter);
153 oe->last_flush = iter->timestamp;
154
155 if (show_progress)
156 ui_progress__update(&prog, 1);
157 }
158
159 if (list_empty(head))
160 oe->last = NULL;
161 else if (last_ts <= limit)
162 oe->last = list_entry(head->prev, struct ordered_event, list);
163
164 return 0;
165}
166
167int ordered_events__flush(struct perf_session *s, struct perf_tool *tool,
168 enum oe_flush how)
169{
170 struct ordered_events *oe = &s->ordered_events;
cee3ab9c
JO
171 static const char * const str[] = {
172 "FINAL",
173 "ROUND",
174 "HALF ",
175 };
5f86b80b
JO
176 int err;
177
178 switch (how) {
179 case OE_FLUSH__FINAL:
180 oe->next_flush = ULLONG_MAX;
181 break;
182
183 case OE_FLUSH__HALF:
184 {
185 struct ordered_event *first, *last;
186 struct list_head *head = &oe->events;
187
188 first = list_entry(head->next, struct ordered_event, list);
189 last = oe->last;
190
191 /* Warn if we are called before any event got allocated. */
192 if (WARN_ONCE(!last || list_empty(head), "empty queue"))
193 return 0;
194
195 oe->next_flush = first->timestamp;
196 oe->next_flush += (last->timestamp - first->timestamp) / 2;
197 break;
198 }
199
200 case OE_FLUSH__ROUND:
201 default:
202 break;
203 };
204
cee3ab9c
JO
205 pr_oe_time(oe->next_flush, "next_flush - ordered_events__flush PRE %s, nr_events %u\n",
206 str[how], oe->nr_events);
207 pr_oe_time(oe->max_timestamp, "max_timestamp\n");
208
5f86b80b
JO
209 err = __ordered_events__flush(s, tool);
210
211 if (!err) {
212 if (how == OE_FLUSH__ROUND)
213 oe->next_flush = oe->max_timestamp;
214 }
215
cee3ab9c
JO
216 pr_oe_time(oe->next_flush, "next_flush - ordered_events__flush POST %s, nr_events %u\n",
217 str[how], oe->nr_events);
218 pr_oe_time(oe->last_flush, "last_flush\n");
219
5f86b80b
JO
220 return err;
221}
36522f5c
JO
222
223void ordered_events__init(struct ordered_events *oe)
224{
225 INIT_LIST_HEAD(&oe->events);
226 INIT_LIST_HEAD(&oe->cache);
227 INIT_LIST_HEAD(&oe->to_free);
228 oe->max_alloc_size = (u64) -1;
229 oe->cur_alloc_size = 0;
230}
adc56ed1
JO
231
232void ordered_events__free(struct ordered_events *oe)
233{
234 while (!list_empty(&oe->to_free)) {
235 struct ordered_event *event;
236
237 event = list_entry(oe->to_free.next, struct ordered_event, list);
238 list_del(&event->list);
239 free(event);
240 }
241}