Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:21

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  * Copyright (C) 2013, 2016 embedded brains GmbH & Co. KG
0005  *
0006  * Redistribution and use in source and binary forms, with or without
0007  * modification, are permitted provided that the following conditions
0008  * are met:
0009  * 1. Redistributions of source code must retain the above copyright
0010  *    notice, this list of conditions and the following disclaimer.
0011  * 2. Redistributions in binary form must reproduce the above copyright
0012  *    notice, this list of conditions and the following disclaimer in the
0013  *    documentation and/or other materials provided with the distribution.
0014  *
0015  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0016  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0017  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0018  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0019  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0020  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0021  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0023  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0024  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0025  * POSSIBILITY OF SUCH DAMAGE.
0026  */
0027 
0028 
0029 #ifdef HAVE_CONFIG_H
0030 #include "config.h"
0031 #endif
0032 
0033 #include <rtems/test-info.h>
0034 #include <rtems/score/assert.h>
0035 #include <rtems.h>
0036 
0037 static void stop_worker_timer(rtems_id timer_id, void *arg)
0038 {
0039   rtems_test_parallel_context *ctx = arg;
0040 
0041   _Atomic_Store_ulong(&ctx->stop, 1, ATOMIC_ORDER_RELAXED);
0042 }
0043 
0044 static void start_worker_stop_timer(
0045   rtems_test_parallel_context *ctx,
0046   rtems_interval duration
0047 )
0048 {
0049   rtems_status_code sc;
0050 
0051   _Atomic_Store_ulong(&ctx->stop, 0, ATOMIC_ORDER_RELEASE);
0052 
0053   sc = rtems_timer_fire_after(
0054     ctx->stop_worker_timer_id,
0055     duration,
0056     stop_worker_timer,
0057     ctx
0058   );
0059   _Assert(sc == RTEMS_SUCCESSFUL);
0060   (void) sc;
0061 }
0062 
0063 static void run_tests(
0064   rtems_test_parallel_context *ctx,
0065   const rtems_test_parallel_job *jobs,
0066   size_t job_count
0067 )
0068 {
0069   SMP_barrier_State bs = SMP_BARRIER_STATE_INITIALIZER;
0070   size_t i;
0071 
0072   _SMP_barrier_Wait(&ctx->barrier, &bs, ctx->worker_count);
0073 
0074   for (i = 0; i < job_count; ++i) {
0075     const rtems_test_parallel_job *job = &jobs[i];
0076     size_t n = rtems_scheduler_get_processor_maximum();
0077     size_t j = job->cascade ? 0 : rtems_scheduler_get_processor_maximum() - 1;
0078 
0079     while (j < n) {
0080       size_t active_worker = j + 1;
0081       size_t worker_index;
0082       rtems_interrupt_level level;
0083 
0084       /*
0085        * Determine worker index via the current processor index to get
0086        * consistent job runs with respect to the cache topology.
0087        */
0088       rtems_interrupt_local_disable(level);
0089       _SMP_barrier_Wait(&ctx->barrier, &bs, ctx->worker_count);
0090       worker_index = rtems_scheduler_get_processor();
0091       rtems_interrupt_local_enable(level);
0092 
0093       _Assert(worker_index < ctx->worker_count);
0094 
0095       if (rtems_test_parallel_is_master_worker(worker_index)) {
0096         rtems_interval duration = (*job->init)(ctx, job->arg, active_worker);
0097 
0098         if (duration > 0) {
0099           start_worker_stop_timer(ctx, duration);
0100         }
0101       }
0102 
0103       _SMP_barrier_Wait(&ctx->barrier, &bs, ctx->worker_count);
0104 
0105       if (worker_index <= j) {
0106         (*job->body)(ctx, job->arg, active_worker, worker_index);
0107       }
0108 
0109       _SMP_barrier_Wait(&ctx->barrier, &bs, ctx->worker_count);
0110 
0111       if (rtems_test_parallel_is_master_worker(worker_index)) {
0112         (*job->fini)(ctx, job->arg, active_worker);
0113       }
0114 
0115       _SMP_barrier_Wait(&ctx->barrier, &bs, ctx->worker_count);
0116 
0117       ++j;
0118     }
0119   }
0120 }
0121 
0122 static void worker_task(rtems_task_argument arg)
0123 {
0124   rtems_test_parallel_context *ctx = (rtems_test_parallel_context *) arg;
0125   rtems_status_code sc;
0126 
0127   (void) sc;
0128 
0129   run_tests(ctx, ctx->jobs, ctx->job_count);
0130 
0131   while (true) {
0132     /* Wait for delete by master worker */
0133   }
0134 }
0135 
0136 void rtems_test_parallel(
0137   rtems_test_parallel_context *ctx,
0138   rtems_test_parallel_worker_setup worker_setup,
0139   const rtems_test_parallel_job *jobs,
0140   size_t job_count
0141 )
0142 {
0143   rtems_status_code sc;
0144   size_t worker_index;
0145   rtems_task_priority worker_priority;
0146 
0147   _Atomic_Init_ulong(&ctx->stop, 0);
0148   _SMP_barrier_Control_initialize(&ctx->barrier);
0149   ctx->worker_count = rtems_scheduler_get_processor_maximum();
0150   ctx->worker_ids[0] = rtems_task_self();
0151   ctx->jobs = jobs;
0152   ctx->job_count = job_count;
0153 
0154   if (RTEMS_ARRAY_SIZE(ctx->worker_ids) < ctx->worker_count) {
0155     rtems_fatal_error_occurred(0xdeadbeef);
0156   }
0157 
0158   sc = rtems_task_set_priority(
0159     RTEMS_SELF,
0160     RTEMS_CURRENT_PRIORITY,
0161     &worker_priority
0162   );
0163   if (sc != RTEMS_SUCCESSFUL) {
0164     rtems_fatal_error_occurred(0xdeadbeef);
0165   }
0166 
0167   sc = rtems_timer_create(
0168     rtems_build_name('S', 'T', 'O', 'P'),
0169     &ctx->stop_worker_timer_id
0170   );
0171   if (sc != RTEMS_SUCCESSFUL) {
0172     rtems_fatal_error_occurred(0xdeadbeef);
0173   }
0174 
0175   for (worker_index = 1; worker_index < ctx->worker_count; ++worker_index) {
0176     rtems_id worker_id;
0177 
0178     sc = rtems_task_create(
0179       rtems_build_name('W', 'O', 'R', 'K'),
0180       worker_priority,
0181       RTEMS_MINIMUM_STACK_SIZE,
0182       RTEMS_DEFAULT_MODES,
0183       RTEMS_DEFAULT_ATTRIBUTES,
0184       &worker_id
0185     );
0186     if (sc != RTEMS_SUCCESSFUL) {
0187       rtems_fatal_error_occurred(0xdeadbeef);
0188     }
0189 
0190     ctx->worker_ids[worker_index] = worker_id;
0191 
0192     if (worker_setup != NULL) {
0193       (*worker_setup)(ctx, worker_index, worker_id);
0194     }
0195 
0196     sc = rtems_task_start(worker_id, worker_task, (rtems_task_argument) ctx);
0197     _Assert(sc == RTEMS_SUCCESSFUL);
0198   }
0199 
0200   run_tests(ctx, jobs, job_count);
0201 
0202   for (worker_index = 1; worker_index < ctx->worker_count; ++worker_index) {
0203     sc = rtems_task_delete(ctx->worker_ids[worker_index]);
0204     _Assert(sc == RTEMS_SUCCESSFUL);
0205   }
0206 
0207   sc = rtems_timer_delete(ctx->stop_worker_timer_id);
0208   _Assert(sc == RTEMS_SUCCESSFUL);
0209 }