1/* 2 * Copyright (c) 2007, 2008, 2009, 2010, 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 <stdio.h> 11#include <stdint.h> 12#include <string.h> 13#include <barrelfish/barrelfish.h> 14#include <barrelfish/nameservice_client.h> 15#include <bench/bench.h> 16#include <if/bench_defs.h> 17 18// for cache benchmark 19#include <barrelfish/sys_debug.h> 20#include <arch/x86/barrelfish/perfmon.h> 21#include <arch/x86/barrelfish_kpi/perfmon_amd.h> 22 23static bool cache_benchmark; 24static bool start_benchmark_flag = false; 25static struct bench_binding *binding; 26static struct lmp_chan *chan; 27 28#define ITERATIONS 1000 29 30struct timestamps { 31 uint64_t time0; 32 uint64_t time1; 33}; 34static struct timestamps timestamps[ITERATIONS]; 35static struct timestamps overhead[ITERATIONS]; 36static int currentiter; 37 38 39#ifndef __x86_64__ 40#define rdpmc(x) bench_tsc() 41#endif 42 43// server side handler 44static void lrpc_bench_handler(void *arg) 45{ 46 errval_t err; 47 uint64_t val; 48 if (cache_benchmark) { 49 val = rdpmc(0); 50 } else { 51 val = bench_tsc(); 52 } 53 54 // try to pull a message out of the channel 55 struct lmp_recv_msg msg = LMP_RECV_MSG_INIT; 56 err = lmp_chan_recv(chan, &msg, NULL); 57 if (err_is_fail(err)) { 58 DEBUG_ERR(err, "endpoint poll failed"); 59 printf("endpoint_poll failed\n"); 60 abort(); 61 } 62 63 // send back reply 64 struct bench_binding *b = arg; 65 err = b->tx_vtbl.lrpc_bench_reply(b, NOP_CONT, val); 66 if (err_is_fail(err)) { 67 DEBUG_ERR(err, "error sending back reply"); 68 printf("lrpc_bench_reply failed\n"); 69 abort(); 70 } 71 72 // re-register 73 struct event_closure ec = { 74 .handler = lrpc_bench_handler, 75 .arg = b, 76 }; 77 lmp_chan_register_recv(chan, get_default_waitset(), ec); 78} 79 80static void lrpc_init(struct bench_binding *b) 81{ 82 binding = b; 83 chan = &((struct bench_lmp_binding *)b)->chan; 84} 85 86// client side handler 87static void lrpc_bench_reply_handler(struct bench_binding *b, 88 uint64_t value) 89{ 90 timestamps[currentiter].time1 = value; 91} 92 93static void lrpc_init_reply(struct bench_binding *b) 94{ 95 chan = &((struct bench_lmp_binding *)b)->chan; 96 start_benchmark_flag = true; 97} 98 99/// server and client rx vtbl 100static struct bench_rx_vtbl rx_vtbl = { 101 .lrpc_init = lrpc_init, 102 .lrpc_init_reply = lrpc_init_reply, 103 .lrpc_bench_reply = lrpc_bench_reply_handler, 104}; 105 106/// Called on the client side when client connected to the server 107static void bind_cb(void *st, errval_t err, struct bench_binding *b) 108{ 109 assert(err_is_ok(err)); 110 b->rx_vtbl = rx_vtbl; 111 112 err = b->tx_vtbl.lrpc_init(b, NOP_CONT); 113 if (err_is_fail(err)) { 114 DEBUG_ERR(err, "lrpc_init_reply failed"); 115 printf("lrpc_init_reply failed\n"); 116 abort(); 117 } 118} 119 120static void lrpc_benchmark(uint64_t event, uint64_t umask) 121{ 122 errval_t err; 123 124 if (cache_benchmark) { 125 perfmon_setup(curdispatcher(), 0, event, umask, true); 126 127 /* Measure measurement overhead */ 128 for (size_t i = 0; i < ITERATIONS; i++) { 129 overhead[i].time0 = rdpmc(0); 130 sys_debug_flush_cache(); 131 overhead[i].time1 = rdpmc(0); 132 } 133 } 134 135 for(currentiter = 0; currentiter < ITERATIONS; currentiter++) { 136 // yield to receiver to make sure they are ready 137 thread_yield_dispatcher(chan->remote_cap); 138 139 if (cache_benchmark) { 140 timestamps[currentiter].time0 = rdpmc(0); 141 sys_debug_flush_cache(); 142 } else { 143 timestamps[currentiter].time0 = bench_tsc(); 144 } 145 146 err = lmp_ep_send0(chan->remote_cap, LMP_FLAG_SYNC, NULL_CAP); 147 if (err_is_fail(err)) { 148 DEBUG_ERR(err, "LRPC %d failed", currentiter); 149 printf("lmp_ep_send0 failed\n"); 150 abort(); 151 } 152 while (timestamps[currentiter].time1 == 0) { 153 messages_wait_and_handle_next(); 154 } 155 } 156 157 /* Print results */ 158 for (int i = 0; i < ITERATIONS; i++) { 159 printf("page %d took %"PRIu64"\n", i, 160 timestamps[i].time1 - bench_tscoverhead() - 161 timestamps[i].time0); 162 } 163} 164 165/// Called when servers setup their services 166static void export_cb(void *st, errval_t err, iref_t iref) 167{ 168 assert(err_is_ok(err)); 169 err = nameservice_register("lrpc_server", iref); 170 assert(err_is_ok(err)); 171} 172 173/// Called when the client connects 174static errval_t connect_cb(void *st, struct bench_binding *b) 175{ 176 b->rx_vtbl = rx_vtbl; 177 return SYS_ERR_OK; 178} 179 180int main(int argc, char *argv[]) 181{ 182 enum {CLIENT, SERVER} mode = -1; 183 errval_t err; 184 185 for (int i = 1; i < argc; i++) { 186 if (strcmp(argv[i], "client") == 0) { 187 mode = CLIENT; 188 } else if (strcmp(argv[i], "server") == 0) { 189 mode = SERVER; 190 } else if (strcmp(argv[i], "cache") == 0) { 191 cache_benchmark = true; 192 } else { 193 fprintf(stderr, "%s: unknown argument '%s'\n", argv[0], argv[i]); 194 return -1; 195 } 196 } 197 198 if (mode == -1) { 199 fprintf(stderr, "Usage: %s client|server [cache]\n", argv[0]); 200 return -1; 201 } 202 203 if (mode == SERVER) { /* Server */ 204 /* Setup a server */ 205 err = bench_export(NULL, export_cb, connect_cb, get_default_waitset(), 206 IDC_EXPORT_FLAGS_DEFAULT); 207 if (err_is_fail(err)) { 208 DEBUG_ERR(err, "failed to setup a server"); 209 exit(EXIT_FAILURE); 210 } 211 212 while (chan == NULL || binding == NULL) { 213 messages_wait_and_handle_next(); 214 } 215 216 // cancel flounder-generated event loop and install our own 217 lmp_chan_deregister_recv(chan); 218 struct event_closure ec = { 219 .handler = lrpc_bench_handler, 220 .arg = binding, 221 }; 222 lmp_chan_register_recv(chan, get_default_waitset(), ec); 223 224 err = binding->tx_vtbl.lrpc_init_reply(binding, NOP_CONT); 225 if (err_is_fail(err)) { 226 DEBUG_ERR(err, "lrpc_init_reply failed"); 227 printf("lrpc_init_reply failed\n"); 228 abort(); 229 } 230 231 messages_handler_loop(); 232 } 233 234 /* Client */ 235 /* Initialize the benchmarking library */ 236 bench_init(); 237 238 /* Connect to the server */ 239 iref_t serv_iref; 240 err = nameservice_blocking_lookup("lrpc_server", &serv_iref); 241 if (err_is_fail(err)) { 242 DEBUG_ERR(err, "failed to lookup server"); 243 exit(EXIT_FAILURE); 244 } 245 assert(serv_iref != 0); 246 247 err = bench_bind(serv_iref, bind_cb, NULL, get_default_waitset(), 248 IDC_BIND_FLAGS_DEFAULT); 249 if (err_is_fail(err)) { 250 DEBUG_ERR(err, "failed to connect to server"); 251 exit(EXIT_FAILURE); 252 } 253 254 while (!start_benchmark_flag) { 255 messages_wait_and_handle_next(); 256 } 257 258 printf("LRPC call benchmark:\n"); 259 260 if (cache_benchmark) { 261 fprintf(stderr, "cache benchmark NYI, sorry"); 262 return EXIT_FAILURE; 263 264 lrpc_benchmark(EVENT_AMD_DATA_CACHE_MISSES, 0); 265 lrpc_benchmark(EVENT_AMD_DATA_CACHE_LINES_EVICTED, UMASK_COUNT_ALL); 266 lrpc_benchmark(EVENT_AMD_INSTRUCTION_CACHE_MISSES, 0); 267 lrpc_benchmark(EVENT_AMD_L2_FILL_WRITEBACK, UMASK_AMD_L2_FILL_WRITEBACK_FILLS); 268 } else { 269 lrpc_benchmark(0, 0); 270 } 271 272 printf("End of benchmarks.\n"); 273 return 0; 274} 275