From cc034e7d2ffe330b2a45e5ca65254fea108960a8 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Mon, 8 Jul 2024 15:14:55 +1000 Subject: [PATCH] libcsupport/getrusage: Return task and idle time using getrusage Close #5062 --- cpukit/libcsupport/src/getrusage.c | 99 +++++++++++++++++------ testsuites/psxtests/psxgetrusage01/init.c | 27 +++++-- 2 files changed, 95 insertions(+), 31 deletions(-) diff --git a/cpukit/libcsupport/src/getrusage.c b/cpukit/libcsupport/src/getrusage.c index 8d7a0354e3..e849f944f5 100644 --- a/cpukit/libcsupport/src/getrusage.c +++ b/cpukit/libcsupport/src/getrusage.c @@ -30,42 +30,93 @@ #include "config.h" #endif +#define _GNU_SOURCE 1 #include +#undef _GNU_SOURCE + #include #include #include -int getrusage(int who, struct rusage *usage) -{ - struct timespec uptime; - struct timeval rtime; +#include +struct usage_stats { + Timestamp_Control task; + Timestamp_Control idle; +}; + +static bool usage_visitor( Thread_Control *the_thread, void *arg ) +{ + struct usage_stats *stats = (struct usage_stats *) arg; + Timestamp_Control usage; + Timestamp_Control *total; + usage = _Thread_Get_CPU_time_used( the_thread ); + if ( the_thread->is_idle ) { + total = &stats->idle; + } else { + total = &stats->task; + } + _Timestamp_Add_to( total, &usage ); + return false; +} + +static int getrusage_RUSAGE_SELF( + struct rusage *usage +) +{ + /* + * RTEMS only has a single process so there are no children. The + * single process has been running since the system was booted. We + * account for IDLE time as system time so user or task time is the + * uptime time. + */ + struct usage_stats stats; + + _Timestamp_Set_to_zero( &stats.task ); + _Timestamp_Set_to_zero( &stats.idle ); + + rtems_task_iterate( usage_visitor, &stats ); + + _Timestamp_To_timeval( &stats.task, &usage->ru_utime ); + _Timestamp_To_timeval( &stats.idle, &usage->ru_stime ); + + return 0; +} + +static int getrusage_RUSAGE_THREAD( + struct rusage *usage +) +{ + Thread_Control *the_thread; + ISR_lock_Context lock_context; + Timestamp_Control used; + the_thread = _Thread_Get( OBJECTS_ID_OF_SELF, &lock_context ); + used = _Thread_Get_CPU_time_used( the_thread ); + _ISR_lock_ISR_enable( &lock_context ); + _Timestamp_To_timeval( &used, &usage->ru_utime ); + _Timestamp_Set_to_zero( &used ); + _Timestamp_To_timeval( &used, &usage->ru_stime ); + return 0; +} + +int getrusage( + int who, struct rusage *usage +) +{ if ( !usage ) rtems_set_errno_and_return_minus_one( EFAULT ); - /* - * RTEMS only has a single process so there are no children. - * The single process has been running since the system - * was booted and since there is no distinction between system - * and user time, we will just report the uptime. - */ - if (who == RUSAGE_SELF) { - rtems_clock_get_uptime( &uptime ); - - rtime.tv_sec = uptime.tv_sec; - rtime.tv_usec = uptime.tv_nsec / 1000; - - usage->ru_utime = rtime; - usage->ru_stime = rtime; - - return 0; - } - - if (who == RUSAGE_CHILDREN) { + switch ( who ) { + case RUSAGE_SELF: + return getrusage_RUSAGE_SELF( usage ); + case RUSAGE_THREAD: + return getrusage_RUSAGE_THREAD( usage ); + case RUSAGE_CHILDREN: rtems_set_errno_and_return_minus_one( ENOSYS ); + default: + break; } rtems_set_errno_and_return_minus_one( EINVAL ); } - diff --git a/testsuites/psxtests/psxgetrusage01/init.c b/testsuites/psxtests/psxgetrusage01/init.c index 91ea1d3a11..3124a20c62 100644 --- a/testsuites/psxtests/psxgetrusage01/init.c +++ b/testsuites/psxtests/psxgetrusage01/init.c @@ -30,8 +30,11 @@ #include "config.h" #endif -#include +#define _GNU_SOURCE 1 #include +#undef _GNU_SOURCE + +#include #include #include @@ -79,8 +82,8 @@ rtems_task Init( puts( "Consume CPU long enough to have non-zero usage" ); rtems_test_spin_for_ticks( 5 ); - - puts( "getrusage( RUSAGE_SELF, &usage ) -- EINVAL" ); + + puts( "getrusage( RUSAGE_SELF, &usage ) -- 0" ); sc = getrusage( RUSAGE_SELF, &usage ); rtems_test_assert( sc == 0 ); @@ -88,10 +91,20 @@ rtems_task Init( rtems_test_assert( usage.ru_utime.tv_sec == 0 ); rtems_test_assert( usage.ru_utime.tv_usec != 0 ); - /* System and user time is the same */ - rtems_test_assert( usage.ru_utime.tv_sec == usage.ru_stime.tv_sec ); - rtems_test_assert( usage.ru_utime.tv_usec == usage.ru_stime.tv_usec ); - + /* System is the IDLE time and user is the total of task time */ + rtems_test_assert( usage.ru_utime.tv_sec != usage.ru_stime.tv_sec ); + rtems_test_assert( usage.ru_utime.tv_usec != usage.ru_stime.tv_usec ); + + puts( "getrusage( RUSAGE_THREAD, &usage ) -- 0" ); + sc = getrusage( RUSAGE_THREAD, &usage ); + rtems_test_assert( sc == 0 ); + + /* System is the 0 and user is the task time */ + rtems_test_assert( usage.ru_utime.tv_sec != 0 || + usage.ru_utime.tv_usec != 0 ); + rtems_test_assert( usage.ru_stime.tv_sec == 0 && + usage.ru_stime.tv_usec == 0 ); + TEST_END(); rtems_test_exit(0);