mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2026-08-31 11:57:28 +08:00
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:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user