This is central object in this algorithm, it is responsible for spawning threads and managing the order that work units are executed. More...
#include <framescheduler.h>
Public Types | |
typedef DefaultThreadSpecificStorage::Type | Resource |
The kind of Resource the frame scheduler will use. | |
Public Member Functions | |
FrameScheduler (std::fstream *_LogDestination=0, Whole StartingThreadCount=GetCPUCount()) | |
Create a Framescheduler that owns a filestream for logging. More... | |
FrameScheduler (std::ostream *_LogDestination, Whole StartingThreadCount=GetCPUCount()) | |
Create a Framescheduler, that logs to an unowned stream. More... | |
virtual | ~FrameScheduler () |
Destructor. More... | |
virtual void | AddWorkUnitAffinity (iWorkUnit *MoreWork, const String &WorkUnitName) |
Add a normal Mezzanine::Threading::iWorkUnit to this For scheduling. More... | |
virtual void | AddWorkUnitMain (iWorkUnit *MoreWork, const String &WorkUnitName) |
Add a normal Mezzanine::Threading::iWorkUnit to this For fcheduling. More... | |
virtual void | AddWorkUnitMonopoly (MonopolyWorkUnit *MoreWork, const String &WorkUnitName) |
Add a MonopolyWorkUnit for execution at the beginning of the frame. More... | |
virtual bool | AreAllWorkUnitsComplete () |
Is the work of the frame done? More... | |
virtual void | CreateThreads () |
This is the 2nd step (of 6) in a frame. More... | |
void | DependenciesChanged (bool Changed=true) |
Indicate to the framescheduler if dependencies need to be logged. More... | |
virtual void | DoOneFrame () |
Do one frame worth of work. More... | |
virtual MaxInt | GetCurrentFrameStart () const |
When did this frame start? More... | |
virtual Whole | GetDependentCountOf (iWorkUnit *Work, bool UsedCachedDepedentGraph=false) |
How many other WorkUnit instances must wait on this one. More... | |
virtual Whole | GetFrameCount () const |
Get the current number of frames that have elapsed. More... | |
virtual Whole | GetFrameLength () const |
Get the desired length of a frame. More... | |
DefaultRollingAverage< Whole > ::Type & | GetFrameTimeRollingAverage () |
Get The complete record of the durations of the last few frames. More... | |
Whole | GetLastFrameTime () const |
How long was the previous frame? More... | |
Whole | GetLastPauseTime () const |
How long was the pause, if any, last frame? More... | |
std::ostream & | GetLog () |
Get the endpoint for the logs. More... | |
virtual iWorkUnit * | GetNextWorkUnit () |
Gets the next available workunit for execution. More... | |
virtual iWorkUnit * | GetNextWorkUnitAffinity () |
Just like GetNextWorkUnit except that it also searches through and prioritizes work units with affinity too. More... | |
DefaultRollingAverage< Whole > ::Type & | GetPauseTimeRollingAverage () |
Get The complete record of the past durations of the Pauses Each frame. More... | |
virtual Whole | GetThreadCount () |
Get the amount of threads that will be used to execute WorkUnits a the start of the next frame. More... | |
Resource * | GetThreadResource (ThreadId ID=this_thread::get_id()) |
Get the Resource to go with a thread of a given ID. More... | |
Logger * | GetThreadUsableLogger (ThreadId ID=this_thread::get_id()) |
Get the logger safe to use this thread. More... | |
Whole | GetWorkUnitAffinityCount () const |
Returns the amount of iWorkUnit ready to be scheduled in the Affinity pool. More... | |
Whole | GetWorkUnitMainCount () const |
Returns the amount of iWorkUnit ready to be scheduled in the Main pool. More... | |
Whole | GetWorkUnitMonopolyCount () const |
Returns the amount of MonopolyWorkUnit ready to be scheduled. More... | |
void | JoinAllThreads () |
This is the 4th step (of 6) in a frame. More... | |
void | LogDependencies () |
This sends the dependencies to the LogDestination (Skipping any thread specific resources) More... | |
virtual void | RemoveWorkUnitAffinity (iWorkUnit *LessWork) |
Remove a WorkUnit from the Affinity pool of WorkUnits (and not from the Main group or MonpolyWorkUnits). More... | |
virtual void | RemoveWorkUnitMain (iWorkUnit *LessWork) |
Remove a WorkUnit from the main pool of WorkUnits (and not from the groups of Affinity or MonpolyWorkUnits). More... | |
virtual void | RemoveWorkUnitMonopoly (MonopolyWorkUnit *LessWork) |
Remove a WorkUnit from the Monopoly pool of WorkUnits (and not from the Main or Affinity group). More... | |
virtual void | ResetAllWorkUnits () |
This is the 5th step (of 6) in a frame. More... | |
virtual void | RunAllMonopolies () |
This is the 1st step (of 6) in a frame. More... | |
virtual void | RunMainThreadWork () |
This is the 3rd step (of 6) in a frame. More... | |
virtual void | SetFrameLength (const Whole &FrameLength) |
Set the Desired length of a frame in microseconds. More... | |
virtual void | SetFrameRate (const Whole &FrameRate) |
Set the desired Frate rate. More... | |
virtual void | SetThreadCount (const Whole &NewThreadCount) |
Set the amount of threads to use. More... | |
virtual void | SortWorkUnitsAffinity (bool UpdateDependentGraph_=true) |
Sort the WorkUnits that must run on the main thread to allow them to be used more efficiently in the next frame executed. More... | |
virtual void | SortWorkUnitsAll (bool UpdateDependentGraph_=true) |
Sort all the WorkUnits that must run on the main thread to allow them to be used more efficiently in the next frame executed. More... | |
virtual void | SortWorkUnitsMain (bool UpdateDependentGraph_=true) |
Sort the the main pool of WorkUnits to allow them to be used more efficiently in the next frame executed. More... | |
virtual void | UpdateDependentGraph () |
Create a reverse depedent graph that can be used for sorting Mezzanine::Threading::iWorkUnit "iWorkUnit"s to optimize execution each frame. More... | |
void | WaitUntilNextFrame () |
This is the final step (of 6) in a frame. More... | |
Protected Types | |
typedef std::vector < WorkUnitKey > ::const_iterator | ConstIteratorAffinity |
A const iterator suitable for iterating over the main pool of work units. | |
typedef std::vector < WorkUnitKey > ::const_iterator | ConstIteratorMain |
A const iterator suitable for iterating over the main pool of work units. | |
typedef std::vector < MonopolyWorkUnit * > ::const_iterator | ConstIteratorMonopoly |
A const iterator suitable for iterating over the main pool of work units. | |
typedef std::map< iWorkUnit *, std::set< iWorkUnit * > > | DependentGraphType |
A structure designed to minimalistically represent Dependency and Reverse Dependency Graphs in work units. | |
typedef std::vector < WorkUnitKey >::iterator | IteratorAffinity |
An iterator suitable for iterating over the main pool of work units. | |
typedef std::vector < WorkUnitKey >::iterator | IteratorMain |
An iterator suitable for iterating over the main pool of work units. | |
typedef std::vector < MonopolyWorkUnit * > ::iterator | IteratorMonoply |
An iterator suitable for iterating over the main pool of work units. | |
Protected Member Functions | |
void | CleanUpThreads () |
Used in destruction to tear down threads. | |
void | DeleteThreads () |
Simply iterates over and deletes everything in Threads. | |
void | UpdateDependentGraph (const std::vector< WorkUnitKey > &Units) |
Adds the dependencies of the iWorkUnits in the passed containter to the the internal reverse dependency graph. More... | |
void | UpdateWorkUnitKeys (std::vector< WorkUnitKey > &Units) |
Iterate over the passed container of WorkUnitKeys and refresh them with the correct data from their respective iWorkUnits. More... | |
Protected Attributes | |
MaxInt | CurrentFrameStart |
What time did the current Frame Start at. | |
MaxInt | CurrentPauseStart |
What time did the current Frame Start at. | |
Whole | CurrentThreadCount |
How many threads will this try to execute with in the next frame. | |
DependentGraphType | DependentGraph |
This structure allows reverse lookup of dependencies. More... | |
Whole | FrameCount |
Used to store a count of frames from the begining of game execution. More... | |
DefaultRollingAverage< Whole > ::Type | FrameTimeLog |
A rolling average of Frame times. | |
std::ostream * | LogDestination |
When the logs are aggregated, this is where they are sent. | |
bool | LoggingToAnOwnedFileStream |
Set based on which constructor is called, and only used during destruction. | |
SpinLock | LogResources |
Protects DoubleBufferedResources during creation from being accessed by the LogAggregator. | |
ThreadId | MainThreadID |
For some task it is important to know the ID of the main thread. | |
bool | NeedToLogDeps |
Brief Do we have to log ependencies have they changed since last logged? More... | |
DefaultRollingAverage< Whole > ::Type | PauseTimeLog |
A rolling average of Frame Pause times. | |
std::vector< Resource * > | Resources |
This maintains ownership of all the thread specific resources. More... | |
WorkSorter * | Sorter |
If this pointer is non-zero then the WorkSorter it points at will be used to sort WorkUnits. | |
Whole | TargetFrameLength |
The Maximum frame rate this algorithm should run at. | |
std::vector< Thread * > | Threads |
A way to track an arbitrary number of threads. More... | |
Integer | TimingCostAllowance |
To prevent frame time drift this many microseconds is subtracted from the wait period to allow time for calculations. | |
std::vector< WorkUnitKey > | WorkUnitsAffinity |
A collection of iWorkUnits that must be run on the main thread. More... | |
std::vector< WorkUnitKey > | WorkUnitsMain |
A collection of all the work units that are not Monopolies and do not have affinity for a given thread. More... | |
std::vector< MonopolyWorkUnit * > | WorkUnitsMonopolies |
A collection of all the monopolies this scheduler must run and keep ownership of. | |
Friends | |
class | LogAggregator |
class | WorkSorter |
This is central object in this algorithm, it is responsible for spawning threads and managing the order that work units are executed.
For a detailed description of the Algorithm this implements see the Algorithm section on the Main page.
Definition at line 75 of file framescheduler.h.
Mezzanine::Threading::FrameScheduler::FrameScheduler | ( | std::fstream * | _LogDestination = 0 , |
Whole | StartingThreadCount = GetCPUCount() |
||
) |
Create a Framescheduler that owns a filestream for logging.
_LogDestination | An fstream that will be closed and deleted when this framescheduler is destroyed. Defaults to a new Filestream Logging to local file. |
StartingThreadCount | How many threads. Defaults to the value returned by GetCPUCount(). |
Definition at line 166 of file framescheduler.cpp.
Mezzanine::Threading::FrameScheduler::FrameScheduler | ( | std::ostream * | _LogDestination, |
Whole | StartingThreadCount = GetCPUCount() |
||
) |
Create a Framescheduler, that logs to an unowned stream.
_LogDestination | Any stream, other than an fstream, and it will be closed (not deleted) when this frame scheduler is destroyed. |
StartingThreadCount | How many threads. Defaults to the value returned by GetCPUCount(). |
Definition at line 193 of file framescheduler.cpp.
|
virtual |
Destructor.
Deletes all std::fstream, WorkUnit, MonopolyWorkUnit and ThreadSpecificStorage objects that this was passed or created during its lifetime.
Definition at line 221 of file framescheduler.cpp.
|
virtual |
Add a normal Mezzanine::Threading::iWorkUnit to this For scheduling.
MoreWork | A pointer the the WorkUnit, that the FrameScheduler will take ownership of, and schedule for work. |
WorkUnitName | A name to uniquely identify this work unit in the logs |
Definition at line 251 of file framescheduler.cpp.
|
virtual |
Add a normal Mezzanine::Threading::iWorkUnit to this For fcheduling.
MoreWork | A pointer the the WorkUnit, that the FrameScheduler will take ownership of, and schedule for work. |
WorkUnitName | A name to uniquely identify this work unit in the logs |
Definition at line 244 of file framescheduler.cpp.
|
virtual |
Add a MonopolyWorkUnit for execution at the beginning of the frame.
MoreWork | A pointer to the MonopolyWorkUnit to add. |
WorkUnitName | A name to uniquely identify this work unit in the logs |
Definition at line 258 of file framescheduler.cpp.
|
virtual |
Is the work of the frame done?
Definition at line 456 of file framescheduler.cpp.
|
virtual |
This is the 2nd step (of 6) in a frame.
This starts all the threads on their work. Until JoinAllThreads() is called some thread may still be working. This thread starts the man scheduling algorithm working on every thread except the calling thread. This call does not block and tends to return very quickly.
This checks the amount of threads as set by SetFrameLength. It creates any ThreadSpecificStorage instances required and creates threads if they are required. SwapAllBufferedResources() Is called on each ThreadSpecificStorage before being passed into the thread. If extra double buffered resources are required per thread and they need to be swapped each frame, SwapAllBufferedResources() should be inherited or adjusted to account for these new resources.
If the build option MEZZ_USEBARRIERSEACHFRAME Mezz_MinimizeThreadsEachFrame was enabled then this will reuse threads from previous frames, otherwise this will re-use thread specific resources and create a new set of threads. Re-use of threads is synchronized with the Barrier StartFrameSync member variable. It is unclear, and likely platform specific, which option has better performance characteristics.
Definition at line 541 of file framescheduler.cpp.
void Mezzanine::Threading::FrameScheduler::DependenciesChanged | ( | bool | Changed = true ) |
Indicate to the framescheduler if dependencies need to be logged.
Changed | Defaults to true, and sets a flag that tells the framescheduler if it needs to log dependencies. |
If false is passed, this prevents the FrameScheduler from logging until the next change.
Definition at line 672 of file framescheduler.cpp.
|
virtual |
Do one frame worth of work.
This just calls the following functions in the order presented:
This can be replaced calling these functions in this order. You can add any other calls you like between the various stages. This can be done to allow maximum integration with existing projects. It can also be used to prevent a giant migration and replace it with a piecemeal upgrade.
Definition at line 525 of file framescheduler.cpp.
|
virtual |
When did this frame start?
Definition at line 507 of file framescheduler.cpp.
|
virtual |
How many other WorkUnit instances must wait on this one.
Work | The WorkUnit to get the updated count of. |
UsedCachedDepedentGraph | If the cache is already up to date leaving this false, and not updating it can save significant time. |
Definition at line 373 of file framescheduler.cpp.
|
virtual |
Get the current number of frames that have elapsed.
Definition at line 484 of file framescheduler.cpp.
|
virtual |
Get the desired length of a frame.
Definition at line 487 of file framescheduler.cpp.
DefaultRollingAverage< Whole >::Type & Mezzanine::Threading::FrameScheduler::GetFrameTimeRollingAverage | ( | ) |
Get The complete record of the durations of the last few frames.
Definition at line 516 of file framescheduler.cpp.
Whole Mezzanine::Threading::FrameScheduler::GetLastFrameTime | ( | ) | const |
How long was the previous frame?
Definition at line 519 of file framescheduler.cpp.
Whole Mezzanine::Threading::FrameScheduler::GetLastPauseTime | ( | ) | const |
How long was the pause, if any, last frame?
Definition at line 513 of file framescheduler.cpp.
std::ostream & Mezzanine::Threading::FrameScheduler::GetLog | ( | ) |
Get the endpoint for the logs.
Definition at line 718 of file framescheduler.cpp.
|
virtual |
Gets the next available workunit for execution.
This finds the next available WorkUnit which has not started execution, has no dependencies that have not complete, has the most WorkUnits that depend on it (has the highest runtime in the case of a tie).
Definition at line 386 of file framescheduler.cpp.
|
virtual |
Just like GetNextWorkUnit except that it also searches through and prioritizes work units with affinity too.
Definition at line 421 of file framescheduler.cpp.
DefaultRollingAverage< Whole >::Type & Mezzanine::Threading::FrameScheduler::GetPauseTimeRollingAverage | ( | ) |
Get The complete record of the past durations of the Pauses Each frame.
Definition at line 510 of file framescheduler.cpp.
|
virtual |
Get the amount of threads that will be used to execute WorkUnits a the start of the next frame.
Definition at line 501 of file framescheduler.cpp.
FrameScheduler::Resource * Mezzanine::Threading::FrameScheduler::GetThreadResource | ( | ThreadId | ID = this_thread::get_id() ) |
Get the Resource to go with a thread of a given ID.
This gets the Resource that goes with a given thread by performing a linear search through the available threads.
This is cheap computationly but will likely perform much slower than other methods of getting the resource, because the ID is unlikely be be cached and it may require a system call to retrieve. If used consider wrapping it in #ifdef MEZZ_DEBUG + #endif to disable for release builds.
ID | This uses the current Threads ID by default but can search for any thread. |
Definition at line 649 of file framescheduler.cpp.
Logger * Mezzanine::Threading::FrameScheduler::GetThreadUsableLogger | ( | ThreadId | ID = this_thread::get_id() ) |
Get the logger safe to use this thread.
ID | This uses the current Threads ID by default but can search for any thread. |
Definition at line 664 of file framescheduler.cpp.
Whole Mezzanine::Threading::FrameScheduler::GetWorkUnitAffinityCount | ( | ) | const |
Returns the amount of iWorkUnit ready to be scheduled in the Affinity pool.
Definition at line 640 of file framescheduler.cpp.
Whole Mezzanine::Threading::FrameScheduler::GetWorkUnitMainCount | ( | ) | const |
Returns the amount of iWorkUnit ready to be scheduled in the Main pool.
Definition at line 643 of file framescheduler.cpp.
Whole Mezzanine::Threading::FrameScheduler::GetWorkUnitMonopolyCount | ( | ) | const |
Returns the amount of MonopolyWorkUnit ready to be scheduled.
Definition at line 637 of file framescheduler.cpp.
void Mezzanine::Threading::FrameScheduler::JoinAllThreads | ( | ) |
This is the 4th step (of 6) in a frame.
Used when completing the work of a frame, to cleaning end the execution of the threads. This function will only return when all the work started by CreateThreads() and RunMainThreadWork() have completed. This call blocks until all threads executing. If a thread takes too long then this simply waits for it to finish. No attempt is made to timeout or interupt a work unit before it finishes.
Definition at line 577 of file framescheduler.cpp.
void Mezzanine::Threading::FrameScheduler::LogDependencies | ( | ) |
This sends the dependencies to the LogDestination (Skipping any thread specific resources)
Definition at line 675 of file framescheduler.cpp.
|
virtual |
Remove a WorkUnit from the Affinity pool of WorkUnits (and not from the Main group or MonpolyWorkUnits).
LessWork | A pointer to the workunit the calling coding will reclaim ownership of and will no longer be scheduled, and have its dependencies removed. |
Definition at line 319 of file framescheduler.cpp.
|
virtual |
Remove a WorkUnit from the main pool of WorkUnits (and not from the groups of Affinity or MonpolyWorkUnits).
LessWork | A pointer to the workunit the calling coding will reclaim ownership of and will no longer be scheduled, and have its dependencies removed. |
Definition at line 293 of file framescheduler.cpp.
|
virtual |
Remove a WorkUnit from the Monopoly pool of WorkUnits (and not from the Main or Affinity group).
LessWork | A pointer to the MonopolyWorkUnit the calling coding will reclaim ownership of and will no longer be scheduled, and have its dependencies removed. |
Definition at line 345 of file framescheduler.cpp.
|
virtual |
This is the 5th step (of 6) in a frame.
Take any steps required to prepare all owned WorkUnits for execution next frame. This usually includes reseting all the work units running state to NotStarted. This can cause work units to be executed multiple times if a thread is still executing.
Definition at line 601 of file framescheduler.cpp.
|
virtual |
This is the 1st step (of 6) in a frame.
This iterates over the listing of MonopolyWorkUnits and executes each one in the order it was added. This should be considered as consuming all available CPU time until it returns. This call blocks until execution of monopolies is complete.
Definition at line 535 of file framescheduler.cpp.
|
virtual |
This is the 3rd step (of 6) in a frame.
This runs the main portion of the scheduling algorithm on the main thread. This call blocks until the execution of all workunits with main thread affinity are complete and all other work units have at least started. This could return and other threads could still be working.
Before executing any work this checks a flag to determine if it should log the current work unit dependencies. After this check or logging has occurred this then this releases the spinlock on the log, so there is a chance of brief contention between a LogAggregator and this if depedencies have just changed or change frequently.
Definition at line 568 of file framescheduler.cpp.
|
virtual |
Set the Desired length of a frame in microseconds.
FrameLength | The desired minimum length of the frame. Use 0 for no pause. |
Definition at line 498 of file framescheduler.cpp.
|
virtual |
Set the desired Frate rate.
FrameRate | in frames per second |
Defaults to 60, to maximize smoothmess of execution (no human can see that fast), while not killing battery life. This is a maximum framerate, if WorkUnits take too long to execute this will not make them finish faster. This controls a delay to prevent the machine's resources from being completely tapped.
Set this to 0 to never pause and run as fast as possible.
Definition at line 490 of file framescheduler.cpp.
|
virtual |
Set the amount of threads to use.
NewThreadCount | The amount of threads to use starting at the begining of the next frame. |
Definition at line 504 of file framescheduler.cpp.
|
virtual |
Sort the WorkUnits that must run on the main thread to allow them to be used more efficiently in the next frame executed.
UpdateDependentGraph_ | Should the internal cache of reverse dependents be updated. |
See DependentGraph for the appropriate times to use this.
Definition at line 276 of file framescheduler.cpp.
|
virtual |
Sort all the WorkUnits that must run on the main thread to allow them to be used more efficiently in the next frame executed.
UpdateDependentGraph_ | Should the internal cache of reverse dependents be updated. |
See DependentGraph for the appropriate times to use this.
Definition at line 287 of file framescheduler.cpp.
|
virtual |
Sort the the main pool of WorkUnits to allow them to be used more efficiently in the next frame executed.
UpdateDependentGraph_ | Should the internal cache of reverse dependents be updated. |
See DependentGraph for the appropriate times to use this.
Definition at line 265 of file framescheduler.cpp.
|
protected |
Adds the dependencies of the iWorkUnits in the passed containter to the the internal reverse dependency graph.
Units | The container to examine for dependency relationships. |
Definition at line 146 of file framescheduler.cpp.
|
virtual |
Create a reverse depedent graph that can be used for sorting Mezzanine::Threading::iWorkUnit "iWorkUnit"s to optimize execution each frame.
This can be called automatically from any of several places that make sense by passing a boolean true value. These place include create a WorkUnitKey or Sorting the work units in a framescheduler.
Definition at line 474 of file framescheduler.cpp.
|
protected |
Iterate over the passed container of WorkUnitKeys and refresh them with the correct data from their respective iWorkUnits.
Units | The container to examine for WorkUnitKey metadata. |
Definition at line 158 of file framescheduler.cpp.
void Mezzanine::Threading::FrameScheduler::WaitUntilNextFrame | ( | ) |
This is the final step (of 6) in a frame.
Wait until this frame has consumed its fair share of a second. This uses the value passed in SetFrameRate to determine what portion of a second each frame should use. If a frame took too long to execute this calculates that and returns.
Wait 1/TargetFrame seconds, minus time already run. This also starts the timer for the next frame so any other logic that needs to run after the frame does not interfere with frame timing. Because This is designed to wait fractions of a second any amount of waiting above 1 second fails automaticall.
Definition at line 614 of file framescheduler.cpp.
|
protected |
This structure allows reverse lookup of dependencies.
This is is a key part of the workunit sorting algorithm. This is calculated during calls to generate WorkUnitKeys,
Definition at line 119 of file framescheduler.h.
|
protected |
Used to store a count of frames from the begining of game execution.
Definition at line 190 of file framescheduler.h.
|
protected |
Brief Do we have to log ependencies have they changed since last logged?
Since each workunit tracks its own dependencies this cannot easily be directly checked. There is a function to set and since dependencies are likely to be between adding a working and runninf a frame, adding a workunit sets this flag.
Definition at line 208 of file framescheduler.h.
|
protected |
This maintains ownership of all the thread specific resources.
Definition at line 128 of file framescheduler.h.
|
protected |
A way to track an arbitrary number of threads.
Definition at line 132 of file framescheduler.h.
|
protected |
A collection of iWorkUnits that must be run on the main thread.
This is very similar to WorkUnitsMain except that the iWorkUnits are only run in the main thread and are sorted by calls to SortWorkUnitsAll or SortWorkUnitsAffinity .
Definition at line 100 of file framescheduler.h.
|
protected |
A collection of all the work units that are not Monopolies and do not have affinity for a given thread.
This stores a sorted listing(currently a vector) of WorkUnitKey instances. These include just the metadata required for sorting iWorkUnits. Higher priority iWorkUnits are higher/later in the collection. This list is sorted by calls to SortWorkUnitsMain or SortWorkUnitsAll.
Definition at line 89 of file framescheduler.h.