|
Peano
|
Process set of ready tasks. More...
#include <ProcessSetOfReadyTasks.h>


Public Member Functions | |
| ProcessSetOfReadyTasks (TaskNumber taskNumber, FusableTasksQueue &taskQueue) | |
| Construct process ready task. | |
| virtual void | run () override |
| Run the task. | |
| TaskNumber | getNumber () const |
Public Member Functions inherited from tarch::multicore::Task | |
| Task (int taskType, int priority) | |
| Construct task. | |
| virtual | ~Task () |
| int | getTaskType () const |
| int | getPriority () const |
| void | setPriority (int priority) |
| Set priority. | |
| virtual bool | canFuse () const |
| virtual void | fuse (const std::vector< Task * > &otherTasks, int targetDevice=Host) |
| Fuse multiple tasks. | |
| virtual std::string | toString () const |
Static Public Attributes | |
| static constexpr TaskNumber | AdministerYourOwnTemporaryTaskLocalNumber = -3 |
Static Public Attributes inherited from tarch::multicore::Task | |
| static constexpr int | DefaultPriority = 1024 |
| static constexpr int | Host = -1 |
| static constexpr int | DontFuse = -1 |
Private Member Functions | |
| void | processFusedTask (Task *myTask, const std::vector< tarch::multicore::Task * > &tasksOfSameType, int device) |
| Process a fused task. | |
Private Attributes | |
| FusableTasksQueue & | _taskQueue |
| const int | _taskNumber |
| const bool | _administerYourOwnTemporaryTaskLocalNumber |
Static Private Attributes | |
| static tarch::logging::Log | _log |
| static const std::string | ProcessFusedTasksStatisticsIdentifier |
| static tarch::multicore::TaskEnumerator | _enumerator |
Additional Inherited Members | |
Protected Attributes inherited from tarch::multicore::Task | |
| const int | _taskType |
| int | _priority |
Process set of ready tasks.
Process ready tasks is a class which grabs a set of ready tasks and finishes them. The clue here is that this task itself is again tied to one fusable task and that this task might change its internal implementation:
If we benchmark FusionImplementation::ProducerConsumerTaskSequence, then our performance will likely suffer quite a lot. We should, in practice avoid to have to many of these ProcessSetOfReadyTasks instances.
If a task has in-dependencies, then each ProcessSetOfReadyTasks instance is always paired up with an instance of LogReadyTask which runs before. That is, we know that an instance of LogReadyTask has put the task of interest into the ready queue identified by _taskQueue. This way, fusion does not kick in prior to the actual task depositing.
I originally built in a guarantee that the termination of this task also means that the fusable task with the same task number has terminated. This can lead to nasty deadlocks. Assume that we have two instances of ProcessSetOfReadyTask t1 and t2 and t1 grabs some tasks A,B,C,D, while t2 takes E,F,G,H. If t2 now waits for A as it is tied to A and t1 is tied to H, then we have a deadlock.
So what I do is that I separate the fusion handling from the tackling of an individual task, i.e. ProcessSetOfReadyTasks and ProcessOneReadyTask are distinct tasks with different behaviour: One takes an arbitrary number of fusable tasks but there can be many of them. The other one takes a specific task but only one of them.
When either of them takes ownership of a fusable task, it registers itself as owner. Therefore, no cross-dependencies aka deadlocks can arise anymore.
This deadlock is also the reason why we work with three different task types in general, and we avoid that they are merged into each other.
If we study the task queue and our task of interest is already completed, we return immediately. If this is not the case, we process tasks as described above, but we also bookkeep how many tasks we currently see in the queue.
Such intelligence can be used for decision making or autotuning, but atm it is not exploited in any way.
Definition at line 88 of file ProcessSetOfReadyTasks.h.
| tarch::multicore::taskfusion::ProcessSetOfReadyTasks::ProcessSetOfReadyTasks | ( | TaskNumber | taskNumber, |
| FusableTasksQueue & | taskQueue | ||
| ) |
Construct process ready task.
The ready task should correspond to a proper task number. I usually pick a number of a fused task. As the fused task is parked somewhere in the queues, we know this number is available. But it doesn't have to be. The important thing just is that this task number is the same one that we later on use for spawnTask(), as we take this number and put it next to running tasks in run().
| taskNumber | Task number that you also used for spawnTask(). |
| TaskNumber tarch::multicore::taskfusion::ProcessSetOfReadyTasks::getNumber | ( | ) | const |
|
private |
Process a fused task.
A fused task is a task (which can be fused) and a list of further tasks which are of the same type and, hence, can be fused, too. This routine has to process all tasks, delete all the instances, i.e. both myTask and all pointers stored in tasksOfSameType, and return. It is blocking in the sense that we are guaranteed that tasks have completed once this function returns. For the execution, we rely on myTask's fuse() operation, i.e. this routine is solely there for the memory management.
This is the only routine in the whole code where the actual specific fuse() of a task is invoked. This is the single point of contact.
I originally had this function in tarch::multicore. However, it is really only used here. Further to that, I found it inappropriate to host it in the general namespace, which also serves as kind of an API to higher code layers. The fusion itself is never triggered from a higher level directly.
| myTask | First task. This is a task which can be fused. The pointer is valid. The ownership of myTask is handed over to the called routine, i.e. processFusedTask() has to ensure that it is deleted. |
| tasksOfSameType | List of tasks of the same type. The list can be empty. processFusedTask() has to ensure that all tasks stored within the list are executed and subsequently destroyed. |
| device | Target device on which the fused tasks should be executed. Can be host if the tasks should end up on the host. |
|
overridevirtual |
Run the task.
If the fusable task we are tied to is already completed - a property we can check through hasTaskBeenProcessed() - we return immediately and nothing is to be done. Another ProcessSetOfReadyTasks instance has snapped "our" task and we can degenerate.
If the task is not yet complete, we check if there's potential to fuse and trigger the fused handling.
Very simple implementation running through a few basic checks:
If there are not enough tasks to be fused, the routine degenerates to nop.
This routine is totally thread-safe.
Implements tarch::multicore::Task.
|
private |
Definition at line 93 of file ProcessSetOfReadyTasks.h.
|
staticprivate |
Definition at line 136 of file ProcessSetOfReadyTasks.h.
|
staticprivate |
Definition at line 95 of file ProcessSetOfReadyTasks.h.
|
private |
Definition at line 91 of file ProcessSetOfReadyTasks.h.
|
private |
Definition at line 90 of file ProcessSetOfReadyTasks.h.
|
staticconstexpr |
Definition at line 138 of file ProcessSetOfReadyTasks.h.
|
staticprivate |
Definition at line 98 of file ProcessSetOfReadyTasks.h.