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 | } |