Delay primitives

Delay primitives manipulate timestamps. Two types of examples of delay primitives are pure delays, and servers.

pure-delay

A pure-delay primitive generates an output with the same value as the input sample, but with a timestamp that is greater than that of the input sample. The difference between the input sample timestamp and the output timestamp is a fixed, user-defined value. Consider for example the DE primitive Delay:

defprimitive
{
  name        { Delay }
  domain      { DE }
  desc
  {
    The time stamp of the input particles is increased by a fixed amount of time.
  }

  input
  {
    name { input }
    type { anytype }
  }

  output
  {
    name { output }
    type { =input }
  }

  defparameter
  {
    name        { delay }
    type        { float }
    default     { "1.0" }
    desc        { "Amount of time delay." }
  }

  constructor
  {
    delayType = true;
  }

  go
  {
    completionTime = arrivalTime + (double)delay;
    output.put(completionTime) = input.get();
  }
}

Inside the go method description, the completionTime is calculated by adding the delay to the arrival time of the current event. The last two lines will be explained in more detail later.

server

Another type of delay primitive is a server. In a server primitive, the input event waits until a simulated resource becomes free to attend to it. An example is the DE primitive Server:

defprimitive
{
  name        { Server }
  domain      { DE }
  desc
  {
    This primitive emulates a server.
If input events arrive when it is not busy,
it delays them by the service time (a constant parameter).
If they arrive when it is busy, it delays them by more.
It must become free, and then serve them.
  }

  input
  {
    name { input }
    type { anytype }
  }

  output
  {
    name { output }
    type { =input }
  }

  defparameter
  {
    name        { serviceTime }
    type        { float }
    default     { "1.0" }
    desc        { "Service time." }
  }

  constructor
  {
    delayType = TRUE;
  }

  go
  {
    // No overlapped execution. set the time.
    if (arrivalTime > completionTime)
      completionTime = arrivalTime + double(serviceTime);
    else
      completionTime += double(serviceTime);

    Particle& pp = input.get();
    output.put(completionTime) = pp;
  }
}

This primitive uses the completionTime member to store the time at which it becomes free after processing an input. On a given firing, if the arrivalTime is greater than the completionTime, meaning that the input event has arrived when the server was free, the server then delays the input by the serviceTime only. Otherwise, the timestamp of the output event is calculated as the serviceTime plus the time at which the server becomes free, the completionTime.

Both pure delays and servers are delay primitives. Hence their constructor sets the delayType member. This information is used by the scheduler. The technical meaning of the delayType flag needs some explanation. Such a primitive guarantees that it will never produce any output event with zero delay. All its output events will have timestamps larger than the time of the firing in which they are emitted. Primitives that can produce zero-delay events should leave delayType set to its default value of FALSE.

Actually, primitives often cheat a little bit on this rule. As just shown, the standard DE primitive Delay sets delayType even if the user sets the primitive’s delay parameter to zero. This causes the primitive to be treated as though it had a positive delay for the purpose of assigning firing priorities, which is normally what is wanted. Both pure delays and servers are delay primitives. Hence their constructor sets the delayType member. This information is used by the scheduler, and is particularly important when determining which event (of several simultaneous) to process first.