Statistics
| Branch: | Revision:

root / test-coroutine.c @ 0056c093

History | View | Annotate | Download (4.1 kB)

1 aa7ee42e Stefan Hajnoczi
/*
2 aa7ee42e Stefan Hajnoczi
 * Coroutine tests
3 aa7ee42e Stefan Hajnoczi
 *
4 aa7ee42e Stefan Hajnoczi
 * Copyright IBM, Corp. 2011
5 aa7ee42e Stefan Hajnoczi
 *
6 aa7ee42e Stefan Hajnoczi
 * Authors:
7 aa7ee42e Stefan Hajnoczi
 *  Stefan Hajnoczi    <stefanha@linux.vnet.ibm.com>
8 aa7ee42e Stefan Hajnoczi
 *
9 aa7ee42e Stefan Hajnoczi
 * This work is licensed under the terms of the GNU LGPL, version 2 or later.
10 aa7ee42e Stefan Hajnoczi
 * See the COPYING.LIB file in the top-level directory.
11 aa7ee42e Stefan Hajnoczi
 *
12 aa7ee42e Stefan Hajnoczi
 */
13 aa7ee42e Stefan Hajnoczi
14 aa7ee42e Stefan Hajnoczi
#include <glib.h>
15 aa7ee42e Stefan Hajnoczi
#include "qemu-coroutine.h"
16 aa7ee42e Stefan Hajnoczi
17 aa7ee42e Stefan Hajnoczi
/*
18 aa7ee42e Stefan Hajnoczi
 * Check that qemu_in_coroutine() works
19 aa7ee42e Stefan Hajnoczi
 */
20 aa7ee42e Stefan Hajnoczi
21 aa7ee42e Stefan Hajnoczi
static void coroutine_fn verify_in_coroutine(void *opaque)
22 aa7ee42e Stefan Hajnoczi
{
23 aa7ee42e Stefan Hajnoczi
    g_assert(qemu_in_coroutine());
24 aa7ee42e Stefan Hajnoczi
}
25 aa7ee42e Stefan Hajnoczi
26 aa7ee42e Stefan Hajnoczi
static void test_in_coroutine(void)
27 aa7ee42e Stefan Hajnoczi
{
28 aa7ee42e Stefan Hajnoczi
    Coroutine *coroutine;
29 aa7ee42e Stefan Hajnoczi
30 aa7ee42e Stefan Hajnoczi
    g_assert(!qemu_in_coroutine());
31 aa7ee42e Stefan Hajnoczi
32 aa7ee42e Stefan Hajnoczi
    coroutine = qemu_coroutine_create(verify_in_coroutine);
33 aa7ee42e Stefan Hajnoczi
    qemu_coroutine_enter(coroutine, NULL);
34 aa7ee42e Stefan Hajnoczi
}
35 aa7ee42e Stefan Hajnoczi
36 aa7ee42e Stefan Hajnoczi
/*
37 aa7ee42e Stefan Hajnoczi
 * Check that qemu_coroutine_self() works
38 aa7ee42e Stefan Hajnoczi
 */
39 aa7ee42e Stefan Hajnoczi
40 aa7ee42e Stefan Hajnoczi
static void coroutine_fn verify_self(void *opaque)
41 aa7ee42e Stefan Hajnoczi
{
42 aa7ee42e Stefan Hajnoczi
    g_assert(qemu_coroutine_self() == opaque);
43 aa7ee42e Stefan Hajnoczi
}
44 aa7ee42e Stefan Hajnoczi
45 aa7ee42e Stefan Hajnoczi
static void test_self(void)
46 aa7ee42e Stefan Hajnoczi
{
47 aa7ee42e Stefan Hajnoczi
    Coroutine *coroutine;
48 aa7ee42e Stefan Hajnoczi
49 aa7ee42e Stefan Hajnoczi
    coroutine = qemu_coroutine_create(verify_self);
50 aa7ee42e Stefan Hajnoczi
    qemu_coroutine_enter(coroutine, coroutine);
51 aa7ee42e Stefan Hajnoczi
}
52 aa7ee42e Stefan Hajnoczi
53 aa7ee42e Stefan Hajnoczi
/*
54 aa7ee42e Stefan Hajnoczi
 * Check that coroutines may nest multiple levels
55 aa7ee42e Stefan Hajnoczi
 */
56 aa7ee42e Stefan Hajnoczi
57 aa7ee42e Stefan Hajnoczi
typedef struct {
58 aa7ee42e Stefan Hajnoczi
    unsigned int n_enter;   /* num coroutines entered */
59 aa7ee42e Stefan Hajnoczi
    unsigned int n_return;  /* num coroutines returned */
60 aa7ee42e Stefan Hajnoczi
    unsigned int max;       /* maximum level of nesting */
61 aa7ee42e Stefan Hajnoczi
} NestData;
62 aa7ee42e Stefan Hajnoczi
63 aa7ee42e Stefan Hajnoczi
static void coroutine_fn nest(void *opaque)
64 aa7ee42e Stefan Hajnoczi
{
65 aa7ee42e Stefan Hajnoczi
    NestData *nd = opaque;
66 aa7ee42e Stefan Hajnoczi
67 aa7ee42e Stefan Hajnoczi
    nd->n_enter++;
68 aa7ee42e Stefan Hajnoczi
69 aa7ee42e Stefan Hajnoczi
    if (nd->n_enter < nd->max) {
70 aa7ee42e Stefan Hajnoczi
        Coroutine *child;
71 aa7ee42e Stefan Hajnoczi
72 aa7ee42e Stefan Hajnoczi
        child = qemu_coroutine_create(nest);
73 aa7ee42e Stefan Hajnoczi
        qemu_coroutine_enter(child, nd);
74 aa7ee42e Stefan Hajnoczi
    }
75 aa7ee42e Stefan Hajnoczi
76 aa7ee42e Stefan Hajnoczi
    nd->n_return++;
77 aa7ee42e Stefan Hajnoczi
}
78 aa7ee42e Stefan Hajnoczi
79 aa7ee42e Stefan Hajnoczi
static void test_nesting(void)
80 aa7ee42e Stefan Hajnoczi
{
81 aa7ee42e Stefan Hajnoczi
    Coroutine *root;
82 aa7ee42e Stefan Hajnoczi
    NestData nd = {
83 aa7ee42e Stefan Hajnoczi
        .n_enter  = 0,
84 aa7ee42e Stefan Hajnoczi
        .n_return = 0,
85 aa7ee42e Stefan Hajnoczi
        .max      = 128,
86 aa7ee42e Stefan Hajnoczi
    };
87 aa7ee42e Stefan Hajnoczi
88 aa7ee42e Stefan Hajnoczi
    root = qemu_coroutine_create(nest);
89 aa7ee42e Stefan Hajnoczi
    qemu_coroutine_enter(root, &nd);
90 aa7ee42e Stefan Hajnoczi
91 aa7ee42e Stefan Hajnoczi
    /* Must enter and return from max nesting level */
92 aa7ee42e Stefan Hajnoczi
    g_assert_cmpint(nd.n_enter, ==, nd.max);
93 aa7ee42e Stefan Hajnoczi
    g_assert_cmpint(nd.n_return, ==, nd.max);
94 aa7ee42e Stefan Hajnoczi
}
95 aa7ee42e Stefan Hajnoczi
96 aa7ee42e Stefan Hajnoczi
/*
97 aa7ee42e Stefan Hajnoczi
 * Check that yield/enter transfer control correctly
98 aa7ee42e Stefan Hajnoczi
 */
99 aa7ee42e Stefan Hajnoczi
100 aa7ee42e Stefan Hajnoczi
static void coroutine_fn yield_5_times(void *opaque)
101 aa7ee42e Stefan Hajnoczi
{
102 aa7ee42e Stefan Hajnoczi
    bool *done = opaque;
103 aa7ee42e Stefan Hajnoczi
    int i;
104 aa7ee42e Stefan Hajnoczi
105 aa7ee42e Stefan Hajnoczi
    for (i = 0; i < 5; i++) {
106 aa7ee42e Stefan Hajnoczi
        qemu_coroutine_yield();
107 aa7ee42e Stefan Hajnoczi
    }
108 aa7ee42e Stefan Hajnoczi
    *done = true;
109 aa7ee42e Stefan Hajnoczi
}
110 aa7ee42e Stefan Hajnoczi
111 aa7ee42e Stefan Hajnoczi
static void test_yield(void)
112 aa7ee42e Stefan Hajnoczi
{
113 aa7ee42e Stefan Hajnoczi
    Coroutine *coroutine;
114 aa7ee42e Stefan Hajnoczi
    bool done = false;
115 aa7ee42e Stefan Hajnoczi
    int i = -1; /* one extra time to return from coroutine */
116 aa7ee42e Stefan Hajnoczi
117 aa7ee42e Stefan Hajnoczi
    coroutine = qemu_coroutine_create(yield_5_times);
118 aa7ee42e Stefan Hajnoczi
    while (!done) {
119 aa7ee42e Stefan Hajnoczi
        qemu_coroutine_enter(coroutine, &done);
120 aa7ee42e Stefan Hajnoczi
        i++;
121 aa7ee42e Stefan Hajnoczi
    }
122 aa7ee42e Stefan Hajnoczi
    g_assert_cmpint(i, ==, 5); /* coroutine must yield 5 times */
123 aa7ee42e Stefan Hajnoczi
}
124 aa7ee42e Stefan Hajnoczi
125 aa7ee42e Stefan Hajnoczi
/*
126 aa7ee42e Stefan Hajnoczi
 * Check that creation, enter, and return work
127 aa7ee42e Stefan Hajnoczi
 */
128 aa7ee42e Stefan Hajnoczi
129 aa7ee42e Stefan Hajnoczi
static void coroutine_fn set_and_exit(void *opaque)
130 aa7ee42e Stefan Hajnoczi
{
131 aa7ee42e Stefan Hajnoczi
    bool *done = opaque;
132 aa7ee42e Stefan Hajnoczi
133 aa7ee42e Stefan Hajnoczi
    *done = true;
134 aa7ee42e Stefan Hajnoczi
}
135 aa7ee42e Stefan Hajnoczi
136 aa7ee42e Stefan Hajnoczi
static void test_lifecycle(void)
137 aa7ee42e Stefan Hajnoczi
{
138 aa7ee42e Stefan Hajnoczi
    Coroutine *coroutine;
139 aa7ee42e Stefan Hajnoczi
    bool done = false;
140 aa7ee42e Stefan Hajnoczi
141 aa7ee42e Stefan Hajnoczi
    /* Create, enter, and return from coroutine */
142 aa7ee42e Stefan Hajnoczi
    coroutine = qemu_coroutine_create(set_and_exit);
143 aa7ee42e Stefan Hajnoczi
    qemu_coroutine_enter(coroutine, &done);
144 aa7ee42e Stefan Hajnoczi
    g_assert(done); /* expect done to be true (first time) */
145 aa7ee42e Stefan Hajnoczi
146 aa7ee42e Stefan Hajnoczi
    /* Repeat to check that no state affects this test */
147 aa7ee42e Stefan Hajnoczi
    done = false;
148 aa7ee42e Stefan Hajnoczi
    coroutine = qemu_coroutine_create(set_and_exit);
149 aa7ee42e Stefan Hajnoczi
    qemu_coroutine_enter(coroutine, &done);
150 aa7ee42e Stefan Hajnoczi
    g_assert(done); /* expect done to be true (second time) */
151 aa7ee42e Stefan Hajnoczi
}
152 aa7ee42e Stefan Hajnoczi
153 5e3840ce Stefan Hajnoczi
/*
154 5e3840ce Stefan Hajnoczi
 * Lifecycle benchmark
155 5e3840ce Stefan Hajnoczi
 */
156 5e3840ce Stefan Hajnoczi
157 5e3840ce Stefan Hajnoczi
static void coroutine_fn empty_coroutine(void *opaque)
158 5e3840ce Stefan Hajnoczi
{
159 5e3840ce Stefan Hajnoczi
    /* Do nothing */
160 5e3840ce Stefan Hajnoczi
}
161 5e3840ce Stefan Hajnoczi
162 5e3840ce Stefan Hajnoczi
static void perf_lifecycle(void)
163 5e3840ce Stefan Hajnoczi
{
164 5e3840ce Stefan Hajnoczi
    Coroutine *coroutine;
165 5e3840ce Stefan Hajnoczi
    unsigned int i, max;
166 5e3840ce Stefan Hajnoczi
    double duration;
167 5e3840ce Stefan Hajnoczi
168 5e3840ce Stefan Hajnoczi
    max = 1000000;
169 5e3840ce Stefan Hajnoczi
170 5e3840ce Stefan Hajnoczi
    g_test_timer_start();
171 5e3840ce Stefan Hajnoczi
    for (i = 0; i < max; i++) {
172 5e3840ce Stefan Hajnoczi
        coroutine = qemu_coroutine_create(empty_coroutine);
173 5e3840ce Stefan Hajnoczi
        qemu_coroutine_enter(coroutine, NULL);
174 5e3840ce Stefan Hajnoczi
    }
175 5e3840ce Stefan Hajnoczi
    duration = g_test_timer_elapsed();
176 5e3840ce Stefan Hajnoczi
177 5e3840ce Stefan Hajnoczi
    g_test_message("Lifecycle %u iterations: %f s\n", max, duration);
178 5e3840ce Stefan Hajnoczi
}
179 5e3840ce Stefan Hajnoczi
180 aa7ee42e Stefan Hajnoczi
int main(int argc, char **argv)
181 aa7ee42e Stefan Hajnoczi
{
182 aa7ee42e Stefan Hajnoczi
    g_test_init(&argc, &argv, NULL);
183 aa7ee42e Stefan Hajnoczi
    g_test_add_func("/basic/lifecycle", test_lifecycle);
184 aa7ee42e Stefan Hajnoczi
    g_test_add_func("/basic/yield", test_yield);
185 aa7ee42e Stefan Hajnoczi
    g_test_add_func("/basic/nesting", test_nesting);
186 aa7ee42e Stefan Hajnoczi
    g_test_add_func("/basic/self", test_self);
187 aa7ee42e Stefan Hajnoczi
    g_test_add_func("/basic/in_coroutine", test_in_coroutine);
188 5e3840ce Stefan Hajnoczi
    if (g_test_perf()) {
189 5e3840ce Stefan Hajnoczi
        g_test_add_func("/perf/lifecycle", perf_lifecycle);
190 5e3840ce Stefan Hajnoczi
    }
191 aa7ee42e Stefan Hajnoczi
    return g_test_run();
192 aa7ee42e Stefan Hajnoczi
}