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; }
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 }