Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  * Copyright (C) 2014, 2017 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 #ifdef HAVE_CONFIG_H
0029 #include "config.h"
0030 #endif
0031 
0032 #include <rtems/counter.h>
0033 #include <rtems.h>
0034 
0035 #include <stdio.h>
0036 #include <stdlib.h>
0037 #include <inttypes.h>
0038 #include <alloca.h>
0039 
0040 #include "tmacros.h"
0041 
0042 #define FUNCTION_LEVELS 16
0043 
0044 #define SAMPLES 123
0045 
0046 #define CPU_COUNT 32
0047 
0048 const char rtems_test_name[] = "TMCONTEXT 1";
0049 
0050 static rtems_counter_ticks t[SAMPLES];
0051 
0052 static size_t cache_line_size;
0053 
0054 static size_t data_size;
0055 
0056 static volatile int *main_data;
0057 
0058 static Context_Control ctx;
0059 
0060 static int dirty_data_cache(volatile int *data, size_t n, size_t clsz, int j)
0061 {
0062   size_t m = n / sizeof(*data);
0063   size_t k = clsz / sizeof(*data);
0064   size_t i;
0065 
0066   for (i = 0; i < m; i += k) {
0067     data[i] = i + j;
0068   }
0069 
0070   return i + j;
0071 }
0072 
0073 static __attribute__((__noipa__)) void call_at_level(
0074   int start,
0075   int fl,
0076   int s
0077 )
0078 {
0079 #if defined(__sparc__)
0080   if (fl == start) {
0081     /* Flush register windows */
0082     __asm__ volatile ("ta 3" : : : "memory");
0083   }
0084 #endif
0085 
0086   if (fl > 0) {
0087     call_at_level(
0088       start,
0089       fl - 1,
0090       s
0091     );
0092     __asm__ volatile ("" : : : "memory");
0093   } else {
0094     char *volatile space;
0095     rtems_counter_ticks a;
0096     rtems_counter_ticks b;
0097 
0098     a = rtems_counter_read();
0099 
0100     /* Ensure that we use an untouched stack area */
0101     space = alloca(1024);
0102     (void) space;
0103 
0104     _Context_Switch(&ctx, &ctx);
0105 
0106     b = rtems_counter_read();
0107     t[s] = rtems_counter_difference(b, a);
0108   }
0109 }
0110 
0111 static void load_task(rtems_task_argument arg)
0112 {
0113   volatile int *load_data = (volatile int *) arg;
0114   size_t n = data_size;
0115   size_t clsz = cache_line_size;
0116   int j = (int) rtems_scheduler_get_processor();
0117 
0118   while (true) {
0119     j = dirty_data_cache(load_data, n, clsz, j);
0120   }
0121 }
0122 
0123 static int cmp(const void *ap, const void *bp)
0124 {
0125   const rtems_counter_ticks *a = ap;
0126   const rtems_counter_ticks *b = bp;
0127 
0128   return *a - *b;
0129 }
0130 
0131 static void sort_t(void)
0132 {
0133   qsort(&t[0], SAMPLES, sizeof(t[0]), cmp);
0134 }
0135 
0136 static __attribute__((__noipa__)) void test_by_function_level(int fl, bool dirty)
0137 {
0138   RTEMS_INTERRUPT_LOCK_DECLARE(, lock)
0139   rtems_interrupt_lock_context lock_context;
0140   int s;
0141   uint64_t min;
0142   uint64_t q1;
0143   uint64_t q2;
0144   uint64_t q3;
0145   uint64_t max;
0146 
0147   rtems_interrupt_lock_initialize(&lock, "test");
0148   rtems_interrupt_lock_acquire(&lock, &lock_context);
0149 
0150   for (s = 0; s < SAMPLES; ++s) {
0151     if (dirty) {
0152       dirty_data_cache(main_data, data_size, cache_line_size, fl);
0153       rtems_cache_invalidate_entire_instruction();
0154     }
0155 
0156     call_at_level(fl, fl, s);
0157   }
0158 
0159   rtems_interrupt_lock_release(&lock, &lock_context);
0160   rtems_interrupt_lock_destroy(&lock);
0161 
0162   sort_t();
0163 
0164   min = t[0];
0165   q1 = t[(1 * SAMPLES) / 4];
0166   q2 = t[SAMPLES / 2];
0167   q3 = t[(3 * SAMPLES) / 4];
0168   max = t[SAMPLES - 1];
0169 
0170   printf(
0171     "%s\n      [%" PRIu64 ", %" PRIu64 ", %" PRIu64 ", %" PRIu64 ", %" PRIu64 "]",
0172     fl == 0 ? "" : ",",
0173     rtems_counter_ticks_to_nanoseconds(min),
0174     rtems_counter_ticks_to_nanoseconds(q1),
0175     rtems_counter_ticks_to_nanoseconds(q2),
0176     rtems_counter_ticks_to_nanoseconds(q3),
0177     rtems_counter_ticks_to_nanoseconds(max)
0178   );
0179 }
0180 
0181 static void test(bool first, bool dirty, uint32_t load)
0182 {
0183   int fl;
0184 
0185   printf(
0186     "\n  %s{\n"
0187     "    \"environment\": \"",
0188     first ? "" : "}, "
0189   );
0190 
0191   if (dirty) {
0192     if (load > 0) {
0193       printf("Load/%" PRIu32 "", load);
0194     } else {
0195       printf("DirtyCache");
0196     }
0197   } else {
0198     printf("HotCache");
0199   }
0200 
0201   printf(
0202     "\",\n"
0203     "    \"stats-by-function-nest-level\": ["
0204   );
0205 
0206   for (fl = 0; fl < FUNCTION_LEVELS; ++fl) {
0207     test_by_function_level(fl, dirty);
0208   }
0209 
0210   printf(
0211     "\n    ]"
0212   );
0213 }
0214 
0215 static void Init(rtems_task_argument arg)
0216 {
0217   uint32_t load = 0;
0218 
0219   TEST_BEGIN();
0220 
0221   printf("*** BEGIN OF JSON DATA ***\n[");
0222 
0223   cache_line_size = rtems_cache_get_data_line_size();
0224   if (cache_line_size == 0) {
0225     cache_line_size = 32;
0226   }
0227 
0228   data_size = rtems_cache_get_data_cache_size(0);
0229   if (data_size == 0) {
0230     data_size = cache_line_size;
0231   }
0232 
0233   main_data = malloc(data_size);
0234   rtems_test_assert(main_data != NULL);
0235 
0236   test(true, false, load);
0237   test(false, true, load);
0238 
0239   for (load = 1; load < rtems_scheduler_get_processor_maximum(); ++load) {
0240     rtems_status_code sc;
0241     rtems_id id;
0242     volatile int *load_data = NULL;
0243 
0244     load_data = malloc(data_size);
0245     if (load_data == NULL) {
0246       load_data = main_data;
0247     }
0248 
0249     sc = rtems_task_create(
0250       rtems_build_name('L', 'O', 'A', 'D'),
0251       1,
0252       RTEMS_MINIMUM_STACK_SIZE,
0253       RTEMS_DEFAULT_MODES,
0254       RTEMS_DEFAULT_ATTRIBUTES,
0255       &id
0256     );
0257     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0258 
0259     sc = rtems_task_start(id, load_task, (rtems_task_argument) load_data);
0260     rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0261 
0262     test(false, true, load);
0263   }
0264 
0265   printf("\n  }\n]\n*** END OF JSON DATA ***\n");
0266 
0267   TEST_END();
0268   rtems_test_exit(0);
0269 }
0270 
0271 /*
0272  * Do not use a clock driver, since this will disturb the test in the "normal"
0273  * environment.
0274  */
0275 #define CONFIGURE_APPLICATION_DOES_NOT_NEED_CLOCK_DRIVER
0276 
0277 #define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
0278 
0279 #define CONFIGURE_MAXIMUM_TASKS (1 + CPU_COUNT)
0280 
0281 #define CONFIGURE_INIT_TASK_STACK_SIZE (32 * 1024)
0282 
0283 #define CONFIGURE_MAXIMUM_PROCESSORS CPU_COUNT
0284 
0285 #define CONFIGURE_RTEMS_INIT_TASKS_TABLE
0286 
0287 #define CONFIGURE_INIT
0288 
0289 #include <rtems/confdefs.h>