Changeset d37adfe5 in rtems


Ignore:
Timestamp:
Mar 3, 2016, 6:02:03 AM (4 years ago)
Author:
Sebastian Huber <sebastian.huber@…>
Branches:
master
Children:
75aef54
Parents:
1547b623
git-author:
Sebastian Huber <sebastian.huber@…> (03/03/16 06:02:03)
git-committer:
Sebastian Huber <sebastian.huber@…> (03/17/16 07:27:47)
Message:

score: Fix CPU time used by executing threads

The CPU time used of a thread was previously maintained per-processor
mostly during _Thread_Dispatch(). However, on SMP configurations the
actual processor of a thread is difficult to figure out since thread
dispatching is a highly asynchronous process (e.g. via inter-processor
interrupts). Only the intended processor of a thread is known to the
scheduler easily. Do the CPU usage accounting during thread heir
updates in the context of the scheduler operations. Provide the
function _Thread_Get_CPU_time_used() to get the CPU usage of a thread
using proper locks to get a consistent value.

Close #2627.

Location:
cpukit
Files:
1 added
11 edited

Legend:

Unmodified
Added
Removed
  • cpukit/libcsupport/src/__times.c

    r1547b623 rd37adfe5  
    2727
    2828#include <sys/times.h>
     29#include <sys/time.h>
     30
     31#include <string.h>
    2932#include <time.h>
    30 #include <sys/time.h>
    31 #include <errno.h>
     33
    3234#include <rtems/seterr.h>
    3335#include <rtems/score/todimpl.h>
     
    4345{
    4446  rtems_interval ticks, us_per_tick;
    45   Thread_Control *executing;
    4647
    4748  if ( !ptms )
    4849    rtems_set_errno_and_return_minus_one( EFAULT );
     50
     51  memset( ptms, 0, sizeof( *ptms ) );
    4952
    5053  /*
     
    6366   */
    6467  {
     68    Timestamp_Control  cpu_time_used;
    6569    Timestamp_Control  per_tick;
    6670    uint32_t           ticks_of_executing;
    6771    uint32_t           fractional_ticks;
    68     Per_CPU_Control   *cpu_self;
    6972
     73    _Thread_Get_CPU_time_used( _Thread_Get_executing(), &cpu_time_used );
    7074    _Timestamp_Set(
    7175      &per_tick,
     
    7579          TOD_NANOSECONDS_PER_SECOND)
    7680    );
    77 
    78     cpu_self = _Thread_Dispatch_disable();
    79     executing = _Thread_Executing;
    80     _Thread_Update_cpu_time_used(
    81       executing,
    82       &_Thread_Time_of_last_context_switch
    83     );
    8481    _Timestamp_Divide(
    85       &executing->cpu_time_used,
     82      &cpu_time_used,
    8683      &per_tick,
    8784      &ticks_of_executing,
    8885      &fractional_ticks
    8986    );
    90     _Thread_Dispatch_enable( cpu_self );
     87
    9188    ptms->tms_utime = ticks_of_executing * us_per_tick;
    9289  }
     90
    9391  ptms->tms_stime  = ticks * us_per_tick;
    94   ptms->tms_cutime = 0;
    95   ptms->tms_cstime = 0;
    9692
    9793  return ticks * us_per_tick;
  • cpukit/libmisc/cpuuse/cpuusagereport.c

    r1547b623 rd37adfe5  
    4545  char                 name[13];
    4646  uint32_t             ival, fval;
    47   Timestamp_Control  uptime, total, ran, uptime_at_last_reset;
     47  Timestamp_Control  uptime, total, used, uptime_at_last_reset;
    4848  uint32_t seconds, nanoseconds;
    4949
     
    9191        );
    9292
    93         {
    94           Timestamp_Control last;
     93        _Thread_Get_CPU_time_used( the_thread, &used );
     94        _TOD_Get_uptime( &uptime );
     95        _Timestamp_Subtract( &uptime_at_last_reset, &uptime, &total );
     96        _Timestamp_Divide( &used, &total, &ival, &fval );
    9597
    96           /*
    97            * If this is the currently executing thread, account for time
    98            * since the last context switch.
    99            */
    100           ran = the_thread->cpu_time_used;
    101           if ( _Thread_Get_time_of_last_context_switch( the_thread, &last ) ) {
    102             Timestamp_Control used;
    103             _TOD_Get_uptime( &uptime );
    104             _Timestamp_Subtract( &last, &uptime, &used );
    105             _Timestamp_Add_to( &ran, &used );
    106           } else {
    107             _TOD_Get_uptime( &uptime );
    108           }
    109           _Timestamp_Subtract( &uptime_at_last_reset, &uptime, &total );
    110           _Timestamp_Divide( &ran, &total, &ival, &fval );
     98        /*
     99         * Print the information
     100         */
    111101
    112           /*
    113            * Print the information
    114            */
    115 
    116           seconds = _Timestamp_Get_seconds( &ran );
    117           nanoseconds = _Timestamp_Get_nanoseconds( &ran ) /
    118             TOD_NANOSECONDS_PER_MICROSECOND;
    119           (*print)( context,
    120             "%7" PRIu32 ".%06" PRIu32 " |%4" PRIu32 ".%03" PRIu32 "\n",
    121             seconds, nanoseconds,
    122             ival, fval
    123           );
    124         }
     102        seconds = _Timestamp_Get_seconds( &used );
     103        nanoseconds = _Timestamp_Get_nanoseconds( &used ) /
     104          TOD_NANOSECONDS_PER_MICROSECOND;
     105        (*print)( context,
     106          "%7" PRIu32 ".%06" PRIu32 " |%4" PRIu32 ".%03" PRIu32 "\n",
     107          seconds, nanoseconds,
     108          ival, fval
     109        );
    125110      }
    126111    }
  • cpukit/libmisc/cpuuse/cpuusagereset.c

    r1547b623 rd37adfe5  
    2222#include <rtems/score/percpu.h>
    2323#include <rtems/score/todimpl.h>
     24#include <rtems/score/schedulerimpl.h>
    2425#include <rtems/score/watchdogimpl.h>
    2526
     
    2829)
    2930{
     31  ISR_lock_Context lock_context;
     32
     33  _Scheduler_Acquire( the_thread, &lock_context );
    3034  _Timestamp_Set_to_zero( &the_thread->cpu_time_used );
     35  _Scheduler_Release( the_thread, &lock_context );
    3136}
    3237
     
    4550    Per_CPU_Control *cpu = _Per_CPU_Get_by_index( cpu_index );
    4651
    47     cpu->time_of_last_context_switch = CPU_usage_Uptime_at_last_reset;
     52    cpu->cpu_usage_timestamp = CPU_usage_Uptime_at_last_reset;
    4853  }
    4954
  • cpukit/libmisc/cpuuse/cpuusagetop.c

    r1547b623 rd37adfe5  
    219219{
    220220  rtems_cpu_usage_data* data = (rtems_cpu_usage_data*) arg;
    221   Timestamp_Control     usage = thread->cpu_time_used;
     221  Timestamp_Control     usage;
    222222  Timestamp_Control     current = data->zero;
    223223  int                   j;
    224224
    225225  data->stack_size += thread->Start.Initial_stack.size;
     226
     227  _Thread_Get_CPU_time_used(thread, &usage);
    226228
    227229  for (j = 0; j < data->last_task_count; j++)
     
    498500
    499501      /*
    500        * If this is the currently executing thread, account for time since
    501        * the last context switch.
    502        */
    503       if (_Thread_Get_time_of_last_context_switch(thread, &last))
    504       {
    505         Timestamp_Control used;
    506         Timestamp_Control now;
    507 
    508         /*
    509          * Get the current uptime and assume we are not pre-empted to
    510          * measure the time from the last switch this thread and now.
    511          */
    512         _TOD_Get_uptime(&now);
    513         _Timestamp_Subtract(&last, &now, &used);
    514         _Timestamp_Add_to(&usage, &used);
    515         _Timestamp_Add_to(&current_usage, &used);
    516       }
    517 
    518       /*
    519502       * Print the information
    520503       */
  • cpukit/rtems/src/ratemonperiod.c

    r1547b623 rd37adfe5  
    4646   *  Determine cpu usage since period initiated.
    4747   */
    48   used = owning_thread->cpu_time_used;
    49 
    50   if (owning_thread == _Thread_Executing) {
    51 
    52     Timestamp_Control ran;
    53 
    54     /* How much time time since last context switch */
    55     _Timestamp_Subtract(
    56       &_Thread_Time_of_last_context_switch, &uptime, &ran
    57     );
    58 
    59     /* cpu usage += ran */
    60     _Timestamp_Add_to( &used, &ran );
    61 
    62     /*
    63      *  The cpu usage info was reset while executing.  Can't
    64      *  determine a status.
    65      */
    66     if (_Timestamp_Less_than(&used, &the_period->cpu_usage_period_initiated))
    67       return false;
    68 
    69      /* used = current cpu usage - cpu usage at start of period */
    70     _Timestamp_Subtract(
    71        &the_period->cpu_usage_period_initiated,
    72        &used,
    73        cpu_since_last_period
    74     );
    75   }
     48  _Thread_Get_CPU_time_used( owning_thread, &used );
     49
     50  /*
     51   *  The cpu usage info was reset while executing.  Can't
     52   *  determine a status.
     53   */
     54  if ( _Timestamp_Less_than( &used, &the_period->cpu_usage_period_initiated ) )
     55    return false;
     56
     57   /* used = current cpu usage - cpu usage at start of period */
     58  _Timestamp_Subtract(
     59    &the_period->cpu_usage_period_initiated,
     60    &used,
     61    cpu_since_last_period
     62  );
    7663
    7764  return true;
     
    8067void _Rate_monotonic_Restart( Rate_monotonic_Control *the_period )
    8168{
    82   Thread_Control    *owning_thread = the_period->owner;
    83   Timestamp_Control  uptime;
    84   ISR_Level          level;
    85 
    86   _TOD_Get_uptime( &uptime );
     69  ISR_Level level;
    8770
    8871  /*
    8972   *  Set the starting point and the CPU time used for the statistics.
    9073   */
    91   the_period->time_period_initiated = uptime;
    92   the_period->cpu_usage_period_initiated = owning_thread->cpu_time_used;
    93 
    94   /*
    95    *  We need to take into account how much time the
    96    *  executing thread has run since the last context switch.  When this
    97    *  routine is invoked from rtems_rate_monotonic_period, the owner will
    98    *  be the executing thread.  When this routine is invoked from
    99    *  _Rate_monotonic_Timeout, it will not.
    100    */
    101   if (owning_thread == _Thread_Executing) {
    102     Timestamp_Control ran;
    103 
    104     /*
    105      *  Adjust the CPU time used to account for the time since last
    106      *  context switch.
    107      */
    108     _Timestamp_Subtract(
    109       &_Thread_Time_of_last_context_switch, &uptime, &ran
    110     );
    111 
    112     _Timestamp_Add_to( &the_period->cpu_usage_period_initiated, &ran );
    113   }
    114 
    115   _Scheduler_Release_job( owning_thread, the_period->next_length );
     74  _TOD_Get_uptime( &the_period->time_period_initiated );
     75  _Thread_Get_CPU_time_used(
     76    the_period->owner,
     77    &the_period->cpu_usage_period_initiated
     78  );
     79
     80  _Scheduler_Release_job( the_period->owner, the_period->next_length );
    11681
    11782  _ISR_Disable( level );
  • cpukit/score/Makefile.am

    r1547b623 rd37adfe5  
    306306libscore_a_SOURCES += src/threadentryadaptornumeric.c
    307307libscore_a_SOURCES += src/threadentryadaptorpointer.c
     308libscore_a_SOURCES += src/threadgetcputimeused.c
    308309libscore_a_SOURCES += src/threadglobalconstruction.c
    309310libscore_a_SOURCES += src/threadtimeout.c
  • cpukit/score/include/rtems/score/percpu.h

    r1547b623 rd37adfe5  
    334334  volatile bool dispatch_necessary;
    335335
    336   /** This is the time of the last context switch on this CPU. */
    337   Timestamp_Control time_of_last_context_switch;
     336  /**
     337   * @brief The CPU usage timestamp contains the time point of the last heir
     338   * thread change or last CPU usage update of the executing thread of this
     339   * processor.
     340   *
     341   * Protected by the scheduler lock.
     342   *
     343   * @see _Scheduler_Update_heir(), _Thread_Dispatch_update_heir() and
     344   * _Thread_Get_CPU_time_used().
     345   */
     346  Timestamp_Control cpu_usage_timestamp;
    338347
    339348  /**
     
    682691#define _Thread_Dispatch_necessary \
    683692  _Per_CPU_Get()->dispatch_necessary
    684 #define _Thread_Time_of_last_context_switch \
    685   _Per_CPU_Get()->time_of_last_context_switch
    686693
    687694/**
  • cpukit/score/include/rtems/score/schedulerimpl.h

    r1547b623 rd37adfe5  
    627627
    628628#endif /* defined(__RTEMS_HAVE_SYS_CPUSET_H__) */
    629 
    630 RTEMS_INLINE_ROUTINE void _Scheduler_Update_heir(
    631   Thread_Control *new_heir,
    632   bool            force_dispatch
    633 )
    634 {
    635   Thread_Control *heir = _Thread_Heir;
    636 
    637   if ( heir != new_heir && ( heir->is_preemptible || force_dispatch ) ) {
    638     _Thread_Heir = new_heir;
    639     _Thread_Dispatch_necessary = true;
    640   }
    641 }
    642629
    643630RTEMS_INLINE_ROUTINE void _Scheduler_Generic_block(
     
    13571344ISR_LOCK_DECLARE( extern, _Scheduler_Lock )
    13581345
     1346RTEMS_INLINE_ROUTINE void _Scheduler_Update_heir(
     1347  Thread_Control *new_heir,
     1348  bool            force_dispatch
     1349)
     1350{
     1351  Thread_Control *heir = _Thread_Heir;
     1352
     1353  if ( heir != new_heir && ( heir->is_preemptible || force_dispatch ) ) {
     1354#if defined(RTEMS_SMP)
     1355    /* We need this state only for _Thread_Get_CPU_time_used() */
     1356    _Scheduler_Thread_change_state( heir, THREAD_SCHEDULER_BLOCKED );
     1357    _Scheduler_Thread_change_state( new_heir, THREAD_SCHEDULER_SCHEDULED );
     1358#endif
     1359    _Thread_Update_CPU_time_used( heir, _Thread_Get_CPU( heir ) );
     1360    _Thread_Heir = new_heir;
     1361    _Thread_Dispatch_necessary = true;
     1362  }
     1363}
     1364
    13591365/**
    13601366 * @brief Acquires the scheduler instance of the thread.
  • cpukit/score/include/rtems/score/threadimpl.h

    r1547b623 rd37adfe5  
    579579
    580580/**
    581  * @brief Returns @a true and sets time_of_context_switch to the
    582  * time of the last context switch when the thread is currently executing
    583  * in the system, otherwise @a false.
    584  */
    585 RTEMS_INLINE_ROUTINE bool _Thread_Get_time_of_last_context_switch(
    586   Thread_Control    *the_thread,
    587   Timestamp_Control *time_of_context_switch
    588 )
    589 {
    590   bool retval = false;
    591 
    592   _Thread_Disable_dispatch();
    593   #ifndef RTEMS_SMP
    594     if ( _Thread_Executing->Object.id == the_thread->Object.id ) {
    595       *time_of_context_switch = _Thread_Time_of_last_context_switch;
    596       retval = true;
    597     }
    598   #else
    599     if ( _Thread_Is_executing_on_a_processor( the_thread ) ) {
    600       *time_of_context_switch =
    601         _Thread_Get_CPU( the_thread )->time_of_last_context_switch;
    602       retval = true;
    603     }
    604   #endif
    605   _Thread_Enable_dispatch();
    606   return retval;
    607 }
    608 
    609 
    610 /**
    611581 * This function returns true if the_thread is the heir
    612582 * thread, and false otherwise.
     
    804774}
    805775
     776RTEMS_INLINE_ROUTINE void _Thread_Update_CPU_time_used(
     777  Thread_Control  *the_thread,
     778  Per_CPU_Control *cpu
     779)
     780{
     781  Timestamp_Control last;
     782  Timestamp_Control ran;
     783
     784  last = cpu->cpu_usage_timestamp;
     785  _TOD_Get_uptime( &cpu->cpu_usage_timestamp );
     786  _Timestamp_Subtract( &last, &cpu->cpu_usage_timestamp, &ran );
     787  _Timestamp_Add_to( &the_thread->cpu_time_used, &ran );
     788}
     789
    806790#if defined( RTEMS_SMP )
    807791RTEMS_INLINE_ROUTINE void _Thread_Dispatch_update_heir(
     
    811795)
    812796{
     797  _Thread_Update_CPU_time_used( cpu_for_heir->heir, cpu_for_heir );
     798
    813799  cpu_for_heir->heir = heir;
    814800
     
    821807#endif
    822808
    823 RTEMS_INLINE_ROUTINE void _Thread_Update_cpu_time_used(
    824   Thread_Control *executing,
    825   Timestamp_Control *time_of_last_context_switch
    826 )
    827 {
    828   Timestamp_Control uptime;
    829   Timestamp_Control ran;
    830 
    831   _TOD_Get_uptime( &uptime );
    832   _Timestamp_Subtract(
    833     time_of_last_context_switch,
    834     &uptime,
    835     &ran
    836   );
    837   *time_of_last_context_switch = uptime;
    838   _Timestamp_Add_to( &executing->cpu_time_used, &ran );
    839 }
     809void _Thread_Get_CPU_time_used(
     810  Thread_Control    *the_thread,
     811  Timestamp_Control *cpu_time_used
     812);
    840813
    841814RTEMS_INLINE_ROUTINE void _Thread_Action_control_initialize(
  • cpukit/score/src/schedulersmpstartidle.c

    r1547b623 rd37adfe5  
    2323  Scheduler_SMP_Node *node = _Scheduler_SMP_Thread_get_node( thread );
    2424
     25  _Scheduler_Thread_change_state( thread, THREAD_SCHEDULER_SCHEDULED );
    2526  node->state = SCHEDULER_SMP_NODE_SCHEDULED;
    2627
  • cpukit/score/src/threaddispatch.c

    r1547b623 rd37adfe5  
    109109#endif
    110110
    111     _Thread_Update_cpu_time_used(
    112       executing,
    113       &cpu_self->time_of_last_context_switch
    114     );
    115 
    116111    _User_extensions_Thread_switch( executing, heir );
    117112    _Thread_Save_fp( executing );
Note: See TracChangeset for help on using the changeset viewer.