Statistics
| Branch: | Revision:

root / tests / test-thread-pool.c @ 17862378

History | View | Annotate | Download (5.6 kB)

1 74c856e9 Paolo Bonzini
#include <glib.h>
2 74c856e9 Paolo Bonzini
#include "qemu-common.h"
3 737e150e Paolo Bonzini
#include "block/aio.h"
4 737e150e Paolo Bonzini
#include "block/thread-pool.h"
5 737e150e Paolo Bonzini
#include "block/block.h"
6 74c856e9 Paolo Bonzini
7 74c856e9 Paolo Bonzini
static int active;
8 74c856e9 Paolo Bonzini
9 74c856e9 Paolo Bonzini
typedef struct {
10 74c856e9 Paolo Bonzini
    BlockDriverAIOCB *aiocb;
11 74c856e9 Paolo Bonzini
    int n;
12 74c856e9 Paolo Bonzini
    int ret;
13 74c856e9 Paolo Bonzini
} WorkerTestData;
14 74c856e9 Paolo Bonzini
15 74c856e9 Paolo Bonzini
static int worker_cb(void *opaque)
16 74c856e9 Paolo Bonzini
{
17 74c856e9 Paolo Bonzini
    WorkerTestData *data = opaque;
18 74c856e9 Paolo Bonzini
    return __sync_fetch_and_add(&data->n, 1);
19 74c856e9 Paolo Bonzini
}
20 74c856e9 Paolo Bonzini
21 74c856e9 Paolo Bonzini
static int long_cb(void *opaque)
22 74c856e9 Paolo Bonzini
{
23 74c856e9 Paolo Bonzini
    WorkerTestData *data = opaque;
24 74c856e9 Paolo Bonzini
    __sync_fetch_and_add(&data->n, 1);
25 74c856e9 Paolo Bonzini
    g_usleep(2000000);
26 74c856e9 Paolo Bonzini
    __sync_fetch_and_add(&data->n, 1);
27 74c856e9 Paolo Bonzini
    return 0;
28 74c856e9 Paolo Bonzini
}
29 74c856e9 Paolo Bonzini
30 74c856e9 Paolo Bonzini
static void done_cb(void *opaque, int ret)
31 74c856e9 Paolo Bonzini
{
32 74c856e9 Paolo Bonzini
    WorkerTestData *data = opaque;
33 74c856e9 Paolo Bonzini
    g_assert_cmpint(data->ret, ==, -EINPROGRESS);
34 74c856e9 Paolo Bonzini
    data->ret = ret;
35 74c856e9 Paolo Bonzini
    data->aiocb = NULL;
36 74c856e9 Paolo Bonzini
37 74c856e9 Paolo Bonzini
    /* Callbacks are serialized, so no need to use atomic ops.  */
38 74c856e9 Paolo Bonzini
    active--;
39 74c856e9 Paolo Bonzini
}
40 74c856e9 Paolo Bonzini
41 74c856e9 Paolo Bonzini
/* A non-blocking poll of the main AIO context (we cannot use aio_poll
42 74c856e9 Paolo Bonzini
 * because we do not know the AioContext).
43 74c856e9 Paolo Bonzini
 */
44 74c856e9 Paolo Bonzini
static void qemu_aio_wait_nonblocking(void)
45 74c856e9 Paolo Bonzini
{
46 74c856e9 Paolo Bonzini
    qemu_notify_event();
47 74c856e9 Paolo Bonzini
    qemu_aio_wait();
48 74c856e9 Paolo Bonzini
}
49 74c856e9 Paolo Bonzini
50 8a805c22 Stefan Hajnoczi
/* Wait until all aio and bh activity has finished */
51 8a805c22 Stefan Hajnoczi
static void qemu_aio_wait_all(void)
52 8a805c22 Stefan Hajnoczi
{
53 8a805c22 Stefan Hajnoczi
    while (qemu_aio_wait()) {
54 8a805c22 Stefan Hajnoczi
        /* Do nothing */
55 8a805c22 Stefan Hajnoczi
    }
56 8a805c22 Stefan Hajnoczi
}
57 8a805c22 Stefan Hajnoczi
58 74c856e9 Paolo Bonzini
static void test_submit(void)
59 74c856e9 Paolo Bonzini
{
60 74c856e9 Paolo Bonzini
    WorkerTestData data = { .n = 0 };
61 74c856e9 Paolo Bonzini
    thread_pool_submit(worker_cb, &data);
62 8a805c22 Stefan Hajnoczi
    qemu_aio_wait_all();
63 74c856e9 Paolo Bonzini
    g_assert_cmpint(data.n, ==, 1);
64 74c856e9 Paolo Bonzini
}
65 74c856e9 Paolo Bonzini
66 74c856e9 Paolo Bonzini
static void test_submit_aio(void)
67 74c856e9 Paolo Bonzini
{
68 74c856e9 Paolo Bonzini
    WorkerTestData data = { .n = 0, .ret = -EINPROGRESS };
69 74c856e9 Paolo Bonzini
    data.aiocb = thread_pool_submit_aio(worker_cb, &data, done_cb, &data);
70 74c856e9 Paolo Bonzini
71 74c856e9 Paolo Bonzini
    /* The callbacks are not called until after the first wait.  */
72 74c856e9 Paolo Bonzini
    active = 1;
73 74c856e9 Paolo Bonzini
    g_assert_cmpint(data.ret, ==, -EINPROGRESS);
74 8a805c22 Stefan Hajnoczi
    qemu_aio_wait_all();
75 74c856e9 Paolo Bonzini
    g_assert_cmpint(active, ==, 0);
76 74c856e9 Paolo Bonzini
    g_assert_cmpint(data.n, ==, 1);
77 74c856e9 Paolo Bonzini
    g_assert_cmpint(data.ret, ==, 0);
78 74c856e9 Paolo Bonzini
}
79 74c856e9 Paolo Bonzini
80 74c856e9 Paolo Bonzini
static void co_test_cb(void *opaque)
81 74c856e9 Paolo Bonzini
{
82 74c856e9 Paolo Bonzini
    WorkerTestData *data = opaque;
83 74c856e9 Paolo Bonzini
84 74c856e9 Paolo Bonzini
    active = 1;
85 74c856e9 Paolo Bonzini
    data->n = 0;
86 74c856e9 Paolo Bonzini
    data->ret = -EINPROGRESS;
87 74c856e9 Paolo Bonzini
    thread_pool_submit_co(worker_cb, data);
88 74c856e9 Paolo Bonzini
89 74c856e9 Paolo Bonzini
    /* The test continues in test_submit_co, after qemu_coroutine_enter... */
90 74c856e9 Paolo Bonzini
91 74c856e9 Paolo Bonzini
    g_assert_cmpint(data->n, ==, 1);
92 74c856e9 Paolo Bonzini
    data->ret = 0;
93 74c856e9 Paolo Bonzini
    active--;
94 74c856e9 Paolo Bonzini
95 8a805c22 Stefan Hajnoczi
    /* The test continues in test_submit_co, after qemu_aio_wait_all... */
96 74c856e9 Paolo Bonzini
}
97 74c856e9 Paolo Bonzini
98 74c856e9 Paolo Bonzini
static void test_submit_co(void)
99 74c856e9 Paolo Bonzini
{
100 74c856e9 Paolo Bonzini
    WorkerTestData data;
101 74c856e9 Paolo Bonzini
    Coroutine *co = qemu_coroutine_create(co_test_cb);
102 74c856e9 Paolo Bonzini
103 74c856e9 Paolo Bonzini
    qemu_coroutine_enter(co, &data);
104 74c856e9 Paolo Bonzini
105 74c856e9 Paolo Bonzini
    /* Back here once the worker has started.  */
106 74c856e9 Paolo Bonzini
107 74c856e9 Paolo Bonzini
    g_assert_cmpint(active, ==, 1);
108 74c856e9 Paolo Bonzini
    g_assert_cmpint(data.ret, ==, -EINPROGRESS);
109 74c856e9 Paolo Bonzini
110 8a805c22 Stefan Hajnoczi
    /* qemu_aio_wait_all will execute the rest of the coroutine.  */
111 74c856e9 Paolo Bonzini
112 8a805c22 Stefan Hajnoczi
    qemu_aio_wait_all();
113 74c856e9 Paolo Bonzini
114 74c856e9 Paolo Bonzini
    /* Back here after the coroutine has finished.  */
115 74c856e9 Paolo Bonzini
116 74c856e9 Paolo Bonzini
    g_assert_cmpint(active, ==, 0);
117 74c856e9 Paolo Bonzini
    g_assert_cmpint(data.ret, ==, 0);
118 74c856e9 Paolo Bonzini
}
119 74c856e9 Paolo Bonzini
120 74c856e9 Paolo Bonzini
static void test_submit_many(void)
121 74c856e9 Paolo Bonzini
{
122 74c856e9 Paolo Bonzini
    WorkerTestData data[100];
123 74c856e9 Paolo Bonzini
    int i;
124 74c856e9 Paolo Bonzini
125 74c856e9 Paolo Bonzini
    /* Start more work items than there will be threads.  */
126 74c856e9 Paolo Bonzini
    for (i = 0; i < 100; i++) {
127 74c856e9 Paolo Bonzini
        data[i].n = 0;
128 74c856e9 Paolo Bonzini
        data[i].ret = -EINPROGRESS;
129 74c856e9 Paolo Bonzini
        thread_pool_submit_aio(worker_cb, &data[i], done_cb, &data[i]);
130 74c856e9 Paolo Bonzini
    }
131 74c856e9 Paolo Bonzini
132 74c856e9 Paolo Bonzini
    active = 100;
133 74c856e9 Paolo Bonzini
    while (active > 0) {
134 74c856e9 Paolo Bonzini
        qemu_aio_wait();
135 74c856e9 Paolo Bonzini
    }
136 74c856e9 Paolo Bonzini
    for (i = 0; i < 100; i++) {
137 74c856e9 Paolo Bonzini
        g_assert_cmpint(data[i].n, ==, 1);
138 74c856e9 Paolo Bonzini
        g_assert_cmpint(data[i].ret, ==, 0);
139 74c856e9 Paolo Bonzini
    }
140 74c856e9 Paolo Bonzini
}
141 74c856e9 Paolo Bonzini
142 74c856e9 Paolo Bonzini
static void test_cancel(void)
143 74c856e9 Paolo Bonzini
{
144 74c856e9 Paolo Bonzini
    WorkerTestData data[100];
145 d60478c5 Paolo Bonzini
    int num_canceled;
146 74c856e9 Paolo Bonzini
    int i;
147 74c856e9 Paolo Bonzini
148 74c856e9 Paolo Bonzini
    /* Start more work items than there will be threads, to ensure
149 74c856e9 Paolo Bonzini
     * the pool is full.
150 74c856e9 Paolo Bonzini
     */
151 74c856e9 Paolo Bonzini
    test_submit_many();
152 74c856e9 Paolo Bonzini
153 74c856e9 Paolo Bonzini
    /* Start long running jobs, to ensure we can cancel some.  */
154 74c856e9 Paolo Bonzini
    for (i = 0; i < 100; i++) {
155 74c856e9 Paolo Bonzini
        data[i].n = 0;
156 74c856e9 Paolo Bonzini
        data[i].ret = -EINPROGRESS;
157 74c856e9 Paolo Bonzini
        data[i].aiocb = thread_pool_submit_aio(long_cb, &data[i],
158 74c856e9 Paolo Bonzini
                                               done_cb, &data[i]);
159 74c856e9 Paolo Bonzini
    }
160 74c856e9 Paolo Bonzini
161 74c856e9 Paolo Bonzini
    /* Starting the threads may be left to a bottom half.  Let it
162 74c856e9 Paolo Bonzini
     * run, but do not waste too much time...
163 74c856e9 Paolo Bonzini
     */
164 74c856e9 Paolo Bonzini
    active = 100;
165 74c856e9 Paolo Bonzini
    qemu_aio_wait_nonblocking();
166 74c856e9 Paolo Bonzini
167 74c856e9 Paolo Bonzini
    /* Wait some time for the threads to start, with some sanity
168 74c856e9 Paolo Bonzini
     * testing on the behavior of the scheduler...
169 74c856e9 Paolo Bonzini
     */
170 74c856e9 Paolo Bonzini
    g_assert_cmpint(active, ==, 100);
171 74c856e9 Paolo Bonzini
    g_usleep(1000000);
172 74c856e9 Paolo Bonzini
    g_assert_cmpint(active, >, 50);
173 74c856e9 Paolo Bonzini
174 74c856e9 Paolo Bonzini
    /* Cancel the jobs that haven't been started yet.  */
175 d60478c5 Paolo Bonzini
    num_canceled = 0;
176 74c856e9 Paolo Bonzini
    for (i = 0; i < 100; i++) {
177 74c856e9 Paolo Bonzini
        if (__sync_val_compare_and_swap(&data[i].n, 0, 3) == 0) {
178 74c856e9 Paolo Bonzini
            data[i].ret = -ECANCELED;
179 74c856e9 Paolo Bonzini
            bdrv_aio_cancel(data[i].aiocb);
180 74c856e9 Paolo Bonzini
            active--;
181 d60478c5 Paolo Bonzini
            num_canceled++;
182 74c856e9 Paolo Bonzini
        }
183 74c856e9 Paolo Bonzini
    }
184 d60478c5 Paolo Bonzini
    g_assert_cmpint(active, >, 0);
185 d60478c5 Paolo Bonzini
    g_assert_cmpint(num_canceled, <, 100);
186 74c856e9 Paolo Bonzini
187 74c856e9 Paolo Bonzini
    /* Canceling the others will be a blocking operation.  */
188 74c856e9 Paolo Bonzini
    for (i = 0; i < 100; i++) {
189 74c856e9 Paolo Bonzini
        if (data[i].n != 3) {
190 74c856e9 Paolo Bonzini
            bdrv_aio_cancel(data[i].aiocb);
191 74c856e9 Paolo Bonzini
        }
192 74c856e9 Paolo Bonzini
    }
193 74c856e9 Paolo Bonzini
194 74c856e9 Paolo Bonzini
    /* Finish execution and execute any remaining callbacks.  */
195 8a805c22 Stefan Hajnoczi
    qemu_aio_wait_all();
196 74c856e9 Paolo Bonzini
    g_assert_cmpint(active, ==, 0);
197 74c856e9 Paolo Bonzini
    for (i = 0; i < 100; i++) {
198 74c856e9 Paolo Bonzini
        if (data[i].n == 3) {
199 74c856e9 Paolo Bonzini
            g_assert_cmpint(data[i].ret, ==, -ECANCELED);
200 74c856e9 Paolo Bonzini
            g_assert(data[i].aiocb != NULL);
201 74c856e9 Paolo Bonzini
        } else {
202 74c856e9 Paolo Bonzini
            g_assert_cmpint(data[i].n, ==, 2);
203 74c856e9 Paolo Bonzini
            g_assert_cmpint(data[i].ret, ==, 0);
204 74c856e9 Paolo Bonzini
            g_assert(data[i].aiocb == NULL);
205 74c856e9 Paolo Bonzini
        }
206 74c856e9 Paolo Bonzini
    }
207 74c856e9 Paolo Bonzini
}
208 74c856e9 Paolo Bonzini
209 74c856e9 Paolo Bonzini
int main(int argc, char **argv)
210 74c856e9 Paolo Bonzini
{
211 74c856e9 Paolo Bonzini
    /* These should be removed once each AioContext has its thread pool.
212 74c856e9 Paolo Bonzini
     * The test should create its own AioContext.
213 74c856e9 Paolo Bonzini
     */
214 74c856e9 Paolo Bonzini
    qemu_init_main_loop();
215 74c856e9 Paolo Bonzini
    bdrv_init();
216 74c856e9 Paolo Bonzini
217 74c856e9 Paolo Bonzini
    g_test_init(&argc, &argv, NULL);
218 74c856e9 Paolo Bonzini
    g_test_add_func("/thread-pool/submit", test_submit);
219 74c856e9 Paolo Bonzini
    g_test_add_func("/thread-pool/submit-aio", test_submit_aio);
220 74c856e9 Paolo Bonzini
    g_test_add_func("/thread-pool/submit-co", test_submit_co);
221 74c856e9 Paolo Bonzini
    g_test_add_func("/thread-pool/submit-many", test_submit_many);
222 74c856e9 Paolo Bonzini
    g_test_add_func("/thread-pool/cancel", test_cancel);
223 74c856e9 Paolo Bonzini
    return g_test_run();
224 74c856e9 Paolo Bonzini
}