3.4. pyopus.parallel.evtdrvms — Master-slave event-driven algorithm model (obsolete)

Inheritance diagram of pyopus.parallel.evtdrvms

Master-slave event-driven algorithm model (PyOPUS subsystem name: EDMS)

This is a master-slave algorithm model that first spawns slaves across computing nodes and then communicates with them via messages. An algorithm is described with messages and responses of actors (master and slaves) to the received messages. This module is obsolete and will be removed. It does not support multilevel parallelism. Use the pyopus.parallel.cooperative module instead.

In master-slave algorithms one task is the master task while all other tasks are slave tasks. The master is usually the task that sends jobs to slaves and collects the results sent back by slave tasks.

An event-driven algorithm is described with a set of message handler functions. Every message handler function takes (handles) one type of messages, processes them, and returns new messages and destinations (task identifier objects) for these messages. The produced messages are sent to their destinations.

A message filter is a function that takes a message source identifier object as its argument and returns True if the message should be handled or False if it should be discarded. Discarded messages are never processed.

A dispatcher is a function which detects the message type, applies the corresponding filter, and if the filter returns True hands the message over to the corresponding message handler function.

Every task in an event-driven algorithm is running a so-called event loop which collects incoming messages and dispatches them to corresponding message handler functions. usually the master task’s event loop is more complicated than the event loop of slave tasks.

We denote by local mode the mode of operation where there are no slave tasks present and all messages have the same destination - the master. This means that the master hands out the work and the master also does all the work.

If implemented correctly every parallel algorithm can be transformed in such way that it is capable of running in local mode (on a single CPU core).

class pyopus.parallel.evtdrvms.MsgSlaveStarted(taskID)

A message sent by a slave to the master immediately after it is started. The taskID member holds the task identifier object of the slave.

class pyopus.parallel.evtdrvms.MsgStartup(taskID, isMaster=False, localMode=False)

This message is received by a master/slave immediately after startup (before the event loop is entered).

taskID is the identifier object of the task that receives the message. If the virtual machine is down taskID is None.

The isMaster member is True if the task that receives this message is the master.

The localMode member is True if the task that receives this message starts in local mode.

class pyopus.parallel.evtdrvms.MsgHalt

When this message is received the event loop exits in next iteration.

class pyopus.parallel.evtdrvms.MsgIdle(taskID)

These messages are generated when a task is marked as idle. They are also generated in local mode when master processes all messages and no responses are produced. They are needed if we want an algorithm to work in both master-slave and local mode.

If the taskID member is None, this is a local Idle message (master is running in local mode and it has become idle). Otherwise the taskID is the task identifier object of the idle task.

class pyopus.parallel.evtdrvms.EventDrivenMS(vm=None, maxSlaves=None, minSlaves=0, debug=0, slaveIdleMessages=True, localIdleMessages=False)

The EventDrivenMS class provides an event-driven algorithm model. It takes care of starting up the slave tasks. If there are not enough hosts available for starting slave tasks EventDrivenMS can also run in so-called local mode where only the master event loop is running with all messages having the same destination - the master (denoted by using None instead on a task identifier object for destination). The opposite of local mode is the master-slave mode.

For an algorithm to be capable of running in both master-slave and in local mode the chain of messages must be interrupted from time-to-time (after all input messages have been dispatched, none of the message handlers may produce any output message). At such points in time EventDrivenMS checks if there is enough hosts available for starting slave tasks. If there are enough hosts, slave tasks are started and the local mode is replaced by master-slave mode.

vm is the VirtualMachine object through which EventDrivenMS performs the spawning and communicates with slaves.

maxSlaves denotes the desired number of slaves. The actual number of slaves spawned depends on the number of free slots in the virtual machine. If there are n free slots the number of spawned slaves is at most n.

minSlaves denotes the minimal number of slaves needed for the parallel algorithm to function in master-slave mode. If the number of slaves falls below minSlaves the algorithm is run in local mode. If local mode is not allowed the algorithm fails.

If debug is greater than 0, debug messages are printed to standard output.

If slaveIdleMessages is True a MsgIdle message is generated in the master’s event loop and dispatched to the master every time a slave is marked as idle. A slave is marked as idle immediately after it is started and marked as busy a message is sent to it. An event handler called from the master’s event loop can mark a slave as (not) idle by calling the markSlaveIdle() method.

A MsgIdle message is generated once for every started slave. Despite the fact that it can be replaced by the MsgSlaveStarted message it is still useful. If a user installs a custom MsgSlaveStarted handler and forgets to call the original one, things stop working because the default MsgSlaveStarted handler should take care of slave management, but is now bypassed. It is safer to use MsgSlaveIdle which is not used for slave management.

If localIdleMessages is set to True and we are running in local mode a MsgIdle message is generated every time all messages incoming to the master are handled and the message handlers produce no output messages. This is needed for the algorithm to be able to switch from local back to master-slave mode (happens at such idle moments). Without local MsgIdle messages local run is not possible. Marking a master running in local mode as idle by calling the markSlaveIdle() method with None as the slave task identifier object has no effect.

For every slave task there is a local storage dictionary in the master task that holds the data used by the master for managing the slave. The dictionary can be retrieved by specifying the slave task identifier object to the taskStorage() method. For local mode there is also a local storage dictionary available. It can be retrieved by specifying None as the task identifier object.

addHandler(messageType, handler, filter=None)

Adds a new entry for messages of the type messageType (should be a class) to the message handler and filter table. The handler and filter for the nmessageType are given by handler and filter. if filter is None all messages of the type messageType are handled.

A message handler is a function that takes two arguments:

  • the task identifier object of the task that produced the message and
  • the message object.

Message handlers return a list of zero or more tuples of the form (destination, message) giving the output messages and their destinations.

A filter is a function that takes one argument (the message source task identifier object) and returns True if the message should be handled or False otherwise.

If a handler/filter for a messageType is installed multiple times, the last installed handler/filter pair is the one that is used for handling the messages.

allowLocal(source)

A filter that allows the handling of messages generated in local mode (source = None). Messages from all other sources are discarded.

allowSpawned(source)

A filter that allows the handling of messages coming for spawnned tasks. Handling of messages generated in local mode (source = None) is not allowed.

allowStarted(source)

A filter that allows the handling of messages comming from spawnned tasks from which we already received the MsgSlaveStarted message. Also allows the messages generated in local mode (source = None) to be handled.

fillHandlerTable()

Sets up the message handler and filters table. Override this method in derived classes, but don’t forget to call the parent’s fillhandlerTable() method before making any calls to the addHandler() method.

handleHalt(source, message)

Message handler for the MsgHalt message.

Sets the exitLoop variable to True indicating that the event loop should exit. Produces no response message.

handleHostAdd(source, message)

Message handler for the MsgHostAdd message (virtual machine notification).

It tries to spawn new slaves.

It produces no response message.

handleHostDelete(source, message)

Message handler for the MsgHostDelete message (virtual machine notification).

Does nothing, because the tasks that were running on the host that failed will produce MsgTaskExit messages.

It produces no response message.

handleIdle(source, message)

Message handler for the MsgIdle message.

If the taskID member of the message is None the message was sent because the master is idle in local mode. In all other cases taskID member holds the task identifier object of the idle slave.

This is an empty handler (should be overriden by derived classes. It produces no response message.

handleMessage(source, message)

Handles a message received from source.

First it checks if there is an entry for the message type in the message handler table. If no entry is found the message is discarded.

Next it applies a filter to the message, provided that a filter is set for the corresponding message type. If the filter returns False the message is discarded.

Finally the handler is called. The message and the source are passed to the handler. The list of responses (tuples of the form (destination, message)) is collected from the handler and returned. If the handler returns None an empty response list is assumed.

Returns the response list or None if the message was discarded.

Note that messages may come from sources that were not spawned by the master. Most notably these are workers spawned by the previous master. Therefore filters should always be used.

handleSlaveStarted(source, message)

Message handler for the MsgSlaveStarted message.

Marks the slave identified by the taskID member of the message as started and idle. Creates local storage for the slave.

Produces no response message.

handleStartup(source, message)

Message handler for the MsgStartup message.

This handler can find out if it was called from the master event loop by examining the isMaster member of the message.

If the taskID member of the message holds the task identifier object of the task that received the message. None does not indicate that the master is running in local mode.

The localMode member of the message is True if the task starts in local mode.

This is an empty handler (should be overriden by derived classes.

It should not produces any response message. If it does the responses are discarded.

handleTaskExit(source, message)

Message handler for the MsgTaskExit message (virtual machine notification).

It removes the task that exited from the list of slaves. Then it tries to spawn new slaves (if there are enough free slots).

It produces no response message.

markSlaveIdle(taskID, idle=True)

Marks a slave task as idle if idle is True. Otherwise it marks it as not idle (busy).

markSlaveSpawned(taskID)

Marks a slave task as spawned.

markSlaveStarted(taskID)

Marks a slave task as started.

masterEventLoop()

This is the master’s event loop. Users should call this function to start the event-driven algorithm.

First it sets the exitLoop member to False.

Then it checks if a virtual machine is available. If it is, slaves are spawned. If the number of slaves is below minSlaves the algorithm tries to run in local mode.

An exception is raised if the alogrithm tries to run in local mode and local idle messages are disabled (localIdleMessages is False).

If a virtual machine is available slaves are spawned. The initial mode of operation (local or master-slave) is set.

A MsgStartup message is generated with isMaster set to True and localMode indicating the mode the algorithm starts in. The message is mmediately handled and the resposes are discarded.

Next the main loop is entered. Every iteration of this loop does the following

  1. Re-checks if we are in local mode or master-slave mode.
  2. If a virtual machine is available performs the following steps
    1. If not in local mode, no incoming messages are pending, and slaveIdleMessages is True, generate MsgIdle messages for idle slaves and handle them. Send out the responses.
    2. If in local mode do a nonblocking receive. In master-slave mode do a blocking receive.
    3. Handle the received message and send out the responses.
  3. If we are in local mode and localIdleMessages is True performs the following steps
    1. Generate a local MsgIdle message (taskID set to None) and put it in message
    2. Handle message and collect responses.
    3. If there is more than one response, raise an exception.
    4. If there are no responses go to step 6.
    5. Set message to the first (and only) response and go back to step 2.
    6. Done.

The loop exits when it detects the exitLoop member is True.

After the loop exits the slaves are shut down by calling the shutdownSlaves() method.

removeSlave(taskID)

Removes a slave task identified by the taskID object from the list of slaves and deletes its local storage.

Returns True if a task identified by taskID was present when the function was called.

shutdownSlaves()

Stops all slave tasks by sending them a MsgHalt message. It waits for the MsgTaskExit message to be received from every task.

slaveEventLoop()

This is the slave event loop. Users should never call this function. It is invoked automatically when a slave task is spawned.

First it sets the exitLoop member to False.

Next it removes all slave information inherited from the master’s EventDrivenMS object.

A MsgSlaveStarted message is sent to the parent task (the master) with the taskID member set to the identifier object of the task that called this function.

Next a msgStartup message is generated with the taskID member set to the task identifier object of the task that called this function, the isMaster member set to False and the localMode member set to False. The message is immediately handled and the resposes are discarded.

The main loop is entered. The loop performs the following steps

  1. Receive a message (blocking)
  2. Handle it.
  3. Send out the responses.

The loop exits when it detects the exitLoop member is True.

spawnSlaves()

Spawns slaves on the hosts in the virtual machine.

Retrieves the number of free slots from the virtual machine. The upper limit on the number of slaves is set by maxSlaves. If maxSlaves is None the upper limit is equal to teh number of free slots.

The spawning is performed without specifying the hosts on which the tasks shoukld be spawned. The choice of slots is left over to the virtual machine.

A slave is started by spawning the runSlave() function and passing it a refernce to self (object of class EventDrivenMS). A successfully spawned slave is added to the list of spawned slaves. It becomes operational (gets its own local storage) when a MsgSlaveStarted message is received from the slave indicating that it has entered the slave event loop.

taskStorage(taskID)

Returns the local storage dictionary of the task corresponding to the taskID object. The local storage for spawned slaves is created when a MsgSlaveStarted message is handled and deleted when a MsgTaskExit message is handled.

There is also a local storage for the master running in local mode. It is obtained by passing None for taskID.

If no storage is available for the task with taskID it returns None.

Previous topic

3.3. pyopus.parallel.cooperative — Cooperative multitasking OS with task outsourcing

Next topic

3.5. pyopus.parallel.jobdispatch — Parallel job dispatcher based on the evtdrvms module (obsolete)

This Page