1/* 2 * Copyright (c) 2009, 2010, 2011, ETH Zurich. 3 * All rights reserved. 4 * 5 * This file is distributed under the terms in the attached LICENSE file. 6 * If you do not find this file, copies can be found by writing to: 7 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 8 */ 9 10#include <string.h> 11#include <stdio.h> 12#include <assert.h> 13#include <inttypes.h> 14#include <barrelfish/barrelfish.h> 15#include <barrelfish/bulk_transfer.h> 16#include <barrelfish/nameservice_client.h> 17#include <barrelfish/sys_debug.h> 18#include <if/bulkbench_defs.h> 19#include <bench/bench.h> 20 21#define MAXROUND 1000 22#define INIT_ROUNDS 10 23#define MINBUFSIZE (1 << 16) 24#define MAXBUFSIZE (1 << 24) 25#define BULKSIZE 65536 26 27#define BULK_PAGE_MAP VREGION_FLAGS_READ_WRITE 28 29static char buffer[BULKSIZE]; 30static bool request_done = false; 31static struct bulkbench_binding *peer = NULL; 32static size_t block_size, bulk_inflight = 0; 33static struct bulk_transfer bt; 34static struct bulk_transfer_slave btr; 35static bool client = false, use_memcpy = false; 36static char *mode = "server"; 37 38/* done by client */ 39/* server sends the msg once he has created a cap and mapped it locally. 40 * Server passes that cap to client so that client can also mount it. */ 41static void bulk_sys_init(struct bulkbench_binding *b, struct capref shared_mem) 42{ 43 errval_t err; 44 45 // Map the frame in local memory 46 void *pool; 47 err = vspace_map_one_frame_attr(&pool, BULKSIZE, shared_mem, 48 BULK_PAGE_MAP, NULL, NULL); 49 assert(pool != NULL); 50 assert(err_is_ok(err)); 51 52 // Init receiver 53 err = bulk_slave_init(pool, BULKSIZE, &btr); 54 assert(err_is_ok(err)); 55 printf("%s: bulk_sys_init: done\n", mode); 56 57 err = peer->tx_vtbl.bulk_init_reply(peer, NOP_CONT); 58 assert(err_is_ok(err)); 59} 60 61/* Done by server */ 62static void bulk_init_reply(struct bulkbench_binding *b) 63{ 64 assert(!request_done); 65 request_done = true; 66 printf("%s: bulk_init_reply: done\n", mode); 67 68} 69 70static void bulk_message_request(struct bulkbench_binding *b, uint64_t id, 71 uint64_t size, uint8_t last_fragment) 72{ 73 void *buf = bulk_slave_buf_get_mem(&btr, id, NULL); 74 static int iter = 0; 75 static bool startup_round = true; 76 static uint64_t timestamp[MAXROUND]; 77 78 printf("%s: bulk_message_request: started for id %"PRIu64"\n", mode, id); 79 80 assert(last_fragment); 81 82 if(use_memcpy) { 83 memcpy(buffer, buf, size); 84 } 85 86 timestamp[iter] = bench_tsc(); 87 iter++; 88 if(iter == MAXROUND) { 89 iter = 0; 90 if(startup_round) { 91 startup_round = false; 92 } else { 93 for(int i = 1; i < MAXROUND; i++) { 94 uint64_t diff = timestamp[i] - timestamp[i - 1]; 95 printf("rawresult %" PRIu64 "\n", diff); 96 } 97 printf("client done.\n"); 98 abort(); 99 } 100 } 101 102 printf("%s: bulk_message_request: almost done for id %"PRIu64", sending reply\n", 103 mode, id); 104 105 errval_t err = 106 peer->tx_vtbl.bulk_message_reply(peer, NOP_CONT, id, last_fragment); 107 assert(err_is_ok(err)); 108 printf("%s: bulk_message_request: done for id %"PRIu64", with sending reply\n", 109 mode, id); 110 111} 112 113/* in server */ 114static void bulk_message_reply(struct bulkbench_binding *b, uint64_t id, 115 uint8_t last_fragment) 116{ 117 errval_t err = bulk_free(&bt, id); 118 assert(err_is_ok(err)); 119 bulk_inflight--; 120 printf("%s: bulk_msg_reply: %"PRIu64" done\n", mode, id); 121} 122 123static struct bulkbench_rx_vtbl bulkbench_vtbl = { 124 .bulk_init = bulk_sys_init, 125 .bulk_init_reply = bulk_init_reply, 126 .bulk_message_request = bulk_message_request, 127 .bulk_message_reply = bulk_message_reply 128}; 129 130static void _listening(void *st, errval_t err, iref_t iref) 131{ 132 assert(err_is_ok(err)); 133 134 /* Register the service with the nameserver */ 135 err = nameservice_register("bulkbench", iref); 136 if (err_is_fail(err)) { 137 DEBUG_ERR(err, "nameservice_register failed"); 138 abort(); 139 } 140 printf("%s: _listening:nameservice bulkbench registered\n", mode); 141} 142 143static errval_t _connected(void *st, struct bulkbench_binding *b) 144{ 145 b->rx_vtbl = bulkbench_vtbl; 146 peer = b; 147 assert(!request_done); 148 request_done = true; 149 printf("%s: _connected: connection arrived\n", mode); 150 return SYS_ERR_OK; 151} 152 153static void client_connected(void *st, errval_t err, 154 struct bulkbench_binding *b) 155{ 156 assert(err_is_ok(err)); 157 b->rx_vtbl = bulkbench_vtbl; 158 peer = b; 159 printf("%s: client_connected: done\n", mode); 160} 161 162/* in server */ 163static void send(char *buf, size_t size) 164{ 165 errval_t err; 166 167 printf("%s: send: started\n", mode); 168 for(size_t i = 0; i < size; i += block_size) { 169 struct bulk_buf *bb; 170 /* get memory chunk from shared memory */ 171 do { 172 bb = bulk_alloc(&bt); 173 if(bb == NULL) { 174 // dispatch one 175 event_dispatch(get_default_waitset()); 176 } 177 } while(bb == NULL); 178 179 bulk_inflight++; 180 void *bbuf = bulk_buf_get_mem(bb); 181 size_t sendsize = i + block_size < size ? block_size : size - i; 182 bool last_fragment = i + block_size < size ? false : true; 183 184 memcpy(bbuf, buf, sendsize); 185 uintptr_t id = bulk_prepare_send(bb); 186 187 retry: 188 err = peer->tx_vtbl.bulk_message_request(peer, NOP_CONT, id, size, 189 last_fragment); 190 if(err_is_fail(err)) { 191 if(err_no(err) == FLOUNDER_ERR_TX_BUSY) { 192 // Dispatch one 193 event_dispatch(get_default_waitset()); 194 goto retry; 195 } else { 196 DEBUG_ERR(err, "Failure in send()"); 197 abort(); 198 } 199 } 200 } 201 printf("%s: send: done\n", mode); 202} 203 204int main(int argc, char *argv[]) 205{ 206 /* int round; */ 207 /* size_t bufsize; */ 208 errval_t err; 209 210 if(argc < 4) { 211 printf("Usage: %s blocksize send/recv memcpy/nomemcpy\n", 212 argv[0]); 213 exit(EXIT_FAILURE); 214 } 215 216 bench_init(); 217 218 block_size = atoi(argv[1]); 219 assert(block_size <= BULKSIZE); 220 if(!strcmp(argv[2], "recv")) { 221 client = true; 222 mode = "client"; 223 } 224 if(!strcmp(argv[3], "memcpy")) { 225 use_memcpy = true; 226 } 227 228 // Runs only on the peer 229 if(client) { 230 iref_t iref; 231 err = nameservice_blocking_lookup("bulkbench", &iref); 232 if (err_is_fail(err)) { 233 DEBUG_ERR(err, "nameservice_blocking_lookup failed"); 234 abort(); 235 } 236 assert(iref != 0); 237 238 err = bulkbench_bind(iref, client_connected, NULL, get_default_waitset(), 239 IDC_BIND_FLAGS_DEFAULT); 240 assert(err_is_ok(err)); 241 242 for(;;) { 243 event_dispatch(get_default_waitset()); 244 } 245 } 246 247 // Export service 248 request_done = false; 249 err = bulkbench_export(NULL, _listening, _connected, get_default_waitset(), 250 IDC_EXPORT_FLAGS_DEFAULT); 251 if (err_is_fail(err)) { 252 DEBUG_ERR(err, "rcce_export failed"); 253 abort(); 254 } 255 while (!request_done) { 256 event_dispatch(get_default_waitset()); 257 } 258 259 // Init sender 260 struct capref frame; 261 err = bulk_create(BULKSIZE, block_size, &frame, &bt); 262 assert(err_is_ok(err)); 263 264 err = peer->tx_vtbl.bulk_init(peer, NOP_CONT, frame); 265 assert(err_is_ok(err)); 266 267 request_done = false; 268 while (!request_done) { 269 event_dispatch(get_default_waitset()); 270 } 271 272 for(;;) { 273 send(buffer, block_size); 274 } 275 276 // Run the benchmark 277 /* for(bufsize = MINBUFSIZE; bufsize <= MAXBUFSIZE; bufsize *= 2) { */ 278 /* for (round = 0; round < MAXROUND; round++) { */ 279 /* send(buffer, bufsize); */ 280 /* } */ 281 282 // Let the benchmark cool down 283 /* while(bulk_inflight > 0) { */ 284 /* event_dispatch(get_default_waitset()); */ 285 /* } */ 286 /* } */ 287 288 printf("client done\n"); 289 return 0; 290} 291