1/**
2 * \file
3 * \brief Benchmark revoke of cap with no remote relations (no framework)
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#include <trace/trace.h>
22
23#include "benchapi.h"
24
25#define REVOKE_COPIES 10
26
27//{{{1 Management node: state management
28
29struct global_state {
30    struct capref ram;
31    int nodecount;
32    int copies_done;
33    int currcopies;
34};
35
36errval_t mgmt_init_benchmark(void **st, int nodecount)
37{
38     *st = malloc(sizeof(struct global_state));
39     if (!*st) {
40         return LIB_ERR_MALLOC_FAIL;
41     }
42     struct global_state *gs = *st;
43     gs->nodecount = nodecount;
44     gs->copies_done = 0;
45     return ram_alloc(&gs->ram, BASE_PAGE_BITS);
46}
47
48struct node_state {
49    struct capref cap;
50    struct capref ram;
51    uint32_t numcopies;
52    struct capref *copies;
53    uint64_t *delcycles;
54    uint32_t benchcount;
55};
56
57static coreid_t my_core_id = -1;
58
59static void node_create_copies(struct node_state *ns)
60{
61    errval_t err;
62    ns->copies = calloc(ns->numcopies, sizeof(struct capref));
63    for (int i = 0; i < ns->numcopies; i++) {
64        err = slot_alloc(&ns->copies[i]);
65        PANIC_IF_ERR(err, "slot_alloc for copy %d\n", i);
66        err = cap_copy(ns->copies[i], ns->ram);
67        PANIC_IF_ERR(err, "cap_copy for copy %d\n", i);
68    }
69}
70
71static size_t get_mdb_size(void)
72{
73    errval_t err;
74    size_t cap_base_count = 0;
75    err = sys_debug_get_mdb_size(&cap_base_count);
76    assert(err_is_ok(err));
77    return cap_base_count;
78}
79
80int main(int argc, char *argv[])
81{
82    if (argc > 1) {
83        printf("# Benchmarking REVOKE NO REMOTE: nodes=%d\n", atoi(argv[1]));
84
85        printf("# Starting out with %d copies, will double up to %d...\n",
86                NUM_COPIES_START, NUM_COPIES_END);
87    }
88
89    struct global_state *gs;
90    errval_t err;
91
92    // Initialize global state
93    err = mgmt_init_benchmark((void**)&gs, 1);
94    assert(err_is_ok(err));
95
96    // Initialize tracing
97    err = mgmt_init_tracing();
98    assert(err_is_ok(err));
99
100    // Initialize node state
101    struct node_state ns_;
102    struct node_state *ns = &ns_;
103    ns->ram = gs->ram;
104    ns->benchcount = ITERS;
105    ns->delcycles = calloc(ns->benchcount, sizeof(uint64_t));
106    assert(ns->delcycles);
107
108    my_core_id = disp_get_core_id();
109
110    bench_init();
111
112    // allocate slots for copies
113    struct capref copies[REVOKE_COPIES];
114    for (int c = 0; c < REVOKE_COPIES; c++) {
115        err = slot_alloc(&copies[c]);
116        assert(err_is_ok(err));
117    }
118
119    TRACE(CAPOPS, START, 0);
120
121    for (gs->currcopies = NUM_COPIES_START;
122         gs->currcopies <= NUM_COPIES_END;
123         gs->currcopies *= 2)
124    {
125        ns->numcopies = gs->currcopies;
126        printf("# node %d: creating %d cap copies\n", my_core_id, ns->numcopies);
127        node_create_copies(ns);
128        printf("# node %d: %zu capabilities on node\n", my_core_id, get_mdb_size());
129        struct capref cap;
130        err = ram_alloc(&cap, BASE_PAGE_BITS);
131        assert(err_is_ok(err));
132        // printf("# node %d: starting benchmark iterations\n", my_core_id);
133        for (int i = 0; i < ns->benchcount; i++) {
134            uint64_t start, end;
135            // Make some copies to be deleted during revoke
136            // printf("# node %d: creating copies\n", my_core_id);
137            for (int c = 0; c < REVOKE_COPIES; c++) {
138                err = cap_copy(copies[c], cap);
139                PANIC_IF_ERR(err, "creating copy for revoke");
140                assert(err_is_ok(err));
141            }
142            // printf("# node %d: doing revoke\n", my_core_id);
143            start = bench_tsc();
144            TRACE(CAPOPS, USER_REVOKE_CALL, (ns->numcopies << 16) | i);
145            err = cap_revoke(cap);
146            TRACE(CAPOPS, USER_REVOKE_RESP, (ns->numcopies << 16) | i);
147            end = bench_tsc();
148            ns->delcycles[i] = end - start;
149            assert(err_is_ok(err));
150            PANIC_IF_ERR(err, "# core %d: revoke failed", my_core_id);
151            if (i % (ns->benchcount / 10) == 0) {
152                // printf("# node %d: %d percent done\n", my_core_id, i / (ns->benchcount/100));
153            }
154        }
155        err = cap_destroy(cap);
156        assert(err_is_ok(err));
157        PANIC_IF_ERR(err, "# core %d: final cap_destroy", my_core_id);
158
159        printf("# node %d: tsc_per_us = %ld; numcopies = %d\n",
160                my_core_id, bench_tsc_per_us(), ns->numcopies);
161        printf("# delete latency in cycles\n");
162        for (int i = 0; i < ns->benchcount; i++) {
163            printf("%ld\n", ns->delcycles[i]);
164        }
165        // Cleanup before next round
166        for (int i = 0; i < ns->numcopies; i++) {
167            err = cap_destroy(ns->copies[i]);
168            assert(err_is_ok(err));
169        }
170        free(ns->copies);
171        printf("# Round done!\n");
172    }
173
174    TRACE(CAPOPS, STOP, 0);
175    mgmt_trace_flush(NOP_CONT);
176
177    // We're not printing this line here, as it's printed from the standalone
178    // runner, that allows us to run single-core benchmarks sequentially on
179    // multiple cores
180    // printf("# Benchmark done!\n");
181    return 0;
182}
183