1/** \file
2 *  \brief Process Management test.
3 */
4
5/*
6 * Copyright (c) 2017, ETH Zurich.
7 * All rights reserved.
8 *
9 * This file is distributed under the terms in the attached LICENSE file.
10 * If you do not find this file, copies can be found by writing to:
11 * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
12 */
13
14#include <stdlib.h>
15
16#include <barrelfish/barrelfish.h>
17#include <barrelfish/deferred.h>
18#include <barrelfish/sys_debug.h>
19#include <barrelfish/spawn_client.h>
20#include <bench/bench.h>
21
22#define PROC_MGMT_BENCH 1
23#define PROC_MGMT_BENCH_MIN_RUNS 20
24
25static errval_t test_spawn(coreid_t core_id, char *argv[],
26	                       struct capref *ret_domain_cap)
27{
28	assert(ret_domain_cap != NULL);
29
30	errval_t err = spawn_program(core_id, "proc_mgmt_test",
31		                         argv, NULL, 0, ret_domain_cap);
32	if (err_is_fail(err)) {
33        return err;
34	}
35    return SYS_ERR_OK;
36}
37
38/*
39static void test_span(coreid_t core_id)
40{
41 	errval_t err = proc_mgmt_span(core_id);
42 	if (err_is_fail(err)) {
43    }
44}
45
46static void test_kill(struct capref domain_cap)
47{
48 	errval_t err = proc_mgmt_kill(domain_cap);
49 	if (err_is_ok(err)) {
50        USER_PANIC("Failed killing domain")
51    }
52}
53
54static void test_wait(struct capref domain_cap)
55{
56 	uint8_t code;
57 	errval_t err = proc_mgmt_wait(domain_cap, &code);
58 	if (err_is_fail(err)) {
59        USER_PANIC("Failed waiting for domain");
60 	}
61}
62*/
63
64static inline cycles_t calculate_time(cycles_t tsc_start, cycles_t tsc_end)
65{
66    cycles_t result;
67    if (tsc_end < tsc_start) {
68        result = (LONG_MAX - tsc_start) + tsc_end - bench_tscoverhead();
69    } else {
70        result = (tsc_end - tsc_start - bench_tscoverhead());
71    }
72    return result;
73}
74
75static void print_ps(domainid_t* domains, size_t len)
76{
77    errval_t err;
78    for(size_t i = 0; i < len; i++) {
79        struct spawn_ps_entry pse;
80        char *argbuf, status;
81        size_t arglen;
82        errval_t reterr;
83
84        err = spawn_get_status(domains[i], &pse, &argbuf, &arglen, &reterr);
85        if (err_is_fail(err)) {
86            USER_PANIC("PS FAILED \n");
87        }
88        if(err_is_fail(reterr)) {
89            USER_PANIC("PS FAILED \n");
90        }
91
92        switch(pse.status) {
93        case 0:
94            status = 'N';
95            break;
96
97        case 1:
98            status = 'R';
99            break;
100
101        case 2:
102            status = 'S';
103            break;
104
105        case 3:
106            status = 'S';
107            break;
108
109        default:
110            status = '?';
111            break;
112        }
113
114        printf("%-8u\t%c\t", domains[i], status);
115        size_t pos = 0;
116        for(int p = 0; pos < arglen && p < MAX_CMDLINE_ARGS;) {
117            printf("%s ", &argbuf[pos]);
118            char *end = memchr(&argbuf[pos], '\0', arglen - pos);
119            assert(end != NULL);
120            pos = end - argbuf + 1;
121        }
122        printf("\n");
123
124        free(argbuf);
125    }
126}
127
128static void run_benchmark_spawn(coreid_t target_core)
129{
130    bench_init();
131
132    cycles_t tsc_start, tsc_end;
133    cycles_t result;
134    cycles_t tscperus;
135
136    bench_ctl_t *ctl = calloc(1, sizeof(*ctl));
137    ctl->mode = BENCH_MODE_FIXEDRUNS;
138    ctl->result_dimensions = 1;
139    ctl->min_runs = PROC_MGMT_BENCH_MIN_RUNS;
140    ctl->data = calloc(ctl->min_runs * ctl->result_dimensions,
141                       sizeof(*ctl->data));
142
143    errval_t err = sys_debug_get_tsc_per_ms(&tscperus);
144    assert(err_is_ok(err));
145    tscperus /= 1000;
146
147    struct capref domain_cap;
148
149    char *spawn_argv[] = { "proc_mgmt_test", "0", "norun", NULL};
150    do {
151        tsc_start = bench_tsc();
152
153        test_spawn(target_core, spawn_argv, &domain_cap);
154
155        tsc_end = bench_tsc();
156        result = calculate_time(tsc_start, tsc_end);
157    } while (!bench_ctl_add_run(ctl, &result));
158
159    cap_destroy(domain_cap);
160    bench_ctl_dump_analysis(ctl, 0, "client", tscperus);
161
162    bench_ctl_destroy(ctl);
163}
164
165int main(int argc, char **argv)
166{
167    errval_t err;
168	if (argc == 3) {
169        if (strcmp("starter", argv[2]) == 0) {
170            // just continue;
171        } else if (strcmp("norun", argv[2]) == 0) {
172            // directly return
173            return 0;
174        } else if (strcmp("run", argv[2]) == 0) {
175            // Run infinite loop
176            printf("Running infinite Loop");
177            while(true) {
178                printf("Running infinite Loop");
179                barrelfish_usleep(1000*1000);
180                event_dispatch_non_block(get_default_waitset());
181            }
182        } else if (strcmp("sleeper", argv[2]) == 0) {
183            // Process that we wait for to finish
184            printf("Running for a few seconds \n");
185            barrelfish_usleep(10*1000*1000);
186            printf("Sleeper exit\n");
187            return 0;
188        } else if (strcmp("span", argv[2]) == 0) {
189            // Process that spans domains
190            if (disp_get_core_id() == 0) {
191                spawn_span(1);
192            } else {
193                spawn_span(0);
194            }
195            while(true) {
196                event_dispatch(get_default_waitset());
197            }
198        } else {
199            USER_PANIC("Unknown Role \n ");
200        }
201
202	} else {
203        USER_PANIC("Not enough arguments to run test \n ");
204    }
205
206    struct capref domain_cap;
207    printf("Testing kill on same core\n");
208    char *spawn_argv[] = { "proc_mgmt_test", "0", "run", NULL};
209    err = test_spawn(disp_get_core_id(), spawn_argv, &domain_cap);
210    if (err_is_fail(err)) {
211        USER_PANIC("Failed spawning program proc_mgmt_test \n");
212    }
213
214    //starting a process takes some time ...
215    barrelfish_usleep(5*1000*1000);
216
217    printf("Killing process \n");
218 	err = spawn_kill(domain_cap);
219 	if (err_is_fail(err)) {
220        USER_PANIC("Failed waiting for domain \n");
221 	}
222
223    // Killing a process takes some time ...
224    barrelfish_usleep(5*1000*1000);
225
226    printf("Testing kill on other core\n");
227    err = test_spawn(disp_get_core_id()+1, spawn_argv, &domain_cap);
228    if (err_is_fail(err)) {
229        USER_PANIC("Failed spawning program proc_mgmt_test \n");
230    }
231
232    barrelfish_usleep(5*1000*1000);
233
234    printf("Killing process \n");
235 	err = spawn_kill(domain_cap);
236 	if (err_is_fail(err)) {
237        USER_PANIC("Failed waiting for domain \n");
238 	}
239
240    // TODO check if process was killed
241    printf("Testing spaning on different core\n");
242    char *spawn_argv3[] = { "proc_mgmt_test", "0", "span", NULL};
243    err = test_spawn(disp_get_core_id()+1, spawn_argv3, &domain_cap);
244    if (err_is_fail(err)) {
245        USER_PANIC("Failed spawning program proc_mgmt_test \n");
246    }
247
248    printf("Testing spaning on same core\n");
249    err = test_spawn(disp_get_core_id(), spawn_argv3, &domain_cap);
250    if (err_is_fail(err)) {
251        USER_PANIC("Failed spawning program proc_mgmt_test \n");
252    }
253
254    printf("Testing wait on different core process\n");
255    char *spawn_argv2[] = { "proc_mgmt_test", "0", "sleeper", NULL};
256    err = test_spawn(disp_get_core_id()+1, spawn_argv2, &domain_cap);
257    if (err_is_fail(err)) {
258        USER_PANIC("Failed spawning program proc_mgmt_test \n");
259    }
260
261    barrelfish_usleep(5*1000*1000);
262
263 	uint8_t code;
264    printf("Waiting for process on different core to finish \n");
265 	err = spawn_wait(domain_cap, &code, false);
266 	if (err_is_fail(err)) {
267        USER_PANIC("Failed waiting for domain \n");
268 	}
269    printf("Unblocked \n");
270
271    printf("Testing wait on same core process\n");
272    err = test_spawn(disp_get_core_id(), spawn_argv2, &domain_cap);
273    if (err_is_fail(err)) {
274        USER_PANIC("Failed spawning program proc_mgmt_test \n");
275    }
276
277    barrelfish_usleep(5*1000*1000);
278
279    printf("Waiting for process on same core to finish \n");
280 	err = spawn_wait(domain_cap, &code, true);
281 	if (err_is_fail(err)) {
282        USER_PANIC("Failed waiting for domain \n");
283 	}
284    printf("Nowait hang return code %d \n", code);
285 	err = spawn_wait(domain_cap, &code, false);
286 	if (err_is_fail(err)) {
287        USER_PANIC("Failed waiting for domain \n");
288 	}
289    printf("Unblocked \n");
290
291 	err = spawn_wait(domain_cap, &code, true);
292 	if (err_is_fail(err)) {
293        USER_PANIC("Failed waiting for domain \n");
294 	}
295    printf("Nowait hang return code %d \n", code);
296    printf("Running benchmarks core 0 \n");
297    run_benchmark_spawn(disp_get_core_id());
298    printf("Running benchmarks core 1 \n");
299    run_benchmark_spawn(disp_get_core_id()+1);
300
301    for (int j = 0; j < 10; j++) {
302        domainid_t* domains;
303        size_t len;
304        printf("Get domain list sorted \n");
305        err = spawn_get_domain_list(true, &domains, &len);
306        if (err_is_fail(err)){
307            USER_PANIC("Failed getting domain ids \n");
308        }
309
310        print_ps(domains, len);
311        free(domains);
312
313        printf("Get domain list unsorted \n");
314        err = spawn_get_domain_list(false, &domains, &len);
315        if (err_is_fail(err)){
316            USER_PANIC("Failed getting domain ids \n");
317        }
318
319        print_ps(domains, len);
320
321        free(domains);
322    }
323    printf("TEST DONE\n");
324    return 0;
325}
326