source: rtems/cpukit/include/rtems/test.h @ 7e86e00

5
Last change on this file since 7e86e00 was 1e483a62, checked in by Sebastian Huber <sebastian.huber@…>, on 02/02/18 at 06:43:39

test: Add rtems_test_busy_cpu_usage()

  • Property mode set to 100644
File size: 8.1 KB
Line 
1/*
2 * Copyright (c) 2014, 2018 embedded brains GmbH.  All rights reserved.
3 *
4 *  embedded brains GmbH
5 *  Dornierstr. 4
6 *  82178 Puchheim
7 *  Germany
8 *  <rtems@embedded-brains.de>
9 *
10 * The license and distribution terms for this file may be
11 * found in the file LICENSE in this distribution or at
12 * http://www.rtems.org/license/LICENSE.
13 */
14
15#ifndef _RTEMS_TEST_H
16#define _RTEMS_TEST_H
17
18#include <rtems.h>
19#include <rtems/printer.h>
20#include <rtems/score/atomic.h>
21#include <rtems/score/smpbarrier.h>
22
23#ifdef __cplusplus
24extern "C" {
25#endif /* __cplusplus */
26
27/**
28 * @defgroup RTEMSTest Test Support
29 *
30 * @brief Test support functions.
31 *
32 * @{
33 */
34
35/**
36 * @brief Each test must define a test name string.
37 */
38extern const char rtems_test_name[];
39
40/**
41 * @brief Each test must define a printer.
42 */
43extern rtems_printer rtems_test_printer;
44
45/**
46 * @brief Fatal extension for tests.
47 */
48void rtems_test_fatal_extension(
49  rtems_fatal_source source,
50  bool always_set_to_false,
51  rtems_fatal_code code
52);
53
54/**
55 * @brief Initial extension for tests.
56 */
57#define RTEMS_TEST_INITIAL_EXTENSION \
58  { NULL, NULL, NULL, NULL, NULL, NULL, NULL, rtems_test_fatal_extension }
59
60/**
61 * @brief Test states.
62 */
63typedef enum
64{
65  RTEMS_TEST_STATE_PASS,
66  RTEMS_TEST_STATE_FAIL,
67  RTEMS_TEST_STATE_USER_INPUT,
68  RTEMS_TEST_STATE_INDETERMINATE,
69  RTEMS_TEST_STATE_BENCHMARK
70} RTEMS_TEST_STATE;
71
72#if (TEST_STATE_EXPECTED_FAIL && TEST_STATE_USER_INPUT) || \
73    (TEST_STATE_EXPECTED_FAIL && TEST_STATE_INDETERMINATE) || \
74    (TEST_STATE_EXPECTED_FAIL && TEST_STATE_BENCHMARK) || \
75    (TEST_STATE_USER_INPUT    && TEST_STATE_INDETERMINATE) || \
76    (TEST_STATE_USER_INPUT    && TEST_STATE_BENCHMARK) || \
77    (TEST_STATE_INDETERMINATE && TEST_STATE_BENCHMARK)
78  #error Test states must be unique
79#endif
80
81#if TEST_STATE_EXPECTED_FAIL
82  #define TEST_STATE RTEMS_TEST_STATE_FAIL
83#elif TEST_STATE_USER_INPUT
84  #define TEST_STATE RTEMS_TEST_STATE_USER_INPUT
85#elif TEST_STATE_INDETERMINATE
86  #define TEST_STATE RTEMS_TEST_STATE_INDETERMINATE
87#elif TEST_STATE_BENCHMARK
88  #define TEST_STATE RTEMS_TEST_STATE_BENCHMARK
89#else
90  #define TEST_STATE RTEMS_TEST_STATE_PASS
91#endif
92
93/**
94 * @brief Prints a begin of test message using printf().
95 *
96 * @returns As specified by printf().
97 */
98int rtems_test_begin(const char* name, const RTEMS_TEST_STATE state);
99
100/**
101 * @brief Prints an end of test message using printf().
102 *
103 * @returns As specified by printf().
104 */
105int rtems_test_end(const char* name);
106
107/**
108 * @brief Exit the test without calling exit() since it closes stdin, etc and
109 * pulls in stdio code
110 */
111void rtems_test_exit(int status) RTEMS_NO_RETURN;
112
113/**
114 * @brief Prints via the RTEMS printer.
115 *
116 * @returns As specified by printf().
117 */
118int rtems_test_printf(const char* format, ...) RTEMS_PRINTFLIKE(1, 2);
119
120#define RTEMS_TEST_PARALLEL_PROCESSOR_MAX 32
121
122typedef struct rtems_test_parallel_job rtems_test_parallel_job;
123
124/**
125 * @brief Internal context for parallel job execution.
126 */
127typedef struct {
128  Atomic_Ulong stop;
129  SMP_barrier_Control barrier;
130  size_t worker_count;
131  rtems_id worker_ids[RTEMS_TEST_PARALLEL_PROCESSOR_MAX];
132  rtems_id stop_worker_timer_id;
133  const struct rtems_test_parallel_job *jobs;
134  size_t job_count;
135} rtems_test_parallel_context;
136
137/**
138 * @brief Worker task setup handler.
139 *
140 * Called during rtems_test_parallel() to optionally setup a worker task before
141 * it is started.
142 *
143 * @param[in] ctx The parallel context.
144 * @param[in] worker_index The worker index.
145 * @param[in] worker_id The worker task identifier.
146 */
147typedef void (*rtems_test_parallel_worker_setup)(
148  rtems_test_parallel_context *ctx,
149  size_t worker_index,
150  rtems_id worker_id
151);
152
153/**
154 * @brief Basic parallel job description.
155 */
156struct rtems_test_parallel_job {
157  /**
158   * @brief Job initialization handler.
159   *
160   * This handler executes only in the context of the master worker before the
161   * job body handler.
162   *
163   * @param[in] ctx The parallel context.
164   * @param[in] arg The user specified argument.
165   * @param[in] active_workers Count of active workers.  Depends on the cascade
166   *   option.
167   *
168   * @return The desired job body execution time in clock ticks.  See
169   *   rtems_test_parallel_stop_job().
170   */
171  rtems_interval (*init)(
172    rtems_test_parallel_context *ctx,
173    void *arg,
174    size_t active_workers
175  );
176
177  /**
178   * @brief Job body handler.
179   *
180   * @param[in] ctx The parallel context.
181   * @param[in] arg The user specified argument.
182   * @param[in] active_workers Count of active workers.  Depends on the cascade
183   *   option.
184   * @param[in] worker_index The worker index.  It ranges from 0 to the
185   *   processor count minus one.
186   */
187  void (*body)(
188    rtems_test_parallel_context *ctx,
189    void *arg,
190    size_t active_workers,
191    size_t worker_index
192  );
193
194  /**
195   * @brief Job finalization handler.
196   *
197   * This handler executes only in the context of the master worker after the
198   * job body handler.
199   *
200   * @param[in] ctx The parallel context.
201   * @param[in] arg The user specified argument.
202   * @param[in] active_workers Count of active workers.  Depends on the cascade
203   *   option.
204   */
205  void (*fini)(
206    rtems_test_parallel_context *ctx,
207    void *arg,
208    size_t active_workers
209  );
210
211  /**
212   * @brief Job specific argument.
213   */
214  void *arg;
215
216  /**
217   * @brief Job cascading flag.
218   *
219   * This flag indicates whether the job should be executed in a cascaded
220   * manner (the job is executed on one processor first, two processors
221   * afterwards and incremented step by step until all processors are used).
222   */
223  bool cascade;
224};
225
226/**
227 * @brief Indicates if a job body should stop its work loop.
228 *
229 * @param[in] ctx The parallel context.
230 *
231 * @retval true The job body should stop its work loop and return to the caller.
232 * @retval false Otherwise.
233 */
234static inline bool rtems_test_parallel_stop_job(
235  const rtems_test_parallel_context *ctx
236)
237{
238  return _Atomic_Load_ulong(&ctx->stop, ATOMIC_ORDER_RELAXED) != 0;
239}
240
241/**
242 * @brief Indicates if a worker is the master worker.
243 *
244 * The master worker is the thread that called rtems_test_parallel().
245 *
246 * @param[in] worker_index The worker index.
247 *
248 * @retval true This is the master worker.
249 * @retval false Otherwise.
250 */
251static inline bool rtems_test_parallel_is_master_worker(size_t worker_index)
252{
253  return worker_index == 0;
254}
255
256/**
257 * @brief Returns the task identifier for a worker.
258 *
259 * @param[in] ctx The parallel context.
260 * @param[in] worker_index The worker index.
261 *
262 * @return The task identifier of the worker.
263 */
264static inline rtems_id rtems_test_parallel_get_task_id(
265  const rtems_test_parallel_context *ctx,
266  size_t worker_index
267)
268{
269  return ctx->worker_ids[worker_index];
270}
271
272/**
273 * @brief Runs a bunch of jobs in parallel on all processors of the system.
274 *
275 * The worker tasks inherit the priority of the executing task.
276 *
277 * There are SMP barriers before and after the job body.
278 *
279 * @param[in] ctx The parallel context.
280 * @param[in] worker_setup Optional handler to setup a worker task before it is
281 *   started.
282 * @param[in] jobs The table of jobs.
283 * @param[in] job_count The count of jobs in the job table.
284 */
285void rtems_test_parallel(
286  rtems_test_parallel_context *ctx,
287  rtems_test_parallel_worker_setup worker_setup,
288  const rtems_test_parallel_job *jobs,
289  size_t job_count
290);
291
292/**
293 * @brief Performs a busy loop for the specified seconds and nanoseconds based
294 * on the CPU usage of the executing thread.
295 *
296 * This function continuously reads the CPU usage of the executing thread.
297 * This operation may lead to a scheduler instance lock contention in SMP
298 * configurations.
299 *
300 * @param[in] seconds The busy seconds.
301 * @param[in] nanoseconds The busy nanoseconds.
302 */
303void rtems_test_busy_cpu_usage(time_t seconds, long nanoseconds);
304
305/**
306 * @brief Performs a busy loop with the specified iteration count.
307 *
308 * This function is optimized to not perform memory accesses and should have a
309 * small jitter.
310 *
311 * @param[in] count The iteration count.
312 */
313void rtems_test_busy(uint_fast32_t count);
314
315/**
316 * @brief Returns a count value for rtems_test_busy() which yields roughly a
317 * duration of one clock tick.
318 */
319uint_fast32_t rtems_test_get_one_tick_busy_count(void);
320
321/** @} */
322
323#ifdef __cplusplus
324}
325#endif /* __cplusplus */
326
327#endif /* _RTEMS_TEST_H */
Note: See TracBrowser for help on using the repository browser.