1 /* 2 * Copyright (c) 2021 Nordic Semiconductor ASA 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 7 /** 8 * @file 9 * 10 * @brief Zephyr testing framework ztress macros 11 */ 12 13 #ifndef TESTSUITE_ZTEST_INCLUDE_ZTRESS_H__ 14 #define TESTSUITE_ZTEST_INCLUDE_ZTRESS_H__ 15 16 #include <zephyr/sys/util.h> 17 #include <zephyr/kernel.h> 18 19 #ifdef __cplusplus 20 extern "C" { 21 #endif 22 23 /** @internal Internal ID's to distinguish context type. */ 24 #define ZTRESS_ID_THREAD 0 25 #define ZTRESS_ID_K_TIMER 1 26 27 /** 28 * @defgroup ztest_ztress Ztest ztress macros 29 * @ingroup ztest 30 * 31 * This module provides test stress when using Ztest. 32 * 33 * @{ 34 */ 35 36 /** @brief Descriptor of a k_timer handler execution context. 37 * 38 * The handler is executed in the k_timer handler context which typically means 39 * interrupt context. This context will preempt any other used in the set. 40 * 41 * @note There can only be up to one k_timer context in the set and it must be the 42 * first argument of @ref ZTRESS_EXECUTE. 43 * 44 * @param handler User handler of type @ref ztress_handler. 45 * 46 * @param user_data User data passed to the @p handler. 47 * 48 * @param exec_cnt Number of handler executions to complete the test. If 0 then 49 * this is not included in completion criteria. 50 * 51 * @param init_timeout Initial backoff time base (given in @ref k_timeout_t). It 52 * is adjusted during the test to optimize CPU load. The actual timeout used for 53 * the timer is randomized. 54 */ 55 #define ZTRESS_TIMER(handler, user_data, exec_cnt, init_timeout) \ 56 (ZTRESS_ID_K_TIMER, handler, user_data, exec_cnt, 0, init_timeout) 57 58 /** @brief Descriptor of a thread execution context. 59 * 60 * The handler is executed in the thread context. The priority of the thread is 61 * determined based on the order in which contexts are listed in @ref ZTRESS_EXECUTE. 62 * 63 * @note thread sleeps for random amount of time. Additionally, the thread busy-waits 64 * for a random length of time to further increase randomization in the test. 65 * 66 * @param handler User handler of type @ref ztress_handler. 67 * 68 * @param user_data User data passed to the @p handler. 69 * 70 * @param exec_cnt Number of handler executions to complete the test. If 0 then 71 * this is not included in completion criteria. 72 * 73 * @param preempt_cnt Number of preemptions of that context to complete the test. 74 * If 0 then this is not included in completion criteria. 75 * 76 * @param init_timeout Initial backoff time base (given in @ref k_timeout_t). It 77 * is adjusted during the test to optimize CPU load. The actual timeout used for 78 * sleeping is randomized. 79 */ 80 #define ZTRESS_THREAD(handler, user_data, exec_cnt, preempt_cnt, init_timeout) \ 81 (ZTRESS_ID_THREAD, handler, user_data, exec_cnt, preempt_cnt, init_timeout) 82 83 /** @brief User handler called in one of the configured contexts. 84 * 85 * @param user_data User data provided in the context descriptor. 86 * 87 * @param cnt Current execution counter. Counted from 0. 88 * 89 * @param last Flag set to true indicates that it is the last execution because 90 * completion criteria are met, test timed out or was aborted. 91 * 92 * @param prio Context priority counting from 0 which indicates the highest priority. 93 * 94 * @retval true continue test. 95 * @retval false stop executing the current context. 96 */ 97 typedef bool (*ztress_handler)(void *user_data, uint32_t cnt, bool last, int prio); 98 99 /** @internal Context structure. */ 100 struct ztress_context_data { 101 /* Handler. */ 102 ztress_handler handler; 103 104 /* User data */ 105 void *user_data; 106 107 /* Minimum number of executions to complete the test. */ 108 uint32_t exec_cnt; 109 110 /* Minimum number of preemptions to complete the test. Valid only for 111 * thread context. 112 */ 113 uint32_t preempt_cnt; 114 115 /* Initial timeout. */ 116 k_timeout_t t; 117 }; 118 119 /** @brief Initialize context structure. 120 * 121 * For argument types see @ref ztress_context_data. For more details see 122 * @ref ZTRESS_THREAD. 123 * 124 * @param _handler Handler. 125 * @param _user_data User data passed to the handler. 126 * @param _exec_cnt Execution count limit. 127 * @param _preempt_cnt Preemption count limit. 128 * @param _t Initial timeout. 129 */ 130 #define ZTRESS_CONTEXT_INITIALIZER(_handler, _user_data, _exec_cnt, _preempt_cnt, _t) \ 131 { \ 132 .handler = (_handler), \ 133 .user_data = (_user_data), \ 134 .exec_cnt = (_exec_cnt), \ 135 .preempt_cnt = (_preempt_cnt), \ 136 .t = (_t) \ 137 } 138 139 /** @internal Strip first argument (context type) and call struct initializer. */ 140 #define Z_ZTRESS_GET_HANDLER_DATA2(_, ...) \ 141 ZTRESS_CONTEXT_INITIALIZER(__VA_ARGS__) 142 143 /** @internal Macro for initializing context data. */ 144 #define Z_ZTRESS_GET_HANDLER_DATA(data) \ 145 Z_ZTRESS_GET_HANDLER_DATA2 data 146 147 /** @internal Macro for checking if provided context is a timer context. */ 148 #define Z_ZTRESS_HAS_TIMER(data, ...) \ 149 GET_ARG_N(1, __DEBRACKET data) 150 151 /** @internal If context descriptor is @ref ZTRESS_TIMER, it returns index of that 152 * descriptor in the list of arguments. 153 */ 154 #define Z_ZTRESS_TIMER_IDX(idx, data) \ 155 ((GET_ARG_N(1, __DEBRACKET data)) == ZTRESS_ID_K_TIMER ? idx : 0) 156 157 /** @intenal Macro validates that @ref ZTRESS_TIMER context is not used except for 158 * the first item in the list of contexts. 159 */ 160 #define Z_ZTRESS_TIMER_CONTEXT_VALIDATE(...) \ 161 BUILD_ASSERT((FOR_EACH_IDX(Z_ZTRESS_TIMER_IDX, (+), __VA_ARGS__)) == 0, \ 162 "There can only be up to one ZTRESS_TIMER context and it must " \ 163 "be the first in the list") 164 165 /** @brief Setup and run stress test. 166 * 167 * It initialises all contexts and calls @ref ztress_execute. 168 * 169 * @param ... List of contexts. Contexts are configured using @ref ZTRESS_TIMER 170 * and @ref ZTRESS_THREAD macros. @ref ZTRESS_TIMER must be the first argument if 171 * used. Each thread context has an assigned priority. The priority is assigned in 172 * a descending order (first listed thread context has the highest priority). 173 * The maximum number of supported thread contexts, including the timer context, 174 * is configurable in Kconfig (ZTRESS_MAX_THREADS). 175 */ 176 #define ZTRESS_EXECUTE(...) do { \ 177 Z_ZTRESS_TIMER_CONTEXT_VALIDATE(__VA_ARGS__); \ 178 int has_timer = Z_ZTRESS_HAS_TIMER(__VA_ARGS__); \ 179 struct ztress_context_data _ctx_data1[] = { \ 180 FOR_EACH(Z_ZTRESS_GET_HANDLER_DATA, (,), __VA_ARGS__) \ 181 }; \ 182 size_t cnt = ARRAY_SIZE(_ctx_data1) - has_timer; \ 183 static struct ztress_context_data _ctx_data[ARRAY_SIZE(_ctx_data1)]; \ 184 for (size_t i = 0; i < ARRAY_SIZE(_ctx_data1); i++) { \ 185 _ctx_data[i] = _ctx_data1[i]; \ 186 } \ 187 int exec_err = ztress_execute(has_timer ? &_ctx_data[0] : NULL, \ 188 &_ctx_data[has_timer], cnt); \ 189 \ 190 zassert_equal(exec_err, 0, "ztress_execute failed (err: %d)", exec_err); \ 191 } while (0) 192 193 /** Execute contexts. 194 * 195 * The test runs until all completion requirements are met or until the test times out 196 * (use @ref ztress_set_timeout to configure timeout) or until the test is aborted 197 * (@ref ztress_abort). 198 * 199 * on test completion a report is printed (@ref ztress_report is called internally). 200 * 201 * @param timer_data Timer context. NULL if timer context is not used. 202 * @param thread_data List of thread contexts descriptors in priority descending order. 203 * @param cnt Number of thread contexts. 204 * 205 * @retval -EINVAL If configuration is invalid. 206 * @retval 0 if test is successfully performed. 207 */ 208 int ztress_execute(struct ztress_context_data *timer_data, 209 struct ztress_context_data *thread_data, 210 size_t cnt); 211 212 /** @brief Abort ongoing stress test. */ 213 void ztress_abort(void); 214 215 /** @brief Set test timeout. 216 * 217 * Test is terminated after timeout disregarding completion criteria. Setting 218 * is persistent between executions. 219 * 220 * @param t Timeout. 221 */ 222 void ztress_set_timeout(k_timeout_t t); 223 224 /** @brief Print last test report. 225 * 226 * Report contains number of executions and preemptions for each context, initial 227 * and adjusted timeouts and CPU load during the test. 228 */ 229 void ztress_report(void); 230 231 /** @brief Get number of executions of a given context in the last test. 232 * 233 * @param id Context id. 0 means the highest priority. 234 * 235 * @return Number of executions. 236 */ 237 int ztress_exec_count(uint32_t id); 238 239 /** @brief Get number of preemptions of a given context in the last test. 240 * 241 * @param id Context id. 0 means the highest priority. 242 * 243 * @return Number of preemptions. 244 */ 245 int ztress_preempt_count(uint32_t id); 246 247 /** @brief Get optimized timeout base of a given context in the last test. 248 * 249 * Optimized value can be used to update initial value. It will improve the test 250 * since optimal CPU load will be reach immediately. 251 * 252 * @param id Context id. 0 means the highest priority. 253 * 254 * @return Optimized timeout base. 255 */ 256 uint32_t ztress_optimized_ticks(uint32_t id); 257 258 /** 259 * @} 260 */ 261 262 #ifdef __cplusplus 263 } 264 #endif 265 266 #endif /* TESTSUITE_ZTEST_INCLUDE_ZTRESS_H__ */ 267