1/**
2 * \file
3 * \brief Computes a matrix multiplication. Tries to do that in a cache-aware way.
4 */
5
6/*
7 * Copyright (c) 2007, 2008, 2009, 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, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <string.h>
16#include <barrelfish/barrelfish.h>
17#include <stdio.h>
18#include <stdlib.h>
19#include <skb/skb.h>
20// #include <if/monitor_defs.h>
21#include <barrelfish/dispatch.h>
22#include <if/skb_map_defs.h>
23
24
25//define that if you want to use the cache aware list allocation
26#define CACHE_AWARE
27
28//how many cores does this application support?
29#define MAXCORES 32
30
31
32static struct skb_map_client_response *mycl;
33static struct skb_map_client_response * clients[32];
34static int available_cores[MAXCORES];
35static int available_valid = 0;
36
37//prototypes
38static void spawnmyself(bool bsp);
39static void map_init_server(void);
40static void map_init_client(uint64_t core_id);
41
42
43
44#ifdef CACHE_AWARE
45static int l1_line_size;
46
47static void get_l1_line_size(void)
48{
49    //because the information might not yet be added to the SKB...
50    for (int i = 0; i < 3; i++) {
51        skb_execute("cache(_,_,1,data,_,_,LineSize,_),write(output,LineSize).");
52        while (skb_read_error_code() == SKB_PROCESSING) messages_wait_and_handle_next();
53        if (skb_read_error_code() == 0) {
54            break;
55        }
56        thread_yield();
57    }
58    if (skb_read_error_code() == 0) {
59        l1_line_size = atoi(skb_get_output());
60    } else {
61        printf("\nerror code = %d\n", skb_read_error_code());
62        printf("\nerror output = %s\n", skb_get_error_output());
63        l1_line_size = 64;
64        printf("\nassuming %d bytes\n", l1_line_size);
65    }
66    printf("\ncache line size is %d bytes.\n", l1_line_size);
67}
68
69//************************* memory management **********************************
70struct memmmgt {
71    struct capref frame;
72    void *va;
73    uint64_t bitmap[];
74};
75
76static struct capref mmgtframe;
77static void *mmgtva;
78static uint64_t nrbitmapfields;
79static uint64_t structsize;
80static uint64_t nrstructs;
81
82//1 bit corresponds to a memory block of 1 L1 cache line
83static int init_mem(void)
84{
85    int r;
86
87    r = frame_alloc(&mmgtframe, BASE_PAGE_SIZE, NULL);
88    if (r != 0) {
89        return (r);
90    }
91    mmgtva = vspace_map(mmgtframe, 0, BASE_PAGE_SIZE, NULL, NULL);
92    if (mmgtva == 0) {
93        return (-1);
94    }
95    nrbitmapfields = (BASE_PAGE_SIZE / l1_line_size) / 64;
96    structsize = nrbitmapfields + sizeof(struct memmmgt);
97    int adjust = structsize % l1_line_size;
98    if (adjust != 0) {
99        structsize += (l1_line_size - adjust);
100    }
101    nrstructs = BASE_PAGE_SIZE / structsize;
102    memset(mmgtva, 0, BASE_PAGE_SIZE);
103    printf("\nstructsize = %lu, #structs = %lu\n", structsize, nrstructs);
104    return 0;
105}
106
107static void *alloc_mem(int size)
108{
109    int r;
110
111    int nr_blocks = size / l1_line_size + ((size % l1_line_size) != 0);
112    int mask = (1 << nr_blocks) - 1;
113
114    for (int i = 0; i < nrstructs; i++) {
115        struct memmmgt *tmp = (struct memmmgt*)(i * structsize + mmgtva);
116        if (tmp->va == 0) {
117            r = frame_alloc(&(tmp->frame), BASE_PAGE_SIZE, NULL);
118            if (r != 0) {
119                return (0);
120            }
121            tmp->va = vspace_map(tmp->frame, 0, BASE_PAGE_SIZE, NULL, NULL);
122            if (tmp->va == 0) {
123                return (0);
124            }
125        }
126        for (int j = 0; j < nrbitmapfields; j++) {
127            for (int k = 0; k < (64 - nr_blocks); k++) {
128                if ((tmp->bitmap[j] & (mask << k)) == 0) {
129                    tmp->bitmap[j] |= (mask << k);
130                    return (tmp->va + ((j * 64) + k) * l1_line_size);
131                }
132            }
133        }
134    }
135    return (0);
136}
137
138static uint64_t get_offset_from_page(void *va)
139{
140    for (int i = 0; i < nrstructs; i++) {
141        struct memmmgt *tmp = (struct memmmgt*)(i * structsize + mmgtva);
142        if ((va >= tmp->va) && (va <= tmp->va)) {
143            return (va - tmp->va);
144        }
145    }
146//page not found... (shouldn't happen...
147//does not matter, then the allocation strategy will not be optimal,
148//but will still work
149    return (0);
150}
151
152static int *alloc_list(int size)
153{
154    int eff_size = sizeof(int) * (size + 1);
155    int adjust = eff_size % l1_line_size;
156    if (adjust != 0) {
157        eff_size += (l1_line_size - adjust);
158    }
159    assert((eff_size % l1_line_size) == 0);
160    int *tmp = (int*)alloc_mem(eff_size);
161    printf("\ntmp = %p\n", tmp);
162    assert(tmp != 0);
163    assert(((vaddr_t)tmp % l1_line_size) == 0);
164    tmp[0] = size;
165    return (tmp);
166}
167
168static void free_list(int *list)
169{
170    printf("\nXXX: free_list does nothing.\n");
171}
172#else
173static int *alloc_list(int size)
174{
175    int *tmp = (int*)malloc(size * sizeof(int));
176    assert(tmp != 0);
177    tmp[0] = size;
178    return (tmp);
179}
180static void free_list(int *list)
181{
182    free(list);
183}
184#endif
185
186//*********************************************
187
188//**************** thread allocation plan **************************************
189int nr_threads;
190struct threadalloc {
191    uint8_t core_id;
192    vaddr_t start, end;
193};
194
195struct threadalloc ta[MAXCORES];
196
197//**************** parsing the thread results from the SKB *********************
198static void threadplan(paddr_t startaddress, paddr_t endaddress)
199{
200    printf("\nmap: requesting threadplan...\n");
201    uint64_t nr_threads, start, end;
202    uint32_t core_id;
203    char query[128];
204
205    if (available_valid == 0) {
206        return;
207    }
208    char threadlist[128];
209    sprintf(threadlist, "%d", available_cores[0]);
210    for (int i = 1; i < available_valid; i++) {
211        sprintf(threadlist,"%s,%d", threadlist, available_cores[i]);
212    }
213    printf("\nthreadlist = %s\n", threadlist);
214    sprintf(query, "allocthread([%s], %lu, %lu, L), length(L,Len),"
215            "write(ouput,Len), write(output,L).",
216            threadlist, startaddress, endaddress);
217    skb_execute(query);
218    while (skb_read_error_code() == SKB_PROCESSING) messages_wait_and_handle_next();
219    printf("\nerror code = %d\n", skb_read_error_code());
220    printf("\noutput = %s\n", skb_get_output());
221    printf("\nerror output = %s\n", skb_get_error_output());
222
223    char *output = skb_get_output();
224//    sscanf(output,"%lu",&nr_threads);
225    nr_threads = atoi(output);
226    printf("\nshould allocate %lu threads.\n", nr_threads);
227    for (int i = 0; i < nr_threads; i++) {
228        while (!((output[0] >= '0') && (output[0] <= '9'))) output++;
229//        sscanf(output, "range(%u, %lu, %lu)", &core_id, &start, &end);
230        core_id = atoi(output);
231        while (!((output[0] >= '0') && (output[0] <= '9'))) output++;
232        start = atoi(output);
233        while (!((output[0] >= '0') && (output[0] <= '9'))) output++;
234        end = atoi(output);
235        printf("thread on core %u, range [%lu, %lu]\n", core_id, start, end);
236        output++;
237    }
238}
239
240
241//*********************************************
242
243static void map(int(*f)(int),int *list, int **newlist)
244{
245    int *tmp = alloc_list(list[0]);
246    *newlist = tmp;
247    for (int i = 0; i < list[0]; i++) {
248        tmp[i + 1] = f(list[i + 1]);
249    }
250}
251
252static void print_list(int *list)
253{
254    printf("[");
255    for (int i = 0; i < list[0]; i++) {
256        printf("%d,", list[i + 1]);
257    }
258    printf("]\n");
259}
260
261
262
263//********************************* user functions *****************************
264static int sqr_list(int in)
265{
266    return (in * in);
267}
268
269typedef int(*f)(int);
270static f functions[] = {sqr_list};
271
272static uint64_t core_id;
273
274int main(int argc, char **argv)
275{
276    printf("map: connecting to the SKB...\n");
277    skb_client_connect();
278    printf("map: connected.\n");
279
280    skb_create_buffer();
281
282    core_id = disp_get_core_id();
283    printf("\nmap: running one core %lu\n", core_id);
284    printf("\nmap %lu: argc = %d\n", core_id, argc);
285
286
287//get the L1 cache line size and initialize the memory management accordingly
288#ifdef CACHE_AWARE
289    get_l1_line_size();
290    init_mem();
291#endif
292    if (argc == 1) { //this is the bootstrap copy of the domain
293        map_init_server();
294        spawnmyself(true);
295    } else {
296        printf("\nmap %lu: waiting for requests from the main domain\n", core_id);
297        map_init_client(core_id);
298        mycl->f->initialized(mycl, core_id);
299        messages_handler_loop();
300    }
301
302    ////wait a bit for the cloned domains to come up...
303    //messages_wait_and_handle_next();
304    messages_handler_loop();
305
306    threadplan(0, 64);
307
308//allocate a list at cache line boundaries. Fill it with values and apply
309//a square function on every element using map. Print the newly allocated result
310//list.
311    int *list1 = alloc_list(17);
312    for (int i = 0; i < 17; i++) {
313        list1[1 + i] = i;
314    }
315    print_list(list1);
316    int *list2;
317    uint64_t offset = get_offset_from_page(list1);
318    offset = offset;
319    map(functions[0], list1, &list2);
320    print_list(list2);
321
322    free_list(list1);
323    free_list(list2);
324
325    messages_handler_loop();
326    return 0;
327}
328
329
330
331
332
333
334
335
336//*********** everything needed to spawn myself to all other cores *************
337
338/* Generic buffer set */
339static void set_generic_buf_reply(struct monitor_client_response *st, errval_t msgerr)
340{
341    assert(err_is_ok(msgerr));
342    errval_t err;
343    printf("\nmap %lu: set_generic_buf_reply\n", core_id);
344    /* Spawn self on all cores except the current */
345    err = st->call_vtbl->spawn_domain_request
346        (st, "map", "map spawned", 0, 2);
347    assert(err_is_ok(err));
348}
349
350/* All clients spawned */
351static void spawn_domain_reply(struct monitor_client_response *st, errval_t err){}
352
353static void spawnmyself(bool bsp)
354{
355    errval_t err;
356
357    printf("\nmap %lu: bsp = %d\n", core_id, bsp);
358    /* Set handlers */
359    get_monitor_closure()->f->spawn_domain_reply = spawn_domain_reply;
360    get_monitor_closure()->f->set_generic_buf_reply = set_generic_buf_reply;
361    if (bsp) { /* bsp */
362        /* Set generic buffer channel with the monitor
363           and spawn bcast on additional cores */
364        err = monitor_client_set_generic_buf();
365        assert(err_is_ok(err));
366    }
367}
368
369
370
371//***************** handlers ****************************************************
372
373static void skb_map_share_page_c(struct skb_map_client_response *cc,
374                               struct capref cap, uint64_t pagenumber)
375{
376
377}
378static void skb_map_share_page_s(struct skb_map_service_response *cc,
379                               struct capref cap, uint64_t pagenumber)
380{
381
382}
383
384static void skb_map_mapfunction_c(struct skb_map_client_response *cc, uint64_t functionnr,
385                                uint64_t startaddress, uint64_t endaddress)
386{
387}
388static void skb_map_mapfunction_s(struct skb_map_service_response *cc, uint64_t functionnr,
389                                uint64_t startaddress, uint64_t endaddress)
390{
391}
392
393static void skb_map_finished_c(struct skb_map_client_response *cc, uint64_t core_id)
394{}
395static void skb_map_finished_s(struct skb_map_service_response *cc, uint64_t core_id)
396{}
397
398static void skb_map_initialized_c(struct skb_map_client_response *cc, uint64_t coreid)
399{
400    printf("\nmap: got connection from %lu\n", coreid);
401    clients[coreid] = cc;
402    available_cores[available_valid++] = coreid;
403}
404
405static void skb_map_initialized_s(struct skb_map_service_response *cc, uint64_t coreid)
406{
407/*
408    printf("\nmap: got connection from %lu\n", coreid);
409    clients[coreid] = cc;
410    available_cores[available_valid++] = coreid;
411*/
412}
413
414
415
416
417
418//***** everything needed to connect as client to the server domain *******
419bool skb_map_connected = false;
420static void client_disconnect_handler(struct skb_map_client_response *st)
421{
422}
423
424
425static void client_connection_service_logic(struct skb_map_client_response *st)
426{
427    skb_map_connected = true;
428    mycl = st;
429}
430
431static void start_client(struct chips_context *context, uint64_t core_id)
432{
433    iref_t iref;
434
435    errval_t e = chips_blocking_lookup(context, "skb_map", &iref);
436    if (err_is_fail(e)) {
437        fprintf(stderr, "map %lu: could not connect to the main map domain.\n"
438                "Terminating.\n", core_id);
439        abort();
440    }
441
442    assert(iref != 0);
443
444
445    static struct skb_map_client_response_vtbl crv = {
446        .sharepage = skb_map_share_page_c,
447        .mapfunction = skb_map_mapfunction_c,
448        .mapfinished = skb_map_finished_c,
449        .initialized = skb_map_initialized_c,
450        ._disconnect = client_disconnect_handler,
451        ._connected = client_connection_service_logic
452    };
453
454    static struct skb_map_client_response cr = {
455        .f = &crv
456    };
457
458    skb_map_connect(iref, &cr, 0);
459}
460
461static void map_init_client(uint64_t core_id)
462{
463    struct chips_context *context = chips_get_context();
464    context->init();
465    start_client(context, core_id);
466    while (!skb_map_connected) {
467        messages_wait_and_handle_next();
468    }
469}
470
471
472
473//***** everything needed to create the server part on all other domains *******
474//connection prototypes
475static void listen_cb(struct skb_map_service *st, iref_t iref);
476static void skb_map_disconnect_handler(struct skb_map_service_response *cl);
477static errval_t connection_service_logic(struct skb_map_service_response *cl);
478
479
480struct client_closure {
481};
482
483struct listen_closure {
484} lc;
485
486struct skb_map_server_call_vtbl skb_map_call_vtbl =
487    {
488        .sharepage = skb_map_share_page_s,
489        .mapfunction = skb_map_mapfunction_s,
490        .mapfinished = skb_map_finished_s,
491        .initialized = skb_map_initialized_s,
492        ._listening = listen_cb,
493        ._disconnect = skb_map_disconnect_handler,
494        ._connected = connection_service_logic,
495    };
496struct skb_map_service skb_map_service =
497    {
498        .f = &skb_map_call_vtbl,
499        .st = &lc
500    };
501
502static errval_t connection_service_logic(struct skb_map_service_response *cl)
503{
504    struct client_closure *cc = (struct client_closure*)
505        malloc(sizeof(struct client_closure));
506
507    cl->st = cc;
508
509    return 0;
510}
511
512static void skb_map_disconnect_handler(struct skb_map_service_response *cl)
513{
514/*
515    struct client_closure *cc =
516        (struct client_closure *) cl->st;
517
518    free(cc);
519    cc = 0;
520    free(closure);
521    closure = 0;
522*/
523}
524
525//called when listen suceeds
526static void listen_cb(struct skb_map_service *st, iref_t iref)
527{
528    assert(iref != 0); //if iref == 0, listen failed.
529    struct chips_context *context = chips_get_context();
530    context->register_service("skb_map", iref, NULL, NULL);
531}
532
533static void map_init_server(void)
534{
535    int r;
536
537    struct chips_context *context = chips_get_context();
538    context->init();
539    r = skb_map_listen(&skb_map_service);
540    assert(r == 0);
541}
542