Branch data Line data Source code
1 : : // SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
2 : : /*
3 : : * Copyright 2013-2019 IBM Corp.
4 : : */
5 : :
6 : : #include <config.h>
7 : : #include <stdlib.h>
8 : : #include <assert.h>
9 : : #include <sched.h>
10 : : #include <stdlib.h>
11 : : #include <stdint.h>
12 : : #include <unistd.h>
13 : : #include <stdio.h>
14 : : #include <stdbool.h>
15 : : #include <sys/types.h>
16 : : #include <sys/wait.h>
17 : :
18 : : #include <skiboot-valgrind.h>
19 : :
20 : : /* Don't include these: PPC-specific */
21 : : #define __CPU_H
22 : : #define __TIME_H
23 : : #define __PROCESSOR_H
24 : :
25 : : #if defined(__i386__) || defined(__x86_64__)
26 : : /* This is more than a lwsync, but it'll work */
27 : 10850485 : static void full_barrier(void)
28 : : {
29 : 10850485 : asm volatile("mfence" : : : "memory");
30 : 10850485 : }
31 : : #define lwsync full_barrier
32 : : #elif defined(__powerpc__) || defined(__powerpc64__)
33 : : static inline void lwsync(void)
34 : : {
35 : : asm volatile("lwsync" : : : "memory");
36 : : }
37 : : #else
38 : : #error "Define lwsync for this arch"
39 : : #endif
40 : :
41 : : #define zalloc(size) calloc((size), 1)
42 : :
43 : : struct cpu_thread {
44 : : uint32_t pir;
45 : : uint32_t chip_id;
46 : : struct trace_info *trace;
47 : : uint32_t server_no;
48 : : bool is_secondary;
49 : : struct cpu_thread *primary;
50 : : };
51 : : static struct cpu_thread *this_cpu(void);
52 : :
53 : : #define CPUS 4
54 : :
55 : : static struct cpu_thread fake_cpus[CPUS];
56 : :
57 : 15 : static inline struct cpu_thread *next_cpu(struct cpu_thread *cpu)
58 : : {
59 : 15 : if (cpu == NULL)
60 : 3 : return &fake_cpus[0];
61 : 12 : cpu++;
62 : 12 : if (cpu == &fake_cpus[CPUS])
63 : 3 : return NULL;
64 : 9 : return cpu;
65 : : }
66 : :
67 : : #define first_cpu() next_cpu(NULL)
68 : :
69 : : #define for_each_cpu(cpu) \
70 : : for (cpu = first_cpu(); cpu; cpu = next_cpu(cpu))
71 : :
72 : : static unsigned long timestamp;
73 : 6418116 : static unsigned long mftb(void)
74 : : {
75 : 6418116 : return timestamp;
76 : : }
77 : :
78 : 2 : static void *local_alloc(unsigned int chip_id,
79 : : size_t size, size_t align)
80 : : {
81 : : void *p;
82 : :
83 : : (void)chip_id;
84 : 2 : if (posix_memalign(&p, align, size))
85 : 0 : p = NULL;
86 : 2 : return p;
87 : : }
88 : :
89 : : struct dt_node;
90 : : extern struct dt_node *opal_node;
91 : :
92 : : #include "../trace.c"
93 : :
94 : : #include "../external/trace/trace.c"
95 : : static struct trace_reader trace_readers[CPUS];
96 : : struct trace_reader *my_trace_reader;
97 : : #include "../device.c"
98 : :
99 : : char __rodata_start[1], __rodata_end[1];
100 : : struct dt_node *opal_node;
101 : : struct debug_descriptor debug_descriptor = {
102 : : .trace_mask = -1
103 : : };
104 : :
105 : 0 : const char *nvram_query_safe(const char *key __unused)
106 : : {
107 : 0 : return NULL;
108 : : }
109 : :
110 : 6418116 : void lock_caller(struct lock *l, const char *caller)
111 : : {
112 : : (void)caller;
113 : 6418116 : assert(!l->lock_val);
114 : 6418116 : l->lock_val = 1;
115 : 6418116 : }
116 : :
117 : 6418116 : void unlock(struct lock *l)
118 : : {
119 : 6418116 : assert(l->lock_val);
120 : 6418116 : l->lock_val = 0;
121 : 6418116 : }
122 : :
123 : : struct cpu_thread *my_fake_cpu;
124 : 12836233 : static struct cpu_thread *this_cpu(void)
125 : : {
126 : 12836233 : return my_fake_cpu;
127 : : }
128 : :
129 : : #include <sys/mman.h>
130 : : #define PER_CHILD_TRACES ((RUNNING_ON_VALGRIND) ? (1024*16) : (1024*1024))
131 : :
132 : 4 : static void write_trace_entries(int id)
133 : : {
134 : : void exit(int);
135 : : unsigned int i;
136 : : union trace trace;
137 : :
138 : 4 : timestamp = id;
139 : 4194308 : for (i = 0; i < PER_CHILD_TRACES; i++) {
140 : 4194304 : timestamp = i * CPUS + id;
141 : : assert(sizeof(trace.hdr) % 8 == 0);
142 : : /* First child never repeats, second repeats once, etc. */
143 : 4194304 : trace_add(&trace, 3 + ((i / (id + 1)) % 0x40),
144 : : sizeof(trace.hdr));
145 : : }
146 : :
147 : : /* Final entry has special type, so parent knows it's over. */
148 : 4 : trace_add(&trace, 0x70, sizeof(trace.hdr));
149 : 4 : exit(0);
150 : : }
151 : :
152 : 2093313 : static bool all_done(const bool done[])
153 : : {
154 : : unsigned int i;
155 : :
156 : 2972555 : for (i = 0; i < CPUS; i++)
157 : 2972554 : if (!done[i])
158 : 2093312 : return false;
159 : 1 : return true;
160 : : }
161 : :
162 : 1 : static void test_parallel(void)
163 : : {
164 : : void *p;
165 : : unsigned int cpu;
166 : 1 : unsigned int i, counts[CPUS] = { 0 }, overflows[CPUS] = { 0 };
167 : 1 : unsigned int repeats[CPUS] = { 0 }, num_overflows[CPUS] = { 0 };
168 : 1 : bool done[CPUS] = { false };
169 : 1 : size_t len = sizeof(struct trace_info) + TBUF_SZ + sizeof(union trace);
170 : 1 : int last = 0;
171 : :
172 : : /* Use a shared mmap to test actual parallel buffers. */
173 : 1 : i = (CPUS*len + getpagesize()-1)&~(getpagesize()-1);
174 : 1 : p = mmap(NULL, i, PROT_READ|PROT_WRITE,
175 : : MAP_ANONYMOUS|MAP_SHARED, -1, 0);
176 : :
177 : 5 : for (i = 0; i < CPUS; i++) {
178 : 4 : fake_cpus[i].trace = p + i * len;
179 : 4 : fake_cpus[i].trace->tb.buf_size = cpu_to_be64(TBUF_SZ);
180 : 4 : fake_cpus[i].trace->tb.max_size = cpu_to_be32(sizeof(union trace));
181 : 4 : fake_cpus[i].is_secondary = false;
182 : 4 : memset(&trace_readers[i], 0, sizeof(struct trace_reader));
183 : 4 : trace_readers[i].tb = &fake_cpus[i].trace->tb;
184 : : }
185 : :
186 : 5 : for (i = 0; i < CPUS; i++) {
187 : 4 : if (!fork()) {
188 : : /* Child. */
189 : 4 : my_fake_cpu = &fake_cpus[i];
190 : 4 : write_trace_entries(i);
191 : : }
192 : : }
193 : :
194 : 2093313 : while (!all_done(done)) {
195 : : union trace t;
196 : :
197 : 2241991 : for (i = 0; i < CPUS; i++) {
198 : 2204827 : if (trace_get(&t, &trace_readers[(i+last) % CPUS]))
199 : 2056148 : break;
200 : : }
201 : :
202 : 2093312 : if (i == CPUS) {
203 : 37164 : sched_yield();
204 : 37193 : continue;
205 : : }
206 : 2056148 : i = (i + last) % CPUS;
207 : 2056148 : last = i;
208 : :
209 : 2056148 : if (t.hdr.type == TRACE_OVERFLOW) {
210 : : /* Conveniently, each record is 16 bytes here. */
211 : 29 : assert(be64_to_cpu(t.overflow.bytes_missed) % 16 == 0);
212 : 29 : overflows[i] += be64_to_cpu(t.overflow.bytes_missed) / 16;
213 : 29 : num_overflows[i]++;
214 : 29 : continue;
215 : : }
216 : :
217 : 2056119 : assert(be16_to_cpu(t.hdr.cpu) < CPUS);
218 : 2056119 : assert(!done[be16_to_cpu(t.hdr.cpu)]);
219 : 2056119 : assert(be64_to_cpu(t.hdr.timestamp) % CPUS == be16_to_cpu(t.hdr.cpu));
220 : 2056119 : if (t.hdr.type == TRACE_REPEAT) {
221 : 838957 : assert(t.hdr.len_div_8 * 8 == sizeof(t.repeat));
222 : 838957 : assert(be16_to_cpu(t.repeat.num) != 0);
223 : 838957 : assert(be16_to_cpu(t.repeat.num) <= be16_to_cpu(t.hdr.cpu));
224 : 838957 : repeats[be16_to_cpu(t.hdr.cpu)] += be16_to_cpu(t.repeat.num);
225 : 1217162 : } else if (t.hdr.type == 0x70) {
226 : 4 : cpu = be16_to_cpu(t.hdr.cpu);
227 : 4 : assert(cpu < CPUS);
228 : 4 : done[cpu] = true;
229 : : } else {
230 : 1217158 : cpu = be16_to_cpu(t.hdr.cpu);
231 : 1217158 : assert(cpu < CPUS);
232 : 1217158 : counts[cpu]++;
233 : : }
234 : : }
235 : :
236 : : /* Gather children. */
237 : 5 : for (i = 0; i < CPUS; i++) {
238 : : int status;
239 : 4 : wait(&status);
240 : : }
241 : :
242 : 5 : for (i = 0; i < CPUS; i++) {
243 : 4 : printf("Child %i: %u produced, %u overflows, %llu total\n", i,
244 : : counts[i], overflows[i],
245 : 4 : (long long)be64_to_cpu(fake_cpus[i].trace->tb.end));
246 : 4 : assert(counts[i] + repeats[i] <= PER_CHILD_TRACES);
247 : : }
248 : : /* Child 0 never repeats. */
249 : 1 : assert(repeats[0] == 0);
250 : 1 : assert(counts[0] + overflows[0] == PER_CHILD_TRACES);
251 : :
252 : : /*
253 : : * FIXME: Other children have some fuzz, since overflows may
254 : : * include repeat record we already read. And odd-numbered
255 : : * overflows may include more repeat records than normal
256 : : * records (they alternate).
257 : : */
258 : 1 : }
259 : :
260 : 1 : int main(void)
261 : : {
262 : : union trace minimal;
263 : : union trace large;
264 : : union trace trace;
265 : : unsigned int i, j;
266 : :
267 : 1 : opal_node = dt_new_root("opal");
268 : 1 : dt_new(dt_new(opal_node, "firmware"), "exports");
269 : 5 : for (i = 0; i < CPUS; i++) {
270 : 4 : fake_cpus[i].server_no = i;
271 : 4 : fake_cpus[i].pir = i;
272 : 4 : fake_cpus[i].is_secondary = (i & 0x1);
273 : 4 : fake_cpus[i].primary = &fake_cpus[i & ~0x1];
274 : : }
275 : 1 : my_fake_cpu = &fake_cpus[0];
276 : 1 : my_trace_reader = &trace_readers[0];
277 : 1 : init_trace_buffers();
278 : :
279 : 5 : for (i = 0; i < CPUS; i++) {
280 : 4 : trace_readers[i].tb = &fake_cpus[i].trace->tb;
281 : 4 : assert(trace_empty(&trace_readers[i]));
282 : 4 : assert(!trace_get(&trace, &trace_readers[i]));
283 : : }
284 : :
285 : : assert(sizeof(trace.hdr) % 8 == 0);
286 : 1 : timestamp = 1;
287 : 1 : trace_add(&minimal, 100, sizeof(trace.hdr));
288 : 1 : assert(trace_get(&trace, my_trace_reader));
289 : 1 : assert(trace.hdr.len_div_8 == minimal.hdr.len_div_8);
290 : 1 : assert(be64_to_cpu(trace.hdr.timestamp) == timestamp);
291 : :
292 : : /* Make it wrap once. */
293 : 65404 : for (i = 0; i < TBUF_SZ / (minimal.hdr.len_div_8 * 8) + 1; i++) {
294 : 65403 : timestamp = i;
295 : 65403 : trace_add(&minimal, 99 + (i%2), sizeof(trace.hdr));
296 : : }
297 : :
298 : 1 : assert(trace_get(&trace, my_trace_reader));
299 : : /* First one must be overflow marker. */
300 : 1 : assert(trace.hdr.type == TRACE_OVERFLOW);
301 : 1 : assert(trace.hdr.len_div_8 * 8 == sizeof(trace.overflow));
302 : 1 : assert(be64_to_cpu(trace.overflow.bytes_missed) == minimal.hdr.len_div_8 * 8);
303 : :
304 : 65403 : for (i = 0; i < TBUF_SZ / (minimal.hdr.len_div_8 * 8); i++) {
305 : 65402 : assert(trace_get(&trace, my_trace_reader));
306 : 65402 : assert(trace.hdr.len_div_8 == minimal.hdr.len_div_8);
307 : 65402 : assert(be64_to_cpu(trace.hdr.timestamp) == i+1);
308 : 65402 : assert(trace.hdr.type == 99 + ((i+1)%2));
309 : : }
310 : 1 : assert(!trace_get(&trace, my_trace_reader));
311 : :
312 : : /* Now put in some weird-length ones, to test overlap.
313 : : * Last power of 2, minus 8. */
314 : 8 : for (j = 0; (1 << j) < sizeof(large); j++);
315 : 1046433 : for (i = 0; i < TBUF_SZ; i++) {
316 : 1046432 : timestamp = i;
317 : 1046432 : trace_add(&large, 100 + (i%2), (1 << (j-1)));
318 : : }
319 : 1 : assert(trace_get(&trace, my_trace_reader));
320 : 1 : assert(trace.hdr.type == TRACE_OVERFLOW);
321 : 1 : assert(trace_get(&trace, my_trace_reader));
322 : 1 : assert(trace.hdr.len_div_8 == large.hdr.len_div_8);
323 : 1 : i = be64_to_cpu(trace.hdr.timestamp);
324 : 16350 : while (trace_get(&trace, my_trace_reader))
325 : 16349 : assert(be64_to_cpu(trace.hdr.timestamp) == ++i);
326 : :
327 : : /* Test repeats. */
328 : 65539 : for (i = 0; i < 65538; i++) {
329 : 65538 : timestamp = i;
330 : 65538 : trace_add(&minimal, 100, sizeof(trace.hdr));
331 : : }
332 : 1 : timestamp = i;
333 : 1 : trace_add(&minimal, 101, sizeof(trace.hdr));
334 : 1 : timestamp = i+1;
335 : 1 : trace_add(&minimal, 101, sizeof(trace.hdr));
336 : :
337 : 1 : assert(trace_get(&trace, my_trace_reader));
338 : 1 : assert(trace.hdr.timestamp == 0);
339 : 1 : assert(trace.hdr.len_div_8 == minimal.hdr.len_div_8);
340 : 1 : assert(trace.hdr.type == 100);
341 : 1 : assert(trace_get(&trace, my_trace_reader));
342 : 1 : assert(trace.hdr.type == TRACE_REPEAT);
343 : 1 : assert(trace.hdr.len_div_8 * 8 == sizeof(trace.repeat));
344 : 1 : assert(be16_to_cpu(trace.repeat.num) == 65535);
345 : 1 : assert(be64_to_cpu(trace.repeat.timestamp) == 65535);
346 : 1 : assert(trace_get(&trace, my_trace_reader));
347 : 1 : assert(be64_to_cpu(trace.hdr.timestamp) == 65536);
348 : 1 : assert(trace.hdr.len_div_8 == minimal.hdr.len_div_8);
349 : 1 : assert(trace.hdr.type == 100);
350 : 1 : assert(trace_get(&trace, my_trace_reader));
351 : 1 : assert(trace.hdr.type == TRACE_REPEAT);
352 : 1 : assert(trace.hdr.len_div_8 * 8 == sizeof(trace.repeat));
353 : 1 : assert(be16_to_cpu(trace.repeat.num) == 1);
354 : 1 : assert(be64_to_cpu(trace.repeat.timestamp) == 65537);
355 : :
356 : 1 : assert(trace_get(&trace, my_trace_reader));
357 : 1 : assert(be64_to_cpu(trace.hdr.timestamp) == 65538);
358 : 1 : assert(trace.hdr.len_div_8 == minimal.hdr.len_div_8);
359 : 1 : assert(trace.hdr.type == 101);
360 : 1 : assert(trace_get(&trace, my_trace_reader));
361 : 1 : assert(trace.hdr.type == TRACE_REPEAT);
362 : 1 : assert(trace.hdr.len_div_8 * 8 == sizeof(trace.repeat));
363 : 1 : assert(be16_to_cpu(trace.repeat.num) == 1);
364 : 1 : assert(be64_to_cpu(trace.repeat.timestamp) == 65539);
365 : :
366 : : /* Now, test adding repeat while we're reading... */
367 : 1 : timestamp = 0;
368 : 1 : trace_add(&minimal, 100, sizeof(trace.hdr));
369 : 1 : assert(trace_get(&trace, my_trace_reader));
370 : 1 : assert(be64_to_cpu(trace.hdr.timestamp) == 0);
371 : 1 : assert(trace.hdr.len_div_8 == minimal.hdr.len_div_8);
372 : 1 : assert(trace.hdr.type == 100);
373 : :
374 : 1046432 : for (i = 1; i < TBUF_SZ; i++) {
375 : 1046431 : timestamp = i;
376 : 1046431 : trace_add(&minimal, 100, sizeof(trace.hdr));
377 : 1046431 : assert(trace_get(&trace, my_trace_reader));
378 : 1046431 : if (i % 65536 == 0) {
379 : 15 : assert(trace.hdr.type == 100);
380 : 15 : assert(trace.hdr.len_div_8 == minimal.hdr.len_div_8);
381 : : } else {
382 : 1046416 : assert(trace.hdr.type == TRACE_REPEAT);
383 : 1046416 : assert(trace.hdr.len_div_8 * 8 == sizeof(trace.repeat));
384 : 1046416 : assert(be16_to_cpu(trace.repeat.num) == 1);
385 : : }
386 : 1046431 : assert(be64_to_cpu(trace.repeat.timestamp) == i);
387 : 1046431 : assert(!trace_get(&trace, my_trace_reader));
388 : : }
389 : :
390 : 5 : for (i = 0; i < CPUS; i++)
391 : 4 : if (!fake_cpus[i].is_secondary)
392 : 2 : free(fake_cpus[i].trace);
393 : :
394 : 1 : test_parallel();
395 : :
396 : 1 : return 0;
397 : : }
|