source: rtems-libbsd/testsuite/smp01/test_main.c @ 5bcdc25

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 5bcdc25 was 5bcdc25, checked in by Sebastian Huber <sebastian.huber@…>, on 03/16/15 at 15:54:56

smp01: New test

  • Property mode set to 100644
File size: 6.4 KB
Line 
1/*
2 * Copyright (c) 2015 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 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <machine/rtems-bsd-kernel-space.h>
33
34#include <rtems/bsd/sys/param.h>
35#include <rtems/bsd/sys/types.h>
36#include <sys/systm.h>
37#include <rtems/bsd/sys/lock.h>
38#include <sys/mutex.h>
39#include <sys/condvar.h>
40
41#include <assert.h>
42#include <inttypes.h>
43#include <stdio.h>
44#include <stdlib.h>
45
46#include <rtems.h>
47#include <rtems/test.h>
48
49#define TEST_NAME "LIBBSD SMP 1"
50
51#define CPU_COUNT 32
52
53#define OBJ_COUNT (CPU_COUNT / 2)
54
55typedef struct {
56        uint32_t mtx_lock[CPU_COUNT];
57        uint32_t mtx_try_success[CPU_COUNT];
58        uint32_t mtx_try_failed[CPU_COUNT];
59        uint32_t cv_signal[CPU_COUNT];
60        uint32_t cv_broadcast[CPU_COUNT];
61        uint32_t cv_timedwait_success[CPU_COUNT];
62        uint32_t cv_timedwait_timeout[CPU_COUNT];
63} test_stats;
64
65typedef struct {
66        rtems_test_parallel_context base;
67        struct mtx mtx[OBJ_COUNT];
68        struct cv cv[OBJ_COUNT];
69        volatile uint32_t value[OBJ_COUNT];
70        test_stats stats;
71} test_context;
72
73static test_context test_instance;
74
75static rtems_interval
76test_duration(void)
77{
78
79        return (10 * rtems_clock_get_ticks_per_second());
80}
81
82static uint32_t
83simple_random(uint32_t v)
84{
85        v *= 1664525;
86        v += 1013904223;
87
88        return (v);
89}
90
91static rtems_interval
92test_init(rtems_test_parallel_context *base, void *arg, size_t active_workers)
93{
94
95        return (test_duration());
96}
97
98static void
99test_fini(rtems_test_parallel_context *base, void *arg, size_t active_workers)
100{
101
102        /* Do nothing */
103}
104
105static void
106busy(void)
107{
108        int i;
109
110        for (i = 0; i < 1000; ++i) {
111                __asm__ volatile ("");
112        }
113}
114
115static uint32_t
116get_obj_count(void)
117{
118        return ((rtems_get_processor_count() + 1) / 2);
119}
120
121static void
122test_mtx_body(rtems_test_parallel_context *base, void *arg,
123    size_t active_workers, size_t worker_index)
124{
125        test_context *ctx = (test_context *)base;
126        uint32_t obj_count = get_obj_count();
127        uint32_t r = worker_index;
128
129        while (!rtems_test_parallel_stop_job(&ctx->base)) {
130                uint32_t op = (r >> 17) % 2;
131                uint32_t i = (r >> 7) % obj_count;
132                struct mtx *mtx = &ctx->mtx[i];
133                volatile uint32_t *value = &ctx->value[i];
134                bool locked;
135
136                switch (op) {
137                case 0:
138                        locked = mtx_trylock(mtx) == 1;
139                        if (locked) {
140                                ++ctx->stats.mtx_try_success[i];
141                        } else {
142                                ++ctx->stats.mtx_try_failed[i];
143                        }
144
145                        break;
146                case 1:
147                        mtx_lock(mtx);
148                        ++ctx->stats.mtx_lock[i];
149                        locked = true;
150                        break;
151                }
152
153                if (locked) {
154                        assert(*value == i);
155                        *value = 0xdeadbeef;
156                        busy();
157                        *value = i;
158                        mtx_unlock(mtx);
159                }
160
161                r = simple_random(r);
162        }
163}
164
165static void
166test_cv_body(rtems_test_parallel_context *base, void *arg,
167    size_t active_workers, size_t worker_index)
168{
169        test_context *ctx = (test_context *)base;
170        uint32_t obj_count = get_obj_count();
171        uint32_t r = worker_index;
172
173        while (!rtems_test_parallel_stop_job(&ctx->base)) {
174                uint32_t op = (r >> 17) % 3;
175                uint32_t i = (r >> 7) % obj_count;
176                struct mtx *mtx = &ctx->mtx[i];
177                struct cv *cv = &ctx->cv[i];
178
179                mtx_lock(mtx);
180
181                switch (op) {
182                case 0:
183                        cv_signal(cv);
184                        ++ctx->stats.cv_signal[i];
185                        break;
186                case 1:
187                        cv_broadcast(cv);
188                        ++ctx->stats.cv_broadcast[i];
189                        break;
190                case 2:
191                        if (cv_timedwait(cv, mtx, 1) == 0) {
192                                ++ctx->stats.cv_timedwait_success[i];
193                        } else {
194                                ++ctx->stats.cv_timedwait_timeout[i];
195                        }
196
197                        break;
198                }
199
200                mtx_unlock(mtx);
201
202                r = simple_random(r);
203        }
204}
205
206static const rtems_test_parallel_job test_jobs[] = {
207        {
208                .init = test_init,
209                .body = test_cv_body,
210                .fini = test_fini
211        }, {
212                .init = test_init,
213                .body = test_mtx_body,
214                .fini = test_fini
215        }
216};
217
218static void setup_worker(
219  rtems_test_parallel_context *base,
220  size_t worker_index,
221  rtems_id worker_id
222)
223{
224        rtems_task_priority prio;
225        rtems_status_code sc;
226
227        prio = ((worker_index - 1) % 2) + 253;
228        sc = rtems_task_set_priority(worker_id, prio, &prio);
229        assert(sc == RTEMS_SUCCESSFUL);
230}
231
232static void
233print_summary(const test_context *ctx)
234{
235        size_t i;
236
237        for (i = 0; i < get_obj_count(); ++i) {
238                printf("mtx lock[%zu]: %" PRIu32 "\n", i,
239                    ctx->stats.mtx_lock[i]);
240                printf("mtx try success[%zu]: %" PRIu32 "\n", i,
241                    ctx->stats.mtx_try_success[i]);
242                printf("mtx try failed[%zu]: %" PRIu32 "\n", i,
243                    ctx->stats.mtx_try_failed[i]);
244        }
245
246        for (i = 0; i < get_obj_count(); ++i) {
247                printf("cv signal[%zu]: %" PRIu32 "\n", i,
248                    ctx->stats.cv_signal[i]);
249                printf("cv broadcast[%zu]: %" PRIu32 "\n", i,
250                    ctx->stats.cv_broadcast[i]);
251                printf("cv wait success[%zu]: %" PRIu32 "\n", i,
252                    ctx->stats.cv_timedwait_success[i]);
253                printf("cv wait timeout[%zu]: %" PRIu32 "\n", i,
254                    ctx->stats.cv_timedwait_timeout[i]);
255        }
256}
257
258static void
259test_main(void)
260{
261        test_context *ctx = &test_instance;
262        size_t i;
263        rtems_id id;
264        rtems_status_code sc;
265
266        for (i = 0; i < OBJ_COUNT; ++i) {
267                ctx->value[i] = i;
268                mtx_init(&ctx->mtx[i], "test", NULL, MTX_DEF);
269                cv_init(&ctx->cv[i], "test");
270        }
271
272        rtems_test_parallel(&ctx->base, setup_worker, &test_jobs[0],
273            RTEMS_ARRAY_SIZE(test_jobs));
274
275        print_summary(ctx);
276
277        for (i = 0; i < OBJ_COUNT; ++i) {
278                mtx_destroy(&ctx->mtx[i]);
279                cv_destroy(&ctx->cv[i]);
280        }
281
282        exit(0);
283}
284
285#define CONFIGURE_SMP_APPLICATION
286
287#define CONFIGURE_SMP_MAXIMUM_PROCESSORS CPU_COUNT
288
289#include <rtems/bsd/test/default-init.h>
Note: See TracBrowser for help on using the repository browser.