diff options
Diffstat (limited to 'tools/perf/util/evlist.c')
-rw-r--r-- | tools/perf/util/evlist.c | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index deb82a4fc312..4b3b84cd71a1 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -95,3 +95,65 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id) | |||
95 | return sid->evsel; | 95 | return sid->evsel; |
96 | return NULL; | 96 | return NULL; |
97 | } | 97 | } |
98 | |||
99 | event_t *perf_evlist__read_on_cpu(struct perf_evlist *evlist, int cpu) | ||
100 | { | ||
101 | /* XXX Move this to perf.c, making it generally available */ | ||
102 | unsigned int page_size = sysconf(_SC_PAGE_SIZE); | ||
103 | struct perf_mmap *md = &evlist->mmap[cpu]; | ||
104 | unsigned int head = perf_mmap__read_head(md); | ||
105 | unsigned int old = md->prev; | ||
106 | unsigned char *data = md->base + page_size; | ||
107 | event_t *event = NULL; | ||
108 | int diff; | ||
109 | |||
110 | /* | ||
111 | * If we're further behind than half the buffer, there's a chance | ||
112 | * the writer will bite our tail and mess up the samples under us. | ||
113 | * | ||
114 | * If we somehow ended up ahead of the head, we got messed up. | ||
115 | * | ||
116 | * In either case, truncate and restart at head. | ||
117 | */ | ||
118 | diff = head - old; | ||
119 | if (diff > md->mask / 2 || diff < 0) { | ||
120 | fprintf(stderr, "WARNING: failed to keep up with mmap data.\n"); | ||
121 | |||
122 | /* | ||
123 | * head points to a known good entry, start there. | ||
124 | */ | ||
125 | old = head; | ||
126 | } | ||
127 | |||
128 | if (old != head) { | ||
129 | size_t size; | ||
130 | |||
131 | event = (event_t *)&data[old & md->mask]; | ||
132 | size = event->header.size; | ||
133 | |||
134 | /* | ||
135 | * Event straddles the mmap boundary -- header should always | ||
136 | * be inside due to u64 alignment of output. | ||
137 | */ | ||
138 | if ((old & md->mask) + size != ((old + size) & md->mask)) { | ||
139 | unsigned int offset = old; | ||
140 | unsigned int len = min(sizeof(*event), size), cpy; | ||
141 | void *dst = &evlist->event_copy; | ||
142 | |||
143 | do { | ||
144 | cpy = min(md->mask + 1 - (offset & md->mask), len); | ||
145 | memcpy(dst, &data[offset & md->mask], cpy); | ||
146 | offset += cpy; | ||
147 | dst += cpy; | ||
148 | len -= cpy; | ||
149 | } while (len); | ||
150 | |||
151 | event = &evlist->event_copy; | ||
152 | } | ||
153 | |||
154 | old += size; | ||
155 | } | ||
156 | |||
157 | md->prev = old; | ||
158 | return event; | ||
159 | } | ||