summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2014-03-10 10:03:55 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2014-03-14 08:46:49 +0100
commit29c9eb601e78d7d7624990d7fe589a506395e096 (patch)
tree76cb0095aeca6aebe5657e3cdd708969676a5f65
parentsapi: Add profiling application level support (diff)
downloadrtems-29c9eb601e78d7d7624990d7fe589a506395e096.tar.bz2
sapi: Add per-CPU profiling application level data
-rw-r--r--cpukit/sapi/include/rtems/profiling.h101
-rw-r--r--cpukit/sapi/src/profilingreportxml.c89
-rw-r--r--testsuites/sptests/spprofiling01/spprofiling01.scn10
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 ***