From 29c9eb601e78d7d7624990d7fe589a506395e096 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 10 Mar 2014 10:03:55 +0100 Subject: sapi: Add per-CPU profiling application level data --- cpukit/sapi/include/rtems/profiling.h | 101 +++++++++++++++++++++ cpukit/sapi/src/profilingreportxml.c | 89 ++++++++++++++++++ testsuites/sptests/spprofiling01/spprofiling01.scn | 10 +- 3 files changed, 199 insertions(+), 1 deletion(-) diff --git a/cpukit/sapi/include/rtems/profiling.h b/cpukit/sapi/include/rtems/profiling.h index b2bdf10a98..3bc59217b9 100644 --- a/cpukit/sapi/include/rtems/profiling.h +++ b/cpukit/sapi/include/rtems/profiling.h @@ -61,6 +61,12 @@ extern "C" { * @brief Type of profiling data. */ typedef enum { + /** + * @brief Type of per-CPU profiling data. + * + * @see rtems_profiling_per_cpu. + */ + RTEMS_PROFILING_PER_CPU } rtems_profiling_type; /** @@ -73,6 +79,96 @@ typedef struct { rtems_profiling_type type; } rtems_profiling_header; +/** + * @brief Per-CPU profiling data. + * + * Theoretically all values in this structure can overflow, but the integer + * types are chosen so that they cannot overflow in practice. On systems with + * a 1GHz CPU counter, the 64-bit integers can overflow in about 58 years. + * Since the system should not spend most of the time in critical sections the + * actual system run-time is much longer. Several other counters in the system + * will overflow before we get a problem in the profiling area. + */ +typedef struct { + /** + * @brief The profiling data header. + */ + rtems_profiling_header header; + + /** + * @brief The processor index of this profiling data. + */ + uint32_t processor_index; + + /** + * @brief The maximum time of disabled thread dispatching in nanoseconds. + */ + uint32_t max_thread_dispatch_disabled_time; + + /** + * @brief Count of times when the thread dispatch disable level changes from + * zero to one in thread context. + * + * This value may overflow. + */ + uint64_t thread_dispatch_disabled_count; + + /** + * @brief Total time of disabled thread dispatching in nanoseconds. + * + * The average time of disabled thread dispatching is the total time of + * disabled thread dispatching divided by the thread dispatch disabled + * count. + * + * This value may overflow. + */ + uint64_t total_thread_dispatch_disabled_time; + + /** + * @brief The maximum interrupt delay in nanoseconds if supported by the + * hardware. + * + * The interrupt delay is the time interval from the recognition of an + * interrupt signal by the hardware up to the execution start of the + * corresponding high-level handler. The interrupt delay is the main + * contributor to the interrupt latency. To measure this time hardware + * support is required. A time stamp unit must capture the interrupt signal + * recognition time. If no hardware support is available, then this field + * will have a constant value of zero. + */ + uint32_t max_interrupt_delay; + + /** + * @brief The maximum time spent to process a single sequence of nested + * interrupts in nanoseconds. + * + * This is the time interval between the change of the interrupt nest level + * from zero to one and the change back from one to zero. It is the measured + * worst-case execution time of interrupt service routines. Please note that + * in case of nested interrupts this time includes the combined execution + * time and not the maximum time of an individual interrupt service routine. + */ + uint32_t max_interrupt_time; + + /** + * @brief Count of times when the interrupt nest level changes from zero to + * one. + * + * This value may overflow. + */ + uint64_t interrupt_count; + + /** + * @brief Total time of interrupt processing in nanoseconds. + * + * The average time of interrupt processing is the total time of interrupt + * processing divided by the interrupt count. + * + * This value may overflow. + */ + uint64_t total_interrupt_time; +} rtems_profiling_per_cpu; + /** * @brief Collection of profiling data. */ @@ -81,6 +177,11 @@ typedef union { * @brief Header to specify the actual profiling data. */ rtems_profiling_header header; + + /** + * @brief Per-CPU profiling data if indicated by the header. + */ + rtems_profiling_per_cpu per_cpu; } rtems_profiling_data; /** diff --git a/cpukit/sapi/src/profilingreportxml.c b/cpukit/sapi/src/profilingreportxml.c index d3fe7f7652..409fe3d7eb 100644 --- a/cpukit/sapi/src/profilingreportxml.c +++ b/cpukit/sapi/src/profilingreportxml.c @@ -20,6 +20,8 @@ #ifdef RTEMS_PROFILING +#include + typedef struct { rtems_profiling_printf printf_func; void *printf_arg; @@ -47,9 +49,96 @@ static void indent(context *ctx, uint32_t indentation_level) } } +static void report_per_cpu(context *ctx, const rtems_profiling_per_cpu *per_cpu) +{ + rtems_profiling_printf printf_func = ctx->printf_func; + void *printf_arg = ctx->printf_arg; + int rv; + + indent(ctx, 1); + rv = (*printf_func)( + printf_arg, + "\n", + per_cpu->processor_index + ); + update_retval(ctx, rv); + + indent(ctx, 2); + rv = (*printf_func)( + printf_arg, + "%" PRIu32 + "\n", + per_cpu->max_thread_dispatch_disabled_time + ); + update_retval(ctx, rv); + + indent(ctx, 2); + rv = (*printf_func)( + printf_arg, + "%" PRIu64 "\n", + per_cpu->thread_dispatch_disabled_count + ); + update_retval(ctx, rv); + + indent(ctx, 2); + rv = (*printf_func)( + printf_arg, + "%" PRIu64 + "\n", + per_cpu->total_thread_dispatch_disabled_time + ); + update_retval(ctx, rv); + + indent(ctx, 2); + rv = (*printf_func)( + printf_arg, + "%" PRIu32 + "\n", + per_cpu->max_interrupt_time + ); + update_retval(ctx, rv); + + indent(ctx, 2); + rv = (*printf_func)( + printf_arg, + "%" PRIu32 "\n", + per_cpu->max_interrupt_delay + ); + update_retval(ctx, rv); + + indent(ctx, 2); + rv = (*printf_func)( + printf_arg, + "%" PRIu64 "\n", + per_cpu->interrupt_count + ); + update_retval(ctx, rv); + + indent(ctx, 2); + rv = (*printf_func)( + printf_arg, + "%" PRIu64 "\n", + per_cpu->total_interrupt_time + ); + update_retval(ctx, rv); + + indent(ctx, 1); + rv = (*printf_func)( + printf_arg, + "\n" + ); + update_retval(ctx, rv); +} + static void report(void *arg, const rtems_profiling_data *data) { context *ctx = arg; + + switch (data->header.type) { + case RTEMS_PROFILING_PER_CPU: + report_per_cpu(ctx, &data->per_cpu); + break; + } } #endif /* RTEMS_PROFILING */ diff --git a/testsuites/sptests/spprofiling01/spprofiling01.scn b/testsuites/sptests/spprofiling01/spprofiling01.scn index 2c289db941..a00baa1e86 100644 --- a/testsuites/sptests/spprofiling01/spprofiling01.scn +++ b/testsuites/sptests/spprofiling01/spprofiling01.scn @@ -1,5 +1,13 @@ *** TEST SPPROFILING 1 *** + + 0 + 0 + 0 + 0 + 0 + 0 + -characters produced by rtems_profiling_report_xml(): 50 +characters produced by rtems_profiling_report_xml(): 516 *** END OF TEST SPPROFILING 1 *** -- cgit v1.2.3