Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2020 Intel Corporation.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "spdk/stdinc.h"
7 : :
8 : : #include "spdk_internal/cunit.h"
9 : : #include "common/lib/test_env.c"
10 : : #include "event/reactor.c"
11 : : #include "spdk/thread.h"
12 : : #include "spdk_internal/thread.h"
13 : : #include "event/scheduler_static.c"
14 : : #include "../module/scheduler/dynamic/scheduler_dynamic.c"
15 : :
16 : : static void
17 : 4 : test_create_reactor(void)
18 : : {
19 : 4 : struct spdk_reactor *reactor;
20 : : int rc;
21 : :
22 : : /* See SPDK issue #3004. Seems like a bug with gcc + asan on Fedora 38, so we can't
23 : : * allocate g_reactors on the stack and need to explicitly used aligned allocation here.
24 : : */
25 : 4 : rc = posix_memalign((void **)&reactor, SPDK_CACHE_LINE_SIZE, sizeof(*reactor));
26 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(rc == 0);
27 : :
28 : 4 : g_reactors = reactor;
29 : 4 : g_reactor_count = 1;
30 : :
31 : 4 : reactor_construct(reactor, 0);
32 : :
33 : 4 : CU_ASSERT(spdk_reactor_get(0) == reactor);
34 : :
35 : 4 : spdk_ring_free(reactor->events);
36 : 4 : reactor_interrupt_fini(reactor);
37 : 4 : free(reactor);
38 : 4 : g_reactors = NULL;
39 : 4 : }
40 : :
41 : : static void
42 : 4 : test_init_reactors(void)
43 : : {
44 : : uint32_t core;
45 : :
46 : 4 : MOCK_SET(spdk_env_get_current_core, 0);
47 : :
48 : 4 : allocate_cores(3);
49 : :
50 : 4 : CU_ASSERT(spdk_reactors_init(SPDK_DEFAULT_MSG_MEMPOOL_SIZE) == 0);
51 : :
52 : 4 : CU_ASSERT(g_reactor_state == SPDK_REACTOR_STATE_INITIALIZED);
53 [ + + ]: 16 : for (core = 0; core < 3; core++) {
54 : 12 : CU_ASSERT(spdk_reactor_get(core) != NULL);
55 : : }
56 : :
57 : 4 : spdk_reactors_fini();
58 : :
59 : 4 : free_cores();
60 : :
61 : 4 : MOCK_CLEAR(spdk_env_get_current_core);
62 : 4 : }
63 : :
64 : : static void
65 : 4 : ut_event_fn(void *arg1, void *arg2)
66 : : {
67 : 4 : uint8_t *test1 = arg1;
68 : 4 : uint8_t *test2 = arg2;
69 : :
70 : 4 : *test1 = 1;
71 : 4 : *test2 = 0xFF;
72 : 4 : }
73 : :
74 : : static void
75 : 4 : test_event_call(void)
76 : : {
77 : 4 : uint8_t test1 = 0, test2 = 0;
78 : : struct spdk_event *evt;
79 : : struct spdk_reactor *reactor;
80 : :
81 : 4 : MOCK_SET(spdk_env_get_current_core, 0);
82 : :
83 : 4 : allocate_cores(1);
84 : :
85 : 4 : CU_ASSERT(spdk_reactors_init(SPDK_DEFAULT_MSG_MEMPOOL_SIZE) == 0);
86 : :
87 : 4 : evt = spdk_event_allocate(0, ut_event_fn, &test1, &test2);
88 : 4 : CU_ASSERT(evt != NULL);
89 : :
90 : 4 : MOCK_SET(spdk_env_get_current_core, 0);
91 : :
92 : 4 : spdk_event_call(evt);
93 : :
94 : 4 : reactor = spdk_reactor_get(0);
95 : 4 : CU_ASSERT(reactor != NULL);
96 : :
97 : 4 : CU_ASSERT(event_queue_run_batch(reactor) == 1);
98 : 4 : CU_ASSERT(test1 == 1);
99 : 4 : CU_ASSERT(test2 == 0xFF);
100 : :
101 : 4 : MOCK_CLEAR(spdk_env_get_current_core);
102 : :
103 : 4 : spdk_reactors_fini();
104 : :
105 : 4 : free_cores();
106 : :
107 : 4 : MOCK_CLEAR(spdk_env_get_current_core);
108 : 4 : }
109 : :
110 : : static void
111 : 4 : test_schedule_thread(void)
112 : : {
113 : 4 : struct spdk_cpuset cpuset = {};
114 : : struct spdk_thread *thread;
115 : : struct spdk_reactor *reactor;
116 : : struct spdk_lw_thread *lw_thread;
117 : :
118 : 4 : MOCK_SET(spdk_env_get_current_core, 0);
119 : :
120 : 4 : allocate_cores(5);
121 : :
122 : 4 : CU_ASSERT(spdk_reactors_init(SPDK_DEFAULT_MSG_MEMPOOL_SIZE) == 0);
123 : :
124 : 4 : spdk_cpuset_set_cpu(&cpuset, 3, true);
125 : 4 : g_next_core = 4;
126 : :
127 : 4 : MOCK_SET(spdk_env_get_current_core, 3);
128 : :
129 : : /* _reactor_schedule_thread() will be called in spdk_thread_create()
130 : : * at its end because it is passed to SPDK thread library by
131 : : * spdk_thread_lib_init().
132 : : */
133 : 4 : thread = spdk_thread_create(NULL, &cpuset);
134 : 4 : CU_ASSERT(thread != NULL);
135 : :
136 : 4 : reactor = spdk_reactor_get(3);
137 : 4 : CU_ASSERT(reactor != NULL);
138 : :
139 : 4 : CU_ASSERT(event_queue_run_batch(reactor) == 1);
140 : :
141 : 4 : MOCK_CLEAR(spdk_env_get_current_core);
142 : :
143 : 4 : lw_thread = TAILQ_FIRST(&reactor->threads);
144 : 4 : CU_ASSERT(lw_thread != NULL);
145 : 4 : CU_ASSERT(spdk_thread_get_from_ctx(lw_thread) == thread);
146 : :
147 [ - + ]: 4 : TAILQ_REMOVE(&reactor->threads, lw_thread, link);
148 : 4 : reactor->thread_count--;
149 : 4 : spdk_set_thread(thread);
150 : 4 : spdk_thread_exit(thread);
151 [ + + ]: 8 : while (!spdk_thread_is_exited(thread)) {
152 : 4 : spdk_thread_poll(thread, 0, 0);
153 : : }
154 : 4 : spdk_thread_destroy(thread);
155 : 4 : spdk_set_thread(NULL);
156 : :
157 : 4 : spdk_reactors_fini();
158 : :
159 : 4 : free_cores();
160 : 4 : }
161 : :
162 : : static void
163 : 4 : test_reschedule_thread(void)
164 : : {
165 : 4 : struct spdk_cpuset cpuset = {};
166 : : struct spdk_thread *thread;
167 : : struct spdk_reactor *reactor;
168 : : struct spdk_lw_thread *lw_thread;
169 : :
170 : 4 : MOCK_SET(spdk_env_get_current_core, 0);
171 : :
172 : 4 : allocate_cores(3);
173 : :
174 : 4 : CU_ASSERT(spdk_reactors_init(SPDK_DEFAULT_MSG_MEMPOOL_SIZE) == 0);
175 : :
176 : 4 : spdk_cpuset_set_cpu(&g_reactor_core_mask, 0, true);
177 : 4 : spdk_cpuset_set_cpu(&g_reactor_core_mask, 1, true);
178 : 4 : spdk_cpuset_set_cpu(&g_reactor_core_mask, 2, true);
179 : 4 : g_next_core = 0;
180 : :
181 : 4 : MOCK_SET(spdk_env_get_current_core, 1);
182 : : /* Create and schedule the thread to core 1. */
183 : 4 : spdk_cpuset_set_cpu(&cpuset, 1, true);
184 : :
185 : 4 : thread = spdk_thread_create(NULL, &cpuset);
186 : 4 : CU_ASSERT(thread != NULL);
187 : 4 : lw_thread = spdk_thread_get_ctx(thread);
188 : :
189 : 4 : reactor = spdk_reactor_get(1);
190 : 4 : CU_ASSERT(reactor != NULL);
191 : :
192 : 4 : CU_ASSERT(event_queue_run_batch(reactor) == 1);
193 : 4 : CU_ASSERT(TAILQ_FIRST(&reactor->threads) == lw_thread);
194 : :
195 : 4 : spdk_set_thread(thread);
196 : :
197 : : /* Call spdk_thread_set_cpumask() twice with different cpumask values.
198 : : * The cpumask of the 2nd call will be used in reschedule operation.
199 : : */
200 : :
201 : 4 : spdk_cpuset_zero(&cpuset);
202 : 4 : spdk_cpuset_set_cpu(&cpuset, 0, true);
203 : 4 : CU_ASSERT(spdk_thread_set_cpumask(&cpuset) == 0);
204 : :
205 : 4 : spdk_cpuset_zero(&cpuset);
206 : 4 : spdk_cpuset_set_cpu(&cpuset, 2, true);
207 : 4 : CU_ASSERT(spdk_thread_set_cpumask(&cpuset) == 0);
208 : :
209 [ - + ]: 4 : CU_ASSERT(lw_thread->resched == true);
210 : :
211 : 4 : reactor_run(reactor);
212 : :
213 [ - + ]: 4 : CU_ASSERT(lw_thread->resched == false);
214 : 4 : CU_ASSERT(TAILQ_EMPTY(&reactor->threads));
215 : :
216 : 4 : reactor = spdk_reactor_get(0);
217 : 4 : CU_ASSERT(reactor != NULL);
218 : 4 : MOCK_SET(spdk_env_get_current_core, 0);
219 : :
220 : 4 : CU_ASSERT(event_queue_run_batch(reactor) == 0);
221 : :
222 : 4 : reactor = spdk_reactor_get(2);
223 : 4 : CU_ASSERT(reactor != NULL);
224 : 4 : MOCK_SET(spdk_env_get_current_core, 2);
225 : :
226 : 4 : CU_ASSERT(event_queue_run_batch(reactor) == 1);
227 : :
228 : 4 : CU_ASSERT(TAILQ_FIRST(&reactor->threads) == lw_thread);
229 : :
230 : 4 : MOCK_CLEAR(spdk_env_get_current_core);
231 : :
232 [ - + ]: 4 : TAILQ_REMOVE(&reactor->threads, lw_thread, link);
233 : 4 : reactor->thread_count--;
234 : 4 : spdk_set_thread(thread);
235 : 4 : spdk_thread_exit(thread);
236 [ + + ]: 8 : while (!spdk_thread_is_exited(thread)) {
237 : 4 : spdk_thread_poll(thread, 0, 0);
238 : : }
239 : 4 : spdk_thread_destroy(thread);
240 : 4 : spdk_set_thread(NULL);
241 : :
242 : 4 : spdk_reactors_fini();
243 : :
244 : 4 : free_cores();
245 : 4 : }
246 : :
247 : : static void
248 : 4 : for_each_reactor_done(void *arg1, void *arg2)
249 : : {
250 : 4 : uint32_t *count = arg1;
251 : 4 : bool *done = arg2;
252 : :
253 : 4 : (*count)++;
254 : 4 : *done = true;
255 : 4 : }
256 : :
257 : : static void
258 : 20 : for_each_reactor_cb(void *arg1, void *arg2)
259 : : {
260 : 20 : uint32_t *count = arg1;
261 : :
262 : 20 : (*count)++;
263 : 20 : }
264 : :
265 : : static void
266 : 4 : test_for_each_reactor(void)
267 : : {
268 : 4 : uint32_t count = 0, i;
269 : 4 : bool done = false;
270 : : struct spdk_reactor *reactor;
271 : :
272 : 4 : MOCK_SET(spdk_env_get_current_core, 0);
273 : :
274 : 4 : allocate_cores(5);
275 : :
276 : 4 : CU_ASSERT(spdk_reactors_init(SPDK_DEFAULT_MSG_MEMPOOL_SIZE) == 0);
277 : :
278 : 4 : spdk_for_each_reactor(for_each_reactor_cb, &count, &done, for_each_reactor_done);
279 : :
280 : 4 : MOCK_CLEAR(spdk_env_get_current_core);
281 : :
282 : : /* We have not processed any event yet, so count and done should be 0 and false,
283 : : * respectively.
284 : : */
285 : 4 : CU_ASSERT(count == 0);
286 : :
287 : : /* Poll each reactor to verify the event is passed to each */
288 [ + + ]: 24 : for (i = 0; i < 5; i++) {
289 : 20 : reactor = spdk_reactor_get(i);
290 : 20 : CU_ASSERT(reactor != NULL);
291 : 20 : MOCK_SET(spdk_env_get_current_core, i);
292 : :
293 : 20 : event_queue_run_batch(reactor);
294 : 20 : CU_ASSERT(count == (i + 1));
295 [ - + ]: 20 : CU_ASSERT(done == false);
296 : 20 : MOCK_CLEAR(spdk_env_get_current_core);
297 : : }
298 : :
299 : 4 : MOCK_SET(spdk_env_get_current_core, 0);
300 : : /* After each reactor is called, the completion calls it one more time. */
301 : 4 : reactor = spdk_reactor_get(0);
302 : 4 : CU_ASSERT(reactor != NULL);
303 : :
304 : 4 : event_queue_run_batch(reactor);
305 : 4 : CU_ASSERT(count == 6);
306 [ - + ]: 4 : CU_ASSERT(done == true);
307 : 4 : MOCK_CLEAR(spdk_env_get_current_core);
308 : :
309 : 4 : spdk_reactors_fini();
310 : :
311 : 4 : free_cores();
312 : 4 : }
313 : :
314 : : static int
315 : 48 : poller_run_idle(void *ctx)
316 : : {
317 : 48 : uint64_t delay_us = (uint64_t)ctx;
318 : :
319 : 48 : spdk_delay_us(delay_us);
320 : :
321 : 48 : return 0;
322 : : }
323 : :
324 : : static int
325 : 32 : poller_run_busy(void *ctx)
326 : : {
327 : 32 : uint64_t delay_us = (uint64_t)ctx;
328 : :
329 : 32 : spdk_delay_us(delay_us);
330 : :
331 : 32 : return 1;
332 : : }
333 : :
334 : : static void
335 : 4 : test_reactor_stats(void)
336 : : {
337 : 4 : struct spdk_cpuset cpuset = {};
338 : : struct spdk_thread *thread1, *thread2;
339 : : struct spdk_reactor *reactor;
340 : 4 : struct spdk_poller *busy1, *idle1, *busy2, *idle2;
341 : 4 : struct spdk_thread_stats stats;
342 : : int rc __attribute__((unused));
343 : :
344 : : /* Test case is the following:
345 : : * Create a reactor on CPU core0.
346 : : * Create thread1 and thread2 simultaneously on reactor0 at TSC = 100.
347 : : * Reactor runs
348 : : * - thread1 for 100 with busy
349 : : * - thread2 for 200 with idle
350 : : * - thread1 for 300 with idle
351 : : * - thread2 for 400 with busy.
352 : : * Then,
353 : : * - both elapsed TSC of thread1 and thread2 should be 1100 (= 100 + 1000).
354 : : * - busy TSC of reactor should be 500 (= 100 + 400).
355 : : * - idle TSC of reactor should be 500 (= 200 + 300).
356 : : *
357 : : * After that reactor0 runs with no threads for 900 TSC.
358 : : * Create thread1 on reactor0 at TSC = 2000.
359 : : * Reactor runs
360 : : * - thread1 for 100 with busy
361 : : * Then,
362 : : * - elapsed TSC of thread1 should be 2100 (= 2000+ 100).
363 : : * - busy TSC of reactor should be 600 (= 500 + 100).
364 : : * - idle TSC of reactor should be 500 (= 500 + 900).
365 : : */
366 : :
367 : 4 : MOCK_SET(spdk_env_get_current_core, 0);
368 : :
369 : 4 : allocate_cores(1);
370 : :
371 : 4 : CU_ASSERT(spdk_reactors_init(SPDK_DEFAULT_MSG_MEMPOOL_SIZE) == 0);
372 : :
373 : 4 : spdk_cpuset_set_cpu(&cpuset, 0, true);
374 : :
375 : 4 : reactor = spdk_reactor_get(0);
376 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(reactor != NULL);
377 : :
378 : : /* First reactor_run() sets the tsc_last. */
379 : 4 : MOCK_SET(spdk_get_ticks, 100);
380 : 4 : reactor->tsc_last = spdk_get_ticks();
381 : :
382 : 4 : thread1 = spdk_thread_create(NULL, &cpuset);
383 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(thread1 != NULL);
384 : :
385 : 4 : thread2 = spdk_thread_create(NULL, &cpuset);
386 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(thread2 != NULL);
387 : :
388 : 4 : spdk_set_thread(thread1);
389 : 4 : busy1 = spdk_poller_register(poller_run_busy, (void *)100, 0);
390 : 4 : CU_ASSERT(busy1 != NULL);
391 : :
392 : 4 : spdk_set_thread(thread2);
393 : 4 : idle2 = spdk_poller_register(poller_run_idle, (void *)300, 0);
394 : 4 : CU_ASSERT(idle2 != NULL);
395 : :
396 : 4 : _reactor_run(reactor);
397 : :
398 : 4 : spdk_set_thread(thread1);
399 : 4 : CU_ASSERT(spdk_thread_get_last_tsc(thread1) == 200);
400 : 4 : CU_ASSERT(spdk_thread_get_stats(&stats) == 0);
401 : 4 : CU_ASSERT(stats.busy_tsc == 100);
402 : 4 : CU_ASSERT(stats.idle_tsc == 0);
403 : 4 : spdk_set_thread(thread2);
404 : 4 : CU_ASSERT(spdk_thread_get_last_tsc(thread2) == 500);
405 : 4 : CU_ASSERT(spdk_thread_get_stats(&stats) == 0);
406 : 4 : CU_ASSERT(stats.busy_tsc == 0);
407 : 4 : CU_ASSERT(stats.idle_tsc == 300);
408 : :
409 : 4 : CU_ASSERT(reactor->busy_tsc == 100);
410 : 4 : CU_ASSERT(reactor->idle_tsc == 300);
411 : :
412 : : /* 100 + 100 + 300 = 500 ticks elapsed */
413 : 4 : CU_ASSERT(reactor->tsc_last == 500);
414 : :
415 : 4 : spdk_set_thread(thread1);
416 : 4 : spdk_poller_unregister(&busy1);
417 : 4 : idle1 = spdk_poller_register(poller_run_idle, (void *)200, 0);
418 : 4 : CU_ASSERT(idle1 != NULL);
419 : :
420 : 4 : spdk_set_thread(thread2);
421 : 4 : spdk_poller_unregister(&idle2);
422 : 4 : busy2 = spdk_poller_register(poller_run_busy, (void *)400, 0);
423 : 4 : CU_ASSERT(busy2 != NULL);
424 : :
425 : 4 : _reactor_run(reactor);
426 : :
427 : 4 : spdk_set_thread(thread1);
428 : 4 : CU_ASSERT(spdk_thread_get_last_tsc(thread1) == 700);
429 : 4 : CU_ASSERT(spdk_thread_get_stats(&stats) == 0);
430 : 4 : CU_ASSERT(stats.busy_tsc == 100);
431 : 4 : CU_ASSERT(stats.idle_tsc == 200);
432 : 4 : spdk_set_thread(thread2);
433 : 4 : CU_ASSERT(spdk_thread_get_last_tsc(thread2) == 1100);
434 : 4 : CU_ASSERT(spdk_thread_get_stats(&stats) == 0);
435 : 4 : CU_ASSERT(stats.busy_tsc == 400);
436 : 4 : CU_ASSERT(stats.idle_tsc == 300);
437 : :
438 : 4 : CU_ASSERT(reactor->busy_tsc == 500);
439 : 4 : CU_ASSERT(reactor->idle_tsc == 500);
440 : :
441 : : /* 500 + 200 + 400 = 1100 ticks elapsed */
442 : 4 : CU_ASSERT(reactor->tsc_last == 1100);
443 : :
444 : 4 : spdk_set_thread(thread1);
445 : 4 : spdk_poller_unregister(&idle1);
446 : 4 : spdk_thread_exit(thread1);
447 : :
448 : 4 : spdk_set_thread(thread2);
449 : 4 : spdk_poller_unregister(&busy2);
450 : 4 : spdk_thread_exit(thread2);
451 : :
452 : 4 : _reactor_run(reactor);
453 : :
454 : : /* After 900 ticks new thread is created. */
455 : : /* 1100 + 900 = 2000 ticks elapsed */
456 : 4 : MOCK_SET(spdk_get_ticks, 2000);
457 : 4 : _reactor_run(reactor);
458 : 4 : CU_ASSERT(reactor->tsc_last == 2000);
459 : :
460 : 4 : thread1 = spdk_thread_create(NULL, &cpuset);
461 [ - + ]: 4 : SPDK_CU_ASSERT_FATAL(thread1 != NULL);
462 : :
463 : 4 : spdk_set_thread(thread1);
464 : 4 : busy1 = spdk_poller_register(poller_run_busy, (void *)100, 0);
465 : 4 : CU_ASSERT(busy1 != NULL);
466 : :
467 : 4 : _reactor_run(reactor);
468 : :
469 : 4 : spdk_set_thread(thread1);
470 : 4 : CU_ASSERT(spdk_thread_get_last_tsc(thread1) == 2100);
471 : 4 : CU_ASSERT(spdk_thread_get_stats(&stats) == 0);
472 : 4 : CU_ASSERT(stats.busy_tsc == 100);
473 : 4 : CU_ASSERT(stats.idle_tsc == 0);
474 : :
475 : 4 : CU_ASSERT(reactor->busy_tsc == 600);
476 : 4 : CU_ASSERT(reactor->idle_tsc == 1400);
477 : :
478 : : /* 2000 + 100 = 2100 ticks elapsed */
479 : 4 : CU_ASSERT(reactor->tsc_last == 2100);
480 : :
481 : 4 : spdk_set_thread(thread1);
482 : 4 : spdk_poller_unregister(&busy1);
483 : 4 : spdk_thread_exit(thread1);
484 : :
485 : 4 : _reactor_run(reactor);
486 : :
487 : 4 : CU_ASSERT(TAILQ_EMPTY(&reactor->threads));
488 : :
489 : : /* No further than 2100 ticks elapsed */
490 : 4 : CU_ASSERT(reactor->tsc_last == 2100);
491 : :
492 : 4 : spdk_reactors_fini();
493 : :
494 : 4 : free_cores();
495 : :
496 : 4 : MOCK_CLEAR(spdk_env_get_current_core);
497 : 4 : }
498 : :
499 : : static uint32_t
500 : 24 : _run_events_till_completion(uint32_t reactor_count)
501 : : {
502 : : struct spdk_reactor *reactor;
503 : 24 : struct spdk_thread *app_thread = spdk_thread_get_app_thread();
504 : : uint32_t i, events;
505 : 24 : uint32_t total_events = 0;
506 : :
507 : : do {
508 : 88 : events = 0;
509 [ + + ]: 300 : for (i = 0; i < reactor_count; i++) {
510 : 212 : reactor = spdk_reactor_get(i);
511 : 212 : CU_ASSERT(reactor != NULL);
512 : 212 : MOCK_SET(spdk_env_get_current_core, i);
513 : 212 : events += event_queue_run_batch(reactor);
514 : :
515 : : /* Some events still require app_thread to run */
516 : 212 : MOCK_SET(spdk_env_get_current_core, g_scheduling_reactor->lcore);
517 : 212 : spdk_thread_poll(app_thread, 0, 0);
518 : :
519 : 212 : MOCK_CLEAR(spdk_env_get_current_core);
520 : : }
521 : 88 : total_events += events;
522 [ + + ]: 88 : } while (events > 0);
523 : :
524 : 24 : return total_events;
525 : : }
526 : :
527 : : static void
528 : 4 : test_scheduler(void)
529 : : {
530 : 4 : struct spdk_cpuset cpuset = {};
531 : 4 : struct spdk_thread *thread[3];
532 : : struct spdk_reactor *reactor;
533 : 4 : struct spdk_poller *busy, *idle;
534 : 4 : uint64_t reactor_busy_tsc[3], reactor_idle_tsc[3];
535 : 4 : uint64_t thread_busy_tsc[3], thread_idle_tsc[3];
536 : : uint64_t current_time, end_time, busy_time, idle_time;
537 : 4 : struct spdk_thread_stats stats;
538 : : int i;
539 : :
540 : 4 : MOCK_SET(spdk_env_get_current_core, 0);
541 : :
542 : 4 : allocate_cores(3);
543 : :
544 : 4 : CU_ASSERT(spdk_reactors_init(SPDK_DEFAULT_MSG_MEMPOOL_SIZE) == 0);
545 : :
546 : 4 : spdk_scheduler_set("dynamic");
547 : :
548 [ + + ]: 16 : for (i = 0; i < 3; i++) {
549 : 12 : spdk_cpuset_set_cpu(&g_reactor_core_mask, i, true);
550 : : }
551 : 4 : g_next_core = 0;
552 : :
553 : : /* Create threads. */
554 [ + + ]: 16 : for (i = 0; i < 3; i++) {
555 : 12 : spdk_cpuset_zero(&cpuset);
556 : 12 : spdk_cpuset_set_cpu(&cpuset, i, true);
557 : 12 : thread[i] = spdk_thread_create(NULL, &cpuset);
558 : 12 : CU_ASSERT(thread[i] != NULL);
559 : 12 : thread_busy_tsc[i] = 0;
560 : 12 : thread_idle_tsc[i] = 0;
561 : : }
562 : :
563 [ + + ]: 16 : for (i = 0; i < 3; i++) {
564 : 12 : reactor = spdk_reactor_get(i);
565 : 12 : CU_ASSERT(reactor != NULL);
566 : 12 : MOCK_SET(spdk_env_get_current_core, i);
567 : 12 : event_queue_run_batch(reactor);
568 : 12 : CU_ASSERT(!TAILQ_EMPTY(&reactor->threads));
569 : 12 : reactor_busy_tsc[i] = 0;
570 : 12 : reactor_idle_tsc[i] = 0;
571 : : }
572 : :
573 : 4 : g_reactor_state = SPDK_REACTOR_STATE_RUNNING;
574 : :
575 : 4 : MOCK_SET(spdk_env_get_current_core, 0);
576 : :
577 : : /* Init threads stats (low load) */
578 : : /* Each reactor starts at 100 tsc,
579 : : * ends at 100 + 100 = 200 tsc. */
580 : 4 : current_time = 100;
581 : 4 : idle_time = 100;
582 : 4 : busy_time = 0;
583 : 4 : end_time = current_time + idle_time + busy_time;
584 [ + + ]: 16 : for (i = 0; i < 3; i++) {
585 : 12 : spdk_set_thread(thread[i]);
586 : 12 : idle = spdk_poller_register(poller_run_idle, (void *)idle_time, 0);
587 : 12 : reactor = spdk_reactor_get(i);
588 : 12 : CU_ASSERT(reactor != NULL);
589 : 12 : MOCK_SET(spdk_get_ticks, current_time);
590 : 12 : reactor->tsc_last = spdk_get_ticks();
591 : 12 : _reactor_run(reactor);
592 : 12 : CU_ASSERT(reactor->tsc_last == end_time);
593 : 12 : spdk_poller_unregister(&idle);
594 : :
595 : 12 : CU_ASSERT(spdk_thread_get_last_tsc(thread[i]) == end_time);
596 : 12 : CU_ASSERT(spdk_thread_get_stats(&stats) == 0);
597 : 12 : CU_ASSERT(stats.busy_tsc == busy_time);
598 : 12 : thread_busy_tsc[i] = stats.busy_tsc;
599 : 12 : CU_ASSERT(stats.idle_tsc == idle_time);
600 : 12 : thread_idle_tsc[i] = stats.idle_tsc;
601 : 12 : CU_ASSERT(reactor->busy_tsc == busy_time);
602 : 12 : reactor_busy_tsc[i] = reactor->busy_tsc;
603 : 12 : CU_ASSERT(reactor->idle_tsc == idle_time);
604 : 12 : reactor_idle_tsc[i] = reactor->idle_tsc;
605 : : }
606 : 4 : CU_ASSERT(spdk_get_ticks() == end_time);
607 : 4 : current_time = 200;
608 : :
609 : 4 : MOCK_SET(spdk_env_get_current_core, 0);
610 : 4 : _reactors_scheduler_gather_metrics(NULL, NULL);
611 : :
612 : 4 : _run_events_till_completion(3);
613 : 4 : MOCK_SET(spdk_env_get_current_core, 0);
614 : :
615 : : /* Threads were idle, so all of them should be placed on core 0.
616 : : * All reactors start and end at 200 tsc, since for this iteration
617 : : * the threads have no pollers (so they consume no idle or busy tsc).
618 : : */
619 [ + + ]: 16 : for (i = 0; i < 3; i++) {
620 : 12 : reactor = spdk_reactor_get(i);
621 : 12 : CU_ASSERT(reactor != NULL);
622 : 12 : MOCK_SET(spdk_get_ticks, current_time);
623 : 12 : _reactor_run(reactor);
624 : 12 : CU_ASSERT(reactor->tsc_last == current_time);
625 : 12 : CU_ASSERT(reactor->busy_tsc == reactor_busy_tsc[i]);
626 : 12 : CU_ASSERT(reactor->idle_tsc == reactor_idle_tsc[i]);
627 : 12 : spdk_set_thread(thread[i]);
628 : 12 : CU_ASSERT(spdk_thread_get_last_tsc(thread[i]) == current_time);
629 : 12 : CU_ASSERT(spdk_thread_get_stats(&stats) == 0);
630 : 12 : CU_ASSERT(stats.busy_tsc == thread_busy_tsc[i]);
631 : 12 : CU_ASSERT(stats.idle_tsc == thread_idle_tsc[i]);
632 : : }
633 : 4 : CU_ASSERT(spdk_get_ticks() == current_time);
634 : :
635 : : /* 2 threads should be scheduled to core 0 */
636 : 4 : reactor = spdk_reactor_get(0);
637 : 4 : CU_ASSERT(reactor != NULL);
638 : 4 : MOCK_SET(spdk_env_get_current_core, 0);
639 : 4 : event_queue_run_batch(reactor);
640 : :
641 : 4 : reactor = spdk_reactor_get(0);
642 : 4 : CU_ASSERT(reactor != NULL);
643 : 4 : CU_ASSERT(!TAILQ_EMPTY(&reactor->threads));
644 : 4 : reactor = spdk_reactor_get(1);
645 : 4 : CU_ASSERT(reactor != NULL);
646 : 4 : CU_ASSERT(TAILQ_EMPTY(&reactor->threads));
647 : 4 : reactor = spdk_reactor_get(2);
648 : 4 : CU_ASSERT(reactor != NULL);
649 : 4 : CU_ASSERT(TAILQ_EMPTY(&reactor->threads));
650 : :
651 : : /* Make threads busy */
652 : 4 : reactor = spdk_reactor_get(0);
653 : 4 : CU_ASSERT(reactor != NULL);
654 : :
655 : : /* All threads run on single reactor,
656 : : * reactor 0 starts at 200 tsc,
657 : : * ending at 200 + (100 * 3) = 500 tsc. */
658 : 4 : MOCK_SET(spdk_get_ticks, current_time);
659 : 4 : busy_time = 100;
660 : 4 : idle_time = 0;
661 [ + + ]: 16 : for (i = 0; i < 3; i++) {
662 : 12 : spdk_set_thread(thread[i]);
663 : 12 : busy = spdk_poller_register(poller_run_busy, (void *)busy_time, 0);
664 : 12 : _reactor_run(reactor);
665 : 12 : spdk_poller_unregister(&busy);
666 : 12 : current_time += busy_time;
667 : :
668 : 12 : CU_ASSERT(reactor->tsc_last == current_time);
669 : 12 : CU_ASSERT(spdk_thread_get_last_tsc(thread[i]) == current_time);
670 : 12 : CU_ASSERT(spdk_thread_get_stats(&stats) == 0);
671 : 12 : CU_ASSERT(stats.busy_tsc == thread_busy_tsc[i] + busy_time);
672 : 12 : CU_ASSERT(stats.idle_tsc == thread_idle_tsc[i] + idle_time);;
673 : : }
674 : 4 : CU_ASSERT(reactor->busy_tsc == reactor_busy_tsc[0] + 3 * busy_time);
675 : 4 : CU_ASSERT(reactor->idle_tsc == reactor_idle_tsc[0] + 3 * idle_time);
676 : 4 : CU_ASSERT(spdk_get_ticks() == current_time);
677 : :
678 : : /* Run scheduler again, this time all threads are busy */
679 : 4 : MOCK_SET(spdk_env_get_current_core, 0);
680 : 4 : _reactors_scheduler_gather_metrics(NULL, NULL);
681 : :
682 : 4 : _run_events_till_completion(3);
683 : 4 : MOCK_SET(spdk_env_get_current_core, 0);
684 : :
685 : : /* Threads were busy, 2 will stay on core 0, 1 will move to core 1 */
686 [ + + ]: 16 : for (i = 0; i < 3; i++) {
687 : 12 : MOCK_SET(spdk_env_get_current_core, i);
688 : 12 : reactor = spdk_reactor_get(i);
689 : 12 : CU_ASSERT(reactor != NULL);
690 : 12 : _reactor_run(reactor);
691 : : }
692 : :
693 [ + + ]: 16 : for (i = 0; i < 3; i++) {
694 : 12 : reactor = spdk_reactor_get(i);
695 : 12 : CU_ASSERT(reactor != NULL);
696 : 12 : CU_ASSERT(!TAILQ_EMPTY(&reactor->threads));
697 : : }
698 : :
699 : 4 : g_reactor_state = SPDK_REACTOR_STATE_INITIALIZED;
700 : :
701 : : /* Destroy threads */
702 [ + + ]: 16 : for (i = 0; i < 3; i++) {
703 : 12 : spdk_set_thread(thread[i]);
704 : 12 : spdk_thread_exit(thread[i]);
705 : : }
706 [ + + ]: 16 : for (i = 0; i < 3; i++) {
707 : 12 : reactor = spdk_reactor_get(i);
708 : 12 : CU_ASSERT(reactor != NULL);
709 : 12 : reactor_run(reactor);
710 : : }
711 : :
712 : 4 : spdk_set_thread(NULL);
713 : :
714 : 4 : MOCK_CLEAR(spdk_env_get_current_core);
715 : :
716 : 4 : spdk_reactors_fini();
717 : :
718 : 4 : free_cores();
719 : 4 : }
720 : :
721 : : static void
722 : 4 : test_bind_thread(void)
723 : : {
724 : 4 : struct spdk_cpuset cpuset = {};
725 : 4 : struct spdk_thread *thread[3];
726 : : struct spdk_reactor *reactor;
727 : 4 : struct spdk_poller *idle;
728 : 4 : uint64_t reactor_busy_tsc[3], reactor_idle_tsc[3];
729 : 4 : uint64_t thread_busy_tsc[3], thread_idle_tsc[3];
730 : : uint64_t current_time, end_time, busy_time, idle_time;
731 : 4 : struct spdk_thread_stats stats;
732 : : int i;
733 : :
734 : 4 : MOCK_SET(spdk_env_get_current_core, 0);
735 : :
736 : 4 : allocate_cores(3);
737 : :
738 : 4 : CU_ASSERT(spdk_reactors_init(SPDK_DEFAULT_MSG_MEMPOOL_SIZE) == 0);
739 : :
740 : 4 : spdk_scheduler_set("dynamic");
741 : :
742 [ + + ]: 16 : for (i = 0; i < 3; i++) {
743 : 12 : spdk_cpuset_set_cpu(&g_reactor_core_mask, i, true);
744 : : }
745 : 4 : g_next_core = 0;
746 : :
747 : : /* Create threads. */
748 [ + + ]: 16 : for (i = 0; i < 3; i++) {
749 : 12 : spdk_cpuset_zero(&cpuset);
750 : 12 : spdk_cpuset_set_cpu(&cpuset, i, true);
751 : 12 : thread[i] = spdk_thread_create(NULL, &cpuset);
752 : 12 : CU_ASSERT(thread[i] != NULL);
753 : 12 : thread_busy_tsc[i] = 0;
754 : 12 : thread_idle_tsc[i] = 0;
755 : : }
756 : :
757 [ + + ]: 16 : for (i = 0; i < 3; i++) {
758 : 12 : reactor = spdk_reactor_get(i);
759 : 12 : CU_ASSERT(reactor != NULL);
760 : 12 : MOCK_SET(spdk_env_get_current_core, i);
761 : 12 : event_queue_run_batch(reactor);
762 : 12 : CU_ASSERT(!TAILQ_EMPTY(&reactor->threads));
763 : 12 : reactor_busy_tsc[i] = 0;
764 : 12 : reactor_idle_tsc[i] = 0;
765 : : }
766 : :
767 : 4 : g_reactor_state = SPDK_REACTOR_STATE_RUNNING;
768 : :
769 : 4 : MOCK_SET(spdk_env_get_current_core, 0);
770 : :
771 : : /* Init threads stats (low load) */
772 : : /* Each reactor starts at 100 tsc,
773 : : * ends at 100 + 100 = 200 tsc. */
774 : 4 : current_time = 100;
775 : 4 : idle_time = 100;
776 : 4 : busy_time = 0;
777 : 4 : end_time = current_time + idle_time + busy_time;
778 [ + + ]: 16 : for (i = 0; i < 3; i++) {
779 : 12 : spdk_set_thread(thread[i]);
780 : 12 : idle = spdk_poller_register(poller_run_idle, (void *)idle_time, 0);
781 : 12 : reactor = spdk_reactor_get(i);
782 : 12 : CU_ASSERT(reactor != NULL);
783 : 12 : MOCK_SET(spdk_get_ticks, current_time);
784 : 12 : reactor->tsc_last = spdk_get_ticks();
785 : 12 : _reactor_run(reactor);
786 : 12 : CU_ASSERT(reactor->tsc_last == end_time);
787 : 12 : spdk_poller_unregister(&idle);
788 : :
789 : 12 : CU_ASSERT(spdk_thread_get_last_tsc(thread[i]) == end_time);
790 : 12 : CU_ASSERT(spdk_thread_get_stats(&stats) == 0);
791 : 12 : CU_ASSERT(stats.busy_tsc == busy_time);
792 : 12 : thread_busy_tsc[i] = stats.busy_tsc;
793 : 12 : CU_ASSERT(stats.idle_tsc == idle_time);
794 : 12 : thread_idle_tsc[i] = stats.idle_tsc;
795 : 12 : CU_ASSERT(reactor->busy_tsc == busy_time);
796 : 12 : reactor_busy_tsc[i] = reactor->busy_tsc;
797 : 12 : CU_ASSERT(reactor->idle_tsc == idle_time);
798 : 12 : reactor_idle_tsc[i] = reactor->idle_tsc;
799 : : }
800 : 4 : CU_ASSERT(spdk_get_ticks() == end_time);
801 : 4 : current_time = 200;
802 : : /* Bind thread 1 */
803 : 4 : spdk_thread_bind(thread[1], true);
804 : 4 : CU_ASSERT(spdk_thread_is_bound(thread[1]) == true);
805 : 4 : MOCK_SET(spdk_env_get_current_core, 0);
806 : 4 : _reactors_scheduler_gather_metrics(NULL, NULL);
807 : 4 : _run_events_till_completion(3);
808 : 4 : MOCK_SET(spdk_env_get_current_core, 0);
809 : :
810 : : /* Threads were idle, so all of them should be placed on core 0 except thread 1
811 : : * since it has been limited on core 1
812 : : * All reactors start and end at 200 tsc, since for this iteration
813 : : * the threads have no pollers (so they consume no idle or busy tsc).
814 : : */
815 [ + + ]: 16 : for (i = 0; i < 3; i++) {
816 : 12 : reactor = spdk_reactor_get(i);
817 : 12 : CU_ASSERT(reactor != NULL);
818 : 12 : MOCK_SET(spdk_get_ticks, current_time);
819 : 12 : _reactor_run(reactor);
820 : 12 : CU_ASSERT(reactor->tsc_last == current_time);
821 : 12 : CU_ASSERT(reactor->busy_tsc == reactor_busy_tsc[i]);
822 : 12 : CU_ASSERT(reactor->idle_tsc == reactor_idle_tsc[i]);
823 : 12 : spdk_set_thread(thread[i]);
824 : 12 : CU_ASSERT(spdk_thread_get_last_tsc(thread[i]) == current_time);
825 : 12 : CU_ASSERT(spdk_thread_get_stats(&stats) == 0);
826 : 12 : CU_ASSERT(stats.busy_tsc == thread_busy_tsc[i]);
827 : 12 : CU_ASSERT(stats.idle_tsc == thread_idle_tsc[i]);
828 : : }
829 : 4 : CU_ASSERT(spdk_get_ticks() == current_time);
830 : :
831 : : /* Thread on core 2 should be scheduled to core 0 */
832 : 4 : reactor = spdk_reactor_get(0);
833 : 4 : CU_ASSERT(reactor != NULL);
834 : 4 : MOCK_SET(spdk_env_get_current_core, 0);
835 : 4 : event_queue_run_batch(reactor);
836 : :
837 : 4 : reactor = spdk_reactor_get(0);
838 : 4 : CU_ASSERT(reactor != NULL);
839 : 4 : CU_ASSERT(!TAILQ_EMPTY(&reactor->threads));
840 : : /* Thread 1 has been limited and stiil on core 0 */
841 : 4 : reactor = spdk_reactor_get(1);
842 : 4 : CU_ASSERT(reactor != NULL);
843 : 4 : CU_ASSERT(!TAILQ_EMPTY(&reactor->threads));
844 : :
845 : 4 : reactor = spdk_reactor_get(2);
846 : 4 : CU_ASSERT(reactor != NULL);
847 : 4 : CU_ASSERT(TAILQ_EMPTY(&reactor->threads));
848 : :
849 : 4 : g_reactor_state = SPDK_REACTOR_STATE_INITIALIZED;
850 : :
851 : : /* Destroy threads */
852 [ + + ]: 16 : for (i = 0; i < 3; i++) {
853 : 12 : spdk_set_thread(thread[i]);
854 : 12 : spdk_thread_exit(thread[i]);
855 : : }
856 [ + + ]: 16 : for (i = 0; i < 3; i++) {
857 : 12 : reactor = spdk_reactor_get(i);
858 : 12 : CU_ASSERT(reactor != NULL);
859 : 12 : reactor_run(reactor);
860 : : }
861 : :
862 : 4 : spdk_set_thread(NULL);
863 : :
864 : 4 : MOCK_CLEAR(spdk_env_get_current_core);
865 : :
866 : 4 : spdk_reactors_fini();
867 : :
868 : 4 : free_cores();
869 : 4 : }
870 : :
871 : : uint8_t g_curr_freq;
872 : :
873 : : static int
874 : 4 : core_freq_up(uint32_t lcore)
875 : : {
876 [ + - ]: 4 : if (g_curr_freq != UINT8_MAX) {
877 : 4 : g_curr_freq++;
878 : : }
879 : :
880 : 4 : return 0;
881 : : }
882 : :
883 : : static int
884 : 4 : core_freq_down(uint32_t lcore)
885 : : {
886 [ + - ]: 4 : if (g_curr_freq != 0) {
887 : 4 : g_curr_freq--;
888 : : }
889 : :
890 : 4 : return 0;
891 : : }
892 : :
893 : : static int
894 : 4 : core_freq_max(uint32_t lcore)
895 : : {
896 : 4 : g_curr_freq = UINT8_MAX;
897 : :
898 : 4 : return 0;
899 : : }
900 : :
901 : 0 : DEFINE_STUB(core_freq_min, int, (uint32_t lcore_id), 0);
902 : 0 : DEFINE_STUB(core_caps, int,
903 : : (uint32_t lcore_id, struct spdk_governor_capabilities *capabilities), 0);
904 : 4 : DEFINE_STUB(governor_init, int, (void), 0);
905 : 0 : DEFINE_STUB_V(governor_deinit, (void));
906 : :
907 : : static struct spdk_governor governor = {
908 : : .name = "dpdk_governor",
909 : : .get_core_curr_freq = NULL,
910 : : .core_freq_up = core_freq_up,
911 : : .core_freq_down = core_freq_down,
912 : : .set_core_freq_max = core_freq_max,
913 : : .set_core_freq_min = core_freq_min,
914 : : .get_core_capabilities = core_caps,
915 : : .init = governor_init,
916 : : .deinit = governor_deinit,
917 : : };
918 : :
919 : : static void
920 : 4 : test_governor(void)
921 : : {
922 : 4 : struct spdk_cpuset cpuset = {};
923 : 4 : struct spdk_thread *thread[2];
924 : : struct spdk_lw_thread *lw_thread;
925 : : struct spdk_reactor *reactor;
926 : 4 : struct spdk_poller *busy, *idle;
927 : 4 : uint8_t last_freq = 100;
928 : : int i;
929 : :
930 : 4 : MOCK_SET(spdk_env_get_current_core, 0);
931 : :
932 : 4 : g_curr_freq = last_freq;
933 : 4 : spdk_governor_register(&governor);
934 : :
935 : 4 : allocate_cores(2);
936 : :
937 : 4 : CU_ASSERT(spdk_reactors_init(SPDK_DEFAULT_MSG_MEMPOOL_SIZE) == 0);
938 : :
939 : 4 : spdk_scheduler_set("dynamic");
940 : 4 : spdk_governor_set("dpdk_governor");
941 : :
942 [ + + ]: 12 : for (i = 0; i < 2; i++) {
943 : 8 : spdk_cpuset_set_cpu(&g_reactor_core_mask, i, true);
944 : : }
945 : :
946 : : /* Create threads. */
947 [ + + ]: 12 : for (i = 0; i < 2; i++) {
948 : 8 : spdk_cpuset_zero(&cpuset);
949 : 8 : spdk_cpuset_set_cpu(&cpuset, i, true);
950 : 8 : thread[i] = spdk_thread_create(NULL, &cpuset);
951 : 8 : CU_ASSERT(thread[i] != NULL);
952 : : }
953 : :
954 [ + + ]: 12 : for (i = 0; i < 2; i++) {
955 : 8 : reactor = spdk_reactor_get(i);
956 : 8 : CU_ASSERT(reactor != NULL);
957 : 8 : MOCK_SET(spdk_env_get_current_core, i);
958 : 8 : CU_ASSERT(event_queue_run_batch(reactor) == 1);
959 : 8 : CU_ASSERT(!TAILQ_EMPTY(&reactor->threads));
960 : : }
961 : :
962 : 4 : reactor = spdk_reactor_get(0);
963 : 4 : CU_ASSERT(reactor != NULL);
964 : 4 : MOCK_SET(spdk_env_get_current_core, 0);
965 : :
966 : 4 : g_reactor_state = SPDK_REACTOR_STATE_RUNNING;
967 : :
968 : : /* TEST 1 */
969 : : /* Init thread stats (low load) */
970 : 4 : MOCK_SET(spdk_get_ticks, 100);
971 : 4 : reactor->tsc_last = 100;
972 : :
973 [ + + ]: 12 : for (i = 0; i < 2; i++) {
974 : 8 : spdk_set_thread(thread[i]);
975 : 8 : idle = spdk_poller_register(poller_run_idle, (void *)200, 0);
976 : 8 : reactor = spdk_reactor_get(i);
977 : 8 : CU_ASSERT(reactor != NULL);
978 : 8 : MOCK_SET(spdk_env_get_current_core, i);
979 : 8 : _reactor_run(reactor);
980 : 8 : spdk_poller_unregister(&idle);
981 : :
982 : : /* Update last stats so that we don't have to call scheduler twice */
983 : 8 : lw_thread = spdk_thread_get_ctx(thread[i]);
984 : 8 : lw_thread->current_stats.idle_tsc = 1;
985 : : }
986 : :
987 : 4 : MOCK_SET(spdk_env_get_current_core, 0);
988 : 4 : _reactors_scheduler_gather_metrics(NULL, NULL);
989 : :
990 : 4 : CU_ASSERT(_run_events_till_completion(2) == 2);
991 : 4 : MOCK_SET(spdk_env_get_current_core, 0);
992 : :
993 : : /* Threads were idle, so all of them should be placed on core 0 */
994 [ + + ]: 12 : for (i = 0; i < 2; i++) {
995 : 8 : reactor = spdk_reactor_get(i);
996 : 8 : CU_ASSERT(reactor != NULL);
997 : 8 : _reactor_run(reactor);
998 : : }
999 : :
1000 : : /* 1 thread should be scheduled to core 0 */
1001 : 4 : reactor = spdk_reactor_get(0);
1002 : 4 : CU_ASSERT(reactor != NULL);
1003 : 4 : MOCK_SET(spdk_env_get_current_core, 0);
1004 : 4 : CU_ASSERT(event_queue_run_batch(reactor) == 1);
1005 : :
1006 : : /* Main core should be busy less than 50% time now - frequency should be lowered */
1007 : 4 : CU_ASSERT(g_curr_freq == last_freq - 1);
1008 : :
1009 : 4 : last_freq = g_curr_freq;
1010 : :
1011 : : /* TEST 2 */
1012 : : /* Make first threads busy - both threads will be still on core 0, but frequency will have to be raised */
1013 : 4 : spdk_set_thread(thread[0]);
1014 : 4 : busy = spdk_poller_register(poller_run_busy, (void *)1000, 0);
1015 : 4 : _reactor_run(reactor);
1016 : 4 : spdk_poller_unregister(&busy);
1017 : :
1018 : 4 : spdk_set_thread(thread[1]);
1019 : 4 : idle = spdk_poller_register(poller_run_idle, (void *)100, 0);
1020 : 4 : _reactor_run(reactor);
1021 : 4 : spdk_poller_unregister(&idle);
1022 : :
1023 : : /* Run scheduler again */
1024 : 4 : MOCK_SET(spdk_env_get_current_core, 0);
1025 : 4 : _reactors_scheduler_gather_metrics(NULL, NULL);
1026 : :
1027 : 4 : i = _run_events_till_completion(2);
1028 : : /* Six runs when interrupt mode is supported, two if not. */
1029 [ - + - - ]: 4 : CU_ASSERT(i == 6 || i == 2);
1030 : 4 : MOCK_SET(spdk_env_get_current_core, 0);
1031 : :
1032 : : /* Main core should be busy more than 50% time now - frequency should be raised */
1033 : 4 : CU_ASSERT(g_curr_freq == last_freq + 1);
1034 : :
1035 : : /* TEST 3 */
1036 : : /* Make second thread very busy so that it will be moved to second core */
1037 : 4 : spdk_set_thread(thread[1]);
1038 : 4 : busy = spdk_poller_register(poller_run_busy, (void *)2000, 0);
1039 : 4 : _reactor_run(reactor);
1040 : 4 : spdk_poller_unregister(&busy);
1041 : :
1042 : : /* Update first thread stats */
1043 : 4 : spdk_set_thread(thread[0]);
1044 : 4 : idle = spdk_poller_register(poller_run_idle, (void *)100, 0);
1045 : 4 : _reactor_run(reactor);
1046 : 4 : spdk_poller_unregister(&idle);
1047 : :
1048 : : /* Run scheduler again */
1049 : 4 : MOCK_SET(spdk_env_get_current_core, 0);
1050 : 4 : _reactors_scheduler_gather_metrics(NULL, NULL);
1051 : :
1052 : 4 : i = _run_events_till_completion(2);
1053 : : /* Six runs when interrupt mode is supported, two if not. */
1054 [ - + - - ]: 4 : CU_ASSERT(i == 6 || i == 2);
1055 : 4 : MOCK_SET(spdk_env_get_current_core, 0);
1056 : :
1057 [ + + ]: 12 : for (i = 0; i < 2; i++) {
1058 : 8 : reactor = spdk_reactor_get(i);
1059 : 8 : CU_ASSERT(reactor != NULL);
1060 : 8 : _reactor_run(reactor);
1061 : : }
1062 : :
1063 : : /* Main core frequency should be set to max when we have busy threads on other cores */
1064 : 4 : CU_ASSERT(g_curr_freq == UINT8_MAX);
1065 : :
1066 : 4 : g_reactor_state = SPDK_REACTOR_STATE_INITIALIZED;
1067 : :
1068 : : /* Destroy threads */
1069 [ + + ]: 12 : for (i = 0; i < 2; i++) {
1070 : 8 : spdk_set_thread(thread[i]);
1071 : 8 : spdk_thread_exit(thread[i]);
1072 : : }
1073 [ + + ]: 12 : for (i = 0; i < 2; i++) {
1074 : 8 : reactor = spdk_reactor_get(i);
1075 : 8 : CU_ASSERT(reactor != NULL);
1076 : 8 : reactor_run(reactor);
1077 : : }
1078 : :
1079 : 4 : spdk_set_thread(NULL);
1080 : :
1081 : 4 : MOCK_CLEAR(spdk_env_get_current_core);
1082 : :
1083 : 4 : spdk_reactors_fini();
1084 : :
1085 : 4 : free_cores();
1086 : 4 : }
1087 : :
1088 : : int
1089 : 4 : main(int argc, char **argv)
1090 : : {
1091 : 4 : CU_pSuite suite = NULL;
1092 : : unsigned int num_failures;
1093 : :
1094 : 4 : CU_initialize_registry();
1095 : :
1096 : 4 : suite = CU_add_suite("app_suite", NULL, NULL);
1097 : :
1098 : 4 : CU_ADD_TEST(suite, test_create_reactor);
1099 : 4 : CU_ADD_TEST(suite, test_init_reactors);
1100 : 4 : CU_ADD_TEST(suite, test_event_call);
1101 : 4 : CU_ADD_TEST(suite, test_schedule_thread);
1102 : 4 : CU_ADD_TEST(suite, test_reschedule_thread);
1103 : 4 : CU_ADD_TEST(suite, test_bind_thread);
1104 : 4 : CU_ADD_TEST(suite, test_for_each_reactor);
1105 : 4 : CU_ADD_TEST(suite, test_reactor_stats);
1106 : 4 : CU_ADD_TEST(suite, test_scheduler);
1107 : 4 : CU_ADD_TEST(suite, test_governor);
1108 : :
1109 : 4 : num_failures = spdk_ut_run_tests(argc, argv, NULL);
1110 : 4 : CU_cleanup_registry();
1111 : :
1112 : 4 : return num_failures;
1113 : : }
|