|
40 | 40 | #include <unistd.h>
|
41 | 41 | #include <sched.h>
|
42 | 42 | #include <sys/mman.h>
|
| 43 | +#include <asm/bug.h> |
43 | 44 |
|
44 | 45 |
|
45 | 46 | struct record {
|
@@ -82,44 +83,104 @@ static int process_synthesized_event(struct perf_tool *tool,
|
82 | 83 | return record__write(rec, event, event->header.size);
|
83 | 84 | }
|
84 | 85 |
|
| 86 | +static int |
| 87 | +backward_rb_find_range(void *buf, int mask, u64 head, u64 *start, u64 *end) |
| 88 | +{ |
| 89 | + struct perf_event_header *pheader; |
| 90 | + u64 evt_head = head; |
| 91 | + int size = mask + 1; |
| 92 | + |
| 93 | + pr_debug2("backward_rb_find_range: buf=%p, head=%"PRIx64"\n", buf, head); |
| 94 | + pheader = (struct perf_event_header *)(buf + (head & mask)); |
| 95 | + *start = head; |
| 96 | + while (true) { |
| 97 | + if (evt_head - head >= (unsigned int)size) { |
| 98 | + pr_debug("Finshed reading backward ring buffer: rewind\n"); |
| 99 | + if (evt_head - head > (unsigned int)size) |
| 100 | + evt_head -= pheader->size; |
| 101 | + *end = evt_head; |
| 102 | + return 0; |
| 103 | + } |
| 104 | + |
| 105 | + pheader = (struct perf_event_header *)(buf + (evt_head & mask)); |
| 106 | + |
| 107 | + if (pheader->size == 0) { |
| 108 | + pr_debug("Finshed reading backward ring buffer: get start\n"); |
| 109 | + *end = evt_head; |
| 110 | + return 0; |
| 111 | + } |
| 112 | + |
| 113 | + evt_head += pheader->size; |
| 114 | + pr_debug3("move evt_head: %"PRIx64"\n", evt_head); |
| 115 | + } |
| 116 | + WARN_ONCE(1, "Shouldn't get here\n"); |
| 117 | + return -1; |
| 118 | +} |
| 119 | + |
| 120 | +static int |
| 121 | +rb_find_range(struct perf_evlist *evlist, |
| 122 | + void *data, int mask, u64 head, u64 old, |
| 123 | + u64 *start, u64 *end) |
| 124 | +{ |
| 125 | + if (!evlist->backward) { |
| 126 | + *start = old; |
| 127 | + *end = head; |
| 128 | + return 0; |
| 129 | + } |
| 130 | + |
| 131 | + return backward_rb_find_range(data, mask, head, start, end); |
| 132 | +} |
| 133 | + |
85 | 134 | static int record__mmap_read(struct record *rec, int idx)
|
86 | 135 | {
|
87 | 136 | struct perf_mmap *md = &rec->evlist->mmap[idx];
|
88 | 137 | u64 head = perf_mmap__read_head(md);
|
89 | 138 | u64 old = md->prev;
|
| 139 | + u64 end = head, start = old; |
90 | 140 | unsigned char *data = md->base + page_size;
|
91 | 141 | unsigned long size;
|
92 | 142 | void *buf;
|
93 | 143 | int rc = 0;
|
94 | 144 |
|
95 |
| - if (old == head) |
| 145 | + if (rb_find_range(rec->evlist, data, md->mask, head, |
| 146 | + old, &start, &end)) |
| 147 | + return -1; |
| 148 | + |
| 149 | + if (start == end) |
96 | 150 | return 0;
|
97 | 151 |
|
98 | 152 | rec->samples++;
|
99 | 153 |
|
100 |
| - size = head - old; |
| 154 | + size = end - start; |
| 155 | + if (size > (unsigned long)(md->mask) + 1) { |
| 156 | + WARN_ONCE(1, "failed to keep up with mmap data. (warn only once)\n"); |
| 157 | + |
| 158 | + md->prev = head; |
| 159 | + perf_evlist__mmap_consume(rec->evlist, idx); |
| 160 | + return 0; |
| 161 | + } |
101 | 162 |
|
102 |
| - if ((old & md->mask) + size != (head & md->mask)) { |
103 |
| - buf = &data[old & md->mask]; |
104 |
| - size = md->mask + 1 - (old & md->mask); |
105 |
| - old += size; |
| 163 | + if ((start & md->mask) + size != (end & md->mask)) { |
| 164 | + buf = &data[start & md->mask]; |
| 165 | + size = md->mask + 1 - (start & md->mask); |
| 166 | + start += size; |
106 | 167 |
|
107 | 168 | if (record__write(rec, buf, size) < 0) {
|
108 | 169 | rc = -1;
|
109 | 170 | goto out;
|
110 | 171 | }
|
111 | 172 | }
|
112 | 173 |
|
113 |
| - buf = &data[old & md->mask]; |
114 |
| - size = head - old; |
115 |
| - old += size; |
| 174 | + buf = &data[start & md->mask]; |
| 175 | + size = end - start; |
| 176 | + start += size; |
116 | 177 |
|
117 | 178 | if (record__write(rec, buf, size) < 0) {
|
118 | 179 | rc = -1;
|
119 | 180 | goto out;
|
120 | 181 | }
|
121 | 182 |
|
122 |
| - md->prev = old; |
| 183 | + md->prev = head; |
123 | 184 | perf_evlist__mmap_consume(rec->evlist, idx);
|
124 | 185 | out:
|
125 | 186 | return rc;
|
|
0 commit comments