Parallel mode

Normal mode

BrainStream has built-in options for executing actions parallel-wise instead of the standard serial way of executing actions. Since users explicitly need to tell BrainStream when to add a copy of a global variable to the event structure (get) or reversely copy updated content to the global variables (put), BrainStream 'knows' if functions can execute parallel-wise. This is very useful since this way concurrent execution of markers with actions that would alter content of the same variables can be prevented. A 'locking' mechanism is used to guarantee correct parallel execution. If for marker m1 actions are being executed for which at some timepoint variable v1 wil be updated, this variable v1 is 'locked', which prevents execution of any other marker (for example m2) that would request variable v1. As soon as all functions of m1 have been processed, v1 will be 'unlocked' and functions of m2 will then be executed.

To use this feature:
Add a column named: 'client' to the experiment definition table, i.e., the columns become marker, time, function, client. It is then possible to define a remote client that will be responsible for the execution of the timepoints' corresponding functions. The name for this client can be directly a DNS-address or an ip-number, however, for flexibility reasons it is advised to use aliases for those clients and ultimately define the actual client via the block file settings.

BS_INITEVENTinit_all [],get,put[],get,put
stimulusEVENT $self+1
It this example the client alias is: myclient.

- Tell BrainStream? it should use the parallel execution mode by setting RunMode.Parallel=1 (topic [RunMode] and key Parallel).

Parallel = 1

Define actual clients in block settings since then the actual used remote client computer can be changed very easily. There are some options on how to do this:

myclient = '123.456.0.1'%myclient = 'a_DNS_address
myclient = 'cores' % !BrainStream chooses any available parallel core 
myclient = 'core#' % BrainStream.BrainStream always takes core# (# is an arbitrary number) and queues jobs if core is busy
myclient = 'local' % BrainStream.BrainStream executes actions serial-wise (no parallel execution)

For external clients, make sure Matlab is started and its path includes all BrainStream folders as well as all folders holding any of your own user functions. Internal clients (cores or core#) are started automatically by BrainStream. If a repository is used, required remote Matlab path settings can all be automatically copied from the BrainStream server side. However, since folder structures on remote clients might differ from the computer running BrainStream? it is advised to take care of adding required folders to the Matlab path yourself. Do this by writing a function dedicated to this task and add it to the initialization processing step for this client. Make sure this function is in one of your plugin folders and add this folder to the Matlab path at forehand by specifying corresponding blocksetting. Use the name of the specific client as topic and specify the Plugins key to add a list of plugin-folders to the Matlab path at the client side at forehand.

Plugins = {'myplugin_folder'}

To start BrainStream? on this external client start:

where, dns a string holding the ip-address of the computer running BrainStream.

For the specification in the tables, some client names are reserved:
'cores': BrainStream takes the first available core to execute the functions.
'core#: A specific core is requested for execution of the functions. # can be any number (integer).
'local': Revert execution back to serial-wise execution, i.e., no parallel execution.

The maximum number of cores BrainStream will use can be defined via the block settings: topic [RunMode], key NumCores (RunMode.NumCores).

Parallel = 1
BrainStream.NumCores = 4

Experiment definitions need to be set up accordingly. If functions, for some reason, always need to be executed at a specific client, make sure that all corresponding processing steps specify the same client name. This is necessary in case variables of Matlab type object are being used (for instance figure handles). The object itself is internally stored by Matlab at the remote client side, and will only be available over there. To initialize such variables at the client side, insert a marker at the BS_INIT (t=EVENT) and specify mod-actions or functions, an example:

marker time function client myfig
BS_INIT EVENT bs_insert_marker('init_myclient',0)    
init_myclient EVENT init_figure myclient put

Processing pipelines can define any number of clients to be used. Their corresponding processing steps are not restricted to all using a single same client. Every processing step or timepoint can define its own client for execution. The computer running BrainStream should make ports 5001 - 5002 available, these are used to install all clients.

Note that the user event structure will be sent from BrainStream to the remote client and vice versa. Be careful with large amounts of data since they will delay the communication between BrainStream and the remote client. Keep this in mind when defining your experiment. Future releases will automatically improve efficiency of this data transport by only transmitting required information.

(set screenoutputlevel to 'INFO', this will show possible error-related information form the remote-client on your screen directly)

WARNING: correct processing of markers is NOT guaranteed if markers are inserted using bs_insert_marker when running in parallel mode. In this case you should use sndMarker, which sends markers to BrainStream? immediately. If multiple clients insert markers, take into account possible differences in timing or make sure they will never cause any conflicts.

Loop 'tick' mode

The ability to execute user-functions remotely at some specific client already solves a lot of implementation issues, however many experiments also need the support of functions that run in a loop. For this purpose, users can define a so called 'looptick' function. BrainStream? will then integrate this function in a while-loop running at the client. The looptick function should have the following format:

function [event, stoploop, waittime] = looptickfunction(event, tick_count, abort_loop)
stoploop = 0;
waittime = 0;

if tick_count == 1
   % do initializations before the loop starts
if dosomething % add your own expression to determine moment of action
   % do it
   % set waittime > 0 if next looptick call can be delayed
   % set stoploop = 1 if you want to stop the loop
if abort_loop
   % finalize stuff before BrainStream.BrainStream forces the loop to exit

To specify a looptick function in the experiment definition table, add a column with header: looptick. In this column, one function can be specified (don't forget to specify on which client it should run). If the function column defines functions also, they will be executed prior to entering the loop. In the table expansion, other normal functions will still append, however during execution time, the looptick function always remains the last one in row.Defining a second looptick function for a marker will produce an error.

Below the experiment definition table of the topoplotlp library plugin:

marker time function looptick client hdr topoplot
BS_EXIT,BS_QUIT EVENT stpdata_topoplot save
BS_INIT EVENT bs_insert_marker('init_topoplot',0)
init_topoplot EVENT init_topoplot, bs_insert_marker('start_loop',0) topoplotlp get [],get,put
start_loop EVENT rcvdata_topoplottick topoplotlp get get

Note that it is also possible to specify 'regular' functions in the function column. These functions will be executed prior to entering the rcvdata_topoplottick loop.

Changing remote parameters

Information available from user functions executing at the BrainStream? side, can be sent to the remote client immediately using the following function: bs_send_uservars(event,client_nickname,<variable>)

At the remote client side it can be received using: [uservars, success] = bs_recv_user_brainstream(event,client_nickname)

A function that would only update the content of a topoplot would be something like this:

function [event, stoploop, waittime] = rcvdata_topoplottick(event,tick_count,abort_loop)
stoploop = 0;
% Check for topoplot updates every 0.1 s.
waittime = 0.1;
if tick_count == 1
    % init stuff
if abort_loop
    % finalize stuff
% check for new topoplot information
[uservars, success] = bs_recv_user_brainstream(event,'topoplotlp');
if success>=0 && ~isempty(uservars)
    if isempty(uservars{end}) 
        stoploop = 1; % user sent empty value to stop the loop
        % only take the latest sent item (discard earlier sent info) = uservars{end};
        % update the figure
        event = update_topoplot(event);

The topoplot example is already available as a plugin to your experiment. See corresponding plugin section for instructions on how to add it to your own experiment.

Edit | Attach | Print version | History: r2 < r1 | Backlinks | Raw View | Raw edit | More topic actions...
Topic revision: r1 - 10 Nov 2009 - 10:50:54 - MarianneSeverens
This site is powered by the TWiki collaboration platformCopyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback