Exemple #1
0
static void _Rate_monotonic_Update_statistics(
  Rate_monotonic_Control    *the_period
)
{
  Timestamp_Control          executed;
  Timestamp_Control          since_last_period;
  Rate_monotonic_Statistics *stats;
  bool                       valid_status;

  /*
   *  Assume we are only called in states where it is appropriate
   *  to update the statistics.  This should only be RATE_MONOTONIC_ACTIVE
   *  and RATE_MONOTONIC_EXPIRED.
   */

  /*
   *  Update the counts.
   */
  stats = &the_period->Statistics;
  stats->count++;

  if ( the_period->state == RATE_MONOTONIC_EXPIRED )
    stats->missed_count++;

  /*
   *  Grab status for time statistics.
   */
  valid_status =
    _Rate_monotonic_Get_status( the_period, &since_last_period, &executed );
  if (!valid_status)
    return;

  /*
   *  Update CPU time
   */
  _Timestamp_Add_to( &stats->total_cpu_time, &executed );

  if ( _Timestamp_Less_than( &executed, &stats->min_cpu_time ) )
    stats->min_cpu_time = executed;

  if ( _Timestamp_Greater_than( &executed, &stats->max_cpu_time ) )
    stats->max_cpu_time = executed;

  /*
   *  Update Wall time
   */
  _Timestamp_Add_to( &stats->total_wall_time, &since_last_period );

  if ( _Timestamp_Less_than( &since_last_period, &stats->min_wall_time ) )
    stats->min_wall_time = since_last_period;

  if ( _Timestamp_Greater_than( &since_last_period, &stats->max_wall_time ) )
    stats->max_wall_time = since_last_period;
}
Exemple #2
0
bool _Rate_monotonic_Get_status(
  const Rate_monotonic_Control *the_period,
  Timestamp_Control            *wall_since_last_period,
  Timestamp_Control            *cpu_since_last_period
)
{
  Timestamp_Control        uptime;
  Thread_Control          *owning_thread = the_period->owner;
  Timestamp_Control        used;

  /*
   *  Determine elapsed wall time since period initiated.
   */
  _TOD_Get_uptime( &uptime );
  _Timestamp_Subtract(
    &the_period->time_period_initiated, &uptime, wall_since_last_period
  );

  /*
   *  Determine cpu usage since period initiated.
   */
  _Thread_Get_CPU_time_used( owning_thread, &used );

  /*
   *  The cpu usage info was reset while executing.  Can't
   *  determine a status.
   */
  if ( _Timestamp_Less_than( &used, &the_period->cpu_usage_period_initiated ) )
    return false;

   /* used = current cpu usage - cpu usage at start of period */
  _Timestamp_Subtract(
    &the_period->cpu_usage_period_initiated,
    &used,
    cpu_since_last_period
  );

  return true;
}
bool _Scheduler_simple_smp_Assign(
  Thread_Control *consider
)
{
  bool            found;       /* have we found a cpu to place it on? */
  uint32_t        found_cpu;   /* CPU to place this thread */
  bool            blocked;     /* CPU has blocked thread? */
  Thread_Control *pheir;       /* heir on found cpu to potentially replace */
  Thread_Control *h;
  Thread_Control *e;
  uint32_t        cpu;

  /*
   *  Initialize various variables to indicate we have not found
   *  a potential core for the thread under consideration.
   */
  found     = false;
  blocked   = false;
  found_cpu = 0;
  pheir     = NULL;

  for ( cpu=0 ; cpu < _SMP_Processor_count ; cpu++ ) {
    D( "SCHED CPU=%d consider=0x%08x ASSIGN\n", cpu, consider->Object.id );

    /*
     *  If the thread under consideration is already executing or
     *  heir, then we don't have a better option for it.
     */
    e = _Per_CPU_Information[cpu].executing;
    if ( e == consider ) {
      D( "SCHED CPU=%d Executing=0x%08x considering=0x%08x ASSIGNED\n",
        cpu, e->Object.id, consider->Object.id );
      return true;
    }

    if ( !_States_Is_ready( e->current_state ) ) {
      pheir     = e;
      found_cpu = cpu;
      found     = true;
      blocked   = true;
      D( "SCHED CPU=%d PHeir=0x%08x considering=0x%08x BLOCKED\n",
        cpu, e->Object.id, consider->Object.id );
      continue;
    }

    h = _Per_CPU_Information[cpu].heir;
    if ( h == consider ) {
      D( "SCHED CPU=%d Heir=0x%08x considering=0x%08x ASSIGNED\n",
        cpu, h->Object.id, consider->Object.id );
      return true;
    }

    if ( blocked )
      continue;

    /*
     *  If we haven't found a potential CPU to locate the thread
     *  under consideration on, we need to consider if this is a
     *  more important threads first (e.g. priority <).
     *
     *  But when a thread changes its priority and ends up at the end of
     *  the priority group for the new heir, we also need to schedule
     *  a new heir.  This is the "=" part of the check.
     */
    if ( !found ) {
      if ( consider->current_priority <= h->current_priority ) {
        pheir     = h;
        found_cpu = cpu;
        found     = true;
        D( "SCHED CPU=%d PHeir=0x%08x considering=0x%08x MAYBE #1\n",
          cpu, h->Object.id, consider->Object.id );
      }

      continue;
    }

    /*
     *  Past this point, found is true.
     */

    /*
     *  If we have found a potential CPU on which to make the
     *  thread under consideration the heir, then we need to
     *  check if the current CPU is a more appropriate place
     *  for this thread to be placed.
     *
     *  Check 1: heir of potential CPU is more important
     *           then heir of current CPU.  We want to
     *           replace the least important thread possible.
     */
    if ( h->current_priority > pheir->current_priority ) {
      pheir = h;
      found_cpu = cpu;
      D( "SCHED CPU=%d PHeir=0x%08x considering=0x%08x MAYBE #2\n",
        cpu, h->Object.id, consider->Object.id );
      continue;
    }

    if ( h->current_priority > pheir->current_priority )
      continue;

    /*
     *  If heir of potential CPU and of the current CPU are of the SAME
     *  priority, then which has been running longer?
     *
     *           Which CPU has had its executing thread longer?
     */
    if ( _Timestamp_Less_than(
           &_Per_CPU_Information[cpu].time_of_last_context_switch,
           &_Per_CPU_Information[found_cpu].time_of_last_context_switch
         ) ) {
      pheir = h;
      found_cpu = cpu;
      D( "SCHED CPU=%d PHeir=0x%08x considering=0x%08x LONGER\n",
        cpu, h->Object.id, consider->Object.id );
      continue;
    }

    /*
     *  If we are looking at a core with a non-preemptible thread
     *  for potential placement, then favor a core with a preeemtible
     *  thread of the same priority.  This should help avoid priority
     *  inversions and let threads run earlier.
     */
    if ( !pheir->is_preemptible && h->is_preemptible ) {
      D( "SCHED CPU=%d PHeir==0x%08x is NOT PREEMPTIBLE\n", 
        cpu, pheir->Object.id );
      pheir = h;
      found_cpu = cpu;
      D( "SCHED CPU=%d PHeir=0x%08x considering=0x%08x PREEMPTIBLE\n",
        cpu, h->Object.id, consider->Object.id );
      continue;

    }
  }

  /*
   *  If we found a cpu to make this thread heir of, then we
   *  need to consider whether we need a dispatch on that CPU.
   */
  if ( found ) {
    e = _Per_CPU_Information[found_cpu].executing;
    D( "SCHED CPU=%d executing=0x%08x considering=0x%08x FOUND\n",
      found_cpu, e->Object.id, consider->Object.id );
    _Per_CPU_Information[found_cpu].heir = consider;
    if ( !_States_Is_ready( e->current_state ) ) {
       D( "SCHED CPU=%d executing not ready dispatch needed\n", found_cpu);
      _Per_CPU_Information[found_cpu].dispatch_necessary = true;
    } else if ( consider->current_priority < e->current_priority ) {
      if ( e->is_preemptible || consider->current_priority == 0 ) {
         D( "SCHED CPU=%d preempting\n", found_cpu);
        _Per_CPU_Information[found_cpu].dispatch_necessary = true;
      }
    }
  }

  /*
   *  Return true to indicate we changed an heir.  This indicates
   *  scheduling needs to examine more threads.
   */
  return found;
}
bool _Rate_monotonic_Get_status(
  Rate_monotonic_Control        *the_period,
  Rate_monotonic_Period_time_t  *wall_since_last_period,
  Thread_CPU_usage_t            *cpu_since_last_period
)
{
  #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
    Timestamp_Control        uptime;
  #endif
    Thread_Control          *owning_thread = the_period->owner;
    Thread_CPU_usage_t       used;

  /*
   *  Determine elapsed wall time since period initiated.
   */
  #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
    _TOD_Get_uptime( &uptime );
    _Timestamp_Subtract(
      &the_period->time_period_initiated, &uptime, wall_since_last_period
    );
  #else
    *wall_since_last_period =
      _Watchdog_Ticks_since_boot - the_period->time_period_initiated;
  #endif

  /*
   *  Determine cpu usage since period initiated.
   */
  used = owning_thread->cpu_time_used;

  #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
    if (owning_thread == _Thread_Executing) {

      Thread_CPU_usage_t ran;

      /* How much time time since last context switch */
      _Timestamp_Subtract(
        &_Thread_Time_of_last_context_switch, &uptime, &ran
      );

      /* cpu usage += ran */
      _Timestamp_Add_to( &used, &ran );

      /*
       *  The cpu usage info was reset while executing.  Can't
       *  determine a status.
       */
      if (_Timestamp_Less_than(&used, &the_period->cpu_usage_period_initiated))
        return false;

       /* used = current cpu usage - cpu usage at start of period */
      _Timestamp_Subtract(
         &the_period->cpu_usage_period_initiated,
         &used,
         cpu_since_last_period
      );
    }
  #else
      /*
       *  The cpu usage info was reset while executing.  Can't
       *  determine a status.
       */
      if (used < the_period->cpu_usage_period_initiated)
        return false;

      *cpu_since_last_period = used - the_period->cpu_usage_period_initiated;
  #endif
  return true;
}
static void _Rate_monotonic_Update_statistics(
  Rate_monotonic_Control    *the_period
)
{
  Thread_CPU_usage_t              executed;
  Rate_monotonic_Period_time_t    since_last_period;
  Rate_monotonic_Statistics      *stats;
  bool                            valid_status;

  /*
   *  Assume we are only called in states where it is appropriate
   *  to update the statistics.  This should only be RATE_MONOTONIC_ACTIVE
   *  and RATE_MONOTONIC_EXPIRED.
   */

  /*
   *  Update the counts.
   */
  stats = &the_period->Statistics;
  stats->count++;

  if ( the_period->state == RATE_MONOTONIC_EXPIRED )
    stats->missed_count++;

  /*
   *  Grab status for time statistics.
   */
  valid_status =
    _Rate_monotonic_Get_status( the_period, &since_last_period, &executed );
  if (!valid_status)
    return;

  /*
   *  Update CPU time
   */
  #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
    _Timestamp_Add_to( &stats->total_cpu_time, &executed );

    if ( _Timestamp_Less_than( &executed, &stats->min_cpu_time ) )
      stats->min_cpu_time = executed;

    if ( _Timestamp_Greater_than( &executed, &stats->max_cpu_time ) )
      stats->max_cpu_time = executed;
  #else
    stats->total_cpu_time  += executed;

    if ( executed < stats->min_cpu_time )
      stats->min_cpu_time = executed;

    if ( executed > stats->max_cpu_time )
      stats->max_cpu_time = executed;
  #endif

  /*
   *  Update Wall time
   */
  #ifndef __RTEMS_USE_TICKS_FOR_STATISTICS__
    _Timestamp_Add_to( &stats->total_wall_time, &since_last_period );

    if ( _Timestamp_Less_than( &since_last_period, &stats->min_wall_time ) )
      stats->min_wall_time = since_last_period;

    if ( _Timestamp_Greater_than( &since_last_period, &stats->max_wall_time ) )
      stats->max_wall_time = since_last_period;
  #else

    /* Sanity check wall time */
    if ( since_last_period < executed )
      since_last_period = executed;

    stats->total_wall_time += since_last_period;

    if ( since_last_period < stats->min_wall_time )
      stats->min_wall_time = since_last_period;

    if ( since_last_period > stats->max_wall_time )
      stats->max_wall_time = since_last_period;
  #endif
}