rusEFI
The most advanced open source ECU
Loading...
Searching...
No Matches
testbmk.c
Go to the documentation of this file.
1/*
2 ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15*/
16
17#include <rusefi/true_false.h>
18#include "efifeatures.h"
19
20#if EFI_PERF_METRICS
21#include "test.h"
22
23/**
24 * @page test_benchmarks Kernel Benchmarks
25 *
26 * File: @ref testbmk.c
27 *
28 * <h2>Description</h2>
29 * This module implements a series of system benchmarks. The benchmarks are
30 * useful as a stress test and as a reference when comparing ChibiOS/RT
31 * with similar systems.
32 *
33 * <h2>Objective</h2>
34 * Objective of the test module is to provide a performance index for the
35 * most critical system subsystems. The performance numbers allow to
36 * discover performance regressions between successive ChibiOS/RT releases.
37 *
38 * <h2>Preconditions</h2>
39 * None.
40 *
41 * <h2>Test Cases</h2>
42 * - @subpage test_benchmarks_001
43 * - @subpage test_benchmarks_002
44 * - @subpage test_benchmarks_003
45 * - @subpage test_benchmarks_004
46 * - @subpage test_benchmarks_005
47 * - @subpage test_benchmarks_006
48 * - @subpage test_benchmarks_007
49 * - @subpage test_benchmarks_008
50 * - @subpage test_benchmarks_009
51 * - @subpage test_benchmarks_010
52 * - @subpage test_benchmarks_011
53 * - @subpage test_benchmarks_012
54 * - @subpage test_benchmarks_013
55 * .
56 * @file testbmk.c Kernel Benchmarks
57 * @brief Kernel Benchmarks source file
58 * @file testbmk.h
59 * @brief Kernel Benchmarks header file
60 */
61
62static Semaphore sem1;
63#if CH_USE_MUTEXES
64static Mutex mtx1;
65#endif
66
67static msg_t thread1(void *p) {
68 Thread *tp;
69 msg_t msg;
70
71 (void)p;
72 do {
73 tp = chMsgWait();
74 msg = chMsgGet(tp);
75 chMsgRelease(tp, msg);
76 } while (msg);
77 return 0;
78}
79
80#ifdef __GNUC__
81__attribute__((noinline))
82#endif
83static unsigned int msg_loop_test(Thread *tp) {
84
85 uint32_t n = 0;
87 test_start_timer(1000);
88 do {
89 (void)chMsgSend(tp, 1);
90 n++;
91#if defined(SIMULATOR)
93#endif
94 } while (!test_timer_done);
95 (void)chMsgSend(tp, 0);
96 return n;
97}
98
99/**
100 * @page test_benchmarks_001 Messages performance #1
101 *
102 * <h2>Description</h2>
103 * A message server thread is created with a lower priority than the client
104 * thread, the messages throughput per second is measured and the result
105 * printed in the output log.
106 */
107
108static void bmk1_execute(void) {
109 uint32_t n;
110
111 threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriority()-1, thread1, NULL);
112 n = msg_loop_test(threads[0]);
114 test_print("--- Score : ");
115 test_printn(n);
116 test_print(" msgs/S, ");
117 test_printn(n << 1);
118 test_println(" ctxswc/S");
119}
120
121ROMCONST struct testcase testbmk1 = {
122 "Benchmark, messages #1",
123 NULL,
124 NULL,
126};
127
128/**
129 * @page test_benchmarks_002 Messages performance #2
130 *
131 * <h2>Description</h2>
132 * A message server thread is created with an higher priority than the client
133 * thread, the messages throughput per second is measured and the result
134 * printed in the output log.
135 */
136
137static void bmk2_execute(void) {
138 uint32_t n;
139
140 threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriority()+1, thread1, NULL);
141 n = msg_loop_test(threads[0]);
143 test_print("--- Score : ");
144 test_printn(n);
145 test_print(" msgs/S, ");
146 test_printn(n << 1);
147 test_println(" ctxswc/S");
148}
149
150ROMCONST struct testcase testbmk2 = {
151 "Benchmark, messages #2",
152 NULL,
153 NULL,
155};
156
157static msg_t thread2(void *p) {
158
159 return (msg_t)p;
160}
161
162/**
163 * @page test_benchmarks_003 Messages performance #3
164 *
165 * <h2>Description</h2>
166 * A message server thread is created with an higher priority than the client
167 * thread, four lower priority threads crowd the ready list, the messages
168 * throughput per second is measured while the ready list and the result
169 * printed in the output log.
170 */
171
172static void bmk3_execute(void) {
173 uint32_t n;
174
175 threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriority()+1, thread1, NULL);
176 threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriority()-2, thread2, NULL);
177 threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriority()-3, thread2, NULL);
178 threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriority()-4, thread2, NULL);
179 threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriority()-5, thread2, NULL);
180 n = msg_loop_test(threads[0]);
182 test_print("--- Score : ");
183 test_printn(n);
184 test_print(" msgs/S, ");
185 test_printn(n << 1);
186 test_println(" ctxswc/S");
187}
188
189ROMCONST struct testcase testbmk3 = {
190 "Benchmark, messages #3",
191 NULL,
192 NULL,
194};
195
196/**
197 * @page test_benchmarks_004 Context Switch performance
198 *
199 * <h2>Description</h2>
200 * A thread is created that just performs a @p chSchGoSleepS() into a loop,
201 * the thread is awakened as fast is possible by the tester thread.<br>
202 * The Context Switch performance is calculated by measuring the number of
203 * iterations after a second of continuous operations.
204 */
205
206msg_t thread4(void *p) {
207 msg_t msg;
208 Thread *self = chThdSelf();
209
210 (void)p;
211 chSysLock();
212 do {
213 chSchGoSleepS(THD_STATE_SUSPENDED);
214 msg = self->p_u.rdymsg;
215 } while (msg == RDY_OK);
216 chSysUnlock();
217 return 0;
218}
219
220static void bmk4_execute(void) {
221 Thread *tp;
222 uint32_t n;
223
224 tp = threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriority()+1, thread4, NULL);
225 n = 0;
227 test_start_timer(1000);
228 do {
229 chSysLock();
230 chSchWakeupS(tp, RDY_OK);
231 chSchWakeupS(tp, RDY_OK);
232 chSchWakeupS(tp, RDY_OK);
233 chSchWakeupS(tp, RDY_OK);
234 chSysUnlock();
235 n += 4;
236#if defined(SIMULATOR)
238#endif
239 } while (!test_timer_done);
240 chSysLock();
241 chSchWakeupS(tp, RDY_TIMEOUT);
242 chSysUnlock();
243
245 test_print("--- Score : ");
246 test_printn(n * 2);
247 test_println(" ctxswc/S");
248}
249
250ROMCONST struct testcase testbmk4 = {
251 "Benchmark, context switch",
252 NULL,
253 NULL,
255};
256
257/**
258 * @page test_benchmarks_005 Threads performance, full cycle
259 *
260 * <h2>Description</h2>
261 * Threads are continuously created and terminated into a loop. A full
262 * @p chThdCreateStatic() / @p chThdExit() / @p chThdWait() cycle is performed
263 * in each iteration.<br>
264 * The performance is calculated by measuring the number of iterations after
265 * a second of continuous operations.
266 */
267
268static void bmk5_execute(void) {
269
270 uint32_t n = 0;
271 void *wap = wa[0];
272 tprio_t prio = chThdGetPriority() - 1;
274 test_start_timer(1000);
275 do {
276 chThdWait(chThdCreateStatic(wap, WA_SIZE, prio, thread2, NULL));
277 n++;
278#if defined(SIMULATOR)
280#endif
281 } while (!test_timer_done);
282 test_print("--- Score : ");
283 test_printn(n);
284 test_println(" threads/S");
285}
286
287ROMCONST struct testcase testbmk5 = {
288 "Benchmark, threads, full cycle",
289 NULL,
290 NULL,
292};
293
294/**
295 * @page test_benchmarks_006 Threads performance, create/exit only
296 *
297 * <h2>Description</h2>
298 * Threads are continuously created and terminated into a loop. A partial
299 * @p chThdCreateStatic() / @p chThdExit() cycle is performed in each
300 * iteration, the @p chThdWait() is not necessary because the thread is
301 * created at an higher priority so there is no need to wait for it to
302 * terminate.<br>
303 * The performance is calculated by measuring the number of iterations after
304 * a second of continuous operations.
305 */
306
307static void bmk6_execute(void) {
308
309 uint32_t n = 0;
310 void *wap = wa[0];
311 tprio_t prio = chThdGetPriority() + 1;
313 test_start_timer(1000);
314 do {
315 chThdCreateStatic(wap, WA_SIZE, prio, thread2, NULL);
316 n++;
317#if defined(SIMULATOR)
319#endif
320 } while (!test_timer_done);
321 test_print("--- Score : ");
322 test_printn(n);
323 test_println(" threads/S");
324}
325
326ROMCONST struct testcase testbmk6 = {
327 "Benchmark, threads, create only",
328 NULL,
329 NULL,
331};
332
333/**
334 * @page test_benchmarks_007 Mass reschedule performance
335 *
336 * <h2>Description</h2>
337 * Five threads are created and atomically rescheduled by resetting the
338 * semaphore where they are waiting on. The operation is performed into a
339 * continuous loop.<br>
340 * The performance is calculated by measuring the number of iterations after
341 * a second of continuous operations.
342 */
343
344static msg_t thread3(void *p) {
345
346 (void)p;
347 while (!chThdShouldTerminate())
348 chSemWait(&sem1);
349 return 0;
350}
351
352static void bmk7_setup(void) {
353
354 chSemInit(&sem1, 0);
355}
356
357static void bmk7_execute(void) {
358 uint32_t n;
359
360 threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriority()+5, thread3, NULL);
361 threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriority()+4, thread3, NULL);
362 threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriority()+3, thread3, NULL);
363 threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriority()+2, thread3, NULL);
364 threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriority()+1, thread3, NULL);
365
366 n = 0;
368 test_start_timer(1000);
369 do {
370 chSemReset(&sem1, 0);
371 n++;
372#if defined(SIMULATOR)
374#endif
375 } while (!test_timer_done);
377 chSemReset(&sem1, 0);
379
380 test_print("--- Score : ");
381 test_printn(n);
382 test_print(" reschedules/S, ");
383 test_printn(n * 6);
384 test_println(" ctxswc/S");
385}
386
387ROMCONST struct testcase testbmk7 = {
388 "Benchmark, mass reschedule, 5 threads",
390 NULL,
392};
393
394/**
395 * @page test_benchmarks_008 I/O Round-Robin voluntary reschedule.
396 *
397 * <h2>Description</h2>
398 * Five threads are created at equal priority, each thread just increases a
399 * variable and yields.<br>
400 * The performance is calculated by measuring the number of iterations after
401 * a second of continuous operations.
402 */
403
404static msg_t thread8(void *p) {
405
406 do {
407 chThdYield();
408 chThdYield();
409 chThdYield();
410 chThdYield();
411 (*(uint32_t *)p) += 4;
412#if defined(SIMULATOR)
414#endif
415 } while(!chThdShouldTerminate());
416 return 0;
417}
418
419static void bmk8_execute(void) {
420 uint32_t n;
421
422 n = 0;
424
425 threads[0] = chThdCreateStatic(wa[0], WA_SIZE, chThdGetPriority()-1, thread8, (void *)&n);
426 threads[1] = chThdCreateStatic(wa[1], WA_SIZE, chThdGetPriority()-1, thread8, (void *)&n);
427 threads[2] = chThdCreateStatic(wa[2], WA_SIZE, chThdGetPriority()-1, thread8, (void *)&n);
428 threads[3] = chThdCreateStatic(wa[3], WA_SIZE, chThdGetPriority()-1, thread8, (void *)&n);
429 threads[4] = chThdCreateStatic(wa[4], WA_SIZE, chThdGetPriority()-1, thread8, (void *)&n);
430
431 chThdSleepSeconds(1);
434
435 test_print("--- Score : ");
436 test_printn(n);
437 test_println(" ctxswc/S");
438}
439
440ROMCONST struct testcase testbmk8 = {
441 "Benchmark, round robin context switching",
442 NULL,
443 NULL,
445};
446
447#if CH_USE_QUEUES
448/**
449 * @page test_benchmarks_009 I/O Queues throughput
450 *
451 * <h2>Description</h2>
452 * Four bytes are written and then read from an @p InputQueue into a continuous
453 * loop.<br>
454 * The performance is calculated by measuring the number of iterations after
455 * a second of continuous operations.
456 */
457
458static void bmk9_execute(void) {
459 uint32_t n;
460 static uint8_t ib[16];
461 static InputQueue iq;
462
463 chIQInit(&iq, ib, sizeof(ib), NULL, NULL);
464 n = 0;
466 test_start_timer(1000);
467 do {
468 chSysLock();
469 chIQPutI(&iq, 0);
470 chIQPutI(&iq, 1);
471 chIQPutI(&iq, 2);
472 chIQPutI(&iq, 3);
473 chSysUnlock();
474 (void)chIQGet(&iq);
475 (void)chIQGet(&iq);
476 (void)chIQGet(&iq);
477 (void)chIQGet(&iq);
478 n++;
479#if defined(SIMULATOR)
481#endif
482 } while (!test_timer_done);
483 test_print("--- Score : ");
484 test_printn(n * 4);
485 test_println(" bytes/S");
486}
487
488ROMCONST struct testcase testbmk9 = {
489 "Benchmark, I/O Queues throughput",
490 NULL,
491 NULL,
493};
494#endif /* CH_USE_QUEUES */
495
496/**
497 * @page test_benchmarks_010 Virtual Timers set/reset performance
498 *
499 * <h2>Description</h2>
500 * A virtual timer is set and immediately reset into a continuous loop.<br>
501 * The performance is calculated by measuring the number of iterations after
502 * a second of continuous operations.
503 */
504
505static void tmo(void *param) {(void)param;}
506
507static void bmk10_execute(void) {
508 static VirtualTimer vt1, vt2;
509 uint32_t n = 0;
510
512 test_start_timer(1000);
513 do {
514 chSysLock();
515 chVTSetI(&vt1, 1, tmo, NULL);
516 chVTSetI(&vt2, 10000, tmo, NULL);
517 chVTResetI(&vt1);
518 chVTResetI(&vt2);
519 chSysUnlock();
520 n++;
521#if defined(SIMULATOR)
523#endif
524 } while (!test_timer_done);
525 test_print("--- Score : ");
526 test_printn(n * 2);
527 test_println(" timers/S");
528}
529
530ROMCONST struct testcase testbmk10 = {
531 "Benchmark, virtual timers set/reset",
532 NULL,
533 NULL,
535};
536
537#if CH_USE_SEMAPHORES
538/**
539 * @page test_benchmarks_011 Semaphores wait/signal performance
540 *
541 * <h2>Description</h2>
542 * A counting semaphore is taken/released into a continuous loop, no Context
543 * Switch happens because the counter is always non negative.<br>
544 * The performance is calculated by measuring the number of iterations after
545 * a second of continuous operations.
546 */
547
548static void bmk11_setup(void) {
549
550 chSemInit(&sem1, 1);
551}
552
553static void bmk11_execute(void) {
554 uint32_t n = 0;
555
557 test_start_timer(1000);
558 do {
559 chSemWait(&sem1);
560 chSemSignal(&sem1);
561 chSemWait(&sem1);
562 chSemSignal(&sem1);
563 chSemWait(&sem1);
564 chSemSignal(&sem1);
565 chSemWait(&sem1);
566 chSemSignal(&sem1);
567 n++;
568#if defined(SIMULATOR)
570#endif
571 } while (!test_timer_done);
572 test_print("--- Score : ");
573 test_printn(n * 4);
574 test_println(" wait+signal/S");
575}
576
577ROMCONST struct testcase testbmk11 = {
578 "Benchmark, semaphores wait/signal",
580 NULL,
582};
583#endif /* CH_USE_SEMAPHORES */
584
585#if CH_USE_MUTEXES
586/**
587 * @page test_benchmarks_012 Mutexes lock/unlock performance
588 *
589 * <h2>Description</h2>
590 * A mutex is locked/unlocked into a continuous loop, no Context Switch happens
591 * because there are no other threads asking for the mutex.<br>
592 * The performance is calculated by measuring the number of iterations after
593 * a second of continuous operations.
594 */
595
596static void bmk12_setup(void) {
597
598 chMtxInit(&mtx1);
599}
600
601static void bmk12_execute(void) {
602 uint32_t n = 0;
603
605 test_start_timer(1000);
606 do {
607 chMtxLock(&mtx1);
608 chMtxUnlock();
609 chMtxLock(&mtx1);
610 chMtxUnlock();
611 chMtxLock(&mtx1);
612 chMtxUnlock();
613 chMtxLock(&mtx1);
614 chMtxUnlock();
615 n++;
616#if defined(SIMULATOR)
618#endif
619 } while (!test_timer_done);
620 test_print("--- Score : ");
621 test_printn(n * 4);
622 test_println(" lock+unlock/S");
623}
624
625ROMCONST struct testcase testbmk12 = {
626 "Benchmark, mutexes lock/unlock",
628 NULL,
630};
631#endif
632
633/**
634 * @page test_benchmarks_013 RAM Footprint
635 *
636 * <h2>Description</h2>
637 * The memory size of the various kernel objects is printed.
638 */
639
640static void bmk13_execute(void) {
641
642 test_print("--- System: ");
643 test_printn(sizeof(ReadyList) + sizeof(VTList) +
644 PORT_IDLE_THREAD_STACK_SIZE +
645 (sizeof(Thread) + sizeof(struct intctx) +
646 sizeof(struct extctx) +
647 PORT_INT_REQUIRED_STACK) * 2);
648 test_println(" bytes");
649 test_print("--- Thread: ");
650 test_printn(sizeof(Thread));
651 test_println(" bytes");
652 test_print("--- Timer : ");
653 test_printn(sizeof(VirtualTimer));
654 test_println(" bytes");
655#if CH_USE_SEMAPHORES
656 test_print("--- Semaph: ");
657 test_printn(sizeof(Semaphore));
658 test_println(" bytes");
659#endif
660#if CH_USE_EVENTS
661 test_print("--- EventS: ");
662 test_printn(sizeof(EventSource));
663 test_println(" bytes");
664 test_print("--- EventL: ");
665 test_printn(sizeof(EventListener));
666 test_println(" bytes");
667#endif
668#if CH_USE_MUTEXES
669 test_print("--- Mutex : ");
670 test_printn(sizeof(Mutex));
671 test_println(" bytes");
672#endif
673#if CH_USE_CONDVARS
674 test_print("--- CondV.: ");
675 test_printn(sizeof(CondVar));
676 test_println(" bytes");
677#endif
678#if CH_USE_QUEUES
679 test_print("--- Queue : ");
680 test_printn(sizeof(GenericQueue));
681 test_println(" bytes");
682#endif
683#if CH_USE_MAILBOXES
684 test_print("--- MailB.: ");
685 test_printn(sizeof(Mailbox));
686 test_println(" bytes");
687#endif
688}
689
690ROMCONST struct testcase testbmk13 = {
691 "Benchmark, RAM footprint",
692 NULL,
693 NULL,
695};
696
697/**
698 * @brief Test sequence for benchmarks.
699 */
700ROMCONST struct testcase * ROMCONST patternbmk[] = {
701#if !TEST_NO_BENCHMARKS
702 &testbmk1,
703 &testbmk2,
704 &testbmk3,
705 &testbmk4,
706 &testbmk5,
707 &testbmk6,
708 &testbmk7,
709 &testbmk8,
710#if CH_USE_QUEUES
711 &testbmk9,
712#endif
713 &testbmk10,
714#if CH_USE_SEMAPHORES
715 &testbmk11,
716#endif
717#if CH_USE_MUTEXES
718 &testbmk12,
719#endif
720 &testbmk13,
721#endif
722 NULL
723};
724
725#endif /* EFI_PERF_METRICS */
typedef __attribute__
Ignition Mode.
void ChkIntSources(void)
void test_wait_threads(void)
Waits for the completion of all the test-spawned threads.
Definition test.c:189
void test_printn(uint32_t n)
Prints a decimal unsigned number.
Definition test.c:73
thread_t * threads[MAX_THREADS]
Definition test.c:55
void test_terminate_threads(void)
Sets a termination request in all the test-spawned threads.
Definition test.c:178
void *ROMCONST wa[5]
Definition test.c:60
systime_t test_wait_tick(void)
Delays execution until next system time tick.
Definition test.c:227
void test_start_timer(unsigned ms)
Starts the test timer.
Definition test.c:254
void test_print(const char *msgp)
Prints a line without final end-of-line.
Definition test.c:92
bool test_timer_done
Set to TRUE when the test timer reaches its deadline.
Definition test.c:240
void test_println(const char *msgp)
Prints a line.
Definition test.c:103
Structure representing a test case.
Definition test.h:58
Tests support header.
ROMCONST struct testcase *ROMCONST patternbmk[]
Test sequence for benchmarks.
Definition testbmk.c:700
static void bmk7_setup(void)
Definition testbmk.c:352
ROMCONST struct testcase testbmk13
Definition testbmk.c:690
ROMCONST struct testcase testbmk11
Definition testbmk.c:577
static void bmk12_setup(void)
Definition testbmk.c:596
static void bmk8_execute(void)
Definition testbmk.c:419
ROMCONST struct testcase testbmk12
Definition testbmk.c:625
static Mutex mtx1
Definition testbmk.c:64
ROMCONST struct testcase testbmk3
Definition testbmk.c:189
ROMCONST struct testcase testbmk7
Definition testbmk.c:387
static msg_t thread2(void *p)
Definition testbmk.c:157
ROMCONST struct testcase testbmk1
Definition testbmk.c:121
static void bmk10_execute(void)
Definition testbmk.c:507
ROMCONST struct testcase testbmk9
Definition testbmk.c:488
static void bmk7_execute(void)
Definition testbmk.c:357
static msg_t thread3(void *p)
Definition testbmk.c:344
static void bmk2_execute(void)
Definition testbmk.c:137
ROMCONST struct testcase testbmk6
Definition testbmk.c:326
static void bmk13_execute(void)
Definition testbmk.c:640
ROMCONST struct testcase testbmk5
Definition testbmk.c:287
static void bmk1_execute(void)
Definition testbmk.c:108
ROMCONST struct testcase testbmk4
Definition testbmk.c:250
static void bmk3_execute(void)
Definition testbmk.c:172
ROMCONST struct testcase testbmk2
Definition testbmk.c:150
static msg_t thread8(void *p)
Definition testbmk.c:404
static void bmk12_execute(void)
Definition testbmk.c:601
static void bmk4_execute(void)
Definition testbmk.c:220
static void bmk5_execute(void)
Definition testbmk.c:268
static Semaphore sem1
Definition testbmk.c:62
msg_t thread4(void *p)
Definition testbmk.c:206
ROMCONST struct testcase testbmk8
Definition testbmk.c:440
ROMCONST struct testcase testbmk10
Definition testbmk.c:530
static void bmk6_execute(void)
Definition testbmk.c:307
static void bmk9_execute(void)
Definition testbmk.c:458
static void bmk11_execute(void)
Definition testbmk.c:553
static void tmo(void *param)
Definition testbmk.c:505
static void bmk11_setup(void)
Definition testbmk.c:548
static msg_t thread1(void *p)
Definition testbmk.c:67
static tstrWifiInitParam param