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