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&- pulltasks (from- Adaptormodule): as explained in the adaptor's section, tasks change their- dataptrwhen 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 a- process(nothing to do with OS processes) that encapsulates- pushand- pulltasks. This- processis triggered each time there is a- pullor- pushtask execution in the sequence.
- commute&- selecttasks (from- Switchermodule): 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 their- dataptrto follow the right one. Same as before, a dedicated- processis created and triggered.
- Other tasks: a dumb processwill 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.