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