Discrete Event Models of Computation

Example - Starting simulations
No simultaneous events - Handling Simultaneous Events
Infinitesimal Delays - Disadvantages
Operational non-determinism - Denotational non-determinism

In discrete event systems, changes in system behavior are marked by discrete occurrences or events. Events consist of a token and a time stamp. A token can be a scalar value, a matrix, a data structure, and so forth. The time stamp might be a floating-point number (Spice or the Ptolemy Discrete-Event model of computation) or consist of an ordered pair (global clock tick, delta time tick) of integers (VHDL). In VHDL, the ordered pair of integers represents a global time index and a delta time index. The scheduler runs the simulation by maintaining a record of all of the events in the system sorted by time stamp, and advancing time to the earliest time stamp. Thus, there is a total ordering between all events. Given any two events, we can tell if they occur simultaneously or after one another. CAD tools implementing a discrete event model include

Example

Throughout this section, we will discuss the simulation of discrete event systems using the following block diagram:

        -------------------------------- 
       |                                |
       |       ---                      |
        ----> |   |             ---     |
 ---          | C | ---------> |   |    |
| A | ------> |   |            | D | --- 
 ---           ---        ---> |   |     
                         |      ---      
 ---                     |               
| B | -------------------                
 ---                                     
Figure 1: A Discrete Event Block Diagram

This block diagram has two source blocks, A and B, and two input/output blocks C and D. There are no sink blocks.

Getting the Simulation Started

Some discrete event models, such as the Ptolemy Classic Discrete Event model of computation, use the firing rule that an block is active when new data is present on at least one input. According to this rule, source block would never be executed. If we simply ran a system according to this rule without any initial events on the arcs, then time would not advance because there are no events to process and the simulator would terminate. Two possible solutions are:
  1. Place an initial token on every arc at the simulation start time
  2. Require that all source blocks schedule themselves
The Ptolemy Classic Discrete-Event model of computation implements the second case. To implement the second case, the blocks and the scheduler would no longer be decoupled. You may recall that the Synchronous Dataflow and Process Network models of computation decouple the scheduler from the node implementation. Decoupling the nodes and the scheduler For the latter point, consider the nesting of a DE subsystem into a DE system. The DE subsystem must run lock-step with the parent DE system to ensure causality. How does one handle a source block in the DE subsystem?

The Ptolemy Classic DE model of computation requires that all source blocks schedule themselves. A Ptolemy Classic DE scheduler for simulation goes through three steps:

  1. initialization
    1. parameter initialization
    2. graph initialization
    3. parameter validation
    4. scheduling
    5. begin
  2. execution (implemented by the go method)
  3. wrapup
All DE source blocks are derived from the DERepeatStar, whose code is available at $PTOLEMY/src/domains/de/kernel/DERepeatStar.cc. The initialize method creates a hidden feedback arc from a hidden output port to a hidden input port. (The hidden feedback arc is also given a property of infinitesimal delay, which will be covered in Case #3 below.) Hidden means that the arc or port does not show up when the block is graphically displayed. In the begin phase of initialization, a source block would output an initial token at the simulation start time (0.0 s) on the hidden feedback arc. When simulation execution begins, every source block will be fired at the simulation start time. If the source node would be refired at a future time, then the go method of the source node would output on the hidden feedback arc a token with a timestamp equal to the future time.

Case #1: No Simultaneous Events Occur During Simulation

For the first case using the Ptolemy Classic DE model of computation, we will not encounter simultaneous events during the simulation. The blocks in Figure 1 are: That is, both A and B are impulses. Blocks A and B each put out a token with a time stamp of 0.0 sec on their hidden feedback arcs. Source blocks are considered zero-delay blocks.

At the beginning of the simulation, the global queue has

0.0 sec Block A
0.0 sec Block B
The simulator starts at time 0.0 sec. At time of 0.0 sec, the simulator executes blocks A and B. The global queue now also has
1.0 sec Block C
1.5 sec Block D
The simulator now advances time to 1.0 sec, deleted the global queue entries with timestamps prior to 1.0 sec, and executes Block C. Since upper input to Block C has not been initialized, how should C handle this? Two possibilities are
  1. Allow a default value on all arcs, or
  2. Force the block to detect which inputs have new data
The Ptolemy Classic Discrete Event domain uses the second option. When block C executes, it notices new data on the lower input port, and produces a new event at 2.0 sec. The global queue is now
1.5 sec Block D
2.0 sec Block D
The scheduler next advances time to 1.5 sec and executes Block D. When Block D executes, it uses the new data on the lower input and produces a new event on its output 1 sec later:
2.0 sec Block D
2.5 sec Block C
The scheduler advances time to 2.0 sec and executes D again.
2.5 sec Block C
3.0 sec Block C
Now, step back and take a look at the system under simulation.

Will the system come to a halt by itself?

Generally, it does not, and even if it did, the scheduler could not predict it in finite time for all possible systems. The particular system we are using as an example will repeat forever. So, in practice, the user specifies a stopping time.

Case #2: Handling Simultaneous Events

For the second case using the Ptolemy Classic DE model of computation, we define the blocks in Figure 1 as follows: Blocks A and B are DEClock blocks from the Ptolemy Classic collection. The DEClock source code is available at $PTOLEMY/src/domains/de/stars/DEClock.pl. DEClock is derived from DERepeatStar, whose code is available at $PTOLEMY/src/domains/de/kernel/DERepeatStar.cc.

For this second case, we will encounter simultaneous events. The proper handling of simultaneous events increases the difficulty of scheduling because the scheduler must obey the order of data dependencies in the graph.

Blocks A and B pass tokens along a hidden feedback arc to cause the repeated firings to occur. After the scheduler has been initialized, the global queue has the following events in it prior to executing the graph:

0.0 sec Block A
0.0 sec Block B

Let's examine what would happen during the execution at Time 0.0 sec before we arrive at a schedule. Block A would produce an output with time stamp of 0.0 sec, which feeds into Block C. Block C would produce an output with time stamp of 0.0 sec, which feeds into block D. Block B would produce an output with time stamp of 0.0 sec, which feeds into Block D.

How do we derive a schedule to resolve the simultaneous events at block D to ensure causality?

When handling simultaneous events, the scheduler must first determine the data dependencies before executing any blocks in order to enforce causality. We can determine the data dependencies by performing a topological sort, which will be discussed in the Introduction to Graph Theory lecture. A topological sort is not necessarily unique.

In this DE graph, D is a delay block, and A, B, and C are functional blocks. A and B have hidden feedback arcs with a property of infinitesimal delay (i.e., a second dimension of time). The infinitesimal delay indicates that any data produced on the hidden output arc will be at an infinitesimally later time. Since we are trying to resolve a schedule for the current time, the delay property enables the hidden feedback arc to be broken. In addition, D is a delay block, so that any data it produces will happen at a later time than the current time stamp. Here is the amended graph to schedule at a particular time stamp:

               ---                  
              |   |             --- 
 ---          | C | ---------> |   |
| A | ------> |   |            | D |
 ---           ---       ----> |   |
                         |       ---  
 ---                     |            
| B | -------------------            
 ---                                 
Figure 2: The Discrete Event block diagram in Figure 1 used in scheduling execution to resolve simultaneous events. Of the four blocks, only D is a delay block. Since D is a delay block, the feedback arc from D to C can be removed for the purposes on scheduling the execution for the current time stamp.

For the DE system, only D is a delay block. Here all of the topological sorts:

In finding the topological sort, the scheduler has to know if each block will produce a delay or not. In the Ptolemy Classic DE domain, however, delays associated with blocks must always be positive. The delay attribute associated with a DE block is set in the block's constructor in Ptolemy Classic.

What happens if the delay is data-dependent?

It is okay in VHDL. Delays associated with operations in VHDL must be non-negative.

Case #3: Requiring Infinitesimal Delay to Handle Simultaneous Events

For the third case, we define the blocks in Figure 1 as follows: Note that this causes blocks C and D to deadlock because a firing pattern cannot be chosen to satisfy causality. That is, C can't fire until D fires, but D can't fire until C fires. How does the scheduler handle this situation?

Possible outcomes:

In the Ptolemy Classic Discrete Event domain, the user must place an infinitesimal delay (similar to delta time in VHDL) on one of the two arcs of the C-D cycle. Figure 3 places the infinitesimal delay on the feedback arc from C to D. The infinitesimal delay is represented by *, which would appear as a diamond in Ptolemy Classic. Although an infinitesimal delay takes 0 seconds, it specifies that C can execute before D. For simultaneous events, the DE scheduler can now find a firing sequence, e.g. ACBD or BACD or ABCD, by using a topological sort, which will be discussed in the Introduction to Graph Theory lecture.
        ---------------*---------------- 
       |                                |
       |       ---                      |
        ----> |   |             ---     |
 ---          | C | ---------> |   |    |
| A | ------> |   |            | D | --- 
 ---           ---        ---> |   |     
                         |      ---      
 ---                     |               
| B | -------------------                
 ---                                     
Figure 3: Adjusting the DE schematic to handle simultaneous events by adding an infinitesimal delay *.

After scheduling has been initialized but before the simulation starts, here is the state of the global queue:

0.0 sec Block A
0.0 sec Block B
Set Time = 0.0 seconds. The graph consists of four functional (zero-delay) blocks. Perform a topological sort on the graph. The topological sort would produce one of the following schedules: ACBD or BACD or ABCD. Let's use ABCD. After A and B are executed, here's the state of the global queue (note the dequeuing of the tokens consumed when A and B executed):
0.0 sec Block C (lower port)
0.0 sec Block D (lower port)
1.0 sec Block A
1.5 sec Block B
Continue with the schedule to execute C:
0.0 sec Block D (lower port)
0.0 sec Block D (upper port)
1.0 sec Block A
1.5 sec Block B
After executing D, D produces a token on the feedback arc from D to C. That token passes through an infinitesimal delay. The infinitesimal delay can be thought of a second dimension of time in units of e.

At Time = (0.0 + e) seconds, where e means one unit of infinitesimal delay,

(0.0 + e) sec Block C (upper port)
1.0 sec Block A
1.5 sec Block B

At Time = (0.0 + 2 e) seconds

(0.0 + 2 e) sec Block C (upper port)
1.0 sec Block A
1.5 sec Block B

This firing pattern could be continued ad infinitum without the scheduler advancing global time beyond 0.0 seconds.

Disadvantages of Discrete Event Simulators

Since the scheduler and blocks in a discrete-event simulator are heavily dependent on each other, it is difficult to compose discrete event models of computation with other models such as Synchronous Dataflow (SDF). If DE were the parent system and a DE block represented an SDF system, then whenever the DE block executed, it must send a certain number of samples to the SDF system to run at least one period of the graph. If SDF were the parent system and an SDF block represented a DE system, then whenever the SDF block executed, it must guarantee that the same number of output samples always got produced.

Sources of Non-Determinism

The discrete event model of computation is not determinate. This is not too alarming, because discrete event models are used to model the environment in which a design operates and (hopefully) not used to model the design itself.

Slide 8 of the block diagram talk defines determinism:

  1. A behavior is a set of signals that obeys the semantics
  2. A system is determinate if knowing the inputs, there is at most one behavior.
Another way of saying (2) is that for a determinate model, we can use any scheduling algorithm that obeys that semantics and we will obtain the same behavior.

Here is a review of the semantics of the discrete-event model:

  1. Tokens have real-valued time stamps associated with them
  2. Tokens are processed in a causal manner
  3. Tokens conceptually flow on arcs and are sorted by their timestamps
  4. A node may be a functional (no delay) or a delay block. A delay block is not allowed to have 0 seconds of delay.
  5. A node is enabled if at least input port contains "new" data, i.e., a data with a time stamp equal to the current global time
  6. A feedback path must have at least one delay block or an infinitesimal delay to be considered valid.
  7. An infinitesimal delay only breaks a dependence; it does not advance global time, but instead advances a second dimension of time (i.e. "delta" time).
Slide 19 of the block diagram talk gives the following concerning the discrete event model of computation:
  1. "Determinate under simple conditions (strict causality in feedback loops)"
  2. "Simulatable under simple conditions (delta causality in feedback loops)"
Strict causality means that a delay block (with non-zero delay) needs to be in a feedback loop. Sources of non-determinism in an implementation (i.e., in a set of operational semantics):
  1. Timestamps are represented in a floating-point representation; due to rounding/truncation errors, two events that should have been considered simultaneous are not. (VHDL works around this by using integer ticks for global time and integer ticks for delta time as well.)
  2. Consider a loop without any infinitesimal delays on the arcs and with functional blocks and only one delay block. The delay on the delay block is conditional on an input value; if the conditional delay is zero, then the loop deadlocks and the scheduling algorithm could either halt (due to the error) or schedule the rest of the graph. See Ptolemy Classic Programmer's Manual Section 12.2.5

Denotational Non-Determinism

(by Prof. Stephen A. Edwards, Columbia University)

The fundamental problem in DE systems is one of races, e.g. as would occur in reconvergence as in the following graph:

     /----B-----\ 
A---+            D
     \----C-----/ 
Say A generates an event that is sent simultaneously to B and C, who then delay the result by the same constant amount (it doesn't have to be zero). Does D see A, B, or both events when it fires? Most DE systems have a simple-minded event queue that leaves this question unanswered; D sees an event from B and C, but not necessarily in that order.

If the blocks in a DE system are well-behaved for some suitable definition of well-behaved, then this is not a problem. In general, if D is an event-sensitive object (e.g., an edge-sensitive latch), then the behavior would be nondeterministic.

Here is another example. This example concerns an undefined concurrent procedure execution order in Verilog:

always @(posedge clk) $write( a )
always @(posedge clk) $write( b )
The first simulator moved procedures between two push-down stacks, which produced
a b b a a b b a a b b a a b a
Later simulators had to match this now-expected behavior.


Updated 04/04/04.