comparison MasterLoop.c @ 31:e69579a0e797

Works multi-core.. pinned VP to a core loop
author Me
date Wed, 01 Sep 2010 08:23:39 -0700
parents c8823e0bb2b4
children 17d20e5cf924
comparison
equal deleted inserted replaced
8:acd91b87dcdc 9:73e221819099
40 * directly at end of master loop 40 * directly at end of master loop
41 *So VMS__init just births the master virtual processor same way it births 41 *So VMS__init just births the master virtual processor same way it births
42 * all the others -- then does any extra setup needed and puts it into the 42 * all the others -- then does any extra setup needed and puts it into the
43 * work queue. 43 * work queue.
44 *However means have to make masterEnv a global static volatile the same way 44 *However means have to make masterEnv a global static volatile the same way
45 * did with workQ in core loop. -- for performance, put the 45 * did with readyToAnimateQ in core loop. -- for performance, put the
46 * jump to the core loop directly in here, and have it directly jump back. 46 * jump to the core loop directly in here, and have it directly jump back.
47 *
48 *
49 *Aug 18, 2010 -- Going to a separate MasterVP for each core, to see if this
50 * avoids the suspected bug in the system stack that causes bizarre faults
51 * at random places in the system code.
52 *
53 *So, this function is coupled to each of the MasterVPs, -- meaning this
54 * function can't rely on a particular stack and frame -- each MasterVP that
55 * animates this function has a different one.
56 *
57 *At this point, the masterLoop does not write itself into the queue anymore,
58 * instead, the coreLoop acquires the masterLock when it has nothing to
59 * animate, and then animates its own masterLoop. However, still try to put
60 * several AppVPs into the queue to amortize the startup cost of switching
61 * to the MasterVP. Note, don't have to worry about latency of requests much
62 * because most requests generate work for same core -- only latency issue
63 * is case when other cores starved and one core's requests generate work
64 * for them -- so keep max in queue to 3 or 4..
47 */ 65 */
48 void masterLoop( void *initData, VirtProcr *masterPr ) 66 void masterLoop( void *initData, VirtProcr *animatingPr )
49 { 67 {
50 int slotIdx, numFilled, filledSlotIdx, masterHasBeenQueued; 68 int slotIdx;
51 VirtProcr *schedVirtPr; 69 VirtProcr *schedVirtPr;
52 SchedSlot *currSlot, **schedSlots, **filledSlots; 70 SchedSlot *currSlot, **schedSlots;
53 MasterEnv *masterEnv; 71 MasterEnv *masterEnv;
54 VMSQueueStruc *workQ; 72 VMSQueueStruc *readyToAnimateQ;
55 void *jmpPt, *stackPtrAddr, *framePtrAddr, *stillRunningAddr;
56 void *coreLoopFramePtr, *coreLoopStackPtr, *semanticEnv;
57 73
58 SlaveScheduler slaveScheduler; 74 SlaveScheduler slaveScheduler;
59 RequestHandler requestHandler; 75 RequestHandler requestHandler;
76 void *semanticEnv;
60 77
61 //this will run as the first virt processor in workQ, and will be a 78 int thisCoresIdx;
62 // new born -- so will do all the GCC-generated allocating space on 79 VirtProcr *masterPr;
63 // the stack owned by master virt procr -- and will run this last bit 80 volatile VirtProcr *volatileMasterPr;
64 // of setup code.. 81
82 volatileMasterPr = animatingPr;
83 masterPr = volatileMasterPr; //used to force re-define after jmp
84
85 //First animation of each MasterVP will in turn animate this part
86 // of setup code.. (VP creator sets up the stack as if this function
87 // was called normally, but actually get here by jmp)
88 //So, setup values about stack ptr, jmp pt and all that
65 masterPr->nextInstrPt = &&masterLoopStartPt; 89 masterPr->nextInstrPt = &&masterLoopStartPt;
66 90
67 //The second time MasterVP comes out of queue, the first animation of
68 // it hasn't written the stackPtr and framePtr yet -- but the second
69 // animation has already had its stackPtr and framePtr set to the old
70 // value by the coreLoop. Fix this by writing the correct stack and
71 // frame pointers here, at which point they're correct in the first
72 // animation of MasterVP.
73 //TODO: remove writing stackPtr and framePtr at the bottom, for eff
74 stackPtrAddr = &(masterPr->stackPtr);
75 framePtrAddr = &(masterPr->framePtr);
76 91
77 asm volatile("movl %0, %%eax; \ 92 //Note, got rid of writing the stack and frame ptr up here, because
78 movl %%esp, (%%eax); \ 93 // only one
79 movl %1, %%eax; \ 94 // core can ever animate a given MasterVP, so don't need to communicate
80 movl %%ebp, (%%eax); " 95 // new frame and stack ptr to the MasterVP storage before a second
81 /* outputs */ : "=g" (stackPtrAddr), "=g" (framePtrAddr) \ 96 // version of that MasterVP can get animated on a different core.
82 /* inputs */ : \ 97 //Also got rid of the busy-wait.
83 /* clobber */ : "memory", "%eax", "%ebx" \ 98
84 ); 99
100 masterLoopStartPt:
101
102 masterEnv = _VMSMasterEnv;
103
104 //TODO: check that compiles so that always re-define from frame-storage
105 masterPr = volatileMasterPr; //just to make sure after jmp
106 thisCoresIdx = masterPr->coreAnimatedBy;
107 readyToAnimateQ = masterEnv->readyToAnimateQs[thisCoresIdx];
108 schedSlots = masterEnv->allSchedSlots[thisCoresIdx];
109
110 requestHandler = masterEnv->requestHandler;
111 slaveScheduler = masterEnv->slaveScheduler;
112 semanticEnv = masterEnv->semanticEnv;
85 113
86 114
87 masterLoopStartPt: 115 //Poll each slot's Done flag
88
89 //if another reference to same Master VirtProcr still going, busy-wait
90 //Could put this lower, but don't want to think about shared stack..
91 while( _VMSMasterEnv->stillRunning ) /*busy wait*/ ;
92 //TODO: want to do busy-wait as assembly, to be sure stack not touched?
93
94 //this is the only master running now, set flag again
95 _VMSMasterEnv->stillRunning = TRUE;
96 masterEnv = _VMSMasterEnv;
97
98 //TODO: gdb -- check that a volatile _VMSMasterEnv and _VMSWorkQ means
99 // all these will be re-filled every time jump here..
100 workQ = _VMSWorkQ;
101 requestHandler = masterEnv->requestHandler;
102 slaveScheduler = masterEnv->slaveScheduler;
103 schedSlots = masterEnv->schedSlots;
104 filledSlots = masterEnv->filledSlots;
105 masterPr = masterEnv->masterVirtPr; //post-jmp clobbered, re-load
106 semanticEnv = masterEnv->semanticEnv;
107
108 //prepare for scheduling
109 numFilled = 0;
110 masterHasBeenQueued = FALSE;
111
112 //Poll each slot's Done flag -- slot 0 reserved for master, start at 1
113 for( slotIdx = 0; slotIdx < NUM_SCHED_SLOTS; slotIdx++) 116 for( slotIdx = 0; slotIdx < NUM_SCHED_SLOTS; slotIdx++)
114 { 117 {
115 currSlot = schedSlots[ slotIdx ]; 118 currSlot = schedSlots[ slotIdx ];
116 119
117 if( currSlot->workIsDone ) 120 if( currSlot->workIsDone )
123 (*requestHandler)( currSlot->procrAssignedToSlot, semanticEnv ); 126 (*requestHandler)( currSlot->procrAssignedToSlot, semanticEnv );
124 } 127 }
125 if( currSlot->needsProcrAssigned ) 128 if( currSlot->needsProcrAssigned )
126 { //give slot a new virt procr 129 { //give slot a new virt procr
127 schedVirtPr = 130 schedVirtPr =
128 (*slaveScheduler)( semanticEnv ); 131 (*slaveScheduler)( semanticEnv, thisCoresIdx );
129 132
130 if( schedVirtPr != NULL ) 133 if( schedVirtPr != NULL )
131 { currSlot->procrAssignedToSlot = schedVirtPr; 134 { currSlot->procrAssignedToSlot = schedVirtPr;
132 schedVirtPr->schedSlot = currSlot; 135 schedVirtPr->schedSlot = currSlot;
133 currSlot->needsProcrAssigned = FALSE; 136 currSlot->needsProcrAssigned = FALSE;
134 137
135 filledSlots[ numFilled ] = currSlot; 138 writeSRSWQ( schedVirtPr, readyToAnimateQ );
136
137 writeVMSQ( schedVirtPr, workQ );
138 numFilled += 1;
139
140 if( numFilled == masterEnv->numToPrecede )
141 {
142 writeVMSQ( masterEnv->masterVirtPr, workQ );
143 masterHasBeenQueued = TRUE;
144 }
145
146 } 139 }
147 } 140 }
148 } 141 }
149 142
150 if( !masterHasBeenQueued )
151 {
152 writeVMSQ( masterEnv->masterVirtPr, workQ );
153 }
154 143
155 //Adjust the number to precede, for next round -- assume rate of 144 //Save stack ptr and frame, restore CoreLoop's stack and frame,
156 // finishing work is stable -- which is a bad assumption! But, just 145 // and clear the MasterLock
157 // want something working for the moment, look at dynamic behavior
158 // later
159 //TODO: look at dynamic behavior -- time-average numToPrecede or something
160 if( numFilled < NUM_CORES - 1 )
161 {
162 masterEnv->numToPrecede = 1;
163 }
164 else
165 { masterEnv->numToPrecede = numFilled - NUM_CORES + 1;
166 }
167
168 //Save stack ptr and frame -- don't need to, take out later, but safe
169 // Also, wait to set stillRunning to FALSE until just before jump, to
170 // be safe -- although the two simulatneously animated MasterLoops
171 // are on different cores, so have different stacks, so no worries
172 // there.
173 //Restore CoreLoop's stack frame (and stack pointer, to be safe)
174 //TODO: cafefully verify don't need to force saving anything to stack 146 //TODO: cafefully verify don't need to force saving anything to stack
175 // before jumping back to core loop. 147 // before jumping back to core loop.
148 void *stackPtrAddr, *framePtrAddr, *masterLockAddr;
149 void *jmpPt, *coreLoopFramePtr, *coreLoopStackPtr;
150
176 stackPtrAddr = &(masterPr->stackPtr); 151 stackPtrAddr = &(masterPr->stackPtr);
177 framePtrAddr = &(masterPr->framePtr); 152 framePtrAddr = &(masterPr->framePtr);
178 stillRunningAddr = &(_VMSMasterEnv->stillRunning); //when race condition 153 masterLockAddr = &(_VMSMasterEnv->masterLock);
179 //arises, stillRunning is shared between the two cores both animating
180 // MasterLoop -- but those two cores have different esp & ebp, so safe
181 // to change stack and frame pointer here, without one messing up other
182 // one
183 154
184 jmpPt = masterPr->coreLoopStartPt; 155 jmpPt = _VMSMasterEnv->coreLoopStartPt;
185 coreLoopFramePtr = masterPr->coreLoopFramePtr;//need this only 156 coreLoopFramePtr = masterPr->coreLoopFramePtr;//need this only
186 coreLoopStackPtr = masterPr->coreLoopStackPtr;//shouldn't need -- safety 157 coreLoopStackPtr = masterPr->coreLoopStackPtr;//shouldn't need -- safety
187 158
188 asm volatile("movl %0, %%eax; \ 159 asm volatile("movl %0, %%eax; \
189 movl %%esp, (%%eax); \ 160 movl %%esp, (%%eax); \
194 movl %4, %%esp; \ 165 movl %4, %%esp; \
195 movl %5, %%ebp; \ 166 movl %5, %%ebp; \
196 movl $0x0, (%%ebx); \ 167 movl $0x0, (%%ebx); \
197 jmp %%eax;" \ 168 jmp %%eax;" \
198 /* outputs */ : "=g" (stackPtrAddr), "=g" (framePtrAddr), \ 169 /* outputs */ : "=g" (stackPtrAddr), "=g" (framePtrAddr), \
199 "=g"(stillRunningAddr) \ 170 "=g"(masterLockAddr) \
200 /* inputs */ : "g" (jmpPt), "g"(coreLoopStackPtr), "g"(coreLoopFramePtr)\ 171 /* inputs */ : "g" (jmpPt), "g"(coreLoopStackPtr), "g"(coreLoopFramePtr)\
201 /* clobber */ : "memory", "%eax", "%ebx", "%ecx", "%edx", "%edi", "%esi" \ 172 /* clobber */ : "memory", "%eax", "%ebx", "%ecx", "%edx", "%edi", "%esi" \
202 );//can probably make clobber list empty -- but safe for now 173 );//can probably make clobber list empty -- but safe for now
203 } 174 }
204 175