next previous contents
Next: Debugging Maisie Programs Previous: Message Communication Up: Contents

Miscellaneous Features

 


Entity Scheduling Issues

In a Maisie program, an arbitrary number of entities may be mapped to a single processor. The execution of these entities is interleaved by the Maisie scheduler. Entities are scheduled for execution based on the timestamps of their enabling message.

An entity can be in one of four states: idle, ready, active, or terminated. An entity that has been terminated does not participate any further in the program. An entity that has not been terminated is said to be idle, if its message buffer does not contain any enabling message. An entity whose buffer contains an enabling message is said to be ready; at any given point, multiple entities on a processor may be in the ready state. The scheduler selects the ready entity with the earliest enabling message for execution which then becomes active. An active entity is self-scheduled. It relinquishes control to the scheduler only if it is terminated or it executes a wait (or hold) statement. In the latter case, if its buffer contains an enabling message it transits to the ready state (and is hence eligible to become active immediately); if not, it transits to the idle state. It is important to note that an active entity is self-scheduled: the scheduler cannot force it to relinquish control. In particular, an active entity that never executes a wait statement, will never relinquish control to the scheduler.

In the following example, the driver entity creates another entity called first, sends 50000 messages to it and then terminates. As the entity does not execute a wait (or hold) statement, all 50000 messages will be generated and delivered to entity first, before any of them can be processed.

17 entity driver{}
18 {  int i;
19    ename first;
20    first =  new sieve{};
21    for(i = 2 ; i <= 50000; ++i)
22       invoke first with number { i };
23 }



Clock Operations

The simplest way to implement the system clock inside the Maisie runtime system would be to use an integer variable. However, in order to allow the simulations to potentially be executed over longer durations, the clock is implemented as a struct whose type is made available to the programmer as clocktype. The following functions are provided to manipulate the simulation clock:

Example:

maxclock("100000000"); /* set maximum simulation time to 100,000,000 */

Also, functions ctf(t1) and cti(t1) are provided which return the floating point and integer values, respectively, of the clocktype variable t1, assuming that the value of t1 is within the respective ranges.

In most cases, it is expected that the maximum value of the simulation clock (specified using maxclock()) would be within the range of int. In such situations, user need not define any special clocktype variables. They can simply use cti() to convert the clocktype value returned by sclock() into an integer, and then store it in an ordinary integer variable.

The following example illustrates the typical use of the sclock() function. The example shows the Maisie code for a simple pre-emptible priority server which serves two types of jobs: jobh -- the high priority job, and jobl -- the low priority job. The server needs to sample the value of current clock whenever the service of a low priority job starts (line 19), is pre-empted (line 11), or re-starts (line 15) . This is so that the remaining service time of the low priority can be correctly computed whenever it is pre-empted by a high priority job.

1   message jobh {int no_served;} old_jobh;
2   message jobl {int no_served;} old_jobl;
3   int busy,start_time,remaining_time;
4   busy=0;
5   remaining_time=MAXINT;
6   for (;;){
7       wait remaining_time until{
8           old_jobh = mtype(jobh) {
9               old_jobh.no_served++;
10              if(busy)
11              remaining_time = cti(sclock())-start_time;
12              hold(expon());
13              invoke next with jobh=old_jobh;
14              if(busy)
15              start_time=sclock();
16          } or old_jobl = mtype(jobl) st (!busy) {
17              old_jobl.no_served++;
18              busy=1;
19              start_time=cti(sclock());
20              remaining_time=expon();
21          } or mtype(timeout){
22              invoke next with jobl=old_jobl;
23              busy=0;
24              remaining_time=MAXINT;
25          }
26      }
27  }

If the specified value of maximum simulation clock is greater than MAXINT, then it is recommended that the user store the sampled values of simulation clock in specially defined clocktype variables. Since the user may need to perform arithmetic operations on such variables, Maisie provides a number of additional functions to perform standard arithmetic operations on clocktype variables. These functions are described in the following table where t1 and t2 are clocktype variables and f is a variable of type float.

FunctionDescription FunctionDescription
clockset(t1,f)set t1 to f   
clockadd(t1, t2)return (t1 + t2) clocksub(t1, t2)return (t1 - t2)
clockmpl(t1, t2)return (t1 x t2) clockdvd(t1, t2)return (t1 / t2)
     
clockeq(t1, t2)return (t1 == t2)   
clockle(t1, t2)return (t1 <= t2) clocklt(t1, t2)return (t1 < t2)
clockge(t1, t2)return (t1 >= t2) clockgt(t1, t2)return (t1 > t2)


Program Initiation and Termination

Every Maisie program must include an entity called driver. This entity serves a purpose similar to the main function of a C program. Execution of a Maisie program is initiated by executing the first statement in the body of entity driver.

A Maisie simulation terminates in one of the following ways:

When a termination condition is detected, the runtime system sends an endsim message to every entity in the system. An entity may either accept or ignore this message. In the former case, it may use the message to take appropriate actions before termination, including printing accumulated statistical data.



Separate Compilation

Maisie supports separate compilation of entities. However, unlike external functions, if an entity is referenced in file f1 and defined in file f2 (f1 != f2), it must be declared as an extern object in file f1. Additionally, if an entity is referenced externally, it must be declared as an extern object in the file containing the driver entity for the program.

The following example illustrates the use of entity sort as an extern entity:

Example:

file1: entity sort{ n, a} ... file2: extern entity sort{}; /* This declaration cannot be omitted */ entity driver {} { ename s1; int x[20]; s1 = new sort{ 20, x}; }



Library Entities

Maisie supports a library facility which includes simple statistics collection entities, server entities etc. A library entity may be included in a program simply by declaring the entity as an extern entity in the file, say f1 where it is referenced. If the driver entity for the program is not also defined in file f1, then the extern declaration for the library entity must also be repeated in the file containing the driver entity. Similar to the convention used in compiling C programs that reference library functions, a Maisie program that includes a library entity must also be compiled with a `-lmaisie' flag.

Remarks:

  1. Currently only two entities are supported: histo and basic_stats. They are defined in the files histogram.m and stats.m respectively in the directory source/libsrc.



next previous contents
Next: Debugging Maisie Programs Previous: Message Communication Up: Contents

Richard A. Meyer
Wed Apr 24 12:50:23 PDT 1996