summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>2007-05-17 22:46:45 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>2007-05-17 22:46:45 +0000
commitc3330a88ee5d674b09dded32ef1ccba26a9c3034 (patch)
treef7f247449fc18bc299ef695c3503f9b7790db97a
parentAdd .rh clause to extra_arg. (diff)
downloadrtems-c3330a88ee5d674b09dded32ef1ccba26a9c3034.tar.bz2
2007-05-17 Joel Sherrill <joel.sherrill@oarcorp.com>
* ChangeLog, configure.ac, libcsupport/src/__times.c, libmisc/cpuuse/cpuuse.c, libmisc/stackchk/check.c, rtems/include/rtems/rtems/ratemon.h, rtems/src/ratemongetstatus.c, rtems/src/ratemonperiod.c, rtems/src/ratemonreportstatistics.c, rtems/src/ratemonresetall.c, rtems/src/ratemontimeout.c, score/Makefile.am, score/include/rtems/score/thread.h, score/include/rtems/score/timespec.h, score/src/threaddispatch.c, score/src/threadinitialize.c, score/src/threadtickletimeslice.c, score/src/timespecdivide.c: Add nanoseconds granularity to the rate monotonic period statistics and CPU usage statistics. This capability is enabled by default although may be conditionally disabled by the user. It could be too much overhead on small targets but it does not appear to be bad in early testing. Its impact on code size has not been evaluated either. It is possible that both forms of statistics gathering could be disabled with further tweaking of the conditional compilation. * score/src/timespecdividebyinteger.c: New file.
-rw-r--r--cpukit/ChangeLog24
-rw-r--r--cpukit/configure.ac12
-rw-r--r--cpukit/libcsupport/src/__times.c26
-rw-r--r--cpukit/libmisc/cpuuse/cpuuse.c129
-rw-r--r--cpukit/libmisc/stackchk/check.c56
-rw-r--r--cpukit/rtems/include/rtems/rtems/ratemon.h96
-rw-r--r--cpukit/rtems/src/ratemongetstatus.c55
-rw-r--r--cpukit/rtems/src/ratemonperiod.c154
-rw-r--r--cpukit/rtems/src/ratemonreportstatistics.c129
-rw-r--r--cpukit/rtems/src/ratemonresetall.c4
-rw-r--r--cpukit/rtems/src/ratemontimeout.c7
-rw-r--r--cpukit/score/Makefile.am3
-rw-r--r--cpukit/score/include/rtems/score/thread.h37
-rw-r--r--cpukit/score/include/rtems/score/timespec.h23
-rw-r--r--cpukit/score/src/threaddispatch.c19
-rw-r--r--cpukit/score/src/threadinitialize.c27
-rw-r--r--cpukit/score/src/threadtickletimeslice.c11
-rw-r--r--cpukit/score/src/timespecdivide.c31
-rw-r--r--cpukit/score/src/timespecdividebyinteger.c52
19 files changed, 700 insertions, 195 deletions
diff --git a/cpukit/ChangeLog b/cpukit/ChangeLog
index 6d42ab70e8..a59e116fe1 100644
--- a/cpukit/ChangeLog
+++ b/cpukit/ChangeLog
@@ -1,3 +1,23 @@
+2007-05-17 Joel Sherrill <joel.sherrill@oarcorp.com>
+
+ * ChangeLog, configure.ac, libcsupport/src/__times.c,
+ libmisc/cpuuse/cpuuse.c, libmisc/stackchk/check.c,
+ rtems/include/rtems/rtems/ratemon.h, rtems/src/ratemongetstatus.c,
+ rtems/src/ratemonperiod.c, rtems/src/ratemonreportstatistics.c,
+ rtems/src/ratemonresetall.c, rtems/src/ratemontimeout.c,
+ score/Makefile.am, score/include/rtems/score/thread.h,
+ score/include/rtems/score/timespec.h, score/src/threaddispatch.c,
+ score/src/threadinitialize.c, score/src/threadtickletimeslice.c,
+ score/src/timespecdivide.c: Add nanoseconds granularity to the rate
+ monotonic period statistics and CPU usage statistics. This capability
+ is enabled by default although may be conditionally disabled by the
+ user. It could be too much overhead on small targets but it does not
+ appear to be bad in early testing. Its impact on code size has not
+ been evaluated either. It is possible that both forms of statistics
+ gathering could be disabled with further tweaking of the conditional
+ compilation.
+ * score/src/timespecdividebyinteger.c: New file.
+
2007-05-16 Joel Sherrill <joel.sherrill@oarcorp.com>
* libmisc/cpuuse/cpuuse.c: Use rtems_object_get_name and eliminate
@@ -36,8 +56,8 @@
Monotonic Statistics and Period Usage into Rate Monotonic Manager.
Added the following directives: rtems_rate_monotonic_get_statistics,
rtems_rate_monotonic_reset_statistics,
- rtems_rate_montonic_reset_all_statistics,
- rtems_rate_montonic_report_statistics, and rtems_object_get_name.
+ rtems_rate_monotonic_reset_all_statistics,
+ rtems_rate_monotonic_report_statistics, and rtems_object_get_name.
Obsoleted the rtems/rtmonuse.h file as a public interface.
* rtems/src/ratemongetstatistics.c,
rtems/src/ratemonreportstatistics.c, rtems/src/ratemonresetall.c,
diff --git a/cpukit/configure.ac b/cpukit/configure.ac
index e743c2d537..08f7b4725e 100644
--- a/cpukit/configure.ac
+++ b/cpukit/configure.ac
@@ -208,6 +208,18 @@ RTEMS_CPUOPT([SIZEOF_CPU_CONTEXT],
[$ac_cv_sizeof_CPU_CONTEXT],
[The size of a 'CPU_CONTEXT', as computed by sizeof])
+RTEMS_CPUOPT([__RTEMS_USE_TICKS_CPU_USAGE_STATISTICS__],
+ [test x"${USE_TICKS_FOR_CPU_USAGE_STATISTICS}" = x"1"],
+ [1],
+ [disable nanosecond granularity for cpu usage statistics]
+)
+
+RTEMS_CPUOPT([__RTEMS_USE_TICKS_RATE_MONOTONIC_STATISTICS__],
+ [test x"${USE_TICKS_FOR_RATE_MONOTONIC_STATISTICS}" = x"1"],
+ [1],
+ [disable nanosecond granularity for period statistics]
+)
+
RTEMS_CPUOPT([__RTEMS_MAJOR__],
[true],
[$rtems_major],
diff --git a/cpukit/libcsupport/src/__times.c b/cpukit/libcsupport/src/__times.c
index 733befe8c9..669ed5ca25 100644
--- a/cpukit/libcsupport/src/__times.c
+++ b/cpukit/libcsupport/src/__times.c
@@ -22,6 +22,9 @@
#include <sys/time.h>
#include <errno.h>
#include <assert.h>
+#ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
+ #include <rtems/score/timespec.h>
+#endif
clock_t _times(
struct tms *ptms
@@ -48,7 +51,28 @@ clock_t _times(
* this thread.
*/
- ptms->tms_utime = _Thread_Executing->ticks_executed;
+ #ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
+ {
+ struct timespec per_tick;
+ uint32_t ticks;
+ uint32_t fractional_ticks;
+
+ per_tick.tv_sec =
+ _TOD_Microseconds_per_tick / TOD_MILLISECONDS_PER_SECOND;
+ per_tick.tv_nsec =
+ (_TOD_Microseconds_per_tick % TOD_MILLISECONDS_PER_SECOND) / 1000;
+
+ _Timespec_Divide(
+ &_Thread_Executing->cpu_time_used,
+ &per_tick,
+ &ticks,
+ &fractional_ticks
+ );
+ ptms->tms_utime = ticks;
+ }
+ #else
+ ptms->tms_utime = _Thread_Executing->ticks_executed;
+ #endif
ptms->tms_stime = ticks;
ptms->tms_cutime = 0;
ptms->tms_cstime = 0;
diff --git a/cpukit/libmisc/cpuuse/cpuuse.c b/cpukit/libmisc/cpuuse/cpuuse.c
index 9e9be38db8..cf1b6f2b4d 100644
--- a/cpukit/libmisc/cpuuse/cpuuse.c
+++ b/cpukit/libmisc/cpuuse/cpuuse.c
@@ -26,7 +26,18 @@
#include <rtems/cpuuse.h>
#include <rtems/bspIo.h>
-uint32_t CPU_usage_Ticks_at_last_reset;
+#if defined(RTEMS_ENABLE_NANOSECOND_RATE_MONOTONIC_STATISTICS) || \
+ defined(RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS)
+ #include <rtems/score/timespec.h>
+
+ /* We print to 1/10's of milliseconds */
+ #define NANOSECONDS_DIVIDER 100000
+ #define PERCENT_FMT "%04" PRId32
+#endif
+
+#ifndef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
+ uint32_t CPU_usage_Ticks_at_last_reset;
+#endif
/*PAGE
*
@@ -41,27 +52,38 @@ void rtems_cpu_usage_report( void )
Objects_Information *information;
char name[5];
uint32_t ival, fval;
- uint32_t total_units = 0;
-
- for ( api_index = 1 ;
- api_index <= OBJECTS_APIS_LAST ;
- api_index++ ) {
- if ( !_Objects_Information_table[ api_index ] )
- continue;
- information = _Objects_Information_table[ api_index ][ 1 ];
- if ( information ) {
- for ( i=1 ; i <= information->maximum ; i++ ) {
- the_thread = (Thread_Control *)information->local_table[ i ];
-
- if ( the_thread )
- total_units += the_thread->ticks_executed;
+ #ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
+ struct timespec uptime;
+ #else
+ uint32_t total_units = 0;
+ #endif
+
+ /*
+ * When not using nanosecond CPU usage resolution, we have to count
+ * the number of "ticks" we gave credit for to give the user a rough
+ * guideline as to what each number means proportionally.
+ */
+ #ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
+ _TOD_Get_uptime( &uptime );
+ #else
+ for ( api_index = 1 ; api_index <= OBJECTS_APIS_LAST ; api_index++ ) {
+ if ( !_Objects_Information_table[ api_index ] )
+ continue;
+ information = _Objects_Information_table[ api_index ][ 1 ];
+ if ( information ) {
+ for ( i=1 ; i <= information->maximum ; i++ ) {
+ the_thread = (Thread_Control *)information->local_table[ i ];
+
+ if ( the_thread )
+ total_units += the_thread->ticks_executed;
+ }
}
}
- }
-
+ #endif
+
printk( "CPU Usage by thread\n"
- " ID NAME TICKS PERCENT\n"
- );
+ " ID NAME TICKS PERCENT\n"
+ );
for ( api_index = 1 ;
api_index <= OBJECTS_APIS_LAST ;
@@ -77,36 +99,61 @@ void rtems_cpu_usage_report( void )
continue;
rtems_object_get_name( the_thread->Object.id, sizeof(name), name );
-
- ival = total_units ?
- the_thread->ticks_executed * 10000 / total_units : 0;
- fval = ival % 100;
- ival /= 100;
- printk(
- "0x%08" PRIx32 " %4s %8" PRId32 " %3" PRId32
- ".%02" PRId32"\n",
- the_thread->Object.id,
- name,
- the_thread->ticks_executed,
- ival,
- fval
- );
+
+ printk( "0x%08" PRIx32 " %4s ", the_thread->Object.id, name );
+
+ #ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
+ _Timespec_Divide( &the_thread->cpu_time_used, &uptime, &ival, &fval );
+
+ printk(
+ "%" PRId32 ".%06d" /* cpu time used */
+ " %3" PRId32 ".%02" PRId32 "\n", /* percentage */
+ the_thread->cpu_time_used.tv_sec,
+ the_thread->cpu_time_used.tv_nsec /
+ TOD_NANOSECONDS_PER_MICROSECOND,
+ ival,
+ fval
+ );
+ #else
+ ival = (total_units) ?
+ the_thread->ticks_executed * 10000 / total_units : 0;
+ fval = ival % 100;
+ ival /= 100;
+ printk(
+ "%8" PRId32 " %3" PRId32 ".%02" PRId32"\n",
+ the_thread->ticks_executed,
+ ival,
+ fval
+ );
+ #endif
}
}
}
- printk(
- "\nTicks since last reset = %" PRId32 "\n",
- _Watchdog_Ticks_since_boot - CPU_usage_Ticks_at_last_reset
- );
- printk( "\nTotal Units = %" PRId32 "\n", total_units );
+ #ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
+ printk( "Uptime %d.%06d seconds\n\n",
+ uptime.tv_sec,
+ uptime.tv_nsec / TOD_NANOSECONDS_PER_MICROSECOND
+ );
+ #else
+ printk(
+ "Ticks since last reset = %" PRId32 "\n",
+ _Watchdog_Ticks_since_boot - CPU_usage_Ticks_at_last_reset
+ );
+ printk( "Total Units = %" PRId32 "\n\n", total_units );
+ #endif
}
static void CPU_usage_Per_thread_handler(
Thread_Control *the_thread
)
{
- the_thread->ticks_executed = 0;
+ #ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
+ the_thread->cpu_time_used.tv_sec = 0;
+ the_thread->cpu_time_used.tv_nsec = 0;
+ #else
+ the_thread->ticks_executed = 0;
+ #endif
}
/*
@@ -114,7 +161,9 @@ static void CPU_usage_Per_thread_handler(
*/
void rtems_cpu_usage_reset( void )
{
- CPU_usage_Ticks_at_last_reset = _Watchdog_Ticks_since_boot;
+ #ifndef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
+ CPU_usage_Ticks_at_last_reset = _Watchdog_Ticks_since_boot;
+ #endif
rtems_iterate_over_all_threads(CPU_usage_Per_thread_handler);
}
diff --git a/cpukit/libmisc/stackchk/check.c b/cpukit/libmisc/stackchk/check.c
index 37b91dab21..bc9dc66481 100644
--- a/cpukit/libmisc/stackchk/check.c
+++ b/cpukit/libmisc/stackchk/check.c
@@ -215,7 +215,8 @@ void Stack_check_report_blown_task(
Stack_Control *stack = &running->Start.Initial_stack;
printk(
- "BLOWN STACK!!! Offending task(%p): id=0x%08" PRIx32 "; name=0x%08" PRIx32,
+ "BLOWN STACK!!! Offending task(0x%p): "
+ "id=0x%08" PRIx32 "; name=0x%08" PRIx32,
running,
running->Object.id,
(uint32_t) running->Object.name
@@ -233,7 +234,7 @@ void Stack_check_report_blown_task(
#endif
printk(
- " stack covers range %p - %p (%d bytes)\n",
+ " stack covers range 0x%p - 0x%p (%d bytes)\n",
stack->area,
stack->area + stack->size - 1,
stack->size
@@ -325,8 +326,8 @@ void *Stack_check_find_high_water_mark(
base += length - 1;
for (ebase = s; base > ebase; base--)
- if (*base != U32_PATTERN)
- return (void *) base;
+ if (*base != U32_PATTERN)
+ return (void *) base;
#else
/*
* start at lower memory and find first word that does not
@@ -335,39 +336,14 @@ void *Stack_check_find_high_water_mark(
base += PATTERN_SIZE_WORDS;
for (ebase = base + length; base < ebase; base++)
- if (*base != U32_PATTERN)
- return (void *) base;
+ if (*base != U32_PATTERN)
+ return (void *) base;
#endif
return (void *)0;
}
/*
- * Report Name
- */
-
-char *Stack_check_Get_object_name(
- Objects_Control *the_object,
- char **name
-)
-{
- Objects_Information *info;
-
- info = _Objects_Get_information(the_object->id);
- if ( info->is_string ) {
- *name = (char *) the_object->name;
- } else {
- uint32_t u32_name = (uint32_t) the_object->name;
- (*name)[ 0 ] = (u32_name >> 24) & 0xff;
- (*name)[ 1 ] = (u32_name >> 16) & 0xff;
- (*name)[ 2 ] = (u32_name >> 8) & 0xff;
- (*name)[ 3 ] = (u32_name >> 0) & 0xff;
- (*name)[ 4 ] = '\0';
- }
- return *name;
-}
-
-/*
* Stack_check_Dump_threads_usage(
*
* Try to print out how much stack was actually used by the task.
@@ -380,9 +356,7 @@ void Stack_check_Dump_threads_usage(
void *low;
void *high_water_mark;
Stack_Control *stack;
- uint32_t u32_name;
- char name_str[5];
- char *name;
+ char name[5];
if ( !the_thread )
return;
@@ -411,19 +385,17 @@ void Stack_check_Dump_threads_usage(
else
used = 0;
- name = name_str;
if ( the_thread ) {
- name = Stack_check_Get_object_name( &the_thread->Object, &name );
+ rtems_object_get_name( the_thread->Object.id, sizeof(name), name );
} else {
- u32_name = rtems_build_name('I', 'N', 'T', 'R');
- name[ 0 ] = (u32_name >> 24) & 0xff;
- name[ 1 ] = (u32_name >> 16) & 0xff;
- name[ 2 ] = (u32_name >> 8) & 0xff;
- name[ 3 ] = (u32_name >> 0) & 0xff;
+ name[ 0 ] = 'I';
+ name[ 1 ] = 'N';
+ name[ 2 ] = 'T';
+ name[ 3 ] = 'R';
name[ 4 ] = '\0';
}
- printk("0x%08" PRIx32 " %4s %p - %p %8" PRId32 " %8" PRId32 "\n",
+ printk("0x%08" PRIx32 " %4s 0x%p - 0x%p %8" PRId32 " %8" PRId32 "\n",
the_thread ? the_thread->Object.id : ~0,
name,
stack->area,
diff --git a/cpukit/rtems/include/rtems/rtems/ratemon.h b/cpukit/rtems/include/rtems/rtems/ratemon.h
index 84e3454164..3492772e2c 100644
--- a/cpukit/rtems/include/rtems/rtems/ratemon.h
+++ b/cpukit/rtems/include/rtems/rtems/ratemon.h
@@ -32,6 +32,20 @@
extern "C" {
#endif
+/*
+ * The user can define this at configure time and go back to ticks
+ * resolution.
+ */
+#ifndef __RTEMS_USE_TICKS_RATE_MONOTONIC_STATISTICS__
+ /*
+ * Enable the nanosecond accurate statistics
+ *
+ * When not defined, the older style tick accurate granularity
+ * is used.
+ */
+ #define RTEMS_ENABLE_NANOSECOND_RATE_MONOTONIC_STATISTICS
+#endif
+
#include <rtems/score/object.h>
#include <rtems/score/thread.h>
#include <rtems/score/watchdog.h>
@@ -68,12 +82,24 @@ typedef enum {
typedef struct {
uint32_t count;
uint32_t missed_count;
- uint32_t min_cpu_time;
- uint32_t max_cpu_time;
- uint32_t total_cpu_time;
- uint32_t min_wall_time;
- uint32_t max_wall_time;
- uint32_t total_wall_time;
+ #ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
+ struct timespec min_cpu_time;
+ struct timespec max_cpu_time;
+ struct timespec total_cpu_time;
+ #else
+ uint32_t min_cpu_time;
+ uint32_t max_cpu_time;
+ uint32_t total_cpu_time;
+ #endif
+ #ifdef RTEMS_ENABLE_NANOSECOND_RATE_MONOTONIC_STATISTICS
+ struct timespec min_wall_time;
+ struct timespec max_wall_time;
+ struct timespec total_wall_time;
+ #else
+ uint32_t min_wall_time;
+ uint32_t max_wall_time;
+ uint32_t total_wall_time;
+ #endif
} rtems_rate_monotonic_period_statistics;
/*
@@ -83,8 +109,16 @@ typedef struct {
typedef struct {
Objects_Id owner;
rtems_rate_monotonic_period_states state;
- uint32_t ticks_since_last_period;
- uint32_t ticks_executed_since_last_period;
+ #ifdef RTEMS_ENABLE_NANOSECOND_RATE_MONOTONIC_STATISTICS
+ struct timespec since_last_period;
+ #else
+ uint32_t ticks_since_last_period;
+ #endif
+ #ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
+ struct timespec executed_since_last_period;
+ #else
+ uint32_t ticks_executed_since_last_period;
+ #endif
} rtems_rate_monotonic_period_status;
/*
@@ -96,8 +130,16 @@ typedef struct {
Objects_Control Object;
Watchdog_Control Timer;
rtems_rate_monotonic_period_states state;
- uint32_t owner_ticks_executed_at_period;
- uint32_t time_at_period;
+ #ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
+ struct timespec owner_executed_at_period;
+ #else
+ uint32_t owner_ticks_executed_at_period;
+ #endif
+ #ifdef RTEMS_ENABLE_NANOSECOND_RATE_MONOTONIC_STATISTICS
+ struct timespec time_at_period;
+ #else
+ uint32_t time_at_period;
+ #endif
uint32_t next_length;
Thread_Control *owner;
rtems_rate_monotonic_period_statistics Statistics;
@@ -217,24 +259,24 @@ rtems_status_code rtems_rate_monotonic_reset_statistics(
);
/*
- * rtems_rate_montonic_reset_all_statistics
+ * rtems_rate_monotonic_reset_all_statistics
*
* DESCRIPTION:
*
* This directive allows a thread to reset the statistics information
* on ALL period instances.
*/
-void rtems_rate_montonic_reset_all_statistics( void );
+void rtems_rate_monotonic_reset_all_statistics( void );
/*
- * rtems_rate_montonic_report_statistics
+ * rtems_rate_monotonic_report_statistics
*
* DESCRIPTION:
*
* This directive allows a thread to print the statistics information
* on ALL period instances which have non-zero counts using printk.
*/
-void rtems_rate_montonic_report_statistics( void );
+void rtems_rate_monotonic_report_statistics( void );
/*
* rtems_rate_monotonic_period
@@ -278,6 +320,28 @@ void _Rate_monotonic_Timeout(
* This method resets the statistics information for a period instance.
*/
+#ifdef RTEMS_ENABLE_NANOSECOND_RATE_MONOTONIC_STATISTICS
+ #define _Rate_monotonic_Reset_wall_time_statistics( _the_period ) \
+ do { \
+ /* set the minimums to a large value */ \
+ (_the_period)->Statistics.min_wall_time.tv_sec = 0x7fffffff; \
+ (_the_period)->Statistics.min_wall_time.tv_nsec = 0x7fffffff; \
+ } while (0)
+#else
+ #define _Rate_monotonic_Reset_wall_time_statistics( _the_period )
+#endif
+
+#ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
+ #define _Rate_monotonic_Reset_cpu_use_statistics( _the_period ) \
+ do { \
+ /* set the minimums to a large value */ \
+ (_the_period)->Statistics.min_cpu_time.tv_sec = 0x7fffffff; \
+ (_the_period)->Statistics.min_cpu_time.tv_nsec = 0x7fffffff; \
+ } while (0)
+#else
+ #define _Rate_monotonic_Reset_cpu_use_statistics( _the_period )
+#endif
+
#define _Rate_monotonic_Reset_statistics( _the_period ) \
do { \
memset( \
@@ -285,8 +349,10 @@ void _Rate_monotonic_Timeout(
0, \
sizeof( rtems_rate_monotonic_period_statistics ) \
); \
+ _Rate_monotonic_Reset_cpu_use_statistics( _the_period ); \
+ _Rate_monotonic_Reset_wall_time_statistics( _the_period ); \
} while (0)
-
+
#ifndef __RTEMS_APPLICATION__
#include <rtems/rtems/ratemon.inl>
#endif
diff --git a/cpukit/rtems/src/ratemongetstatus.c b/cpukit/rtems/src/ratemongetstatus.c
index d059e1ae3b..d46b133e73 100644
--- a/cpukit/rtems/src/ratemongetstatus.c
+++ b/cpukit/rtems/src/ratemongetstatus.c
@@ -23,6 +23,11 @@
#include <rtems/rtems/ratemon.h>
#include <rtems/score/thread.h>
+#if defined(RTEMS_ENABLE_NANOSECOND_RATE_MONOTONIC_STATISTICS) || \
+ defined(RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS)
+ #include <rtems/score/timespec.h>
+#endif
+
/*PAGE
*
* rtems_rate_monotonic_get_status
@@ -64,15 +69,51 @@ rtems_status_code rtems_rate_monotonic_get_status(
status->state = the_period->state;
if ( status->state == RATE_MONOTONIC_INACTIVE ) {
- status->ticks_since_last_period = 0;
- status->ticks_executed_since_last_period = 0;
+ #ifdef RTEMS_ENABLE_NANOSECOND_RATE_MONOTONIC_STATISTICS
+ status->since_last_period.tv_sec = 0;
+ status->since_last_period.tv_nsec = 0;
+ #else
+ status->ticks_since_last_period = 0;
+ #endif
+ #ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
+ status->executed_since_last_period.tv_sec = 0;
+ status->executed_since_last_period.tv_nsec = 0;
+ #else
+ status->ticks_executed_since_last_period = 0;
+ #endif
} else {
- status->ticks_since_last_period =
- _Watchdog_Ticks_since_boot - the_period->time_at_period;
+ /*
+ * Both nanoseconds granularity options have to know the uptime.
+ * This lets them share one single invocation of _TOD_Get_uptime().
+ */
+ #if defined(RTEMS_ENABLE_NANOSECOND_RATE_MONOTONIC_STATISTICS) || \
+ defined(RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS)
+ struct timespec uptime;
+ _TOD_Get_uptime( &uptime );
+ #endif
+
+ #ifdef RTEMS_ENABLE_NANOSECOND_RATE_MONOTONIC_STATISTICS
+ _Timespec_Subtract(
+ &the_period->time_at_period,
+ &uptime,
+ &status->since_last_period
+ );
+ #else
+ status->ticks_since_last_period =
+ _Watchdog_Ticks_since_boot - the_period->time_at_period;
+ #endif
- status->ticks_executed_since_last_period =
- the_period->owner->ticks_executed -
- the_period->owner_ticks_executed_at_period;
+ #ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
+ _Timespec_Subtract(
+ &_Thread_Time_of_last_context_switch,
+ &uptime,
+ &status->executed_since_last_period
+ );
+ #else
+ status->ticks_executed_since_last_period =
+ the_period->owner->ticks_executed -
+ the_period->owner_ticks_executed_at_period;
+ #endif
}
_Thread_Enable_dispatch();
diff --git a/cpukit/rtems/src/ratemonperiod.c b/cpukit/rtems/src/ratemonperiod.c
index 83ae0e040d..872930e035 100644
--- a/cpukit/rtems/src/ratemonperiod.c
+++ b/cpukit/rtems/src/ratemonperiod.c
@@ -22,13 +22,37 @@
#include <rtems/score/object.h>
#include <rtems/rtems/ratemon.h>
#include <rtems/score/thread.h>
+#if defined(RTEMS_ENABLE_NANOSECOND_RATE_MONOTONIC_STATISTICS) || \
+ defined(RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS)
+ #include <rtems/score/timespec.h>
+ extern struct timespec _Thread_Time_of_last_context_switch;
+#endif
void _Rate_monotonic_Update_statistics(
Rate_monotonic_Control *the_period
)
{
- uint32_t ticks_since_last_period;
- uint32_t ticks_executed_since_last_period;
+ rtems_rate_monotonic_period_statistics *stats;
+ #ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
+ struct timespec executed;
+ #else
+ uint32_t ticks_executed_since_last_period;
+ #endif
+ #ifdef RTEMS_ENABLE_NANOSECOND_RATE_MONOTONIC_STATISTICS
+ struct timespec period_start;
+ struct timespec since_last_period;
+ #else
+ uint32_t ticks_since_last_period;
+ #endif
+ #if defined(RTEMS_ENABLE_NANOSECOND_RATE_MONOTONIC_STATISTICS) || \
+ defined(RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS)
+ struct timespec uptime;
+
+ /*
+ * Obtain the current time since boot
+ */
+ _TOD_Get_uptime( &uptime );
+ #endif
/*
* Assume we are only called in states where it is appropriate
@@ -40,41 +64,92 @@ void _Rate_monotonic_Update_statistics(
* Grab basic information
*/
- ticks_since_last_period =
- _Watchdog_Ticks_since_boot - the_period->time_at_period;
-
- ticks_executed_since_last_period = the_period->owner->ticks_executed -
- the_period->owner_ticks_executed_at_period;
+ #ifdef RTEMS_ENABLE_NANOSECOND_RATE_MONOTONIC_STATISTICS
+ period_start = the_period->time_at_period;
+ the_period->time_at_period = uptime;
+ _Timespec_Subtract( &period_start, &uptime, &since_last_period );
+ #else
+ ticks_since_last_period =
+ _Watchdog_Ticks_since_boot - the_period->time_at_period;
+ the_period->time_at_period = _Watchdog_Ticks_since_boot;
+ #endif
+
+ #ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
+ {
+ struct timespec ran;
+
+ /* executed = current cpu usage - value at start of period */
+ _Timespec_Subtract(
+ &the_period->owner_executed_at_period,
+ &_Thread_Executing->cpu_time_used,
+ &executed
+ );
+
+ /* How much time time since last context switch */
+ _Timespec_Subtract(&_Thread_Time_of_last_context_switch, &uptime, &ran);
+
+ /* executed += ran */
+ _Timespec_Add_to( &executed, &ran );
+ }
+ #else
+ ticks_executed_since_last_period = the_period->owner->ticks_executed -
+ the_period->owner_ticks_executed_at_period;
+ #endif
/*
* Now update the statistics
*/
- the_period->Statistics.count++;
+ stats = &the_period->Statistics;
+ stats->count++;
+
if ( the_period->state == RATE_MONOTONIC_EXPIRED )
- the_period->Statistics.missed_count++;
- the_period->Statistics.total_cpu_time += ticks_executed_since_last_period;
- the_period->Statistics.total_wall_time += ticks_since_last_period;
+ stats->missed_count++;
/*
* Update CPU time
*/
- if ( ticks_executed_since_last_period < the_period->Statistics.min_cpu_time )
- the_period->Statistics.min_cpu_time = ticks_executed_since_last_period;
+ #ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
+ _Timespec_Add_to( &stats->total_cpu_time, &executed );
+
+ if ( _Timespec_Less_than( &executed, &stats->min_cpu_time ) )
+ stats->min_cpu_time = executed;
+
+ if ( _Timespec_Greater_than( &executed, &stats->max_cpu_time ) )
+ stats->max_cpu_time = executed;
+
+ #else
+ stats->total_cpu_time += ticks_executed_since_last_period;
- if ( ticks_executed_since_last_period > the_period->Statistics.max_cpu_time )
- the_period->Statistics.max_cpu_time = ticks_executed_since_last_period;
+ if ( ticks_executed_since_last_period < stats->min_cpu_time )
+ stats->min_cpu_time = ticks_executed_since_last_period;
+
+ if ( ticks_executed_since_last_period > stats->max_cpu_time )
+ stats->max_cpu_time = ticks_executed_since_last_period;
+ #endif
/*
* Update Wall time
*/
- if ( ticks_since_last_period < the_period->Statistics.min_wall_time )
- the_period->Statistics.min_wall_time = ticks_since_last_period;
+ #ifndef RTEMS_ENABLE_NANOSECOND_RATE_MONOTONIC_STATISTICS
+ stats->total_wall_time += ticks_since_last_period;
+
+ if ( ticks_since_last_period < stats->min_wall_time )
+ stats->min_wall_time = ticks_since_last_period;
+
+ if ( ticks_since_last_period > stats->max_wall_time )
+ stats->max_wall_time = ticks_since_last_period;
+ #else
+ _Timespec_Add_to( &stats->total_wall_time, &since_last_period );
- if ( ticks_since_last_period > the_period->Statistics.max_wall_time )
- the_period->Statistics.max_wall_time = ticks_since_last_period;
+ if ( _Timespec_Less_than( &since_last_period, &stats->min_wall_time ) )
+ stats->min_wall_time = since_last_period;
+
+ if ( _Timespec_Greater_than( &since_last_period, &stats->max_wall_time ) )
+ stats->max_wall_time = since_last_period;
+ #endif
}
@@ -146,6 +221,40 @@ rtems_status_code rtems_rate_monotonic_period(
_ISR_Enable( level );
+ #ifdef RTEMS_ENABLE_NANOSECOND_RATE_MONOTONIC_STATISTICS
+ /*
+ * Since the statistics didn't update the starting time,
+ * we do it here.
+ */
+ _TOD_Get_uptime( &the_period->time_at_period );
+ #else
+ the_period->time_at_period = _Watchdog_Ticks_since_boot;
+ #endif
+
+ #ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
+ {
+ struct timespec ran, uptime;
+
+ _TOD_Get_uptime( &uptime );
+
+ the_period->owner_executed_at_period =
+ _Thread_Executing->cpu_time_used;
+
+ /* How much time time since last context switch */
+ _Timespec_Subtract(
+ &_Thread_Time_of_last_context_switch,
+ &uptime,
+ &ran
+ );
+
+ /* thread had executed before the last context switch also */
+ _Timespec_Add_to( &the_period->owner_executed_at_period, &ran );
+ }
+ #else
+ the_period->owner_ticks_executed_at_period =
+ _Thread_Executing->ticks_executed;
+ #endif
+
the_period->state = RATE_MONOTONIC_ACTIVE;
_Watchdog_Initialize(
&the_period->Timer,
@@ -154,10 +263,6 @@ rtems_status_code rtems_rate_monotonic_period(
NULL
);
- the_period->owner_ticks_executed_at_period =
- _Thread_Executing->ticks_executed;
-
- the_period->time_at_period = _Watchdog_Ticks_since_boot;
the_period->next_length = length;
_Watchdog_Insert_ticks( &the_period->Timer, length );
@@ -216,9 +321,6 @@ rtems_status_code rtems_rate_monotonic_period(
_ISR_Enable( level );
the_period->state = RATE_MONOTONIC_ACTIVE;
- the_period->owner_ticks_executed_at_period =
- _Thread_Executing->ticks_executed;
- the_period->time_at_period = _Watchdog_Ticks_since_boot;
the_period->next_length = length;
_Watchdog_Insert_ticks( &the_period->Timer, length );
diff --git a/cpukit/rtems/src/ratemonreportstatistics.c b/cpukit/rtems/src/ratemonreportstatistics.c
index 352bd1d946..35f3c6d30b 100644
--- a/cpukit/rtems/src/ratemonreportstatistics.c
+++ b/cpukit/rtems/src/ratemonreportstatistics.c
@@ -22,6 +22,15 @@
#include <rtems/bspIo.h>
+#if defined(RTEMS_ENABLE_NANOSECOND_RATE_MONOTONIC_STATISTICS) || \
+ defined(RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS)
+ #include <rtems/score/timespec.h>
+
+ /* We print to 1/10's of milliseconds */
+ #define NANOSECONDS_DIVIDER 100000
+ #define PERCENT_FMT "%04" PRId32
+#endif
+
/*
* This directive allows a thread to print the statistics information
* on ALL period instances which have non-zero counts using printk.
@@ -30,19 +39,36 @@
* inside and outside of RTEMS. It is presented as part of the Manager
* but actually uses other services of the Manager.
*/
-void rtems_rate_montonic_report_statistics( void )
+void rtems_rate_monotonic_report_statistics( void )
{
rtems_status_code status;
rtems_id id;
rtems_rate_monotonic_period_statistics the_stats;
rtems_rate_monotonic_period_status the_status;
char name[5];
- uint32_t ival_cpu, fval_cpu;
- uint32_t ival_wall, fval_wall;
- printk(
- "Period information by period\n"
- " ID OWNER PERIODS MISSED CPU TIME WALL TIME\n"
+ printk( "Period information by period\n" );
+/*
+Layout by columns -- in memory of Hollerith :)
+
+1234567890123456789012345678901234567890123456789012345678901234567890123456789\
+ ID OWNER COUNT MISSED X
+ididididid NNNN ccccc mmmmmm X
+
+ Uncomment the following if you are tinkering with the formatting.
+ Be sure to test the various cases.
+ printk("\
+1234567890123456789012345678901234567890123456789012345678901234567890123456789\
+\n");
+*/
+ printk( " ID OWNER COUNT MISSED CPU TIME "
+ #ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
+ " "
+ #endif
+ #ifdef RTEMS_ENABLE_NANOSECOND_RATE_MONOTONIC_STATISTICS
+ " "
+ #endif
+ " WALL TIME\n"
);
/*
@@ -64,27 +90,92 @@ void rtems_rate_montonic_report_statistics( void )
if ( the_stats.count == 0 )
continue;
- ival_cpu = the_stats.total_cpu_time * 100 / the_stats.count;
-
name[ 0 ] = '\0';
if ( the_status.owner ) {
rtems_object_get_name( the_status.owner, sizeof(name), name );
}
- fval_cpu = ival_cpu % 100;
- ival_cpu /= 100;
- ival_wall = the_stats.total_wall_time * 100 / the_stats.count;
- fval_wall = ival_wall % 100;
- ival_wall /= 100;
+ /*
+ * Print part of report line that is not dependent on granularity
+ */
+
printk(
- "0x%08" PRIx32 " %4s %6" PRId32 " %3" PRId32 " "
- "%" PRId32 "/%" PRId32 "/%" PRId32 ".%02" PRId32 " "
- "%" PRId32 "/%" PRId32 "/%" PRId32 ".%02" PRId32 "\n",
+ "0x%08" PRIx32 " %4s %5" PRId32 " %6" PRId32 " ",
id, name,
- the_stats.count, the_stats.missed_count,
- the_stats.min_cpu_time, the_stats.max_cpu_time, ival_cpu, fval_cpu,
- the_stats.min_wall_time, the_stats.max_wall_time, ival_wall, fval_wall
+ the_stats.count, the_stats.missed_count
);
+
+ /*
+ * print CPU Usage part of statistics
+ */
+ {
+ #ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
+ struct timespec cpu_average;
+
+ _Timespec_Divide_by_integer(
+ &the_stats.total_cpu_time,
+ the_stats.count,
+ &cpu_average
+ );
+ printk(
+ "%" PRId32 "." PERCENT_FMT "/" /* min cpu time */
+ "%" PRId32 "." PERCENT_FMT "/" /* max cpu time */
+ "%" PRId32 "." PERCENT_FMT " ", /* avg cpu time */
+ the_stats.min_cpu_time.tv_sec,
+ the_stats.min_cpu_time.tv_nsec / NANOSECONDS_DIVIDER,
+ the_stats.max_cpu_time.tv_sec,
+ the_stats.max_cpu_time.tv_nsec / NANOSECONDS_DIVIDER,
+ cpu_average.tv_sec,
+ cpu_average.tv_nsec / NANOSECONDS_DIVIDER
+ );
+ #else
+ uint32_t ival_cpu, fval_cpu;
+
+ ival_cpu = the_stats.total_cpu_time * 100 / the_stats.count;
+ fval_cpu = ival_cpu % 100;
+ ival_cpu /= 100;
+
+ printk(
+ "%3" PRId32 "/%4" PRId32 "/%3" PRId32 ".%02" PRId32 " ",
+ the_stats.min_cpu_time, the_stats.max_cpu_time, ival_cpu, fval_cpu
+ );
+ #endif
+ }
+
+ /*
+ * print Wall time part of statistics
+ */
+ {
+ #ifdef RTEMS_ENABLE_NANOSECOND_RATE_MONOTONIC_STATISTICS
+ struct timespec wall_average;
+ _Timespec_Divide_by_integer(
+ &the_stats.total_wall_time,
+ the_stats.count,
+ &wall_average
+ );
+ printk(
+ "%" PRId32 "." PERCENT_FMT "/" /* min wall time */
+ "%" PRId32 "." PERCENT_FMT "/" /* max wall time */
+ "%" PRId32 "." PERCENT_FMT "\n", /* avg wall time */
+ the_stats.min_wall_time.tv_sec,
+ the_stats.min_wall_time.tv_nsec / NANOSECONDS_DIVIDER,
+ the_stats.max_wall_time.tv_sec,
+ the_stats.max_wall_time.tv_nsec / NANOSECONDS_DIVIDER,
+ wall_average.tv_sec,
+ wall_average.tv_nsec / NANOSECONDS_DIVIDER
+ );
+ #else
+ uint32_t ival_wall, fval_wall;
+
+ ival_wall = the_stats.total_wall_time * 100 / the_stats.count;
+ fval_wall = ival_wall % 100;
+ ival_wall /= 100;
+ printk(
+ "%3" PRId32 "/%4" PRId32 "/%3" PRId32 ".%02" PRId32 "\n",
+ the_stats.min_wall_time, the_stats.max_wall_time, ival_wall, fval_wall
+ );
+ #endif
+ }
}
}
diff --git a/cpukit/rtems/src/ratemonresetall.c b/cpukit/rtems/src/ratemonresetall.c
index 8b91ddd3e5..104b9b7604 100644
--- a/cpukit/rtems/src/ratemonresetall.c
+++ b/cpukit/rtems/src/ratemonresetall.c
@@ -23,9 +23,9 @@
#include <rtems/score/thread.h>
/*
- * rtems_rate_montonic_reset_all_statistics
+ * rtems_rate_monotonic_reset_all_statistics
*/
-void rtems_rate_montonic_reset_all_statistics( void )
+void rtems_rate_monotonic_reset_all_statistics( void )
{
Objects_Id id;
rtems_status_code status;
diff --git a/cpukit/rtems/src/ratemontimeout.c b/cpukit/rtems/src/ratemontimeout.c
index 3649d574d5..f861774f98 100644
--- a/cpukit/rtems/src/ratemontimeout.c
+++ b/cpukit/rtems/src/ratemontimeout.c
@@ -63,18 +63,11 @@ void _Rate_monotonic_Timeout(
if ( _States_Is_waiting_for_period( the_thread->current_state ) &&
the_thread->Wait.id == the_period->Object.id ) {
_Thread_Unblock( the_thread );
- the_period->owner_ticks_executed_at_period =
- the_thread->ticks_executed;
-
- the_period->time_at_period = _Watchdog_Ticks_since_boot;
_Watchdog_Insert_ticks( &the_period->Timer, the_period->next_length );
} else if ( the_period->state == RATE_MONOTONIC_OWNER_IS_BLOCKING ) {
the_period->state = RATE_MONOTONIC_EXPIRED_WHILE_BLOCKING;
- the_period->owner_ticks_executed_at_period =
- the_thread->ticks_executed;
- the_period->time_at_period = _Watchdog_Ticks_since_boot;
_Watchdog_Insert_ticks( &the_period->Timer, the_period->next_length );
} else
the_period->state = RATE_MONOTONIC_EXPIRED;
diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am
index 2b1c25e513..ad3c68e87e 100644
--- a/cpukit/score/Makefile.am
+++ b/cpukit/score/Makefile.am
@@ -148,7 +148,8 @@ libscore_a_SOURCES += src/threadq.c src/threadqdequeue.c \
## TIMESPEC_C_FILES
libscore_a_SOURCES += src/timespecaddto.c src/timespecfromticks.c \
src/timespecisvalid.c src/timespeclessthan.c src/timespecgreaterthan.c \
- src/timespecsubtract.c src/timespectoticks.c src/timespecdivide.c
+ src/timespecsubtract.c src/timespectoticks.c src/timespecdivide.c \
+ src/timespecdividebyinteger.c
## TOD_C_FILES
libscore_a_SOURCES += src/coretod.c src/coretodset.c src/coretodget.c \
diff --git a/cpukit/score/include/rtems/score/thread.h b/cpukit/score/include/rtems/score/thread.h
index c23f9cf05c..1d8ba50705 100644
--- a/cpukit/score/include/rtems/score/thread.h
+++ b/cpukit/score/include/rtems/score/thread.h
@@ -31,6 +31,20 @@
extern "C" {
#endif
+/*
+ * The user can define this at configure time and go back to ticks
+ * resolution.
+ */
+#ifndef __RTEMS_USE_TICKS_CPU_USAGE_STATISTICS__
+ /*
+ * Enable the nanosecond accurate statistics
+ *
+ * When not defined, the older style tick accurate granularity
+ * is used.
+ */
+ #define RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
+#endif
+
#include <rtems/score/context.h>
#include <rtems/score/cpu.h>
#if defined(RTEMS_MULTIPROCESSING)
@@ -44,6 +58,10 @@ extern "C" {
#include <rtems/score/tqdata.h>
#include <rtems/score/watchdog.h>
+#ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
+ /* XXX include something for timespec */
+#endif
+
/**
* The following defines the "return type" of a thread.
*
@@ -318,10 +336,14 @@ struct Thread_Control_struct {
/** This field is the method invoked with the budgeted time is consumed. */
Thread_CPU_budget_algorithm_callout budget_callout;
- /** This field is the number of clock ticks executed by this thread
+ /** This field is the amount of CPU time consumed by this thread
* since it was created.
*/
- uint32_t ticks_executed;
+ #ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
+ struct timespec cpu_time_used;
+ #else
+ uint32_t ticks_executed;
+ #endif
/** This field points to the Ready FIFO for this priority. */
Chain_Control *ready;
/** This field contains precalculated priority map indices. */
@@ -435,6 +457,17 @@ SCORE_EXTERN Thread_Control *_Thread_Allocated_fp;
*/
SCORE_EXTERN struct _reent **_Thread_libc_reent;
+#ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
+
+ /**
+ * This contains the time since boot when the last context switch occurred.
+ * By placing it in the BSS, it will automatically be zeroed out at
+ * system initialization and does not need to be known outside this
+ * file.
+ */
+ SCORE_EXTERN struct timespec _Thread_Time_of_last_context_switch;
+#endif
+
/**
* This routine performs the initialization necessary for this handler.
*/
diff --git a/cpukit/score/include/rtems/score/timespec.h b/cpukit/score/include/rtems/score/timespec.h
index 2ffde63fc2..cc65e4084a 100644
--- a/cpukit/score/include/rtems/score/timespec.h
+++ b/cpukit/score/include/rtems/score/timespec.h
@@ -135,7 +135,7 @@ void _Timespec_Subtract(
struct timespec *result
);
-/** @brief Divide Timespec
+/** @brief Divide Timespec By Integet
*
* This routine divides a timespec by an integer value. The expected
* use is to assist in benchmark calculations where you typically
@@ -147,12 +147,31 @@ void _Timespec_Subtract(
*
* @return This method fills in @a result.
*/
-void _Timespec_Divide(
+void _Timespec_Divide_by_integer(
const struct timespec *time,
uint32_t iterations,
struct timespec *result
);
+/** @brief Divide Timespec
+ *
+ * This routine divides a timespec by another timespec. The
+ * intended use is for calculating percentages to three decimal points.
+ *
+ * @param[in] lhs is the left hand number
+ * @param[in] rhs is the righ hand number
+ * @param[in] ival_percentage is the integer portion of the average
+ * @param[in] fval_percentage is the thousandths of percentage
+ *
+ * @return This method fills in @a result.
+ */
+void _Timespec_Divide(
+ const struct timespec *lhs,
+ const struct timespec *rhs,
+ uint32_t *ival_percentage,
+ uint32_t *fval_percentage
+);
+
#ifdef __cplusplus
}
#endif
diff --git a/cpukit/score/src/threaddispatch.c b/cpukit/score/src/threaddispatch.c
index 136433be17..4c903b6c2a 100644
--- a/cpukit/score/src/threaddispatch.c
+++ b/cpukit/score/src/threaddispatch.c
@@ -2,7 +2,7 @@
* Thread Handler
*
*
- * COPYRIGHT (c) 1989-1999.
+ * COPYRIGHT (c) 1989-2007.
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may be
@@ -30,6 +30,11 @@
#include <rtems/score/userext.h>
#include <rtems/score/wkspace.h>
+#ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
+
+ #include <rtems/score/timespec.h>
+#endif
+
/*PAGE
*
* _Thread_Dispatch
@@ -78,7 +83,17 @@ void _Thread_Dispatch( void )
heir->cpu_time_budget = _Thread_Ticks_per_timeslice;
_ISR_Enable( level );
- heir->ticks_executed++;
+ #ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
+ {
+ struct timespec uptime, ran;
+ _TOD_Get_uptime( &uptime );
+ _Timespec_Subtract(&_Thread_Time_of_last_context_switch, &uptime, &ran);
+ _Timespec_Add_to( &executing->cpu_time_used, &ran );
+ _Thread_Time_of_last_context_switch = uptime;
+ }
+ #else
+ heir->ticks_executed++;
+ #endif
/*
* Switch libc's task specific data.
diff --git a/cpukit/score/src/threadinitialize.c b/cpukit/score/src/threadinitialize.c
index e61cbac19a..f3e13a4944 100644
--- a/cpukit/score/src/threadinitialize.c
+++ b/cpukit/score/src/threadinitialize.c
@@ -187,17 +187,26 @@ boolean _Thread_Initialize(
break;
}
- the_thread->Start.isr_level = isr_level;
+ the_thread->Start.isr_level = isr_level;
+
+ the_thread->current_state = STATES_DORMANT;
+ the_thread->Wait.queue = NULL;
+ the_thread->resource_count = 0;
+ the_thread->suspend_count = 0;
+ the_thread->real_priority = priority;
+ the_thread->Start.initial_priority = priority;
+ _Thread_Set_priority( the_thread, priority );
- the_thread->current_state = STATES_DORMANT;
- the_thread->Wait.queue = NULL;
- the_thread->resource_count = 0;
- the_thread->suspend_count = 0;
- the_thread->real_priority = priority;
- the_thread->Start.initial_priority = priority;
- the_thread->ticks_executed = 0;
+ /*
+ * Initialize the CPU usage statistics
+ */
- _Thread_Set_priority( the_thread, priority );
+ #ifdef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
+ the_thread->cpu_time_used.tv_sec = 0;
+ the_thread->cpu_time_used.tv_nsec = 0;
+ #else
+ the_thread->ticks_executed = 0;
+ #endif
/*
* Open the object
diff --git a/cpukit/score/src/threadtickletimeslice.c b/cpukit/score/src/threadtickletimeslice.c
index 0666066b28..41f08aa8d0 100644
--- a/cpukit/score/src/threadtickletimeslice.c
+++ b/cpukit/score/src/threadtickletimeslice.c
@@ -49,11 +49,12 @@ void _Thread_Tickle_timeslice( void )
executing = _Thread_Executing;
- /*
- * Increment the number of ticks this thread has been executing
- */
-
- executing->ticks_executed++;
+ #ifndef RTEMS_ENABLE_NANOSECOND_CPU_USAGE_STATISTICS
+ /*
+ * Increment the number of ticks this thread has been executing
+ */
+ executing->ticks_executed++;
+ #endif
/*
* If the thread is not preemptible or is not ready, then
diff --git a/cpukit/score/src/timespecdivide.c b/cpukit/score/src/timespecdivide.c
index 0535c22e11..74d6cdbc78 100644
--- a/cpukit/score/src/timespecdivide.c
+++ b/cpukit/score/src/timespecdivide.c
@@ -23,30 +23,35 @@
#include <rtems/score/tod.h>
void _Timespec_Divide(
- const struct timespec *time,
- uint32_t iterations,
- struct timespec *result
+ const struct timespec *lhs,
+ const struct timespec *rhs,
+ uint32_t *ival_percentage,
+ uint32_t *fval_percentage
)
{
- uint64_t t;
+ uint64_t left, right, answer;
/*
* For math simplicity just convert the timespec to nanoseconds
* in a 64-bit integer.
*/
- t = time->tv_sec * TOD_NANOSECONDS_PER_SECOND;
- t += time->tv_nsec;
+ left = lhs->tv_sec * (uint64_t)TOD_NANOSECONDS_PER_SECOND;
+ left += lhs->tv_nsec;
+ right = rhs->tv_sec * (uint64_t)TOD_NANOSECONDS_PER_SECOND;
+ right += rhs->tv_nsec;
- /*
- * Divide to get nanoseconds per iteration
- */
-
- t /= iterations;
+ if ( rhs == 0 ) {
+ *ival_percentage = 0;
+ *ival_percentage = 0;
+ return;
+ }
/*
* Put it back in the timespec result
*/
- result->tv_sec = t / TOD_NANOSECONDS_PER_SECOND;
- result->tv_nsec = t % TOD_NANOSECONDS_PER_SECOND;
+ answer = (left * 1000) / right;
+
+ *fval_percentage = answer % 1000;
+ *ival_percentage = answer / 1000;
}
diff --git a/cpukit/score/src/timespecdividebyinteger.c b/cpukit/score/src/timespecdividebyinteger.c
new file mode 100644
index 0000000000..eecd7c4e30
--- /dev/null
+++ b/cpukit/score/src/timespecdividebyinteger.c
@@ -0,0 +1,52 @@
+/**
+ * @file score/src/timespecdividebyinteger.c
+ */
+
+/*
+ * COPYRIGHT (c) 1989-2007.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * 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.
+ *
+ * $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems/system.h>
+#include <sys/types.h>
+#include <rtems/score/timespec.h>
+#include <rtems/score/tod.h>
+
+void _Timespec_Divide_by_integer(
+ const struct timespec *time,
+ uint32_t iterations,
+ struct timespec *result
+)
+{
+ uint64_t t;
+
+ /*
+ * For math simplicity just convert the timespec to nanoseconds
+ * in a 64-bit integer.
+ */
+ t = time->tv_sec * TOD_NANOSECONDS_PER_SECOND;
+ t += time->tv_nsec;
+
+ /*
+ * Divide to get nanoseconds per iteration
+ */
+
+ t /= iterations;
+
+ /*
+ * Put it back in the timespec result
+ */
+
+ result->tv_sec = t / TOD_NANOSECONDS_PER_SECOND;
+ result->tv_nsec = t % TOD_NANOSECONDS_PER_SECOND;
+}