diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2014-03-10 10:03:55 +0100 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2014-03-14 08:46:49 +0100 |
commit | 29c9eb601e78d7d7624990d7fe589a506395e096 (patch) | |
tree | 76cb0095aeca6aebe5657e3cdd708969676a5f65 | |
parent | sapi: Add profiling application level support (diff) | |
download | rtems-29c9eb601e78d7d7624990d7fe589a506395e096.tar.bz2 |
sapi: Add per-CPU profiling application level data
-rw-r--r-- | cpukit/sapi/include/rtems/profiling.h | 101 | ||||
-rw-r--r-- | cpukit/sapi/src/profilingreportxml.c | 89 | ||||
-rw-r--r-- | testsuites/sptests/spprofiling01/spprofiling01.scn | 10 |
3 files changed, 199 insertions, 1 deletions
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; /** @@ -74,6 +80,96 @@ typedef struct { } 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. */ typedef union { @@ -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 <inttypes.h> + 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, + "<PerCPUProfilingReport processorIndex=\"%" PRIu32 "\">\n", + per_cpu->processor_index + ); + update_retval(ctx, rv); + + indent(ctx, 2); + rv = (*printf_func)( + printf_arg, + "<MaxThreadDispatchDisabledTime unit=\"ns\">%" PRIu32 + "</MaxThreadDispatchDisabledTime>\n", + per_cpu->max_thread_dispatch_disabled_time + ); + update_retval(ctx, rv); + + indent(ctx, 2); + rv = (*printf_func)( + printf_arg, + "<ThreadDispatchDisabledCount>%" PRIu64 "</ThreadDispatchDisabledCount>\n", + per_cpu->thread_dispatch_disabled_count + ); + update_retval(ctx, rv); + + indent(ctx, 2); + rv = (*printf_func)( + printf_arg, + "<TotalThreadDispatchDisabledTime unit=\"ns\">%" PRIu64 + "</TotalThreadDispatchDisabledTime>\n", + per_cpu->total_thread_dispatch_disabled_time + ); + update_retval(ctx, rv); + + indent(ctx, 2); + rv = (*printf_func)( + printf_arg, + "<MaxInterruptTime unit=\"ns\">%" PRIu32 + "</MaxInterruptTime>\n", + per_cpu->max_interrupt_time + ); + update_retval(ctx, rv); + + indent(ctx, 2); + rv = (*printf_func)( + printf_arg, + "<MaxInterruptDelay unit=\"ns\">%" PRIu32 "</MaxInterruptDelay>\n", + per_cpu->max_interrupt_delay + ); + update_retval(ctx, rv); + + indent(ctx, 2); + rv = (*printf_func)( + printf_arg, + "<InterruptCount>%" PRIu64 "</InterruptCount>\n", + per_cpu->interrupt_count + ); + update_retval(ctx, rv); + + indent(ctx, 2); + rv = (*printf_func)( + printf_arg, + "<TotalInterruptTime unit=\"ns\">%" PRIu64 "</TotalInterruptTime>\n", + per_cpu->total_interrupt_time + ); + update_retval(ctx, rv); + + indent(ctx, 1); + rv = (*printf_func)( + printf_arg, + "</PerCPUProfilingReport>\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 *** <ProfilingReport name="X"> + <PerCPUProfilingReport processorIndex="0"> + <MaxInterruptDelay unit="ns">0</MaxInterruptDelay> + <MaxThreadDispatchDisabledTime unit="ns">0</MaxThreadDispatchDisabledTime> + <ThreadDispatchDisabledCount>0</ThreadDispatchDisabledCount> + <TotalThreadDispatchDisabledTime unit="ns">0</TotalThreadDispatchDisabledTime> + <InterruptCount>0</InterruptCount> + <TotalInterruptTime unit="ns">0</TotalInterruptTime> + </PerCPUProfilingReport> </ProfilingReport> -characters produced by rtems_profiling_report_xml(): 50 +characters produced by rtems_profiling_report_xml(): 516 *** END OF TEST SPPROFILING 1 *** |