1/**
2 * \file
3 * \brief Test spanning of domains across cores
4 */
5
6/*
7 * Copyright (c) 2007, 2008, 2010, ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <stdio.h>
16#include <string.h>
17#include <barrelfish/barrelfish.h>
18#include <barrelfish/dispatch.h>
19#include <trace/trace.h>
20#include <trace_definitions/trace_defs.h>
21
22
23#define LOCKDEC(x)    spinlock_t x;
24#define LOCK(x)     acquire_spinlock(&x)
25#define UNLOCK(x)   release_spinlock(&x)
26
27#define BARDEC(x)                                        \
28    struct {                                             \
29        volatile uint32_t  counter;                      \
30        volatile int   	   cycle;                        \
31    } x;
32
33#define BARINIT(x,y)                                            \
34    x.counter = 0;                                              \
35    x.cycle = 0;
36
37#define NEWBARRIER(x,y) {                                              \
38        int cycle = x.cycle;                                        \
39        if (__sync_fetch_and_add(&x.counter, 1) == (y-1)) {         \
40            x.counter = 0;                                          \
41            x.cycle = !x.cycle;                                     \
42        } else {                                                    \
43            while (cycle == x.cycle);                               \
44        }                                                           \
45    }
46
47#define BARRIER(x,y) {                                  \
48        int cycle = x.cycle;                            \
49        if (__sync_fetch_and_add(&x.counter, 1) == (y-1)) {       \
50            x.counter = 0;                              \
51            x.cycle = !cycle;                           \
52        } else {                                        \
53            while (cycle == x.cycle);                   \
54        }                                               \
55    }
56
57static uint64_t times[32];
58
59int    null(int);
60int    malloctest(int);
61int    printftest(int);
62int    locktest1(int);
63int    locktest4(int);
64int    inctest1(int);
65int    inctest4(int);
66int    bartest1(int);
67int    bartest4(int);
68
69int null(int arg)
70{
71
72    return 0;
73}
74
75extern size_t terminal_write(const char *data, size_t length);
76
77static int sysprinttest(int arg)
78{
79    char out = 'A'+arg;
80    for(int i=0; i<1<<10; i++) {
81        sys_print(&out, 1);
82    }
83    return 0;
84}
85static int termwritetest(int arg)
86{
87    char out = 'A'+arg;
88    for(int i=0; i<1<<10; i++) {
89        terminal_write(&out, 1);
90    }
91    return 0;
92}
93
94int printftest(int arg)
95{
96    char msg[2];
97    msg[0] = 'A'+arg;
98    msg[1] = 0;
99    for(int i=0; i<1<<10; i++) {
100        printf("%s", msg);
101    }
102    return 0;
103}
104
105int malloctest(int arg)
106{
107    for(int i=0; i<1<<10; i++) {
108        if (arg==1) sys_print(".", 1);
109        void *tmp = malloc(i);
110        free(tmp);
111    }
112    return 0;
113}
114
115LOCKDEC(spinlock);
116static uint64_t gcount = 0;
117
118int locktest1(int arg)
119{
120    for(int i=0; i<1<<20; i++) {
121        LOCK(spinlock);
122        gcount++;
123        UNLOCK(spinlock);
124    }
125    return 0;
126}
127int locktest4(int arg)
128{
129    for(int i=0; i<1<<20; i++) {
130        LOCK(spinlock);
131        gcount++;
132        UNLOCK(spinlock);
133        LOCK(spinlock);
134        gcount++;
135        UNLOCK(spinlock);
136        LOCK(spinlock);
137        gcount++;
138        UNLOCK(spinlock);
139        LOCK(spinlock);
140        gcount++;
141        UNLOCK(spinlock);
142    }
143    return 0;
144}
145
146static uint32_t atomiccounter = 0;
147
148int inctest1(int arg)
149{
150    for(int i=0; i<1<<20; i++) {
151        __sync_fetch_and_add(&atomiccounter, 1);
152    }
153    return 0;
154}
155
156int inctest4(int arg)
157{
158    uint64_t lcount = 0;
159    char msg[128];
160    for(int i=0; i<1<<20; i++) {
161        lcount++;
162        __sync_fetch_and_add(&atomiccounter, 1);
163        lcount++;
164        __sync_fetch_and_add(&atomiccounter, 1);
165        lcount++;
166        __sync_fetch_and_add(&atomiccounter, 1);
167        lcount++;
168        __sync_fetch_and_add(&atomiccounter, 1);
169    }
170    sprintf(msg, "%"PRIuCOREID": Count %"PRIx64" %p\n", disp_get_core_id(), lcount, &lcount);
171    sys_print(msg, strlen(msg));
172    return 0;
173}
174
175BARDEC(barrier);
176uint32_t NPROC = 0;
177
178int bartest1(int arg)
179{
180    uint64_t count = 0;
181    char msg[128];
182
183    for(int i=0; i<1<<20; i++) {
184        BARRIER(barrier, NPROC);
185        count++;
186    }
187    // Take address of count to prevent optimisation
188    sprintf(msg, "%"PRIuCOREID": Count %"PRIx64" %p\n", disp_get_core_id(), count, &count);
189    sys_print(msg, strlen(msg));
190    return 0;
191}
192
193int bartest4(int arg)
194{
195    uint64_t count = 0;
196    char msg[128];
197    for(int i=0; i<1<<20; i++) {
198        BARRIER(barrier, NPROC);
199        count++;
200        BARRIER(barrier, NPROC);
201        count++;
202        BARRIER(barrier, NPROC);
203        count++;
204        BARRIER(barrier, NPROC);
205        count++;
206    }
207    // Take address of count to prevent optimisation
208    sprintf(msg, "%"PRIuCOREID": Count %"PRIx64" %p\n", disp_get_core_id(), count, &count);
209    sys_print(msg, strlen(msg));
210    return 0;
211}
212
213static struct thread_mutex print_mutex = THREAD_MUTEX_INITIALIZER;
214
215static int mutextest(int arg)
216{
217    for(int i = 0; i < 100000; i++) {
218        thread_mutex_lock(&print_mutex);
219        printf("%"PRIuCOREID": test_thread %d\n", disp_get_core_id(), i);
220        thread_mutex_unlock(&print_mutex);
221    }
222
223    return 0;
224}
225
226static int remote(void *dummy)
227{
228    uint64_t time = rdtsc();
229    int core = disp_get_core_id();
230    times[core] = time;
231    printf("remote running on %d after %"PRIu64"\n", core, time-times[0]);
232
233    if (core == 1) sys_print("Null\n", 5);
234    BARRIER(barrier, NPROC);
235    //sys_print("*", 1);
236    null(core);
237
238    if (core == 1) sys_print("sys_print\n", 10);
239    BARRIER(barrier, NPROC);
240    sysprinttest(core);
241    BARRIER(barrier, NPROC);
242
243    if (core == 1) sys_print("terminal_write\n", 15);
244    BARRIER(barrier, NPROC);
245    termwritetest(core);
246    BARRIER(barrier, NPROC);
247
248    if (core == 1) sys_print("printf\n", 7);
249    BARRIER(barrier, NPROC);
250    printftest(core);
251    BARRIER(barrier, NPROC);
252
253    if (core == 1) sys_print("malloc\n", 7);
254    BARRIER(barrier, NPROC);
255    malloctest(core);
256    BARRIER(barrier, NPROC);
257
258    if (core == 1) printf("\nlocktest1\n");
259    gcount = 0;
260
261    BARRIER(barrier, NPROC);
262    locktest1(core);
263    BARRIER(barrier, NPROC);
264
265    if (core == 1) {
266        printf("gcount %"PRIx64"\n", gcount);
267        gcount = 0;
268        printf("locktest4\n");
269    }
270
271    BARRIER(barrier, NPROC);
272    locktest4(core);
273    BARRIER(barrier, NPROC);
274
275    if (core == 1) printf("gcount %"PRIx64"\n", gcount);
276
277    if (core == 1) printf("inctest1\n");
278    atomiccounter = 0;
279
280    BARRIER(barrier, NPROC);
281    inctest1(core);
282    BARRIER(barrier, NPROC);
283
284    if (core == 1) {
285        printf("count %"PRIx32"\n", atomiccounter);
286        atomiccounter = 0;
287        printf("inctest4\n");
288    }
289
290    BARRIER(barrier, NPROC);
291    inctest4(core);
292    BARRIER(barrier, NPROC);
293
294    if (core == 1) {
295        printf("count %"PRIx32"\n", atomiccounter);
296        atomiccounter = 0;
297        printf("bartest1\n");
298    }
299    BARRIER(barrier, NPROC);
300    bartest1(core);
301    BARRIER(barrier, NPROC);
302
303    if (core == 1) printf("bartest4\n");
304
305    BARRIER(barrier, NPROC);
306    bartest4(core);
307    BARRIER(barrier, NPROC);
308
309    if (core == 1) printf("mutextest\n");
310
311    BARRIER(barrier, NPROC);
312    mutextest(core);
313    BARRIER(barrier, NPROC);
314
315    if (core == 1) printf("Done\n");
316
317    return 0;
318}
319
320int ndispatchers = 1;
321
322static void domain_spanned_callback(void *arg, errval_t err)
323{
324    //sys_print("D", 1);
325    ndispatchers++;
326}
327
328int main(int argc, char *argv[])
329{
330    errval_t err;
331    if (argc != 2) {
332        printf("Usage %s: <Num additional threads>\n", argv[0]);
333        exit(-1);
334    }
335
336
337    printf("main running on %d\n", disp_get_core_id());
338
339    int cores = strtol(argv[1], NULL, 10) + 1;
340
341    NPROC = cores -1;
342    BARINIT(barrier, NPROC);
343
344    uint64_t before = rdtsc();
345    times[0] = before;
346
347    trace_event(TRACE_SUBSYS_BENCH, TRACE_EVENT_BENCH_PCBENCH, 1);
348    for (int i = 1; i < cores; i++) {
349        printf("spantest: spanning to core %" PRIuCOREID "\n", i);
350        err = domain_new_dispatcher(i + disp_get_core_id(),
351                                    domain_spanned_callback,
352                                    (void*)(uintptr_t)i);
353        if (err_is_fail(err)) {
354            USER_PANIC_ERR(err, "domain_new_dispatcher failed");
355        }
356    }
357
358    while (ndispatchers < cores) {
359        thread_yield();
360    }
361    uint64_t finish = rdtsc();
362
363    trace_event(TRACE_SUBSYS_BENCH, TRACE_EVENT_BENCH_PCBENCH, 0);
364
365    //sys_print("\nDone\n", 6);
366    printf("spantest: Done in %"PRIu64" cycles\n", finish-before);
367
368    //trace_dump();
369
370    for(int i = 1; i < cores; i++) {
371        printf("spantest: create thread oncore %" PRIuCOREID "\n", i);
372        err = domain_thread_create_on(i, remote, NULL, NULL);
373        assert(err_is_ok(err));
374    }
375
376    messages_handler_loop();
377    return 0;
378}
379