source: rtems/cpukit/score/src/schedulersimplesmpschedule.c @ ba7bc099

4.115
Last change on this file since ba7bc099 was ba7bc099, checked in by Joel Sherrill <joel.sherrill@…>, on 05/17/11 at 19:48:44

2011-05-17 Joel Sherrill <joel.sherrill@…>

PR 1789/cpukit

  • sapi/include/confdefs.h, score/Makefile.am, score/preinstall.am: Add Simple SMP Priority Scheduler.
  • score/include/rtems/score/schedulersimplesmp.h, score/src/schedulersimplesmpblock.c, score/src/schedulersimplesmpschedule.c, score/src/schedulersimplesmpunblock.c: New files.
  • Property mode set to 100644
File size: 7.6 KB
Line 
1/*
2 *  Scheduler Simple SMP Handler / Schedule
3 *
4 *  COPYRIGHT (c) 2011.
5 *  On-Line Applications Research Corporation (OAR).
6 *
7 *  The license and distribution terms for this file may be
8 *  found in found in the file LICENSE in this distribution or at
9 *  http://www.rtems.com/license/LICENSE.
10 *
11 *  $Id$
12 */
13
14#if HAVE_CONFIG_H
15#include "config.h"
16#endif
17
18#include <rtems/system.h>
19#include <rtems/score/smp.h>
20#include <rtems/score/schedulersimplesmp.h>
21
22#include <stdio.h>
23
24/*
25 *  The following is very useful on the scheduler simulator when debugging
26 *  this algorithm.  You are not likely to be able to print like this when
27 *  running on a real system.
28 *
29 *  NOTE: This is NOT using RTEMS_DEBUG because this is not consistency
30 *        checking and is VERY VERY noisy.  It is just for debugging
31 *        the algorithm.
32 */
33#if 0
34#define D(format,...) printk( format, __VA_ARGS__)
35#else
36#define D(format,...)
37#endif
38
39/**
40 *  @brief Assign Heir Thread to CPU
41 *
42 *  This method attempts to find a core for the thread under consideration
43 *  (@a consider) to become heir of.  The placement takes into account
44 *  priority, preemptibility, and length of time on core.
45 *
46 *  Combined with the loop in _Scheduler_simple_smp_Schedule, it attempts
47 *  to faithfully implement the behaviour of the Deterministic Priority
48 *  Scheduler while spreading the threads across multiple cores.
49 *
50 *  @param[in] consider is the thread under consideration.  This means
51 *             that the method is looking for the best core to place it
52 *             as heir.
53 *
54 *  @return This method returns true if it was able to make @a consider
55 *          the heir on a core and false otherwise.  When this returns
56 *          false, there is no point in attempting to place an heir of
57 *          of lower priority.
58 */
59
60bool _Scheduler_simple_smp_Assign(
61  Thread_Control *consider
62)
63{
64  bool            found;       /* have we found a cpu to place it on? */
65  uint32_t        found_cpu;   /* CPU to place this thread */
66  bool            blocked;     /* CPU has blocked thread? */
67  Thread_Control *pheir;       /* heir on found cpu to potentially replace */
68  Thread_Control *h;
69  Thread_Control *e;
70  uint32_t        cpu;
71
72  /*
73   *  Initialize various variables to indicate we have not found
74   *  a potential core for the thread under consideration.
75   */
76  found     = false;
77  blocked   = false;
78  found_cpu = 0;
79  pheir     = NULL;
80
81  for ( cpu=0 ; cpu < _SMP_Processor_count ; cpu++ ) {
82    D( "SCHED CPU=%d consider=0x%08x ASSIGN\n", cpu, consider->Object.id );
83
84    /*
85     *  If the thread under consideration is already executing or
86     *  heir, then we don't have a better option for it.
87     */
88    e = _Per_CPU_Information[cpu].executing;
89    if ( e == consider ) {
90      D( "SCHED CPU=%d Executing=0x%08x considering=0x%08x ASSIGNED\n",
91        cpu, e->Object.id, consider->Object.id );
92      return true;
93    }
94
95    if ( !_States_Is_ready( e->current_state ) ) {
96      pheir     = h;
97      found_cpu = cpu;
98      found     = true;
99      blocked   = true;
100      D( "SCHED CPU=%d PHeir=0x%08x considering=0x%08x BLOCKED\n",
101        cpu, h->Object.id, consider->Object.id );
102      continue;
103    }
104
105    h = _Per_CPU_Information[cpu].heir;
106    if ( h == consider ) {
107      D( "SCHED CPU=%d Heir=0x%08x considering=0x%08x ASSIGNED\n",
108        cpu, h->Object.id, consider->Object.id );
109      return true;
110    }
111
112    if ( blocked )
113      continue;
114
115    /*
116     *  If we haven't found a potential CPU to locate the thread
117     *  under consideration on, we need to consider if this is a
118     *  more important threads first (e.g. priority <).
119     *
120     *  But when a thread changes its priority and ends up at the end of
121     *  the priority group for the new heir, we also need to schedule
122     *  a new heir.  This is the "=" part of the check.
123     */
124    if ( !found ) {
125      if ( consider->current_priority <= h->current_priority ) {
126        pheir     = h;
127        found_cpu = cpu;
128        found     = true;
129        D( "SCHED CPU=%d PHeir=0x%08x considering=0x%08x MAYBE #1\n",
130          cpu, h->Object.id, consider->Object.id );
131      }
132
133      continue;
134    }
135
136    /*
137     *  Past this point, found is true.
138     */
139
140    /*
141     *  If we have found a potential CPU on which to make the
142     *  thread under consideration the heir, then we need to
143     *  check if the current CPU is a more appropriate place
144     *  for this thread to be placed.
145     *
146     *  Check 1: heir of potential CPU is more important
147     *           then heir of current CPU.  We want to
148     *           replace the least important thread possible.
149     */
150    if ( h->current_priority > pheir->current_priority ) {
151      pheir = h;
152      found_cpu = cpu;
153      D( "SCHED CPU=%d PHeir=0x%08x considering=0x%08x MAYBE #2\n",
154        cpu, h->Object.id, consider->Object.id );
155      continue;
156    }
157
158    if ( h->current_priority > pheir->current_priority )
159      continue;
160
161    /*
162     *  If heir of potential CPU and of the current CPU are of the SAME
163     *  priority, then which has been running longer?
164     *
165     *           Which CPU has had its executing thread longer?
166     */
167    if ( _Timestamp_Less_than(
168           &_Per_CPU_Information[cpu].time_of_last_context_switch,
169           &_Per_CPU_Information[found_cpu].time_of_last_context_switch
170         ) ) {
171      pheir = h;
172      found_cpu = cpu;
173      D( "SCHED CPU=%d PHeir=0x%08x considering=0x%08x LONGER\n",
174        cpu, h->Object.id, consider->Object.id );
175      continue;
176    }
177
178    /*
179     *  If we are looking at a core with a non-preemptible thread
180     *  for potential placement, then favor a core with a preeemtible
181     *  thread of the same priority.  This should help avoid priority
182     *  inversions and let threads run earlier.
183     */
184    if ( !pheir->is_preemptible && h->is_preemptible ) {
185      pheir = h;
186      found_cpu = cpu;
187      D( "SCHED CPU=%d PHeir=0x%08x considering=0x%08x PREEMPTIBLE\n",
188        cpu, h->Object.id, consider->Object.id );
189      continue;
190   
191    }
192  }
193
194  /*
195   *  If we found a cpu to make this thread heir of, then we
196   *  need to consider whether we need a dispatch on that CPU.
197   */
198  if ( found ) {
199    e = _Per_CPU_Information[found_cpu].executing;
200    D( "SCHED CPU=%d executing=0x%08x considering=0x%08x FOUND\n",
201      found_cpu, e->Object.id, consider->Object.id );
202    _Per_CPU_Information[found_cpu].heir = consider;
203    if ( !_States_Is_ready( e->current_state ) ) {
204       D( "SCHED CPU=%d executing not ready dispatch needed\n", found_cpu);
205      _Per_CPU_Information[found_cpu].dispatch_necessary = true;
206    } else if ( consider->current_priority < e->current_priority ) {
207      if ( e->is_preemptible || consider->current_priority == 0 ) {
208         D( "SCHED CPU=%d preempting\n", found_cpu);
209        _Per_CPU_Information[found_cpu].dispatch_necessary = true;
210      }
211    }
212  }
213
214  /*
215   *  Return true to indicate we changed an heir.  This indicates
216   *  scheduling needs to examine more threads.
217   */
218  return found;
219}
220
221/*
222 *  Reschedule threads -- select heirs for all cores
223 */
224void _Scheduler_simple_smp_Schedule(void)
225{
226  Chain_Control  *c;
227  Chain_Node     *n;
228  Thread_Control *t;
229  uint32_t        cpu;
230
231  c   = (Chain_Control *)_Scheduler.information;
232  cpu = 0;
233
234  /*
235   *  Iterate over the first N (where N is the number of CPU cores) threads
236   *  on the ready chain.  Attempt to assign each as heir on a core.  When
237   *  unable to assign a thread as a new heir, then stop.
238   */
239  for (n = _Chain_First(c); !_Chain_Is_tail(c, n); n = _Chain_Next(n)) {
240    t = (Thread_Control *)n;
241    if ( !_Scheduler_simple_smp_Assign( t ) )
242      break;
243    if ( ++cpu >= _SMP_Processor_count )
244      break;
245  }
246}
Note: See TracBrowser for help on using the repository browser.