Timing in Ikaros
In Ikaros, there are two ways to control the relative timing of modules during execution. The first is the optional delay attribute that can be set on connections to delay the delivery of an output to the input of the next module. The second method is to allocate different time slots to the execution of a module using the period and phase attribute. In this article, we take a detailed look at these two methods.
Using Delays to Synchronize Processing
When the output of a module in Ikaros is connected to an input of another module, the data at the output will appear at the input at the next time step (or iteration). This gives the illlusion that all modules are running synchonously and simultaneously. This is mostly what is wanted, but in complex networks of modules it often necessary to synchronize processing in more complex ways.
To make this possible, the attribute "delay" is used in a connection to determine when an output should appear at an input. The default is:
delay = "1"
The delay can be set to any number of iterations including 0. When a delay of 1 or larger is specified, the output is temporarily stored in a buffer by the kernel until it is time for the receiving module to get the data. The module itself is not affected in any way by this delay and need not know about it internally.
In the example below, the output from module A is delayed for 10 time steps before it reaches module B:
<connection sourcemodule = "A" source = "OUTPUT" targetmodule = "B" target = "INPUT" delay = "10" />
It is possble to mix a number of connections with different delays on connections between the same modules. For example, the following specification sets up a network that detects changes in its input by comparing the output from module A at to different time steps. Here, we assume that he module DIFF computes the difference of its two inputs:
<connection sourcemodule = "A" source = "OUTPUT" targetmodule = "DIFF" target = "INPUT1" delay = "1" /> <connection sourcemodule = "A" source = "OUTPUT" targetmodule = "DIFF" target = "INPUT2" delay = "2" />
When a delay of 0 is specified, the situation is a bit more complicated. In this case, it is necesssary that the modules execute in the correct order within every time step so that the output of one module can be used driectly by the receiving module. Fortunately, this work is done automatically by the kernel and all the user has to care about is to avoid loops with zero delays in the network of modules.
In the following example, the output from module A will be received by module B, proceesed and sent to module C, all within the same iteration. The three modules will essentially operate as a single module.
<connection sourcemodule = "A" source = "OUTPUT" targetmodule = "B" target = "INPUT" delay = "0" /> <connection sourcemodule = "B" source = "OUTPUT" targetmodule = "C" target = "INPUT" delay = "0" />
This technique can be used to set up, for example, a filtering chain that will read an image file, process it through a number of filtering stages, and save it to a new file. All within a single iteration.
When there are many connections between modules, it is neccessary to make sure that there are no loops with delay 0 since this would mean that the input of a module depends on its output that same time step which is obviously impossible. The kernel will produce an error at start-up if there are loops of this kind in the network.
Running Modules in Different Time Slots
It is possible to specify for each module how often it should execute and when this occurs in relation to othe modules. In general modules should be able to run at any time, but there are cases when it is necesary to schedule the execution of a module either because the algorithm it implements requires this or becasue the module interacts with external devices.
The function Tick() will be called when it is time for the module to execute. This is accomplished using two optional attributes in the XML declaration of each module. The attribute "period" sets how often a module should execute and the attribute "phase" sets when this should happen.
For example, setting
period = "2"
in the XML file, will make the module execute only every second iteration (the black squares in the figure below).
If we wanted the module to execute on odd iterations instead, we could also set the "phase" attribute to shift execution one iteration:
phase = "1"
The following XML declarations will create two modules that run on alternating iterations:
<module name = "A" period ="2" phase = "1" > : </module> <module name = "B" period ="2" phase = "0" > : </module>
The relative timing of the modules are shown in the figure below:
The "period" and "phase" attributes can be used to simulate that different modules execute att different speed. For example, a slow process may execute once every second while a faster process may execute a hundred times per second. Note however that all modules currently execute in the same thread in IKAROS which means that the scheduling set by "period" and "phase" does not correspond to real time.
The figure below illustrates a situation when one module B executes five times as often as the other module A and also uses much less time for each execution. Conceptually, the processes run concurrently, but in real time, they run after each other and the different phases will require different amount of time. Here, iteration 0 and 10 take much more time than the ofther iterations. This is no problem for a pure simulation but may cause problems when modules communicate with external devices.
Another consequence of the current implementation is that the output of the slower process will be ready too early in the simulation process. This can be corrected manually by using delays on the connections from the slower module if necessary.
When Ikaros is run in thread mode, which will be available in version 0.8.2, modules will be able to run concurrently as in the sketch above.blog comments powered by Disqus