Skip to content

Commit

Permalink
Exec: ExecuteSlices takes tickCount duration parameter
Browse files Browse the repository at this point in the history
Previously, ExecuteSlices would run a specified number threaded snippet segments and return.
If there was not much to execute in the current clump it exited quickly which caused a lot of overhead.
Now it can stay in the inner loop longer. 50x performance improvement for JavaScript.
  • Loading branch information
Paul Austin committed Jun 4, 2014
1 parent 9138aea commit fc8c495
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 56 deletions.
2 changes: 1 addition & 1 deletion Vireo_Web/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ help:
# -O3 833k / -Os 760k / -Oz 719k

EM_OPT= -O3 -s NO_EXIT_RUNTIME=1
EMFLAGS= -I$(INCDIR) -DkVireoOS_emscripten $(EM_OPT)
EMFLAGS= -I$(INCDIR) -DkVireoOS_emscripten -DVIREO_LEAN $(EM_OPT)

EM_EXPORTS = -s EXPORTED_FUNCTIONS="[\
'_Vireo_Version', \
Expand Down
2 changes: 1 addition & 1 deletion source/CommandLine/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ int VIREO_MAIN(int argc, const char * argv[])


void RunExec() {
gShells._eState = gShells._pShell->TheExecutionContext()->ExecuteSlices(400);
gShells._eState = gShells._pShell->TheExecutionContext()->ExecuteSlices(400, 10000000);
// TODO control frame rate based on time till next thing to exec

if (gShells._eState == kExecutionState_None) {
Expand Down
4 changes: 2 additions & 2 deletions source/core/CEntryPoints.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ VIREO_EXPORT void EggShell_REPL(EggShell* pShell, const Utf8Char* commands, Int3
//------------------------------------------------------------
VIREO_EXPORT Int32 EggShell_ExecuteSlices(EggShell* pShell, Int32 numSlices)
{
return pShell->TheExecutionContext()->ExecuteSlices(numSlices);
return pShell->TheExecutionContext()->ExecuteSlices(numSlices, 20);
}
//------------------------------------------------------------
VIREO_EXPORT void EggShell_SetDelayedLoad(EggShell* pShell, bool value)
Expand All @@ -66,7 +66,7 @@ VIREO_EXPORT void ExecutionContext_EnqueRunQueue(ExecutionContext* pContext, VIC
//------------------------------------------------------------
VIREO_EXPORT Int32 ExecutionContext_ExecuteSlices(ExecutionContext* pContext, Int32 numSlices)
{
return pContext->ExecuteSlices(numSlices);
return pContext->ExecuteSlices(numSlices, 1);
}
//------------------------------------------------------------
VIREO_EXPORT Int32 EggShell_PeekMemory(EggShell* pShell, const char* viName, const char* eltName, Int32 bufferSize, char* buffer)
Expand Down
128 changes: 82 additions & 46 deletions source/core/ExecutionContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ _PROGMEM Instruction0 ExecutionContext::_culDeSac;
InstructionFunction ExecutionContext::_culDeSacFunction;

#ifdef VIVM_SINGLE_EXECUTION_CONTEXT
QueueElt* ExecutionContext::_triggeredIsrList; // Elts waiting for something external to wake them up
Queue ExecutionContext::_runQueue; // Elts ready To run
QueueElt* ExecutionContext::_sleepingList; // Elts waiting for something external to wake them up
QueueElt* ExecutionContext::_runningQueueElt; // Elt actually running
VIClump* ExecutionContext::_triggeredIsrList; // Elts waiting for something external to wake them up
Queue ExecutionContext::_runQueue; // Elts ready To run
VIClump* ExecutionContext::_sleepingList; // Elts waiting for something external to wake them up
VIClump* ExecutionContext::_runningQueueElt; // Elt actually running
uIntFastSmall ExecutionContext::_breakoutCount;
#endif

Expand Down Expand Up @@ -132,17 +132,31 @@ VIREO_FUNCTION_SIGNATURE1(WaitUntilMicroseconds, Int64)
return THREAD_EXEC()->WaitUntilTickCount(PlatformTime::MicrosecondsToTickCount(_Param(0)), _NextInstruction());
}
//------------------------------------------------------------
InstructionCore* ExecutionContext::WaitUntilTickCount(Int64 count, InstructionCore* nextInClump)
InstructionCore* ExecutionContext::WaitUntilTickCount(PlatformTickType tickCount, InstructionCore* nextInClump)
{
VIClump* current = _runningQueueElt;
InstructionCore* next = SuspendRunningQueueElt(nextInClump);

VIREO_ASSERT( (current->_next == null) )
VIREO_ASSERT( (current->_shortCount == 0) )

current->_wakeUpInfo = count;
current->_next = _sleepingList;
_sleepingList = current;
current->_wakeUpInfo = tickCount;

if (_sleepingList == null) {
// No list, now there is one.
current->_next = null;
_sleepingList = current;
} else {
// Insert into the list based on wake-up time.
VIClump** pFix = &_sleepingList;
VIClump* node = *pFix;
while (node && (tickCount < node->_wakeUpInfo)) {
pFix = &(node->_next);
node = *pFix;
}
current->_next = node;
*pFix = current;
}
return next;
}
//------------------------------------------------------------
Expand Down Expand Up @@ -276,51 +290,80 @@ InstructionCore* ExecutionContext::SuspendRunningQueueElt(InstructionCore* nextI
}
}
//------------------------------------------------------------
ExecutionState ExecutionContext::ExecuteSlices(Int32 numSlices)
ExecutionState ExecutionContext::ExecuteSlices(Int32 numSlices, PlatformTickType tickCount)
{
ExecutionContextScope scope(this);

VIREO_ASSERT( (_runningQueueElt == null) )

PlatformTickType currentTime = PlatformTime::TickCount();
PlatformTickType breakOutTime = currentTime + tickCount;

if (_sleepingList != null) {
// Are any sleeping clumps ready to wake up.
CheckOccurrences(PlatformTime::TickCount());
CheckOccurrences(currentTime);
}

_runningQueueElt = _runQueue.Dequeue();
if (_runningQueueElt != null)
InstructionCore* currentInstruction =_runningQueueElt ? _runningQueueElt->_savePc : null;

while (_runningQueueElt)
{
InstructionCore* currentInstruction = _runningQueueElt->_savePc;
_breakoutCount = numSlices; // TODO this was initial hack for first demo
_breakoutCount = numSlices;

VIREO_ASSERT( (currentInstruction != null) )
VIREO_ASSERT( (null == _runningQueueElt->_next) ) // Should not be on queue
VIREO_ASSERT( (0 == _runningQueueElt->_shortCount) ) // Should not be running if triggers > 0
do {
currentInstruction = _PROGMEM_PTR(currentInstruction,_function)(currentInstruction);
currentInstruction = _PROGMEM_PTR(currentInstruction,_function)(currentInstruction);
#ifdef VIVM_UNROLL_EXEC
currentInstruction = _PROGMEM_PTR(currentInstruction,_function)(currentInstruction);
currentInstruction = _PROGMEM_PTR(currentInstruction,_function)(currentInstruction);
currentInstruction = _PROGMEM_PTR(currentInstruction,_function)(currentInstruction);
currentInstruction = _PROGMEM_PTR(currentInstruction,_function)(currentInstruction);
currentInstruction = _PROGMEM_PTR(currentInstruction,_function)(currentInstruction);
currentInstruction = _PROGMEM_PTR(currentInstruction,_function)(currentInstruction);
currentInstruction = _PROGMEM_PTR(currentInstruction,_function)(currentInstruction);
currentInstruction = _PROGMEM_PTR(currentInstruction,_function)(currentInstruction);
currentInstruction = _PROGMEM_PTR(currentInstruction,_function)(currentInstruction);
currentInstruction = _PROGMEM_PTR(currentInstruction,_function)(currentInstruction);
currentInstruction = _PROGMEM_PTR(currentInstruction,_function)(currentInstruction);
currentInstruction = _PROGMEM_PTR(currentInstruction,_function)(currentInstruction);
currentInstruction = _PROGMEM_PTR(currentInstruction,_function)(currentInstruction);
currentInstruction = _PROGMEM_PTR(currentInstruction,_function)(currentInstruction);
currentInstruction = _PROGMEM_PTR(currentInstruction,_function)(currentInstruction);
currentInstruction = _PROGMEM_PTR(currentInstruction,_function)(currentInstruction);
currentInstruction = _PROGMEM_PTR(currentInstruction,_function)(currentInstruction);
currentInstruction = _PROGMEM_PTR(currentInstruction,_function)(currentInstruction);
#endif
} while (_breakoutCount-- > 0);

if (currentInstruction == &_culDeSac) {
VIREO_ASSERT(_runningQueueElt == null)
} else {
VIREO_ASSERT(currentInstruction != null)
VIREO_ASSERT(_runningQueueElt != null)

// Put active elt back in RunQueue, causes rotation if several elements in the Queue
currentTime = PlatformTime::TickCount();
if (_sleepingList != null) {
// Are any sleeping clumps ready to wake up.
CheckOccurrences(currentTime);
}

if (currentTime < breakOutTime) {
if (_runningQueueElt) {
if(!_runQueue.IsEmpty()) {
// Time left, still working, something else to do, rotate tasks
VIREO_ASSERT(currentInstruction != null)
VIREO_ASSERT(_runningQueueElt != null)

_runningQueueElt->_savePc = currentInstruction;
VIClump *eltToReQueue = _runningQueueElt;
_runningQueueElt = null;
_runQueue.Enqueue(eltToReQueue);
_runningQueueElt = _runQueue.Dequeue();
currentInstruction = _runningQueueElt->_savePc;
} else {
// Time left, still working, nothing else to do, continue as is.
VIREO_ASSERT(currentInstruction != null)
VIREO_ASSERT(_runningQueueElt != null)
}
} else {
// Time left, nothing running, see if something woke up.
_runningQueueElt = _runQueue.Dequeue();
}
} else if (_runningQueueElt) {
// No time left, still working, save current state.
VIREO_ASSERT(currentInstruction != &_culDeSac)
_runningQueueElt->_savePc = currentInstruction;
VIClump *eltToReQueue = _runningQueueElt;
_runningQueueElt = null;
_runQueue.Enqueue(eltToReQueue);
} else {
// No time left, nothing running, fine, loop will exit.
}
}

Expand All @@ -337,13 +380,13 @@ ExecutionState ExecutionContext::ExecuteSlices(Int32 numSlices)

return reply;
}

//------------------------------------------------------------
void ExecutionContext::EnqueueRunQueue(VIClump* elt)
{
VIREO_ASSERT((0 == elt->_shortCount))
_runQueue.Enqueue(elt);
}

//------------------------------------------------------------
#ifdef VIVM_SUPPORTS_ISR
// Interrupts should already be disabled when this is called
// so there is no need to add guards inside.
Expand All @@ -359,9 +402,7 @@ void ExecutionContext::IsrEnqueue(QueueElt* elt)
}
}
#endif

// ??? not safe for UInt32 rollover ( the 39.7 day rollover problem)
// CheckOccurrences
//------------------------------------------------------------
void ExecutionContext::CheckOccurrences(PlatformTickType t)
{
VIClump* pClump;
Expand All @@ -377,10 +418,10 @@ void ExecutionContext::CheckOccurrences(PlatformTickType t)
pClump->_next = null;
pClump->_wakeUpInfo = 0; //Put in known state.
_runQueue.Enqueue(elt);
}
else
{
pFix = &pClump->_next;
} else {
// Items are sorted at insertion, so once a time in the future
// is found quit the loop.
break;
}
elt = *pFix;
}
Expand All @@ -401,11 +442,6 @@ void ExecutionContext::CheckOccurrences(PlatformTickType t)
VIREO_ISR_ENABLE
}
#endif

// ??? if msCount is less than last one then wrap around has happened
// go through list,
// each go through each waiting element.
// decrement count by delta, if less than zero then enqueue.
}

DEFINE_VIREO_BEGIN(LabVIEW_Execution1)
Expand Down
4 changes: 2 additions & 2 deletions source/core/TimeTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ PlatformTickType PlatformTime::TickCount()
#elif (kVireoOS_emscripten)

// milliseconds
return (Int64) emscripten_get_now();
return (PlatformTickType) emscripten_get_now();

#elif (kVireoOS_ZynqARM)

Expand Down Expand Up @@ -129,7 +129,7 @@ PlatformTickType PlatformTime::TickCount()
}

//------------------------------------------------------------
Int64 PlatformTime::MicrosecondsToTickCount(PlatformTickType microseconds)
PlatformTickType PlatformTime::MicrosecondsToTickCount(Int64 microseconds)
{
#if defined(_WIN32) || defined(_WIN64)

Expand Down
9 changes: 5 additions & 4 deletions source/include/ExecutionContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,13 @@ class ExecutionContext

private:
ECONTEXT Queue _runQueue; //! Clumps ready to run
ECONTEXT VIClump* _sleepingList; //! Clumps waiting for something external to wake them up
ECONTEXT VIClump* _sleepingList; //! Clumps waiting for a point in time wake them up
ECONTEXT IntSmall _breakoutCount; //! Inner execution loop "breaks out" when this gets to 0

public:
ExecutionContext(TypeManager* typeManager);
ECONTEXT PlatformTickType PlatformTickCount();

#ifdef VIREO_SUPPORTS_ISR
ECONTEXT VIClump* _triggeredIsrList; // Elts waiting for something external to wake them up
ECONTEXT void IsrEnqueue(QueueElt* elt);
Expand All @@ -104,11 +105,11 @@ class ExecutionContext
ECONTEXT void ExecuteFunction(FunctionClump* fclump); // Run a simple function to completion.

// Run the concurrent execution system for a short period of time
ECONTEXT ExecutionState ExecuteSlices(Int32 numSlices);
ECONTEXT ExecutionState ExecuteSlices(Int32 numSlices, PlatformTickType tickCount);
ECONTEXT InstructionCore* SuspendRunningQueueElt(InstructionCore* whereToWakeUp);
InstructionCore* Stop();
ECONTEXT InstructionCore* Stop();
ECONTEXT void ClearBreakout() { _breakoutCount = 0; }
InstructionCore* WaitUntilTickCount(Int64 count, InstructionCore* next);
ECONTEXT InstructionCore* WaitUntilTickCount(PlatformTickType count, InstructionCore* next);
ECONTEXT void EnqueueRunQueue(VIClump* elt);
ECONTEXT VIClump* _runningQueueElt; // Element actually running

Expand Down
3 changes: 3 additions & 0 deletions source/include/TimeTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ namespace Vireo
//------------------------------------------------------------
#if defined (__ARDUINO__)
typedef UInt32 PlatformTickType;
#elif kVireoOS_emscripten
typedef Int64 PlatformTickType;
// typedef Double PlatformTickType; (slightly more native for JavaScript/emscripten)
#else
typedef Int64 PlatformTickType;
#endif
Expand Down

0 comments on commit fc8c495

Please sign in to comment.