1/** 2 * Tests cross core cap management 3 * 4 * 5 * Copyright (c) 2010, 2011, ETH Zurich. 6 * All rights reserved. 7 * 8 * This file is distributed under the terms in the attached LICENSE file. 9 * If you do not find this file, copies can be found by writing to: 10 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group. 11 */ 12#include <barrelfish/barrelfish.h> 13#include <stdio.h> 14#include <if/xcorecapbench_defs.h> 15#include <barrelfish/nameservice_client.h> 16#include <barrelfish/spawn_client.h> 17#include <trace/trace.h> 18#include <string.h> 19#include <bench/bench.h> 20 21#define PARENT_BYTES (1UL << 19) 22#define CHILD_BYTES 4096 23#define CAPS_PER_CORE (PARENT_BYTES / CHILD_BYTES) 24 25/* --- Globals ---*/ 26 27static bool is_bsp; 28static bool exported; 29static bool connected; 30static bool connect; 31static bool start_sending_caps; 32static bool start_retyping_caps; 33static struct xcorecapbench_binding *bindings[MAX_CPUS]; 34static coreid_t my_coreid; 35static coreid_t num_cores; 36static coreid_t wait_for; 37static struct capref my_caps[CAPS_PER_CORE]; 38static struct capref retyped_caps[CAPS_PER_CORE]; 39static cycles_t total_cycles; 40 41/* --- Binding handlers --- */ 42 43static void connect_handler(struct xcorecapbench_binding *b); 44static void start_retyping_handler(struct xcorecapbench_binding *b); 45static void start_sending_handler(struct xcorecapbench_binding *b); 46static void send_cap_handler(struct xcorecapbench_binding *b, 47 struct capref ram_cap); 48static void barrier_done_handler(struct xcorecapbench_binding *b, uint64_t cycles); 49 50struct xcorecapbench_rx_vtbl rx_vtbl = { 51 .start_retyping= start_retyping_handler, 52 .start_sending = start_sending_handler, 53 .send_cap = send_cap_handler, 54 .barrier_done = barrier_done_handler, 55 .connect = connect_handler, 56}; 57 58 59static void create_caps(void) 60{ 61 errval_t err; 62 63 // allocate a bunch of ramcaps 64 for (int i=0; i<CAPS_PER_CORE; i++) { 65 err = ram_alloc(&my_caps[i], log2ceil(CHILD_BYTES)); 66 if (err_is_fail(err)) { 67 DEBUG_ERR(err, "xcorecap: RAM alloc failed\n"); 68 abort(); 69 } 70 err = slot_alloc(&retyped_caps[i]); 71 if (err_is_fail(err)) { 72 DEBUG_ERR(err, "slot alloc err\n"); 73 abort(); 74 } 75 } 76 printf("core %i caps created\n", my_coreid); 77} 78 79static inline bool redo_message(errval_t err) { 80 if (err == FLOUNDER_ERR_TX_BUSY) { 81 messages_wait_and_handle_next(); 82 return true; 83 } else { 84 return false; 85 } 86} 87 88static cycles_t send_caps(void) 89{ 90 errval_t err; 91 cycles_t time_taken = 0; 92 93 srand(bench_tsc()); // random starting seed 94 95 for (int i=0; i<CAPS_PER_CORE; i++) { 96 coreid_t to_core; 97 do { 98 to_core = rand() % num_cores; 99 } while(to_core == my_coreid); 100 101 do { 102 cycles_t start = bench_tsc(); 103 err = bindings[to_core]->tx_vtbl.send_cap( 104 bindings[to_core], NOP_CONT, my_caps[i]); 105 if (i >= 20 && i <= (CAPS_PER_CORE - 20)) { // avoid warmup / cooldown 106 time_taken += (bench_tsc() - start); 107 } 108 } while(redo_message(err)); 109 110 if (err_is_fail(err)) { 111 DEBUG_ERR(err, "xcorecap: cap send failed\n"); 112 abort(); 113 } 114 } 115 116 return time_taken / (CAPS_PER_CORE - 40); 117} 118 119static cycles_t retype_caps(void) 120{ 121 errval_t err; 122 cycles_t time_taken = 0; 123 for (int i=0; i<CAPS_PER_CORE; i++) { 124 cycles_t start = bench_tsc(); 125 err = cap_retype(retyped_caps[i], my_caps[i], 0, ObjType_Frame, CHILD_BYTES, 1); 126 if (i >= 20 && i <= (CAPS_PER_CORE - 20)) { // avoid warmup / cooldown 127 time_taken += (bench_tsc() - start); 128 } 129 if (err_is_fail(err)) { 130 DEBUG_ERR(err, "xcorecap: Retype to frame failed\n"); 131 } 132 } 133 134 return time_taken / (CAPS_PER_CORE - 40); 135} 136 137static void destroy_caps(void) 138{ 139 errval_t err; 140 for (int i=0; i<CAPS_PER_CORE; i++) { 141 err = cap_destroy(retyped_caps[i]); 142 err = cap_revoke(my_caps[i]); 143 if (err_is_fail(err)) { 144 DEBUG_ERR(err, "xcorecap: Retype to frame failed\n"); 145 } 146 } 147} 148 149static void start_sending_handler(struct xcorecapbench_binding *b) 150{ 151 start_sending_caps = true; 152} 153 154static void start_retyping_handler(struct xcorecapbench_binding *b) 155{ 156 start_retyping_caps = true; 157} 158 159static void connect_handler(struct xcorecapbench_binding *b) 160{ 161 connect = true; 162} 163static void barrier_done_handler(struct xcorecapbench_binding *b, 164 uint64_t cycles) 165{ 166 total_cycles += (cycles_t)cycles; 167 assert(wait_for != 0); 168 wait_for--; 169} 170 171static void send_cap_handler(struct xcorecapbench_binding *b, 172 struct capref ram_cap) 173{ 174 // don't do anything 175} 176 177/* ------------------------- Domain spawning code -------------------------- */ 178 179static errval_t spawn_other_cores(int argc, char *argv[]) { 180 errval_t err; 181 182 char core_id_char[32]; 183 snprintf(core_id_char, sizeof(core_id_char), "%d", num_cores); 184 core_id_char[sizeof(core_id_char) - 1] = '\0'; 185 186 char *xargv[] = {argv[0], "client", core_id_char, NULL}; 187 188 for (int i=1; i<num_cores; i++) { 189 /* XXX: assumes core IDs are 0-based and contiguous */ 190 err = spawn_program(i, xargv[0], xargv, NULL, 191 SPAWN_FLAGS_DEFAULT, NULL); 192 if (err_is_fail(err)) { 193 DEBUG_ERR(err, "error spawning other core"); 194 abort(); 195 } 196 } 197 198 return SYS_ERR_OK; 199} 200 201 202/* ---------------------------- Binding Setup Callbacks ------------------- */ 203 204 205static inline void get_service_name(char * service_name, size_t size, 206 coreid_t coreid) 207{ 208 memset(service_name, 0, size); 209 strncpy(service_name, "xcorecapbench_", 210 sizeof("xcorecapbench_")); 211 char local_id[32]; 212 snprintf(local_id, sizeof(local_id), "%d", 213 coreid); 214 strcat(service_name, local_id); 215} 216 217 218static errval_t connect_cb(void *st, struct xcorecapbench_binding *b) 219{ 220 // copy my message receive handler vtable to the binding 221 b->rx_vtbl = rx_vtbl; 222 223 // accept the connection 224 return SYS_ERR_OK; 225} 226 227static void export_cb(void *st, errval_t err, iref_t iref) 228{ 229 if (err_is_fail(err)) { 230 DEBUG_ERR(err, "export failed"); 231 abort(); 232 } 233 234 // register this iref with the name service 235 char my_service_name[128]; 236 get_service_name(my_service_name, 128, disp_get_core_id()); 237 err = nameservice_register(my_service_name, iref); 238 if (err_is_fail(err)) { 239 DEBUG_ERR(err, "nameservice_register failed"); 240 abort(); 241 } 242 exported = true; 243} 244 245static void bind_cb(void *st, errval_t err, struct xcorecapbench_binding *b) 246{ 247 assert(err_is_ok(err)); 248 249 b->rx_vtbl = rx_vtbl; 250 251 coreid_t core = (coreid_t)(uintptr_t) st; 252 bindings[core] = b; 253 254 // check if we are finished 255 for (int i=0; i<num_cores; i++) { 256 if (i != my_coreid && bindings[i] == NULL) { 257 return; // not finished yet 258 } 259 } 260 connected = true; 261} 262 263static void bind_core(coreid_t core) { 264 errval_t err; 265 iref_t iref; 266 char core_service_name[128]; 267 get_service_name(core_service_name, 128, core); 268 err = nameservice_blocking_lookup(core_service_name, &iref); 269 if (err_is_fail(err)) { 270 fprintf(stderr, "could not connect to the xcorecapbench.\n" 271 "Terminating.\n"); 272 abort(); 273 } 274 err = xcorecapbench_bind(iref, bind_cb, (void*)(uintptr_t)core, 275 get_default_waitset(), IDC_BIND_FLAGS_DEFAULT); 276 if (err_is_fail(err)) { 277 DEBUG_ERR(err, "bind failed"); 278 abort(); 279 } 280} 281 282/* ----- Experiment ------- */ 283static void do_experiment_bsp(void) 284{ 285 errval_t err; 286 287 printf("Sending Caps\n"); 288 wait_for = num_cores; 289 total_cycles = 0; 290 291 for (int i=1; i<num_cores; i++) { 292 do { 293 err = bindings[i]->tx_vtbl.start_sending(bindings[i], NOP_CONT); 294 } while (redo_message(err)); 295 296 assert(err_is_ok(err)); 297 } 298 total_cycles += send_caps(); 299 wait_for--; 300 301 // wait for other cores to finish 302 while(wait_for) { 303 messages_wait_and_handle_next(); 304 } 305 306 printf("Retyping Caps\n"); 307 for(int iter=0; iter<10; iter++) { 308 wait_for = num_cores; 309 total_cycles = 0; 310 311 for (int i=1; i<num_cores; i++) { 312 do { 313 err = bindings[i]->tx_vtbl.start_retyping(bindings[i], NOP_CONT); 314 } while (redo_message(err)); 315 316 assert(err_is_ok(err)); 317 } 318 total_cycles += retype_caps(); 319 wait_for--; 320 321 // wait for other cores to finish 322 while(wait_for) { 323 messages_wait_and_handle_next(); 324 } 325 326 destroy_caps(); 327 328 printf("%" PRIuCYCLES "\n", total_cycles / num_cores); 329 } 330 printf("Done\n"); 331} 332 333 334static void do_experiment_client(void) 335{ 336 errval_t err; 337 cycles_t cycles; 338 339 while(!start_sending_caps) { 340 messages_wait_and_handle_next(); 341 } 342 cycles = send_caps(); 343 do { 344 err = bindings[0]->tx_vtbl.barrier_done(bindings[0], NOP_CONT, cycles); 345 } while (redo_message(err)); 346 assert(err_is_ok(err)); 347 348 while (true) { 349 start_retyping_caps = false; 350 while(!start_retyping_caps) { 351 messages_wait_and_handle_next(); 352 } 353 cycles = retype_caps(); 354 355 destroy_caps(); 356 do { 357 err = bindings[0]->tx_vtbl.barrier_done(bindings[0], NOP_CONT, cycles); 358 } while (redo_message(err)); 359 assert(err_is_ok(err)); 360 } 361} 362/* ------------------------------------ MAIN ----------------------------- */ 363 364#define NUM_RAM_CAPS 100 365static struct capref ram_caps[NUM_RAM_CAPS]; 366 367static errval_t my_ram_alloc(struct capref *ret, uint8_t size_bits, 368 uint64_t minbase, uint64_t maxlimit) 369{ 370 if (size_bits != BASE_PAGE_BITS) { 371 printf("%d I cannot allocate this frame %d %d\n", my_coreid, size_bits, BASE_PAGE_BITS); 372 abort(); 373 } 374 static int i = 0; 375 if (i == NUM_RAM_CAPS) { 376 printf("%d, out of ram caps\n", my_coreid); 377 abort(); 378 } 379 *ret = ram_caps[i++]; 380 return SYS_ERR_OK; 381} 382 383static void ram_hack(void) 384{ 385 errval_t err; 386 387 for (int i = 0; i < 100; i++) { 388 err = ram_alloc(&ram_caps[i], BASE_PAGE_BITS); 389 assert(err_is_ok(err)); 390 } 391 392 err = ram_alloc_set(my_ram_alloc); 393 assert(err_is_ok(err)); 394} 395 396int main (int argc, char* argv[]) 397{ 398 errval_t err; 399 my_coreid = disp_get_core_id(); 400 401 exported = false; 402 connected = false; 403 start_sending_caps = false; 404 start_retyping_caps = false; 405 406 // munge up a bunch of caps 407 create_caps(); 408 409 assert (argc >= 2); 410 if (!strncmp(argv[1], "client", sizeof("client"))) { 411 is_bsp = false; 412 assert (argc >= 3); 413 num_cores = atoi(argv[2]); 414 ram_hack(); 415 } else { 416 is_bsp = true; 417 num_cores = atoi(argv[1]); 418 } 419 420 // export our binding 421 exported = false; 422 err = xcorecapbench_export(NULL, export_cb, connect_cb, 423 get_default_waitset(), IDC_EXPORT_FLAGS_DEFAULT); 424 while(!exported) { 425 messages_wait_and_handle_next(); 426 } 427 428 if (is_bsp) { 429 wait_for = num_cores; 430 // spawn other cores 431 printf("Core %d starting xcorecapbench on %i cores\n", my_coreid, 432 num_cores); 433 assert(disp_get_core_id() == 0); 434 spawn_other_cores(argc, argv); 435 } else { 436 printf("Starting xcorecapbench on core %i \n", my_coreid); 437 } 438 439 // connect to other cores 440 connected = false; 441 for(int i=0; i<num_cores; i++) { 442 if (i != my_coreid) { 443 bind_core(i); 444 } 445 } 446 while(!connected) { 447 messages_wait_and_handle_next(); 448 } 449 450 if (is_bsp) { 451 wait_for--; 452 // wait for cores to connect 453 while(wait_for) { 454 messages_wait_and_handle_next(); 455 } 456 } else { 457 err = bindings[0]->tx_vtbl.barrier_done(bindings[0], NOP_CONT, 0); 458 assert(err_is_ok(err)); 459 } 460 461 if (is_bsp) { 462 do_experiment_bsp(); 463 } else { 464 do_experiment_client(); 465 } 466 467 messages_handler_loop(); 468 469 return 0; 470} 471 472