diff options
-rw-r--r-- | cpukit/ChangeLog | 24 | ||||
-rw-r--r-- | cpukit/configure.ac | 12 | ||||
-rw-r--r-- | cpukit/libcsupport/src/__times.c | 26 | ||||
-rw-r--r-- | cpukit/libmisc/cpuuse/cpuuse.c | 129 | ||||
-rw-r--r-- | cpukit/libmisc/stackchk/check.c | 56 | ||||
-rw-r--r-- | cpukit/rtems/include/rtems/rtems/ratemon.h | 96 | ||||
-rw-r--r-- | cpukit/rtems/src/ratemongetstatus.c | 55 | ||||
-rw-r--r-- | cpukit/rtems/src/ratemonperiod.c | 154 | ||||
-rw-r--r-- | cpukit/rtems/src/ratemonreportstatistics.c | 129 | ||||
-rw-r--r-- | cpukit/rtems/src/ratemonresetall.c | 4 | ||||
-rw-r--r-- | cpukit/rtems/src/ratemontimeout.c | 7 | ||||
-rw-r--r-- | cpukit/score/Makefile.am | 3 | ||||
-rw-r--r-- | cpukit/score/include/rtems/score/thread.h | 37 | ||||
-rw-r--r-- | cpukit/score/include/rtems/score/timespec.h | 23 | ||||
-rw-r--r-- | cpukit/score/src/threaddispatch.c | 19 | ||||
-rw-r--r-- | cpukit/score/src/threadinitialize.c | 27 | ||||
-rw-r--r-- | cpukit/score/src/threadtickletimeslice.c | 11 | ||||
-rw-r--r-- | cpukit/score/src/timespecdivide.c | 31 | ||||
-rw-r--r-- | cpukit/score/src/timespecdividebyinteger.c | 52 |
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; +} |