1/** 2 * \file 3 * \brief Microbenchmark to measure the cost of shared memory clock 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 <stdio.h> 16#include <string.h> 17#include <barrelfish/barrelfish.h> 18#include <barrelfish/nameservice_client.h> 19#include <barrelfish/spawn_client.h> 20#include <bench/bench.h> 21#include <if/monitor_defs.h> 22#include <if/bench_defs.h> 23#include "clock.h" 24 25#define MAX_COUNT 1000 26 27static coreid_t my_core_id; 28static coreid_t num_cores; 29static struct capref clock_frame; 30static struct bench_binding *array[MAX_CPUS]; 31static bool start_experiment_flag; 32 33struct timestamp { 34 cycles_t time0; 35 cycles_t time1; 36}; 37 38static struct timestamp timestamps[MAX_COUNT]; 39 40static void run_experiment(void) 41{ 42 for (int i = 0; i < MAX_COUNT; i++) { 43 timestamps[i].time0 = bench_tsc(); 44 clock_get_timestamp(); 45 timestamps[i].time1 = bench_tsc(); 46 } 47} 48 49static void shmc_start(struct bench_binding *b) 50{ 51 run_experiment(); 52 errval_t err; 53 err = b->tx_vtbl.shmc_done(b, NOP_CONT); 54 if (err_is_fail(err)) { 55 USER_PANIC_ERR(err, "sending shmc_done failed"); 56 } 57} 58 59static bool experiment_flag; 60static int experiment_count; 61static void shmc_done(struct bench_binding *b) 62{ 63 static int count = 0; 64 65 count++; 66 if (count == experiment_count) { 67 count = 0; 68 experiment_flag = true; 69 } 70} 71 72static void start_experiment(void) 73{ 74 errval_t err; 75 76 for (int i = 1; i < num_cores; i++) { 77 78 int count = 0; 79 experiment_flag = false; 80 experiment_count = i; 81 for (int j = 0; j < MAX_CPUS; j++) { 82 if (array[j]) { 83 while(1) { 84 err = array[j]->tx_vtbl.shmc_start(array[j], NOP_CONT); 85 if (err_is_ok(err)) { 86 break; 87 } else if (err_no(err) == FLOUNDER_ERR_TX_BUSY) { 88 messages_wait_and_handle_next(); 89 } else { 90 USER_PANIC_ERR(err, "sending shmc_start failed"); 91 } 92 } 93 count++; 94 if (count == i) { 95 break; 96 } 97 } 98 } 99 run_experiment(); 100 101 printf("Running on %d cores\n", i + 1); 102 for (int j = 0; j < MAX_COUNT; j++) { 103 printf("page %d took %"PRIuCYCLES"\n", j, 104 timestamps[j].time1 - timestamps[j].time0 - bench_tscoverhead()); 105 } 106 107 while(!experiment_flag) { 108 messages_wait_and_handle_next(); 109 } 110 } 111 printf("client done\n"); 112} 113 114static void shmc_init_request(struct bench_binding *b, coreid_t id) 115{ 116 array[id] = b; 117 118 errval_t err; 119 err = b->tx_vtbl.shmc_init_reply(b, NOP_CONT, clock_frame); 120 if (err_is_fail(err)) { 121 USER_PANIC_ERR(err, "sending shmc_init_reply failed"); 122 } 123 124 static coreid_t count = 0; 125 count++; 126 if (count + 1 == num_cores) { 127 start_experiment_flag = true; 128 } 129} 130 131static void shmc_init_reply(struct bench_binding *b, struct capref cap) 132{ 133 clock_frame = cap; 134 errval_t err = clock_init(cap); 135 if (err_is_fail(err)) { 136 USER_PANIC_ERR(err, "clock_init failed"); 137 } 138} 139 140static struct bench_rx_vtbl rx_vtbl = { 141 .shmc_init_request = shmc_init_request, 142 .shmc_init_reply = shmc_init_reply, 143 .shmc_start = shmc_start, 144 .shmc_done = shmc_done, 145}; 146 147static void bind_cb(void *st, errval_t err, struct bench_binding *b) 148{ 149 if (err_is_fail(err)) { 150 USER_PANIC_ERR(err, "bind failed"); 151 } 152 153 // copy my message receive handler vtable to the binding 154 b->rx_vtbl = rx_vtbl; 155 156 b->tx_vtbl.shmc_init_request(b, NOP_CONT, my_core_id); 157 if (err_is_fail(err)) { 158 USER_PANIC_ERR(err, "sending shm_init_request failed"); 159 } 160} 161 162static void export_cb(void *st, errval_t err, iref_t iref) 163{ 164 if (err_is_fail(err)) { 165 USER_PANIC_ERR(err, "export failed"); 166 } 167 168 // register this iref with the name service 169 err = nameservice_register("server", iref); 170 if (err_is_fail(err)) { 171 USER_PANIC_ERR(err, "nameservice_register failed"); 172 } 173} 174 175static errval_t connect_cb(void *st, struct bench_binding *b) 176{ 177 b->rx_vtbl = rx_vtbl; 178 return SYS_ERR_OK; 179} 180 181int main(int argc, char *argv[]) 182{ 183 errval_t err; 184 my_core_id = disp_get_core_id(); 185 bench_init(); 186 187 if (argc == 1) { /* server */ 188 // Spawn client on another core 189 char *xargv[] = {"shared_mem_clock_bench", "dummy", NULL}; 190 err = spawn_program_on_all_cores(false, xargv[0], xargv, NULL, 191 SPAWN_FLAGS_DEFAULT, NULL, &num_cores); 192 if (err_is_fail(err)) { 193 USER_PANIC_ERR(err, "error spawning on other cores"); 194 } 195 196 // Export service 197 err = bench_export(NULL, export_cb, connect_cb, get_default_waitset(), 198 IDC_EXPORT_FLAGS_DEFAULT); 199 if (err_is_fail(err)) { 200 USER_PANIC_ERR(err, "export failed"); 201 } 202 203 // Allocate a cap for the shared memory 204 err = frame_alloc(&clock_frame, BASE_PAGE_SIZE, NULL); 205 if (err_is_fail(err)) { 206 USER_PANIC_ERR(err, "frame_alloc failed"); 207 } 208 err = clock_init(clock_frame); 209 if (err_is_fail(err)) { 210 USER_PANIC_ERR(err, "clock_init failed"); 211 } 212 213 // Wait for all connections to be established 214 start_experiment_flag = false; 215 while(!start_experiment_flag) { 216 messages_wait_and_handle_next(); 217 } 218 219 // Start experiments 220 start_experiment(); 221 222 } else { /* client */ 223 // Lookup service 224 iref_t iref; 225 err = nameservice_blocking_lookup("server", &iref); 226 if (err_is_fail(err)) { 227 USER_PANIC_ERR(err, "nameservice_blocking_lookup failed"); 228 } 229 230 // Bind to service 231 err = bench_bind(iref, bind_cb, NULL, get_default_waitset(), 232 IDC_BIND_FLAGS_DEFAULT); 233 if (err_is_fail(err)) { 234 USER_PANIC_ERR(err, "bind failed"); 235 } 236 } 237 238 messages_handler_loop(); 239} 240