1 /*
2 * Copyright (c) 2024 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /*
8 * @file measure time for various condition variable operations
9 * 1. Block waiting for a condition variable
10 * 2. Signal a condition variable (with context switch)
11 */
12
13 #include <zephyr/kernel.h>
14 #include <zephyr/timing/timing.h>
15 #include "utils.h"
16 #include "timing_sc.h"
17
18 static K_CONDVAR_DEFINE(condvar);
19 static K_MUTEX_DEFINE(mutex);
20
start_thread_entry(void * p1,void * p2,void * p3)21 static void start_thread_entry(void *p1, void *p2, void *p3)
22 {
23 uint32_t num_iterations = (uint32_t)(uintptr_t)p1;
24 uint32_t i;
25 timing_t start;
26 timing_t finish;
27 uint64_t sum[2] = {0ull, 0ull};
28
29 k_mutex_lock(&mutex, K_FOREVER);
30
31 k_thread_start(&alt_thread);
32
33 for (i = 0; i < num_iterations; i++) {
34 /* 1. Get the first timestamp and block on condvar */
35
36 start = timing_timestamp_get();
37 k_condvar_wait(&condvar, &mutex, K_FOREVER);
38
39 /* 3. Get the final timstamp */
40
41 finish = timing_timestamp_get();
42
43 sum[0] += timing_cycles_get(&start, ×tamp.sample);
44 sum[1] += timing_cycles_get(×tamp.sample, &finish);
45 }
46
47 /* Wait for alt_thread to finish */
48
49 k_thread_join(&alt_thread, K_FOREVER);
50
51 timestamp.cycles = sum[0];
52 k_sem_take(&pause_sem, K_FOREVER);
53
54 timestamp.cycles = sum[1];
55 }
56
alt_thread_entry(void * p1,void * p2,void * p3)57 static void alt_thread_entry(void *p1, void *p2, void *p3)
58 {
59 uint32_t num_iterations = (uint32_t)(uintptr_t)p1;
60 uint32_t i;
61
62 for (i = 0; i < num_iterations; i++) {
63
64 /* 2. Get midpoint timestamp and signal the condvar */
65
66 timestamp.sample = timing_timestamp_get();
67 k_condvar_signal(&condvar);
68 }
69 }
70
condvar_blocking_ops(uint32_t num_iterations,uint32_t start_options,uint32_t alt_options)71 int condvar_blocking_ops(uint32_t num_iterations, uint32_t start_options,
72 uint32_t alt_options)
73 {
74 int priority;
75 char tag[50];
76 char description[120];
77 uint64_t cycles;
78
79 priority = k_thread_priority_get(k_current_get());
80
81 timing_start();
82
83 k_thread_create(&start_thread, start_stack,
84 K_THREAD_STACK_SIZEOF(start_stack),
85 start_thread_entry,
86 (void *)(uintptr_t)num_iterations,
87 NULL, NULL,
88 priority - 2, start_options, K_FOREVER);
89
90 k_thread_create(&alt_thread, alt_stack,
91 K_THREAD_STACK_SIZEOF(alt_stack),
92 alt_thread_entry,
93 (void *)(uintptr_t)num_iterations,
94 NULL, NULL,
95 priority - 1, alt_options, K_FOREVER);
96
97 k_thread_access_grant(&start_thread, &alt_thread,
98 &condvar, &mutex, &pause_sem);
99 k_thread_access_grant(&alt_thread, &condvar);
100
101 /* Start test thread */
102
103 k_thread_start(&start_thread);
104
105 /* Stats gathered. Display them. */
106
107 snprintf(tag, sizeof(tag), "condvar.wait.blocking.%c_to_%c",
108 (start_options & K_USER) ? 'u' : 'k',
109 (alt_options & K_USER) ? 'u' : 'k');
110 snprintf(description, sizeof(description),
111 "%-40s - Wait for a condvar (context switch)", tag);
112
113 cycles = timestamp.cycles;
114 PRINT_STATS_AVG(description, (uint32_t)cycles,
115 num_iterations, false, "");
116
117 k_sem_give(&pause_sem);
118
119 snprintf(tag, sizeof(tag), "condvar.signal.wake+ctx.%c_to_%c",
120 (alt_options & K_USER) ? 'u' : 'k',
121 (start_options & K_USER) ? 'u' : 'k');
122 snprintf(description, sizeof(description),
123 "%-40s - Signal a condvar (context switch)", tag);
124 cycles = timestamp.cycles;
125 PRINT_STATS_AVG(description, (uint32_t)cycles,
126 num_iterations, false, "");
127
128 k_thread_join(&start_thread, K_FOREVER);
129
130 timing_stop();
131
132 return 0;
133 }
134