Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /*
0004  * Copyright (C) 2014, 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 #ifdef HAVE_CONFIG_H
0029 #include "config.h"
0030 #endif
0031 
0032 #include <stdio.h>
0033 #include <inttypes.h>
0034 
0035 #include <rtems.h>
0036 #include <rtems/counter.h>
0037 
0038 #include "tmacros.h"
0039 
0040 const char rtems_test_name[] = "SPCPUCOUNTER 1";
0041 
0042 #define NS_PER_TICK 1000000
0043 
0044 #define N 10
0045 
0046 typedef struct {
0047   rtems_counter_ticks delay_ns_t[N][2];
0048   rtems_counter_ticks delay_ticks_t[N][2];
0049   rtems_counter_ticks overhead_t[N][5];
0050   rtems_counter_ticks overhead_delta;
0051 } test_context;
0052 
0053 static test_context test_instance;
0054 
0055 static rtems_interval sync_with_clock_tick(void)
0056 {
0057   rtems_interval start = rtems_clock_get_ticks_since_boot();
0058   rtems_interval current;
0059 
0060   do {
0061     current = rtems_clock_get_ticks_since_boot();
0062   } while (current == start);
0063 
0064   return current;
0065 }
0066 
0067 static void test_converter(void)
0068 {
0069   CPU_Counter_ticks frequency;
0070   CPU_Counter_ticks frequency2;
0071   uint64_t ns;
0072   int64_t sbt;
0073 
0074   frequency = rtems_counter_nanoseconds_to_ticks(1000000000);
0075   ns = rtems_counter_ticks_to_nanoseconds(frequency);
0076 
0077   printf("CPU counter frequency: %" PRIu32 "Hz\n", frequency);
0078   printf("nanoseconds for frequency count ticks: %" PRIu64 "\n", ns);
0079 
0080   rtems_test_assert(ns == 1000000000);
0081 
0082   sbt = rtems_counter_ticks_to_sbintime(frequency);
0083   rtems_test_assert(sbt == (INT64_C(1) << 32));
0084 
0085   frequency2 = rtems_counter_sbintime_to_ticks(sbt);
0086   rtems_test_assert(frequency == frequency2);
0087 }
0088 
0089 static void test_delay_nanoseconds(test_context *ctx)
0090 {
0091   int i;
0092 
0093   for (i = 0; i < N; ++i) {
0094     rtems_counter_ticks t0;
0095     rtems_counter_ticks t1;
0096     rtems_interval tick;
0097 
0098     tick = sync_with_clock_tick();
0099 
0100     t0 = rtems_counter_read();
0101     rtems_counter_delay_nanoseconds(NS_PER_TICK);
0102     t1 = rtems_counter_read();
0103 
0104     ctx->delay_ns_t[i][0] = t0;
0105     ctx->delay_ns_t[i][1] = t1;
0106 
0107     rtems_test_assert(tick < rtems_clock_get_ticks_since_boot());
0108   }
0109 }
0110 
0111 static void test_delay_ticks(test_context *ctx)
0112 {
0113   rtems_counter_ticks ticks = rtems_counter_nanoseconds_to_ticks(NS_PER_TICK);
0114   int i;
0115 
0116   for (i = 0; i < N; ++i) {
0117     rtems_counter_ticks t0;
0118     rtems_counter_ticks t1;
0119     rtems_interval tick;
0120 
0121     tick = sync_with_clock_tick();
0122 
0123     t0 = rtems_counter_read();
0124     rtems_counter_delay_ticks(ticks);
0125     t1 = rtems_counter_read();
0126 
0127     ctx->delay_ticks_t[i][0] = t0;
0128     ctx->delay_ticks_t[i][1] = t1;
0129 
0130     rtems_test_assert(tick < rtems_clock_get_ticks_since_boot());
0131   }
0132 }
0133 
0134 static void test_overheads(test_context *ctx)
0135 {
0136   int i;
0137 
0138   for (i = 0; i < N; ++i) {
0139     rtems_counter_ticks t0;
0140     rtems_counter_ticks t1;
0141     rtems_counter_ticks t2;
0142     rtems_counter_ticks t3;
0143     rtems_counter_ticks t4;
0144     rtems_counter_ticks d;
0145 
0146     t0 = rtems_counter_read();
0147     t1 = rtems_counter_read();
0148     d = rtems_counter_difference(t1, t0);
0149     t2 = rtems_counter_read();
0150     rtems_counter_delay_nanoseconds(0);
0151     t3 = rtems_counter_read();
0152     rtems_counter_delay_ticks(0);
0153     t4 = rtems_counter_read();
0154 
0155     ctx->overhead_t[i][0] = t0;
0156     ctx->overhead_t[i][1] = t1;
0157     ctx->overhead_t[i][2] = t2;
0158     ctx->overhead_t[i][3] = t3;
0159     ctx->overhead_t[i][4] = t4;
0160     ctx->overhead_delta = d;
0161   }
0162 }
0163 
0164 static void report_overhead(
0165   const char *name,
0166   rtems_counter_ticks t1,
0167   rtems_counter_ticks t0
0168 )
0169 {
0170   rtems_counter_ticks d;
0171   uint64_t ns;
0172 
0173   d = rtems_counter_difference(t1, t0);
0174   ns = rtems_counter_ticks_to_nanoseconds(d);
0175 
0176   printf(
0177     "overhead %s: %" PRIu64 " ticks, %" PRIu64 "ns\n",
0178     name,
0179     (uint64_t) d,
0180     ns
0181   );
0182 }
0183 
0184 static uint64_t large_delta_to_ns(rtems_counter_ticks d)
0185 {
0186   uint64_t ns;
0187 
0188   ns = rtems_counter_ticks_to_nanoseconds(d);
0189 
0190   /* Special case for CPU counters using the clock driver counter */
0191   if (ns < rtems_configuration_get_nanoseconds_per_tick()) {
0192     printf(
0193       "warning: the RTEMS counter seems to be unable to\n"
0194       "  measure intervals greater than the clock tick interval\n"
0195     );
0196 
0197     ns += rtems_configuration_get_nanoseconds_per_tick();
0198   }
0199 
0200   return ns;
0201 }
0202 
0203 static void test_report(test_context *ctx)
0204 {
0205   double ns_per_tick = NS_PER_TICK;
0206   rtems_counter_ticks d;
0207   uint64_t ns;
0208   size_t i;
0209 
0210   printf("test delay nanoseconds (%i times)\n", N);
0211 
0212   for (i = 0; i < N; ++i) {
0213     d = rtems_counter_difference(ctx->delay_ns_t[i][1], ctx->delay_ns_t[i][0]);
0214     ns = large_delta_to_ns(d);
0215 
0216     printf(
0217       "ns busy wait duration: %" PRIu64 "ns\n"
0218       "ns busy wait relative to clock tick: %f\n",
0219       ns,
0220       (ns - ns_per_tick) / ns_per_tick
0221     );
0222   }
0223 
0224   printf("test delay ticks (%i times)\n", N);
0225 
0226   for (i = 0; i < N; ++i) {
0227     d = rtems_counter_difference(
0228       ctx->delay_ticks_t[i][1],
0229       ctx->delay_ticks_t[i][0]
0230     );
0231     ns = large_delta_to_ns(d);
0232 
0233     printf(
0234       "ticks busy wait duration: %" PRIu64 "ns\n"
0235       "ticks busy wait relative to clock tick: %f\n",
0236       ns,
0237       (ns - ns_per_tick) / ns_per_tick
0238     );
0239   }
0240 
0241   printf("test overheads (%i times)\n", N);
0242 
0243   for (i = 0; i < N; ++i) {
0244     report_overhead("read", ctx->overhead_t[i][1], ctx->overhead_t[i][0]);
0245     report_overhead("difference", ctx->overhead_t[i][2], ctx->overhead_t[i][1]);
0246     report_overhead("delay ns", ctx->overhead_t[i][3], ctx->overhead_t[i][2]);
0247     report_overhead("delay ticks", ctx->overhead_t[i][4], ctx->overhead_t[i][3]);
0248   }
0249 }
0250 
0251 static void Init(rtems_task_argument arg)
0252 {
0253   test_context *ctx = &test_instance;
0254 
0255   rtems_print_printer_fprintf_putc(&rtems_test_printer);
0256   TEST_BEGIN();
0257 
0258   test_delay_nanoseconds(ctx);
0259   test_delay_ticks(ctx);
0260   test_overheads(ctx);
0261   test_converter();
0262   test_report(ctx);
0263 
0264   TEST_END();
0265 
0266   rtems_test_exit(0);
0267 }
0268 
0269 #define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
0270 #define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
0271 
0272 #define CONFIGURE_MICROSECONDS_PER_TICK (NS_PER_TICK / 1000)
0273 
0274 #define CONFIGURE_MAXIMUM_TASKS 1
0275 
0276 #define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_FLOATING_POINT
0277 
0278 #define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
0279 
0280 #define CONFIGURE_RTEMS_INIT_TASKS_TABLE
0281 
0282 #define CONFIGURE_INIT
0283 
0284 #include <rtems/confdefs.h>