score: Add per-CPU profiling

Add per-CPU profiling stats API.  Implement the thread dispatch disable
level profiling.  The interrupt profiling must be implemented in CPU
port specific parts (mostly assembler code).  Add a support function
_Profiling_Outer_most_interrupt_entry_and_exit() for this purpose.
This commit is contained in:
Sebastian Huber
2014-03-14 08:46:49 +01:00
parent 350f88dc6e
commit f980561ee0
11 changed files with 335 additions and 8 deletions
+61
View File
@@ -17,10 +17,71 @@
#endif
#include <rtems/profiling.h>
#include <rtems/counter.h>
#include <rtems.h>
#include <string.h>
static void per_cpu_stats_iterate(
rtems_profiling_visitor visitor,
void *visitor_arg,
rtems_profiling_data *data
)
{
#ifdef RTEMS_PROFILING
uint32_t n = rtems_smp_get_processor_count();
uint32_t i;
memset(data, 0, sizeof(*data));
data->header.type = RTEMS_PROFILING_PER_CPU;
for (i = 0; i < n; ++i) {
const Per_CPU_Control *per_cpu = _Per_CPU_Get_by_index(i);
const Per_CPU_Stats *stats = &per_cpu->Stats;
rtems_profiling_per_cpu *per_cpu_data = &data->per_cpu;
per_cpu_data->processor_index = i;
per_cpu_data->max_thread_dispatch_disabled_time =
rtems_counter_ticks_to_nanoseconds(
stats->max_thread_dispatch_disabled_time
);
per_cpu_data->max_interrupt_time =
rtems_counter_ticks_to_nanoseconds(stats->max_interrupt_time);
per_cpu_data->max_interrupt_delay =
rtems_counter_ticks_to_nanoseconds(stats->max_interrupt_delay);
per_cpu_data->thread_dispatch_disabled_count =
stats->thread_dispatch_disabled_count;
per_cpu_data->total_thread_dispatch_disabled_time =
rtems_counter_ticks_to_nanoseconds(
stats->total_thread_dispatch_disabled_time
);
per_cpu_data->interrupt_count = stats->interrupt_count;
per_cpu_data->total_interrupt_time =
rtems_counter_ticks_to_nanoseconds(
stats->total_interrupt_time
);
(*visitor)(visitor_arg, data);
}
#else
(void) visitor;
(void) visitor_arg;
(void) data;
#endif
}
void rtems_profiling_iterate(
rtems_profiling_visitor visitor,
void *visitor_arg
)
{
rtems_profiling_data data;
per_cpu_stats_iterate(visitor, visitor_arg, &data);
}
+2
View File
@@ -45,6 +45,7 @@ include_rtems_score_HEADERS += include/rtems/score/percpu.h
include_rtems_score_HEADERS += include/rtems/score/priority.h
include_rtems_score_HEADERS += include/rtems/score/prioritybitmap.h
include_rtems_score_HEADERS += include/rtems/score/prioritybitmapimpl.h
include_rtems_score_HEADERS += include/rtems/score/profiling.h
include_rtems_score_HEADERS += include/rtems/score/rbtree.h
include_rtems_score_HEADERS += include/rtems/score/rbtreeimpl.h
include_rtems_score_HEADERS += include/rtems/score/scheduler.h
@@ -331,6 +332,7 @@ libscore_a_SOURCES += src/apiext.c src/chain.c src/chainappend.c \
src/chainnodecount.c \
src/assertthreaddispatchingrepressed.c \
src/interr.c src/isr.c src/wkspace.c src/wkstringduplicate.c
libscore_a_SOURCES += src/profilingisrentryexit.c
EXTRA_DIST = src/Unlimited.txt
+74
View File
@@ -154,6 +154,78 @@ typedef enum {
#endif /* defined( RTEMS_SMP ) */
/**
* @brief Per-CPU statistics.
*/
typedef struct {
#if defined( RTEMS_PROFILING )
/**
* @brief The thread dispatch disabled begin instant in CPU counter ticks.
*
* This value is used to measure the time of disabled thread dispatching.
*/
CPU_Counter_ticks thread_dispatch_disabled_instant;
/**
* @brief The maximum time of disabled thread dispatching in CPU counter
* ticks.
*/
CPU_Counter_ticks max_thread_dispatch_disabled_time;
/**
* @brief The maximum time spent to process a single sequence of nested
* interrupts in CPU counter ticks.
*
* 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.
*/
CPU_Counter_ticks max_interrupt_time;
/**
* @brief The maximum interrupt delay in CPU counter ticks if supported by
* the hardware.
*/
CPU_Counter_ticks max_interrupt_delay;
/**
* @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 CPU counter ticks.
*
* 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 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 CPU counter ticks.
*
* 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;
#endif /* defined( RTEMS_PROFILING ) */
} Per_CPU_Stats;
/**
* @brief Per CPU Core Structure
*
@@ -236,6 +308,8 @@ typedef struct {
*/
Per_CPU_State state;
#endif
Per_CPU_Stats Stats;
} Per_CPU_Control;
#if defined( RTEMS_SMP )
@@ -0,0 +1,113 @@
/**
* @file
*
* @ingroup ScoreProfiling
*
* @brief Profiling Support API
*/
/*
* Copyright (c) 2014 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Dornierstr. 4
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*/
#ifndef _RTEMS_SCORE_PROFILING
#define _RTEMS_SCORE_PROFILING
#include <rtems/score/percpu.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/**
* @defgroup ScoreProfiling Profiling Support
*
* @brief Profiling support.
*
* @{
*/
static inline void _Profiling_Thread_dispatch_disable(
Per_CPU_Control *per_cpu,
uint32_t previous_thread_dispatch_disable_level
)
{
#if defined( RTEMS_PROFILING )
if ( previous_thread_dispatch_disable_level == 0 ) {
Per_CPU_Stats *stats = &per_cpu->Stats;
stats->thread_dispatch_disabled_instant = _CPU_Counter_read();
++stats->thread_dispatch_disabled_count;
}
#else
(void) per_cpu;
(void) previous_thread_dispatch_disable_level;
#endif
}
static inline void _Profiling_Thread_dispatch_enable(
Per_CPU_Control *per_cpu,
uint32_t new_thread_dispatch_disable_level
)
{
#if defined( RTEMS_PROFILING )
if ( new_thread_dispatch_disable_level == 0 ) {
Per_CPU_Stats *stats = &per_cpu->Stats;
CPU_Counter_ticks now = _CPU_Counter_read();
CPU_Counter_ticks delta = _CPU_Counter_difference(
now,
stats->thread_dispatch_disabled_instant
);
stats->total_thread_dispatch_disabled_time += delta;
if ( stats->max_thread_dispatch_disabled_time < delta ) {
stats->max_thread_dispatch_disabled_time = delta;
}
}
#else
(void) per_cpu;
(void) new_thread_dispatch_disable_level;
#endif
}
static inline void _Profiling_Update_max_interrupt_delay(
Per_CPU_Control *per_cpu,
CPU_Counter_ticks interrupt_delay
)
{
#if defined( RTEMS_PROFILING )
Per_CPU_Stats *stats = &per_cpu->Stats;
if ( stats->max_interrupt_delay < interrupt_delay ) {
stats->max_interrupt_delay = interrupt_delay;
}
#else
(void) per_cpu;
(void) interrupt_delay;
#endif
}
void _Profiling_Outer_most_interrupt_entry_and_exit(
Per_CPU_Control *per_cpu,
CPU_Counter_ticks interrupt_entry_instant,
CPU_Counter_ticks interrupt_exit_instant
);
/** @} */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* _RTEMS_SCORE_PROFILING */
@@ -16,6 +16,7 @@
#include <rtems/score/percpu.h>
#include <rtems/score/smplock.h>
#include <rtems/score/profiling.h>
#ifdef __cplusplus
extern "C" {
@@ -140,12 +141,22 @@ RTEMS_INLINE_ROUTINE void _Thread_Dispatch_initialization( void )
*/
RTEMS_INLINE_ROUTINE uint32_t _Thread_Dispatch_increment_disable_level(void)
{
uint32_t level = _Thread_Dispatch_disable_level;
uint32_t disable_level = _Thread_Dispatch_disable_level;
#if defined( RTEMS_PROFILING )
ISR_Level level;
++level;
_Thread_Dispatch_disable_level = level;
_ISR_Disable( level );
_Profiling_Thread_dispatch_disable( _Per_CPU_Get(), disable_level );
#endif
return level;
++disable_level;
_Thread_Dispatch_disable_level = disable_level;
#if defined( RTEMS_PROFILING )
_ISR_Enable( level );
#endif
return disable_level;
}
/**
@@ -155,12 +166,22 @@ RTEMS_INLINE_ROUTINE void _Thread_Dispatch_initialization( void )
*/
RTEMS_INLINE_ROUTINE uint32_t _Thread_Dispatch_decrement_disable_level(void)
{
uint32_t level = _Thread_Dispatch_disable_level;
uint32_t disable_level = _Thread_Dispatch_disable_level;
#if defined( RTEMS_PROFILING )
ISR_Level level;
--level;
_Thread_Dispatch_disable_level = level;
_ISR_Disable( level );
#endif
return level;
--disable_level;
_Thread_Dispatch_disable_level = disable_level;
#if defined( RTEMS_PROFILING )
_Profiling_Thread_dispatch_enable( _Per_CPU_Get(), disable_level );
_ISR_Enable( level );
#endif
return disable_level;
}
#endif /* RTEMS_SMP */
+4
View File
@@ -163,6 +163,10 @@ $(PROJECT_INCLUDE)/rtems/score/prioritybitmapimpl.h: include/rtems/score/priorit
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/prioritybitmapimpl.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/prioritybitmapimpl.h
$(PROJECT_INCLUDE)/rtems/score/profiling.h: include/rtems/score/profiling.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/profiling.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/profiling.h
$(PROJECT_INCLUDE)/rtems/score/rbtree.h: include/rtems/score/rbtree.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/rbtree.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/rbtree.h
+45
View File
@@ -0,0 +1,45 @@
/*
* Copyright (c) 2014 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Dornierstr. 4
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <rtems/score/profiling.h>
void _Profiling_Outer_most_interrupt_entry_and_exit(
Per_CPU_Control *per_cpu,
CPU_Counter_ticks interrupt_entry_instant,
CPU_Counter_ticks interrupt_exit_instant
)
{
#if defined( RTEMS_PROFILING )
Per_CPU_Stats *stats = &per_cpu->Stats;
CPU_Counter_ticks delta = _CPU_Counter_difference(
interrupt_exit_instant,
interrupt_entry_instant
);
++stats->interrupt_count;
stats->total_interrupt_time += delta;
if ( stats->max_interrupt_time < delta ) {
stats->max_interrupt_time = delta;
}
#else
(void) per_cpu;
(void) interrupt_entry_instant;
(void) interrupt_exit_instant;
#endif
}
+2
View File
@@ -40,6 +40,7 @@ void _Thread_Dispatch( void )
per_cpu = _Per_CPU_Get();
_Assert( per_cpu->thread_dispatch_disable_level == 0 );
_Profiling_Thread_dispatch_disable( per_cpu, 0 );
per_cpu->thread_dispatch_disable_level = 1;
#if defined( RTEMS_SMP )
@@ -170,6 +171,7 @@ void _Thread_Dispatch( void )
post_switch:
_Assert( per_cpu->thread_dispatch_disable_level == 1 );
per_cpu->thread_dispatch_disable_level = 0;
_Profiling_Thread_dispatch_enable( per_cpu, 0 );
_Per_CPU_Release_and_ISR_enable( per_cpu, level );
@@ -17,6 +17,7 @@
#include <rtems/score/threaddispatch.h>
#include <rtems/score/assert.h>
#include <rtems/score/profiling.h>
#include <rtems/score/sysstate.h>
#define NO_OWNER_CPU 0xffffffffU
@@ -89,6 +90,7 @@ uint32_t _Thread_Dispatch_increment_disable_level( void )
_Giant_Do_acquire( self_cpu );
disable_level = self_cpu->thread_dispatch_disable_level;
_Profiling_Thread_dispatch_disable( self_cpu, disable_level );
++disable_level;
self_cpu->thread_dispatch_disable_level = disable_level;
@@ -113,6 +115,7 @@ uint32_t _Thread_Dispatch_decrement_disable_level( void )
_Giant_Do_release( self_cpu );
_Assert( disable_level != 0 || _Giant.owner_cpu == NO_OWNER_CPU );
_Profiling_Thread_dispatch_enable( self_cpu, disable_level );
_ISR_Enable_without_giant( isr_level );
return disable_level;
+1
View File
@@ -153,6 +153,7 @@ void _Thread_Handler( void )
_Assert( _ISR_Get_level() != 0 );
per_cpu->thread_dispatch_disable_level = 0;
_Profiling_Thread_dispatch_enable( per_cpu, 0 );
_Per_CPU_Release( per_cpu );
@@ -34,6 +34,7 @@ void _Thread_Start_multitasking( void )
* _Per_CPU_Release().
*/
_Per_CPU_Acquire( self_cpu );
_Profiling_Thread_dispatch_disable( self_cpu, 0 );
self_cpu->thread_dispatch_disable_level = 1;
#endif