--
MiguelErazo - 20 Nov 2007
9 Caveats
This section lists the problems that are most likely encountered in
the development stage of a PRIME SSF model. They include both common
compile-time and runtime errors that could result from mistakes in
models easily overlooked by both inexperienced and experienced users.
We hereby address these common problems as well as places in the model
that require special attention. We stress the important issues in the
model design process.
9.1 Source Code Instrumentation
In the beginning development stage of a PRIME SSF model, it is very
likely the modeler would experience problems related to adding
annotations. These annotations help the source-to-source translator to
identify places at which special code must be inserted to support the
handcrafted multithreading mechanism. Fail to properly add these
annotations may cause cryptic compilation errors and mysterious
runtime bugs.
- the simulation program,
main is actually a predefined
macro, which is designed to rename the user main function. It is so
that the main function defined by the runtime system becomes the
starting function of the simulation program. The user's main function
is renamed to some other name and is invoked by the runtime system
after some initial setup. The caveat of this approach is that the user
should not use the symbol
main other than to define the main
function in a canonical way:
int main(int argc, char** argv) {
...
}
In particular, the user cannot use
main as variable names or
method names.
- //!~SSF PROCEDURE} or
//!~SSF PROCEDURE SIMPLE must be placed at the same line following the declaration of a procedure.
-
//!~SSF PROCEDURE or //!~SSF PROCEDURE SIMPLE must be placed at the line immediately above where the procedure method is defined.
- Procedures must be declared (in class definition in header files) and defined (typically in source files) separately.
- The procedure of a simple process must be annotated with
//!~SSF PROCEDURE SIMPLE. The procedure of a non-simple process must use //!~SSF PROCEDURE. The annotations must match with the type of the process that invokes the procedures.
- If the start procedure of process is an entity method, the method must use the follow function prototype:
void entity_method_name(Process*);
- A simple process must be simple. That is, there must be one and only one wait statement in any possible execution path and the wait statement must be the very last statement to execute before the process' starting procedure reaches the end the function..
- A local variable in a \emph{non-simple} procedure must be declared as a state variable (annotated by
//!~SSF STATE), if the variable is to be used across process suspensions. It's worth mentioning that the boolean variable used to store the return value of the waitOnFor or waitOnUntil methods must be marked by //!~SSF STATE as it logically spans across suspension. When in doubt, always declare the variable as a state variable.
- Remember that the scope of state variables is the entire procedure. Therefore, nested local variables should be avoided in procedures.
- The procedure state variables must always be declared first at the beginning of a procedure, one variable per line, and they must not be initialized during declaration.
- Procedure state variables that are declared by
//!~SSF STATE will be replaced by the source-to-source translator inside the procedure body. That is, all symbols that match the name of the variable will be replaces no matter whether or not they are referring to the same variable syntactically. It is wise to make sure that a procedure state variable is uniquely defined in the procedure body.
-
//!~SSF CALL must be placed immediately above the line of a procedure call. There must be at most one procedure call at a line.
- It is not allowed to make a function call to a procedure method inside a regular (non-procedure) function. It is allowed however to make a regular function call inside a procedure body.
9.2 Event Referencing Rules
PRIME SSF imposes strict rules for referencing simulation events. It
helps improve the efficiency of the simulator by allowing both user
and the runtime system to share the events.
- When an event object is created, it is \emph{owned} by the user. The user can almost do everything to this event, including modifying the content of the event or even reclaiming the event when necessary.
- When the event is given to the runtime system (e.g., by calling the
outChannel::write method), the event becomes owned by the runtime system. This process is irreversible. When a user's callback function is invoked and the event is provided by the runtime system as an argument to the call (such as the callback function defined in the ssf_timer class), or the user explicitly retrieves the arrival event(s) at an input channel (such as the inChannel::activeEvents method), the events are still owned by the runtime system. The user only has limited access right to a system-owned event. The user can inspect the event before the callback function returns or the process becomes suspended again. The user, however, cannot access an event owned by the system after process suspension, unless the user creates another reference to the event by calling the Event::save method.
- An event is read-only if it is not aliased (determined by a call to the
aliased method). If you need to modify an aliased event, you should make an explicit copy of the event first.
- An event that has been saved cannot be reclaimed by the runtime system unless a matching number of
release calls are made. The number of release calls must never be larger than the previous calls to the save method.
- It is required that the copy constructor as well as the
clone method should be provided for any derived event class.
9.3 Entity and Event Registrations
In order to build a simulation model on a distributed platform using
the SSF DML model specification, correct mapping must be established
between the model DML and the class definitions in the source
code. This is done in part by using those macros defined by PRIME SSF.
- Every derived entity class that is public should provide a factory callback method that can be used to create an instance of the entity from a list of parameters. The prototype of the factory method must be
static Entity* entity-factory-method(const ssf_entity_dml_param**);
- The public entity class must be registered with the runtime system to associate the name of the class with the factory callback method:
SSF_REGISTER_ENTITY(entity-name, address-of-entity-factory-method);
The name of the entity is given as the first argument of the
macro and it should match the entity name in the model DML
file (i.e., the value of the
INSTANCEOF attribute).
\item A derived event class should override the
pack method to
help the kernel translate the event object into a machine-independent
byte stream (represented by
ssf_compact).
- A factory callback method must also be defined for the event class. The callback method is responsible for creating a new instance of the event class and deserialize the member data of this event from a byte stream. The prototype of the event factory callback method must be:
static Event* event_factory_method(ssf_compact*);
- A derived event class must use the
SSF_DECLARE_EVENT macro to declare this event class with runtime system in the class definition and use the SSF_REGISTER_EVENT macro to associate the event class with the factory method in the source code.