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