1/** 2 * \file 3 * \brief Benchmark deleting cnode with varying number of occupied slots 4 */ 5 6/* 7 * Copyright (c) 2017, 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, Universitaetstr 6, CH-8092 Zurich. Attn: Systems Group. 13 */ 14 15#include <barrelfish/barrelfish.h> 16#include <if/bench_distops_defs.h> 17 18#include <bitmacros.h> 19 20#include <bench/bench.h> 21 22#include "benchapi.h" 23 24//{{{1 debugging helpers 25static void debug_capref(const char *prefix, struct capref cap) 26{ 27 char buf[128]; 28 debug_print_capref(buf, 128, cap); 29 printf("%s capref = %s\n", prefix, buf); 30} 31 32//{{{1 shared commands 33enum bench_cmd { 34 BENCH_CMD_DO_DELETE, 35 BENCH_CMD_PRINT_STATS, 36 BENCH_CMD_PRINT_DONE, 37}; 38 39//{{{1 Managment node: implement orchestration for benchmark 40 41//{{{2 Management node: state management 42 43struct global_state { 44 struct capref ram; 45 coreid_t *nodes; 46 int nodes_seen; 47 int nodecount; 48 int copies_done; 49 int printnode; 50 int currcopies; 51}; 52 53errval_t mgmt_init_benchmark(void **st, int nodecount) 54{ 55 NUM_COPIES_START = 1; 56 NUM_COPIES_END = 256; 57 58 *st = calloc(1, sizeof(struct global_state)); 59 if (!*st) { 60 return LIB_ERR_MALLOC_FAIL; 61 } 62 struct global_state *gs = *st; 63 gs->nodes = calloc(nodecount, sizeof(coreid_t)); 64 gs->nodecount = nodecount; 65 gs->copies_done = 0; 66 gs->printnode = 0; 67 gs->currcopies = NUM_COPIES_START; 68 return ram_alloc(&gs->ram, BASE_PAGE_BITS); 69} 70 71static int sort_coreid(const void *a_, const void *b_) 72{ 73 // deref pointers as coreids, store as ints 74 int a = *((coreid_t*)a_); 75 int b = *((coreid_t*)b_); 76 // subtract as ints 77 return a-b; 78} 79 80void mgmt_register_node(void *st, coreid_t nodeid) 81{ 82 struct global_state *gs = st; 83 gs->nodes[gs->nodes_seen++] = nodeid; 84 // if we've seen all nodes, sort nodes array and configure printnode 85 if (gs->nodes_seen == gs->nodecount) { 86 qsort(gs->nodes, gs->nodecount, sizeof(coreid_t), sort_coreid); 87 } 88} 89 90struct mgmt_node_state { 91}; 92 93errval_t mgmt_init_node(void **st) 94{ 95 *st = malloc(sizeof(struct mgmt_node_state)); 96 if (!*st) { 97 return LIB_ERR_MALLOC_FAIL; 98 } 99 return SYS_ERR_OK; 100} 101 102//{{{2 Management node: benchmark impl 103void mgmt_run_benchmark(void *st) 104{ 105 struct global_state *gs = st; 106 107 printf("All clients sent hello! Benchmark starting...\n"); 108 109 printf("# Benchmarking DELETE CNODE NO REMOTE CONTENTS: nodes=%d\n", gs->nodecount); 110 111 broadcast_cmd(BENCH_CMD_DO_DELETE, ITERS); 112 unicast_cmd(gs->nodes[gs->printnode++], BENCH_CMD_PRINT_STATS, 0); 113} 114 115void mgmt_cmd(uint32_t cmd, uint32_t arg, struct bench_distops_binding *b) 116{ 117 struct global_state *gs = get_global_state(b); 118 switch(cmd) { 119 case BENCH_CMD_PRINT_DONE: 120 if (gs->printnode == gs->nodecount) { 121 if (gs->currcopies == NUM_COPIES_END) { 122 printf("# Benchmark done!\n"); 123 return; 124 } 125 printf("# Round done!\n"); 126 // Reset counters for next round 127 gs->currcopies *= 2; 128 gs->copies_done = 0; 129 gs->printnode = 0; 130 // Start new round 131 broadcast_cmd(BENCH_CMD_DO_DELETE, ITERS); 132 unicast_cmd(gs->nodes[gs->printnode++], BENCH_CMD_PRINT_STATS, 0); 133 return; 134 } 135 unicast_cmd(gs->nodes[gs->printnode++], BENCH_CMD_PRINT_STATS, 0); 136 break; 137 default: 138 printf("mgmt node got unknown command %d over binding %p\n", cmd, b); 139 break; 140 } 141} 142 143void mgmt_cmd_caps(uint32_t cmd, uint32_t arg, struct capref cap1, 144 struct bench_distops_binding *b) 145{ 146 printf("mgmt node got caps + command %"PRIu32", arg=%d over binding %p:\n", 147 cmd, arg, b); 148 debug_capref("cap1:", cap1); 149} 150 151//{{{1 Node 152 153struct node_state { 154 struct capref cap; 155 struct capref ram; 156 uint32_t numcopies; 157 struct capref *copies; 158 uint64_t *delcycles; 159 uint32_t benchcount; 160}; 161 162static coreid_t my_core_id = -1; 163 164void init_node(struct bench_distops_binding *b) 165{ 166 printf("%s: binding = %p\n", __FUNCTION__, b); 167 168 my_core_id = disp_get_core_id(); 169 170 NUM_COPIES_START = 1; 171 NUM_COPIES_END = 256; 172 173 bench_init(); 174 175 // Allocate client state struct 176 b->st = malloc(sizeof(struct node_state)); 177 assert(b->st); 178 if (!b->st) { 179 USER_PANIC("state malloc() in client"); 180 } 181 struct node_state *ns = b->st; 182 printf("# node %d: allocating ram for cnode\n", my_core_id); 183 errval_t err; 184 err = ram_alloc(&ns->cap, L2_CNODE_BITS+OBJBITS_CTE); 185 assert(err_is_ok(err)); 186 ns->numcopies = NUM_COPIES_START; 187} 188 189void node_cmd(uint32_t cmd, uint32_t arg, struct bench_distops_binding *b) 190{ 191 struct node_state *ns = b->st; 192 errval_t err; 193 194 switch(cmd) { 195 case BENCH_CMD_DO_DELETE: 196 ns->benchcount = arg; 197 ns->delcycles = calloc(arg, sizeof(uint64_t)); 198 assert(ns->delcycles); 199 struct capref cn, slot, tmp; 200 printf("# node %d: doing deletes\n", my_core_id); 201 for (int i = 0; i < ns->benchcount; i++) { 202 // create CNode 203 err = slot_alloc_root(&cn); 204 assert(err_is_ok(err)); 205 assert(!capref_is_null(ns->cap)); 206 err = cnode_create_from_mem(cn, ns->cap, ObjType_L2CNode, 207 &slot.cnode, L2_CNODE_SLOTS); 208 assert(err_is_ok(err)); 209 // put caps in 210 for (slot.slot = 0; slot.slot < ns->numcopies; slot.slot++) { 211 err = ram_alloc(&tmp, BASE_PAGE_BITS); 212 assert(err_is_ok(err)); 213 err = cap_copy(slot, tmp); 214 assert(err_is_ok(err)); 215 err = cap_destroy(tmp); 216 assert(err_is_ok(err)); 217 } 218 // delete CNode 219 uint64_t start, end; 220 start = bench_tsc(); 221 err = cap_delete(cn); 222 end = bench_tsc(); 223 ns->delcycles[i] = end - start; 224 assert(err_is_ok(err)); 225 err = slot_free(cn); 226 assert(err_is_ok(err)); 227 } 228 //printf("node %d: deletes done\n", my_core_id); 229 break; 230 case BENCH_CMD_PRINT_STATS: 231 printf("# node %d: tsc_per_us = %ld; numcopies = %d\n", 232 my_core_id, bench_tsc_per_us(), ns->numcopies); 233 printf("# delete latency in cycles\n"); 234 for (int i = 0; i < ns->benchcount; i++) { 235 printf("%ld\n", ns->delcycles[i]); 236 } 237 err = bench_distops_cmd__tx(b, NOP_CONT, BENCH_CMD_PRINT_DONE, 0); 238 assert(err_is_ok(err)); 239 // Cleanup before next round 240 free(ns->delcycles); 241 ns->numcopies *= 2; 242 break; 243 default: 244 printf("node %d got command %"PRIu32"\n", my_core_id, cmd); 245 break; 246 } 247} 248 249void node_cmd_caps(uint32_t cmd, uint32_t arg, struct capref cap1, 250 struct bench_distops_binding *b) 251{ 252 switch (cmd) { 253 default: 254 printf("node %d got caps + command %"PRIu32", arg=%d:\n", 255 my_core_id, cmd, arg); 256 debug_capref("cap1:", cap1); 257 break; 258 } 259} 260