Sequence¶
A sequence is a set of bound tasks. It represents the graph to execute for each new frame (= new stream). When a sequence is built, the tasks execution order is fixed. Thus, for each frame, the graph is executed following a fixed "sequence" of tasks.
A sequence is a C++ object of the aff3ct::runtime::Sequence
class. The
following sections try to give an overview of the most important attributes and
methods to facilitate the code understanding.
Main Attributes¶
The number of threads that are executing the sequence. Vector of sub-sequences of the main sequence (one per thread).std::vector<size_t> firsts_tasks_id;
std::vector<size_t> lasts_tasks_id;
std::vector<std::vector<runtime::Task*>> firsts_tasks;
std::vector<std::vector<runtime::Task*>> lasts_tasks;
Main Methods¶
This is the public method that runs the sequence in loop. Other variants exist where it is possible to give a stop condition function. This function is one of the most important of the sequence class, it is called by theSequence
constructor. Its main purpose is to parse the sub-sequence
graph and to perform some operations that can modify the user bindings.
Additionally, some tasks can be optimized and/or interpreted as a DSEL keyword.
Warning
Before reading the following paragraph you should be familiar with the Adaptor and Switcher modules.
Here is a list of the transformations that are performed during the
gen_processes
method:
push
&pull
tasks (fromAdaptor
module): as explained in the adaptor's section, tasks change theirdataptr
when they get the new buffers from the inter-stage pool, the new pointer needs to be updated for each socket bound to the old one. This behavior is added through aprocess
(nothing to do with OS processes) that encapsulatespush
andpull
tasks. Thisprocess
is triggered each time there is apull
orpush
task execution in the sequence.commute
&select
tasks (fromSwitcher
module): these two tasks are used to select which path to flow for the execution, when a path is selected the bound sockets need to update theirdataptr
to follow the right one. Same as before, a dedicatedprocess
is created and triggered.- Other tasks: a dumb
process
will be created for each task and it will only call its corresponding task.
gen_processes
to get all the bound sockets (next) of
the modified one, if the encountered socket is of type forward
the function is
called recursively on this new socket (see the
Forward socket and pipeline section). This call is performed
once at sequence build.
Warning
This function is no longer a method of the runtime::Sequence
class, it is
now integrated as an anonymous (= lambda) function in the gen_processes
method. This is because explore_thread_rec
is only used in
gen_processes
.
Warning
This function is no longer a method of the runtime::Sequence
class, it is
now integrated as an anonymous (= lambda) function in the gen_processes
method. This is because explore_thread_rec_reverse
is only used in
gen_processes
.
Sub-sequence¶
When control flow tasks are introduced into a sequence, the
execution is not only defined by the tasks binding but also by their output
sockets. For this purpose, tasks are grouped into sub-sequences. Sub-sequences
are organized in a directed graph with two nodes designated as begin
and end, respectively. This graph is recursively built during a sequence
initialization from the first task and going from bound output
/forward
socket to bound input
/forward
socket. When a control flow task (select
or
commute
) is reached, a new control flow node is created and new children nodes
for each of its paths. Only a single of those paths can be taken during
execution, hence why they are referred to as exclusive paths. This also
means that a sequence with no control flow task will always have a single
sub-sequence, because it has a single path.
Upon execution the sequence will iterate over its sub-sequences and execute
every task they contain, if one of those tasks happens to be a commute
it will
select the children node designated by its path attribute, thus branching in
the execution.
aff3ct::runtime::Sub_sequence
(not to be confused with
aff3ct::module::Subsequence
!) main attributes are described in the following
section.
Main Attributes¶
The sub-sequence types can be:STD
, COMMUTE
and SELECT
. This type is used
by the _exec()
method to determine which exclusive path to take during
execution.
Whenever _exec()
reaches a new sub-sequence it executes every function
contained in this list, there is one for each task in the sub-sequence. Refer to
gen_processes()
to understand how they are created and what they contain.
The ids of the tasks the processes
were generated from, tasks_id[0]
is the
id of the task that processes[0]
was made with.
The sub-sequence's id.
std::vector<std::vector<std::vector<runtime::Socket*>>> rebind_sockets;
std::vector<std::vector<std::vector<void*>>> rebind_dataptrs;
gen_process()
method to save the sockets
and their dataptr
to update during the runtime rebinding.
Digraph Node¶
Sub-sequences make up a directed graph. Whenever a sub-sequence
is accessed, it is through this class (aff3ct::tools::Digraph_node
) as
sub-sequences themselves do not contain information regarding the graph.