1. Introduction

This document is intended for Techila Distributed Computing Engine End-Users who are using MATLAB as their main development environment. If you are unfamiliar with the terminology or the operating principles of the Techila Distributed Computing Engine technology, information on these can be found in Introduction to Techila Distributed Computing Engine.

The structure of this document is as follows:

Introduction contains important information regarding the preparation steps required to use Techila Distributed Computing Engine with MATLAB. This chapter also contains a brief introduction on the naming convention of the MATLAB m-files and introduces the two functions, peach and cloudfor, which are used for distributing computations from MATLAB to the Techila Distributed Computing Engine environment.

Cloudfor Examples contains walkthroughs of code samples that use the cloudfor-function. The example material demonstrates how functions containing locally executable for-loop structures can be converted to distributed versions by using cloudfor-loops. The examples also illustrate how to use control parameters to enable both basic and more advanced cloudfor features. After examining the material in this Chapter you should be able to convert normal for-loops in to cloudfor-loops, manage return values and to enable additional cloudfor features.

Peach Tutorial Examples contains walkthrough of simplistic example code samples that use the peach-function. The example material illustrates how to control the core features of the peach-function, including defining input arguments and transferring data files with the executable program. Examples are also provided on how to distribute perfectly nested loop structures and for performing local testing on your own computer. After examining the material in this Chapter you should be able split a simple locally executable program into two pieces of code (Local Control Code and Worker Code), which in turn can be used to perform the computations in the Techila Distributed Computing Engine environment.

Peach Feature Examples contains several examples that illustrate how to implement different features available in the MATLAB peach-function. Each subchapter in this Chapter contains a walkthrough of an executable piece of code that illustrates how to implement one or more peach-function features. Each Chapter is named according to the feature that will be the focused on. After examining the material in this Chapter you should be able implement several features available in the MATLAB peach-function in your own application.

Interconnect contains cloudfor-examples that illustrate how the Techila interconnect feature can be used to transfer data between Jobs in different scenarios. After examining the material in this Chapter, you should be able to implement Techila interconnect functionality when using cloudfor-loops to distribute your application.

Troubleshooting contains a short troubleshooting guide for some typical error scenarios.

1.1. Preparation

This Chapter contains information of the preparation steps required before you can access the Techila Distributed Computing Engine environment from your MATLAB. These steps include:

1.1.1. Modifying the MATLAB Search Path

Before proceeding, please add the folder containing the Techila Distributed Computing Engine MATLAB functions to the MATLAB search path. This can be done by following the steps listed below.

  1. Change your working directory in MATLAB to the following directory

    <full path>\techila\lib\Matlab

  2. Execute the following command:

    installsdk

This will add the path containing the Techila Distributed Computing Engine MATLAB functions to the MATLAB search path and will attempt to save the search path for use in future MATLAB sessions. This is performed by saving the search path to a file called pathdef.m.

Note! If you do not have rights to modify the pathdef.m file, you might receive a warning message. If this occurs, the MATLAB search path might need to be updated at the start of a new MATLAB session.

If you wish to make the path update process automatic, but do not have rights to modify the pathdef.m file, you can update the MATLAB search path by for example using the userpath or addpath commands. These commands can be added to the startup.m file in the MATLAB startup folder, which will update the MATLAB search path when launching MATLAB. Examples of the commands are shown below:

userpath('<full path>\techila\lib\Matlab')

Or

addpath('<full path>\techila\lib\Matlab')

The <full path> notation should be replaced with the path leading to the techila folder on your system. More information on how to modify the userpath and startup options can be accessed from MATLAB with the following commands:

doc userpath
doc startup
doc addpath

1.1.2. Testing Network Connectivity

In order to connect to your Techila Distributed Computing Engine environment, your computer must be able to establish a network connection with the Techila Server. To test that a network connection can be established, execute the following command in your MATLAB.

techilainit

If the network connection works, the function should return value 0. Any other return value is an indication of a problem. For a description on the error code values, please see Error Codes. The screenshot below shows what the output looks like when the network connection works ok.

techilainit

1.1.3. Choosing the Compiler for MATLAB Applications

Computational MATLAB Projects require that a local MATLAB compiler is available for compiling the Techila Worker Code. Before proceeding, please ensure that the following MATLAB components are available:

When the above components are available, you can setup your MATLAB compiler by executing the following command in MATLAB:

mbuild -setup

The screen capture below illustrates what the output of command looks like when a compiler was successfully configured:

mbuild

Please note that compiled binaries are platform specific and can only be executed on Techila Workers with a compatible platform according to the table below.

Compilation Platform and MATLAB Version Compatible Techila Worker Platforms

Windows 32-bit MATLAB

Windows 64-bit

Windows 64-bit MATLAB

Windows 64-bit

Linux, 64-bit MATLAB

Linux 64-bit

1.2. Example Material

The MATLAB m-files containing the example material examined in this document are located under the "cloudfor", "Tutorial", "Features" and "Interconnect" folders in the Techila SDK. The table below describes where you can find the walkthroughs for the example material.

Techila SDK Folder Example Walkthrough Chapter Description

techila/examples/Matlab/cloudfor

Cloudfor Examples

Contains example material that illustrates the use of the cloudfor -function.

techila/examples/Matlab/Tutorial

Peach Tutorial Examples

Contains tutorial examples that use the peach-function.

techila/examples/Matlab/Features

Peach Feature Examples

Contains feature examples that use the peach-function.

techila/examples/Matlab/Interconnect

Interconnect

Contains examples that illustrate how the Techila interconnect functions can be used when using the cloudfor-function.

1.3. Naming Convention of the MATLAB m-files

The typical naming convention of MATLAB m-files presented in this document is explained below:

  • MATLAB m-files ending with "_dist" contain the Worker Code, which will be compiled and distributed to the Techila Workers when the Local Control Code is executed.

  • MATLAB m-files beginning with "run_" contain the Local Control Code, which will create the computational Project when executed locally on the End-Users computer.

  • MATLAB m-files beginning with "local_" contain locally executable code, which does not communicate with the Techila Distributed Computing Engine environment.

Please note that some m-files and/or functions might be named differently, depending on their role in the computations.

1.4. MATLAB peach-Function

The MATLAB peach-function provides a simple interface that can be used to distribute even the most complex programs or precompiled binaries. The general syntax is shown below.

peach(funcname, params, [files], peachvector, ...)

The peach-function call deploys and executes the function funcname in the Techila Distributed Computing Engine environment with the input arguments defined in the params array. The files array is an optional parameter, which can be used to transfer data files to all participating Techila Workers.

Even the most minimalistic peach-function syntax will always contain the three mandatory parameters: funcname, params and peachvector. The syntax for using these three parameters is shown below:

peach(funcname, params, peachvector)

As can be seen, the files array does not need to be defined if no additional data files need to be transferred.

If the executable function does not require any input arguments, empty curly brackets {} can be used to create an empty params array as shown below:

peach(funcname, {}, peachvector)

The use these parameters is illustrated in the Peach Tutorial Examples. General information on available peach-function parameters can also be displayed by executing the following command in MATLAB.

doc peach

1.5. MATLAB cloudfor-Function

The cloudfor-function provides an even more simplistic way to distribute computationally intensive loop structures to the Techila Distributed Computing Engine environment. The local for-loop structure that will be distributed and executed on Techila Workers is marked with two keywords: cloudfor and cloudend. These keywords mark the beginning and end of the loop structure that will be executed on the Techila Workers.

The image shown below illustrates the general syntax for marking a block of code for simultaneous execution:

image2
Figure 1. Converting for-loop structures to cloudfor-loop structures enables you to execute the computationally intensive operations in the Techila Distributed Computing Engine environment.

The <executable code> notation in the example above represents the operations that will be executed during each iteration of the loop structure. The initval and endval variables correspond to the same values as in the regular for-loop, representing the start and end values for the loop counter.

Please note that all iterations of the cloudfor-loops will be performed simultaneously on Techila Workers, meaning there must not be any recursive dependencies in the code. For example, the conversion shown below is possible as all the iterations are independent.

A=zeros(10,1);
for i=1:10
    A(i)=i;
end
A=zeros(10,1);
cloudfor i=1:10
    A(i)=i;
cloudend

But it is NOT possible to convert the loop structure shown below. This is because the value of A in the current iteration (e.g. i=3) depends on the value of the previous iteration (i=2).

A=5;
for i=1:10
    A=A+A*i;
end

Recursive dependency in the local for-loop, cloudfor-loop cannot be used.

Note! When storing results in a vector or matrix, you will need to initialize the vector or matrix and transfer it to the Jobs. If the result vector or matrix is not initialized and/or transferred, the results will not be processed correctly when the Project has more than one Job. For example, the following code snippet would not work, because the result vector is not initialized and transferred.

% A=zeros(10,1); % Commented out, meaning the result array will not be initialized.
cloudfor i=1:10
%cloudfor('stepsperjob',5)
    A(i)=i;
cloudend

When the cloudfor keyword is encountered, all variables currently defined in the MATLAB Workspace will be transferred to Techila Workers. The number of Jobs will, by default, be automatically set by executing the block of code once on the End-User`s own computer and using the execution time to determine a suitable number of Jobs.

The number of iterations performed in a single Job can also be controlled with the %cloudfor('stepsperjob',<iterations per job>) control parameter as shown below.

cloudfor var=1:10
%cloudfor('stepsperjob', 2)
  <executable code>
cloudend

In the example above, five (5) Jobs would be created. This is because as the maximum value of the loop counter is ten (10) and stepsperjob parameter defines that two (2) iterations would be executed in each Job.

It is also possible to use control parameters available for the peach-function by using the %peach syntax as illustrated in the example below.

cloudfor var=1:10
%cloudfor('stepsperjob', 2)
%peach('UseJVM', 'true')
  <executable code>
cloudend

It is also possible to distribute perfectly nested for-loop structures. In perfectly nested for-loops, all content is inside the innermost for-loop. In situations where you have a locally executable perfectly nested for-loop structure, you can distribute the computations to the Techila Distributed Computing Engine environment by marking the executable code as shown below.

cloudfor var1=1:10
    %cloudfor('stepsperjob',1)
    cloudfor var2=1:10
        %cloudfor('stepsperjob',1)
        <executable code>
        <more executable code>
    cloudend
cloudend

Note! It is not possible to distributing imperfectly nested for-loop structures. In imperfectly nested for-loops, some of the executable code is outside the innermost for-loop. The example below contains an example code snippet which is not valid, because <executable code> is located between the cloudfor statements.

% This is NOT a valid syntax.
cloudfor var1=1:10
    <executable code>
    cloudfor var2=1:10
        <more executable code>
    cloudend
cloudend

It is also possible to use several cloudfor statements on the same level as shown below

cloudfor i=1:10
  <executable code>
cloudend
cloudfor j=1:10
  <executable code>
cloudend

But it is NOT possible to use cloudfor statements on the same level when inside a cloudfor statements.

cloudfor i=1:10
    cloudfor j=1:10
      <executable code>
    cloudend
    cloudfor k=1:10
      <executable code>
    cloudend
cloudend

General information on available control parameters can also be displayed by executing the following command in MATLAB.

doc cloudfor

Please note that cloudfor-loops should only be used to divide the workload in computationally intensive loop structures. If you have a small number of computationally light operations, using cloudfor-loops will not result in better performance. As an exception to this rule, some of examples discussed in this document will be relatively simple, as they are only intended to illustrate the mechanics of using cloudfor-loops.

1.6. Automatically Generated Techila Worker Environment Variables

When executing MATLAB Jobs on Techila Workers, several automatically generated environment variables are automatically available. Below is a summary of environment variables that are available during MATLAB Jobs.

Environment Variable Description Example value

TECHILA_PID

The Project ID number of the Project. This will be same for all Jobs in a Project. 19861

TECHILA_JOBID

The Job Id number of the Job. This number contains the Project ID number and the Job`s index. Jobid is presented as a binary-coded decimal which has 64-bits in total. First 32-bits are used to represent the Project ID number and the last 32-bits are used to represent the Job`s index number. 85302345465857 (This corresponds to Project 19861, Jobidx 1)

TECHILA_JOBID_IN_PROJECT

The Job`s index in the specific Project. The values will range from 1 to the total number of Jobs in the Project. 1

TECHILA_WORKERID

The Techila Worker ID of the Techila Worker that is processing the Job. 332

TECHILA_JOBCOUNT

The total number of Jobs in the Project. 40

Values of these environment variables can be retrieved by e.g. the getenv MATLAB function, which can be used to retrieve the value of an environment variable. Below example illustrates the MATLAB syntax for the retrieving the value of the TECHILA_JOBCOUNT environment variable.

jobcount=str2num(getenv(`TECHILA_JOBCOUNT`));

2. Parameter Highlights

2.1. Allowrevert

When used, the allowrevert control parameter will revert the code to be executed locally in situations where Techila Distributed Computing Engine cannot be used. This can help improve code robustness as the code can be executed even if there is a temporary service break or there is a network connection issue between your computer and the Techila Server. The syntax for enabling allowrevert is shown below:

%cloudfor('allowrevert')
allowrevert

The allowrevert parameter also enables you to share code with other users that do not have access to a Techila Distributed Computing Engine environment. The list below describes the additional considerations that need to be taken into account when sharing cloudfor code with non-Techila users.

  1. Add the allowrevert parameter to the cloudfor loop.

    %cloudfor('allowrevert')
  2. If the cloudfor loop contains an if isdeployed clause, it will need to be removed to ensure that the code can be executed locally.

  3. The receiving party will need to either have the entire Techila SDK or a subset of the Techila SDK files on their computer so that the cloudfor function can be used when executing the code. More information on which files are needed needed in the Techila SDK subset can be found here. Please note that the receiving party will not need a techila_settings.ini file or a keystore file as the code will be executed locally.

  4. The receiving party will also need to update their MATLAB search path to ensure that the cloudfor and peach functions are found. Instructions for this can be found in Modifying the MATLAB Search Path.

  5. After installing the Techila SDK and the updating the MATLAB search path, the receiving party can run the cloudfor version of the code.

3. Cloudfor Examples

This Chapter contains walkthroughs of the example material that use the cloudfor-function. The examples in this Chapter highlight the following subjects:

The example material used this Chapter, including m-files and data files can be found in the subfolders under the following folder in the Techila SDK:

techila\examples\Matlab\cloudfor\<example specific subfolder>

Please note that the example material in this Chapter is only intended to highlight some of the available features in the cloudfor-function. For a complete list of available control parameters, execute the following command in MATLAB.

doc cloudfor

3.1. Controlling the Number of Jobs

This example is intended to illustrate how to distribute the iterations an extremely simple for-loop structure. Executable code snippets are provided of a locally executable for-loop structure and a distributed version that uses cloudfor-loops. Information on how to control the number of iterations calculated during a single Job is also provided.

The material used in this example is located in the following folder in the Techila SDK:

techila\examples\Matlab\cloudfor\1_number_of_jobs

When using cloudfor-loops to distribute a for-loop structure, the maximum number of Jobs in the Project will be automatically limited by the number of iterations in the loop. For example, the loop structure below contains 10 iterations, meaning that the Project can contain a maximum of 10 Jobs.

 cloudfor counter=1:10
   <executable code>
 cloudend

When using the cloudfor-function, one iteration of the loop structure will be executed locally on your computer. This execution time will be used to automatically estimate how many iterations should be performed in a single Job. If the execution time required for the locally executable iteration is short, multiple iterations will be automatically grouped in each Job. If the locally executable iteration requires a long time, the number of iterations performed in each Job will be set to one (1).

If you require more control over the number of iterations that will be performed in each Job, this can be achieved by using the stepsperjob control parameter. The general syntax for using this control parameter is shown below:

%cloudfor('stepsperjob', <iterations>)

Where the <iterations> notation can be used to define the number of iterations that should be performed in each Job. For example, the syntax shown below would define that each Job in the Project should perform two iterations:

%cloudfor('stepsperjob',2)

Please note that when using the stepsperjob parameter, you will also fundamentally be defining the length of a single Job. If you only perform a small number of short iterations in each Job, the Jobs might be extremely short, resulting poor overall efficiency. It is therefore strongly advised to use values that ensure the execution time of a Job will not be too short.

Tip! If you want to avoid running the function calls in your code locally, you can achieve this by wrapping the content of the cloudfor-statement in an if isdeployed block as illustrated below.

cloudfor counter=1:10
%cloudfor('stepsperjob',1)
 if isdeployed
	<executable code>
 end
cloudend

When the code is wrapped in an if isdeployed statement, it will only be executed when it is in compiled form. Please note that when you wrap the code in an if isdeployed statement, you will need to use the stepsperjob parameter to define how many iterations will be processed in each Job.

3.1.1. Locally executable program

The locally executable program used in this example is shown below.

function result=local_loops(loops)
% This function is executed locally on your computer and does not
% communicate with the Techila environment. This function contains a single
% 'for'-loop structure, where the iteration number 'counter' is squared
% each iteration.
%
% To use: result=local_loops(loops)
%
% loops = the number of loops performed
%
% Example: result=local_loops(10)

% Copyright 2011-2013 Techila Technologies Ltd.

result=zeros(1,loops); % Create an empty vector for the result values

% The locally executable for-loop structure.
for counter=1:loops                  % Set the number of iterations
    result(counter)=counter*counter;
end

The code contains a single for-loop, which contains a single multiplication operation where the value of the counter variable is squared. The value of the counter variable will be replaced with the iteration number, which will be different each iteration. The result of the multiplication will be stored in the result vector, which will be used to contain all multiplication results.

The locally executable program can be executed by changing your current working directory in MATLAB to the directory containing the material for this example and executing the command shown below:

result=local_loops(10)

Executing the command shown above will calculate 10 iterations and store the following variables to the result vector. The values generated during this simple program are illustrated in the image below.

image3
Figure 2. Results of the latest iteration are stored in the result-vector. The result of the latest iteration has been circled in this figure.

3.1.2. The distributed version of the program

The distributed version of the locally executable program that uses cloudfor-loops is shown below.

function result=run_loops_dist(loops)
% This function contains the 'cloudfor' version of the locally executable
% program. Calling this function will create a computational Project, where
% the multiplication operations will be executed on the Workers. Each Job will
% calculate two iterations of the loop structure.
%
% To use: result=run_loops_dist(loops)
%
% loops = The number of loops performed. The number of Jobs in the Project
%         will be loops/2.
%
% Example: result=run_loops_dist(10)
%
% The example shown above would create a Project consisting of five Jobs.

% Copyright 2011-2015 Techila Technologies Ltd.

result=zeros(1,loops); % Create an empty vector for the result values

% The keywords 'cloudfor' and 'cloudend' have been used to mark the
% beginning and end of the block of code that will be executed on Workers.
% ------------------------------------------------------------------------
% The %cloudfor(key,value) parameters used in this example are explained below:
% ------------------------------------------------------------------------
% ('stepsperjob',2)       Sets the number of iterations performed in each Job to
%                         two (2)
% ------------------------------------------------------------------------
cloudfor counter=1:loops % Beginning of the cloudfor-block
%cloudfor('stepsperjob',2)
    result(counter)=counter*counter;
cloudend % End of the cloudfor-block

As can be seen, the locally executable for-loop has been replaced with a cloudfor-loop. The for and end words in the locally executable loop have been replaced with the cloudfor and cloudend keywords. This indicates that the block of code that is located in the loop structure will be executed on Techila Workers.

The stepsperjob control parameter has been used to define that two iterations should be calculated in in each Job. This means that for example if the number of loops is set to 10, the number of Jobs will be 5 (number of loops divided by the value of the stepsperjob parameter).

3.1.3. Running the example

The distributed version can be executed by changing your current working directory in MATLAB to the directory containing the material for this example and executing the command shown below:

result=run_loops_dist(10)

After you have executed the command, the computational code will be compiled by using the MATLAB compiler. Depending on your system, the compilation will take roughly one minute. After the compilation is completed, the Project will be automatically created and will consist of five (5) Jobs. These Jobs will be computed on Techila Workers and the results will be streamed back to your computer. Results generated during the Jobs will be stored in the result vector at the applicable indexes. This is illustrated below in the image below

image4
Figure 3. Each Job will calculate two iterations and will return the values. Please note that even though Jobs are not completed in any given order, values of the computation will be automatically stored at the correct indices. The results of the latest Jobs have been circled in this figure.

Tip! To view the effect of the stepsperjob control parameter, enter a different value for the parameter. You can also delete the line containing the control parameter entirely.

3.2. Specifying Which Workspace Variables will be Transferred

By default, all MATLAB Workspace variables will be transferred to all participating Techila Workers. This can sometimes result in unnecessarily large network transfers, where Workspace variables will be transferred to Techila Workers even though they will not be required in the computation.

After the Techila Workers have finished the computational Jobs, all Workspace variables which have changed will be automatically returned and transferred back to then End-Users computer. This can also result in unnecessary network transfers if only some variables are required.

This example illustrates how to specify which MATLAB Workspace variables should be transferred to Techila Workers and which variables should be returned. This is most beneficial in scenarios, where the Workspace contains e.g. large matrixes that consume large amounts of memory, but are not required on Techila Workers or do not contain meaningful results. Specifying Workspace variables in these kinds of situations will reduce the amount of data that will be transferred and can improve overall performance.

The material used in this example is located in the following folder in the Techila SDK:

techila\examples\Matlab\cloudfor\2_workspace_variables

Workspace variables to be transferred to Techila Workers are specified with the inputparam control parameter. The general syntax for defining Workspace variables is shown below.

%cloudfor('inputparam',<comma separated variables>)

Where the <comma separated variable names> notation should be replaced with the names of the Workspace variables that should be transferred to Techila Workers. For example, the following notation specifies that only variables called var1 and var2 should be transferred.

%cloudfor('inputparam',var1,var2)

Please note that when using the inputparam parameter, you will need to ensure that all necessary Workspace variables are listed. These might also include any possible vector and/or matrices that are used to contain the computation results.

Global variables can be transferred by using the global keyword. For example, the following notation specifies that variables var1 and var2 and all global variables should be transferred to the Techila Workers.

%cloudfor('inputparam',var1,var2,global)

Please note that if you wish to transfer workspace variables that require more than 10 Megabytes memory, you will also need to use a control parameter to enable the variables to be transferred. This is a safety measure, which is intended to prevent large, accidental data transfers. To override the 10 Megabyte limit, use the parameter shown below.

%cloudfor('force:largedata')

Workspace variables to be returned from Techila Workers are specified similarly as a comma separated value list by the using the outputparam control parameter. The general syntax for defining Workspace variables that will be returned is shown below.

%cloudfor('outputparam',<comma separated variables>)

For example, the following notation specifies that only variables called out1 and out2 should be returned.

%cloudfor('outputparam',out1,out2)

3.2.1. Locally executable program

The locally executable program used in this example is shown below.

function result = local_workspace
% This function is executed locally on your computer and does not
% communicate with the Techila environment. The function contains two
% nested 'for'-loops. In each iteration, the iteration counters 'ii' and
% 'jj' will be multiplied. The multiplication result will be stored in a
% matrix.
%
% To use: result = local_workspace

% Copyright 2011-2013 Techila Technologies Ltd.

var1=[2 4 6]; % Length of 'var1' will define number of outer loop iterations
var2=[11 51 100]; % Length of 'var1' will define number of inner loop iterations
dummyvar=rand(2000); % Create a dummy variable, not used in computations
result=zeros(length(var1),length(var2)); % Create empty result matrix

% Locally executable nested 'for'-loop structures.
for ii=1:length(var1) % Beginning of the outer loop
    for jj=1:length(var2) % Beginning of the inner loop
        result(ii,jj)=var1(ii)*var2(jj); % Store the multiplication result in the matrix
    end % End of the inner loop
end % End of the outer loop

The program contains a single function, which will multiply elements in the vectors var1 and var2. The result of this multiplication will be stored in the result matrix (size of 3x3) at the coordinates indicated by the loop counter indices.

The function also defines a variable called dummyvar, which is created simply for illustrational purposes and is not used in the operations performed in the loop structure. The purpose of this variable is to demonstrate how using the control parameter to specify transferrable Workspace variables can reduce the amount of network transfer. This is explained in more detail later in this Chapter.

The locally executable program can be executed by changing your current working directory in MATLAB to the directory containing the material for this example and executing the command shown below:

result=local_workspace

Executing the command shown above will calculate 10 iterations and store the following variables to the result vector. The values generated during this simple program are illustrated in the image below.

image5
Figure 4. Result of the latest iteration is stored in the 'result' matrix at the coordinates indicated by the loop counters. The result of the latest iteration has been circled in this figure.

3.2.2. The distributed version of the program

The distributed version of the locally executable program is shown below.

function result = run_workspace_dist()
% This function contains the 'cloudfor' version of the locally executable
% program. Calling this function will create a computational Project, where
% the multiplication operations in the nested loop structure will be executed on
% the Workers. Each Job will calculate one iteration of the loop structures.
%
% To use: result = run_workspace_dist()

% Copyright 2011-2015 Techila Technologies Ltd.

var1=[2 4 6]; % Length of 'var1' will define number of outer loop iterations
var2=[11 51 100]; % Length of 'var1' will define number of inner loop iterations
dummyvar=rand(2000); % Create a dummy variable, not used in computations
result=zeros(length(var1),length(var2)); % Create empty result matrix

% The keywords 'cloudfor' and 'cloudend' have been used to mark the
% beginning and end of the block of code that will be executed on Workers.
% ------------------------------------------------------------------------
% The %cloudfor(key,value) parameters used in this example are explained below:
% ------------------------------------------------------------------------
% ('stepsperjob',1)             Sets the amount of iterations performed in
%                               each Job to one (1)
% ('inputparam',var1,var2,result) Define that only variables 'var1','var2'
%                                         and 'result' will be transferred. This
%                                         means that the variable 'dummyvar' will not
%                                         be transferred.
% ------------------------------------------------------------------------
cloudfor ii=1:length(var1) % Beginning of the cloudfor-block #1
    %cloudfor('stepsperjob',1)
    cloudfor jj=1:length(var2) % Beginning of the cloudfor-block #2
        %cloudfor('stepsperjob',1)
        %cloudfor('inputparam',var1,var2,result)
        result(ii,jj)=var1(ii)*var2(jj); % Store the multiplication result in the matrix
    cloudend % End of cloudfor-block #2
cloudend % End of cloudfor-block #1

The code contains two perfectly nested cloudfor-loops corresponding to the two perfectly nested for-loops in the locally executable program. Each cloudfor-loop also sets value of the stepsperjob parameter to one (1), meaning the number of Jobs in the computational Project will correspond to the total number of iterations. As each loop contains three iterations, the number of Jobs in the Project will be nine (9).

The Workspace variables that should be transferred are listed on the line containing the inputparam control parameter shown below.

%cloudfor('inputparam',var1,var2,result)

This parameter defines that the variables var1, var2 and result should be transferred to the Techila Workers. Variables var1 and var2 are required to perform the multiplication operation and the result variable is required to store the multiplication result. The dummyvar variable is not used in the computation meaning there is no need to transfer it and therefore it is not listed.

3.2.3. Running the example

The distributed version can be executed by changing your current working directory in MATLAB to the directory containing the material for this example and executing the command shown below:

result = run_workspace_dist

Executing the command shown above will calculate the value of each matrix element in a separate Job. This is illustrated below in the image below.

image6
Figure 5. Each Job will calculate the value of one matrix element. Please note that results are received from Techila Workers in the order in which they are completed, meaning the matrix will not be filled in any specific order. Each result will be automatically stored in the correct coordinates.

Tip! To see how the inputparam parameter reduces the amount of data transferred, remove the line containing the inputparam notation. This will cause the dummyvar variable to be transferred to the Techila Workers. This will raise the amount of data over the 10 Megabyte limit, meaning you will also have to override the 10 Megabyte safety limit discussed earlier in this chapter with the %cloudfor('force:largedata') parameter. After you have modified the code, you should see a much larger upload when creating the computational Project.

3.3. Transferring Data Files

By default, only the file containing the executable program will be transferred to the Techila Workers. If the executable program requires access to additional data files during the computation, the data files need to be specified in order to transfer them to the Techila Workers.

This example illustrates how to transfer input files to Techila Workers and how to transfer output files from the Techila Workers back to your computer.

The material used in this example is located in the following folder in the Techila SDK:

techila\examples\Matlab\cloudfor\3_transferring_data_files

Input files can be transferred to all participating Techila Workers by using the datafile control parameter. The general syntax for defining files is shown below.

%cloudfor('datafile',<comma separated list of files>)

For example, the syntax shown below defines that the files file1 and file2 should be placed in a Data Bundle and transferred to Techila Workers.

%cloudfor('datafile',file1,file2)

These files will be automatically transferred to the Techila Worker and copied to the same temporary working directory as the executable program. Files can also be placed in different Data Bundles by using several datafile parameter entries. This can be beneficial for example in situations where some of the files change frequently and some of the files remain unchanged. This is because Bundles are only recreated if the content of the Bundle has changed, meaning placing frequently changing files in one Data Bundle and static files in another Bundle will reduce the amount of unnecessary data transfers.

The syntax shown below illustrates how files can be placed in different Data Bundles. Files file1 and file2 are placed in one Data Bundle and files file3 and file4 are placed in the second Data Bundle.

%cloudfor('datafile',file1,file2)
%cloudfor('datafile',file3,file4)

Additional output files can be returned from Techila Workers by using the OutputFiles parameter. The general syntax for defining the names of output files is shown below.

%peach('OutputFiles',<comma separated list>)

For example, the syntax shown below defines that the files outputfile1 and outputfile2 transferred back from the Techila Workers.

%peach('OutputFiles','outputfile1', 'outputfile2')

If the names of the result files are different each iteration, regular expressions can be used to return a larger selection of output files. For example, the syntax shown below would return all output files beginning with outputfile from the Techila Workers.

%peach('OutputFiles','outputfile.*;regex=true')

Tip! If you wish to perform post-processing on the result files continuously as they are streamed to your computer, you can use callback control parameter and the TECHILA_FOR_RESULT variable. The variable TECHILA_FOR_RESULT will be replaced with the path and name of each result file after it has been transferred to your computer. For example, the syntax shown below would unzip each result file to the current working directory after it has been downloaded to your computer from the Techila Server.

%cloudfor('callback','unzip(TECHILA_FOR_RESULTFILE)')

3.3.1. Locally executable program

The locally executable program used in this example is shown below.

function result=local_datafile()
% This function is executed locally on your computer and does not
% communicate with the Techila environment. The function contains two
% 'for'-loops. One 'for' loop will load input files and create output files,
% the second 'for' loop will load the output files and store variables to
% the output values.
%
% To use: result=local_datafile()

% Copyright 2011-2013 Techila Technologies Ltd.

result=cell(1,3); % Empty cell array for results
loops=length(result); % Set the number of loops to 3.

% In the first for-loop, data is loaded from the input files
% and results stored in output files. The name of the input file and output
% file will depend on the iteration number
for k=1:loops
    load(['input_' num2str(k) '.mat']);          % Load variables from the file
    result1=conv2(x,y,'same');                   % Perform conv2 operation with 'x' and 'y'
    result2=filter2(x,y);                        % Perform filter2 operation with 'x' and 'y'
    filename=['output_local' num2str(k) '.data'];% Filename depends on the iteration number
    save(filename,'result1','result2');          % Save variables to the file
end

% The second loop will load the output files and store the variables to the
% result vector.
for j=1:loops % Loop structure for reading the result files
    result{j}=load(['output_local' num2str(j) '.data'],'-mat'); % Store the result in to a variable
end

end

The program contains a single function, which contains two for loop structures. During the first loop, data files are loaded from the current working directory. A different data file will be loaded each iteration and loading the data files will create two Workspace variables, x and y. These variables are used when performing conv2 and filter2 operations later in the code. These operations will create the result1 and result2 variables. These variables will be stored in an output file and the iteration number will be included in the name of the file. These output files will be stored in the current working directory.

After all iterations in the first loop have been performed the second loop structure will be performed. During this loop structure, values stored in the output files are read from the current working directory and stored in the result variable, which will also be returned from the function.

The locally executable program can be executed by changing your current working directory in MATLAB to the directory containing the material for this example and executing the command shown below:

result=local_datafile

3.3.2. The distributed version of the program

The distributed version of the locally executable program is shown below.

function result = run_datafile_dist()
% This function contains the 'cloudfor' version of the locally executable
% program. Calling this function will create a computational Project, where
% the input files are transferred to Workers and output files returned to
% your computer. Each Job will calculate one iteration of the loop structure.
%
% To use: result = run_datafile_dist()

% Copyright 2011-2015 Techila Technologies Ltd.

result=cell(1,3);     % Empty cell array for results
loops=length(result); % Set the number of loops to 3.

% The keywords 'cloudfor' and 'cloudend' have been used to mark the
% beginning and end of the block of code that will be executed on Workers.
% ------------------------------------------------------------------------
% The %cloudfor(key,value) parameters used in this example are explained below:
% ------------------------------------------------------------------------
% ('stepsperjob',1)              Sets the amount of iterations performed in
%                                each Job to one (1)
% ('resultfilevar',filelist)     Stores the names of the output files to the
%                               'fileslist' variable
%
% ('donotimport','true')         Only add result files to the file list,
%                                do not load result files.
%
% ('datafile',input_1.mat,...
%                input_2.mat)    Transfers files 'input_1.mat'
%                                and to Workers 'input_2.mat' to Workers
% ('datafile',input_3.mat        Transfers file 'input_3.mat' to Workers
%
% ('stream','false')             Disable result streaming
% ------------------------------------------------------------------------
% The %peach(key,value) parameters used in this example are explained below:
% ------------------------------------------------------------------------
% ('OutputFiles','output_dist.*;...
%  regex=true')                 Defines that all files beginning with
%                               'output_dist' should be transferred back to
%                               your computer
% ------------------------------------------------------------------------

cloudfor k=1:loops
    %cloudfor('stream','false')
    %cloudfor('stepsperjob',1)
    %cloudfor('resultfilevar',filelist)
    %cloudfor('donotimport','true')
    %peach('OutputFiles','output_dist.*;regex=true')
    %cloudfor('datafile',input_1.mat,input_2.mat)
    %cloudfor('datafile',input_3.mat)


    load(['input_' num2str(k) '.mat']);          % Load variables from the file
    result1=conv2(x,y,'same');                   % Perform conv2 operation with 'x' and 'y'
    result2=filter2(x,y);                        % Perform filter2 operation with 'x' and 'y'
    filename=['output_dist' num2str(k) '.data'];% Filename depends on the iteration number
    save(filename,'result1','result2');          % Save variables to the file
cloudend

% The second loop will load the output files and store the variables to the
% result vector. An additional line has been added that will unzip the
% result files to the current working directory.
for j=1:loops          % Loop structure for reading the result files
    unzip(filelist{j}) % Unzip the result file to the current working directory
    result{j}=load(['output_dist' num2str(j) '.data'],'-mat'); % Store the result in to the variable
end

end

The cloudfor and cloudend keywords are used to mark the first loop structure for execution on the Techila Workers.

The code sets value of the stepsperjob parameter to one (1), meaning the number of Jobs in the computational Project will correspond to the total number of iterations. This means that the number of Jobs in the Project will be three (3).

Streaming has been disabled with the ('stream','false') parameter. This ensures that the second for-loop will be process output files in the same order as in the locally executable version.

The parameter ('donotimport','true') specifies that result files should not be loaded, but only added to the file list. Result files will be processed in the for-loop that will be executed after the Project has been completed.

The parameter ('resultfilevar',filelist) defines that the name and path of each output file returned from the Techila Workers will be stored in the filelist variable. The locations and names stored in this variable will be used during the second for-loop, where each individual output file will be unzipped to the current working directory.

The data files that will be transferred to all participating Techila Workers are listed on the lines containing the datafile control parameter shown below.

%cloudfor('datafile',input_1.mat,input_2.mat)
%cloudfor('datafile',input_3.mat)

These parameters define that the files input_1.mat, input_2.mat and input_3.mat will be transferred to the Techila Workers. There are two datafile parameter entries, meaning the data files will be placed in two separate Data Bundles. Files input_1.mat and input_2.mat will be placed in one Bundle and file input_3.mat will be placed in another Data Bundle. All files will be copied to the same temporary working directory with the executable program on the Techila Workers. This means the data files can be loaded with the same command as in the locally executable version.

The output files that will be returned from the Techila Workers are listed on the line containing the peach OutputFiles parameter shown below.

%peach('OutputFiles','output_dist.*;regex=true')

The notation uses regular expressions and will cause all files starting with output_dist to be returned from the Techila Workers. These output files will be stored in ZIP-files, one output file per ZIP-file. Regular expressions are used because the name of the generated output file will be different each iteration.

The second loop structure will unzip the ZIP-files containing the actual output files generated on Techila Workers. These output files will be unzipped to the current working directory, from where they will be loaded and variables stored in the files loaded in the result variable.

3.3.3. Running the example

The distributed version can be executed by changing your current working directory in MATLAB to the directory containing the material for this example and executing the command shown below:

result = run_datafile_dist

Executing the command shown above will create a Project consisting of three Jobs. Each Job will calculate one iteration of the loop structure. The return values will be stored in the result cell array at the index indicated by the value of the loop counter k for each Job.

Tip! To see how using different Data Bundles for transferring different data files reduces unnecessary network transfers, modify the content of the input_3.mat file. After modifying the content, execute the run_datafile_dist command as earlier. After executing the command, only one of the Data Bundles (the one containing the input_3.mat file) will be recreated and uploaded to the Techila Server. Files input_1.mat and input_2.mat do not need to be uploaded to the Techila Server, because these are stored in a different Bundle.

3.4. Managing Return Values

This Chapter introduces different methods that can be used to manage return values received from the computational jobs.

The material used in this example is located in the following folder in the Techila SDK:

techila\examples\Matlab\cloudfor\4_managing_result_variables

Default method


By default the return values from the executable program are joined together by replacing the old values. This is typically desired behavior for example in cases where Jobs will return a result, which will be stored in an empty array. In situations where the result values need to be managed differently, cloudfor provides control parameters which can be used to sum, concatenate or replace the results. These are explained later in this Chapter

The table below contains an example on how to convert a simple locally executable loop structure to a distributed version. Return values are managed by using the default method, meaning return values will be stored in an empty array at the correct indices.

Locally Executable Distributed Version
res=zeros(1,10)
for index=1:10
    res(index)=index*10
end
res=zeros(1,10)
cloudfor index=1:10
    res(index)=index*10
cloudend

Concatenating values


Concatenation means that return values are concatenated. Please note that when the streaming transfer method is used (streaming is enabled by default), the results will be concatenated in the order in which they are returned from the Techila Workers. This means that the results might not be in the same order as in the locally executable version. To ensure that results are returned in the same order as in the locally executable version, disable streaming with the %cloudfor('stream','false') parameter.

A return value will be concatenated if it is defined with the %cloudfor('cat',<variable>). parameter. The names of several variables can be given as a comma separated list. For example, the control parameter shown below would concatenate the return values res1 and res2.

%cloudfor('cat',res1,res2)

The table below contains an example on how to convert a simple locally executable loop structure to a distributed version. The distributed version uses the cat parameter to concatenate a variable called res. Please also note the value of the stream control parameter is set to false, meaning results are returned in the same order as in the locally executable version.

Locally Executable Distributed Version
res=[];
for index=1:10
    res=[res  index*10]
end
res=[];
cloudfor index=1:10
%cloudfor('cat',res)
%cloudfor('stream','false')
    res=[res index*10]
cloudend

Summing values


Summation means that the return values are summed, instead of being replaced. This can be beneficial for example in cases where the result of the latest iteration is carried over to the next iteration.

A return value can be summed by using the %cloudfor('sum',<variable>) parameter. Several variables can be given as a comma separated list. For example, the control parameter shown below would sum the return values res1 and res2.

%cloudfor('sum',res1,res2)

The table below contains an example on how to convert a simple locally executable loop structure to a distributed version. The distributed version uses the sum parameter to sum a variable called res.

Locally Executable Distributed Version
res=0;
for index=1:10
    res=res+index*10
end
res=0;
cloudfor index=1:10
%cloudfor('sum', res)
%cloudfor('stepsperjob', 1)
    res=res+index*10
cloudend

Replacing values


Replacing means that the value of the variable will be continuously replaced with the latest result received from the Techila Workers. This is also the default behavior in the current cloudfor-function.

For the sake of consistency, the syntax for defining variables to be replaced is shown below:

%cloudfor('replace',<comma separated variable names>)

Example: The control parameter shown below would replace the return values res1 and res2.

%cloudfor('replace',res1,res2)

Returning the first value


If you wish to return the last value of a variable that was generated during the first Job, this can be done by using the following syntax:

%cloudfor('first', <comma separated variable names >)

This means that you can return the value of the first iteration by specifying that only one iteration should be performed in each Job.

For example, the example code snippet below would return the value of variable res (value 10) that was generated during the first iteration.

res=0;
cloudfor index=1:10
%cloudfor('first', res)
%cloudfor('stepsperjob', 1)
    res=index*10
cloudend

3.4.1. Locally executable program

The locally executable program used in this example is shown below.

function [pi_value, primes]=local_managing_results()
% This function is executed locally on your computer and does not
% communicate with the Techila environment. This function contains one
% 'for'-loop, which will create random points to approximate the value of
% Pi and for searching prime numbers.
%
% To use: [pi_value, primes]=local_managing_results();
%
% pi_value = Contains the approximate value of Pi
% primes   = Contains a list of prime numbers found.

% Copyright 2011-2013 Techila Technologies Ltd.

iter_count=4e5; % Set the number of iterations
pi_counter=0; % Init to contain the value of the Pi approximation
primes=[]; % 0x0 matrix for the concatenated results

% Locally executable for loop
for i_index = 1:iter_count
    pi_counter = pi_counter+mcpi; % Increase pi_counter if 'mcpi' returns 1.
    if isprime(i_index) % Check if the i_index is a prime number
         % Increasing vector length makes this a slow method, used to
         % highlight the concatenation of results.
         primes=[primes i_index];   % Add the prime number as the last element.
    end
end

% Calculate the approximated value of Pi.
pi_value=4*pi_counter/iter_count;

% Print the results based on the operations performed
fprintf('\nThe approximate value of Pi is: %g\n\n',pi_value)
fprintf('Searched the interval from 1 to %s\n',num2str(iter_count))
fprintf('Last 10 prime numbers found: %s\n',num2str(primes(end-9:end)))
end

function res = mcpi()
% This function is used to generate a random point and to see if it is
% located within an unitary circle. Called once for each iteration.
    res=0;
    dist = sqrt(rand()^2+rand()^2);
    if dist <= 1
        res=1;
    end
end

The local_managing_results function will begin by initializing values, which will used to perform the following activities:

  • Determine the number of iterations in the loop structure (iter_count)

  • Keep count of the random points generated within the unitary circle (pi_counter)

  • Contain a list of prime numbers (primes)

The program contains a single for-loop structure, which will perform two different operations. These operations are described below:

  • Sum and carry over any existing data generated during the random number generation routine to the pi_counter variable. This is used in the Monte Carlo Pi approximation routine.

  • Check and concatenate any prime numbers to the primes vector

The locally executable program can be executed by changing your current working directory in MATLAB to the directory containing the material for this example and executing the command shown below:

[pi_value, primes]=local_managing_results();

After executing the command shown above, results should be displayed in the MATLAB Command Window containing information on the approximated value of Pi and the last 10 prime numbers found. The printout should resemble the one shown below.

The approximate value of Pi is: 3.14099

Searched the interval from 1 to 400000
Last 10 prime numbers found: 399887  399899  399911  399913  399937  399941  399953  399979  399983  399989

3.4.2. The distributed version of the program

The distributed version of the locally executable program is shown below.

function [pi_value, primes]=run_managing_results_dist()
% This function contains the 'cloudfor' version of the locally executable
% program. Calling this function will create a computational Project, where
% the output values will be managed similarly as in the locally executable
% program.
%
% To use: [pi_value, primes]=run_managing_results_dist();

% Copyright 2011-2015 Techila Technologies Ltd.

iter_count=4e5; % Set the number of iterations
pi_counter=0; % Init to contain the value of the Pi approximation
primes=[]; % 0x0 matrix for the concatenated results

% The keywords 'cloudfor' and 'cloudend' have been used to mark the
% beginning and end of the block of code that will be executed on Workers.
% ------------------------------------------------------------------------
% The %cloudfor(key,value) parameters used in this example are explained below:
% ------------------------------------------------------------------------
% ('stepsperjob',1e4)           Sets the amount of iterations performed in
%                               each Job to one (1e4). Means the Project
%                               will contain 40 Jobs (4e5/1e4)
% ('cat',primes)                Concatenates the return values stored in
%                               'primes'.
% ('sum',pi_counter)            Sum the return values stored in 'pi_counter'
% ('stream','false')            Disable streaming, because concatenated
%                               results need to be in correct order
% ------------------------------------------------------------------------
cloudfor i_index = 1:iter_count
    %cloudfor('stepsperjob',1e4)
    %cloudfor('cat',primes)
    %cloudfor('stream','false')
    %cloudfor('sum',pi_counter)
    pi_counter = pi_counter+mcpi;
    if isprime(i_index) % Check if the i_index is a prime number
         % Increasing vector length makes this a slow method, used to
         % highlight the concatenation of results.
         primes=[primes i_index];   % Add the prime number as the last element.
    end
cloudend
% Calculate the approximated value of Pi.
pi_value=4*pi_counter/iter_count;

% Print the results based on the operations performed
fprintf('\nThe approximate value of Pi is: %g\n\n',pi_value)
fprintf('Searched the interval from 1 to %s\n',num2str(iter_count))
fprintf('Last 10 prime numbers found: %s\n',num2str(primes(end-9:end)))
end

function res = mcpi()
% This function is used to generate a random point and to see if it is
% located within an unitary circle. This function is automatically included
% in the compilation and can be executed on Workers.
    res=0;
    dist = sqrt(rand()^2+rand()^2);
    if dist <= 1
        res=1;
    end
end

The for and end words in the locally executable loop have been replaced with the cloudfor and cloudend keywords. These indicate the block of code that will be executed on Techila Workers. The function mcpi will be automatically included in the compilation as it is called within the cloudfor-loop structure.

The cloudfor-loop also uses control parameters to manage return values. These parameters are explained below.

%cloudfor('sum',pi_counter)

The control parameter above states that the pi_counter variables returned from the Techila Workers should be summed. This is required as the locally executable program uses the same variable to store and carry over results from previous iterations.

%cloudfor('cat',primes)

The control parameter above states that the primes variables returned from the Techila Workers should be concatenated. This is required as the locally executable program also used concatenation.

%cloudfor('stream','false')

The control parameter above states that streaming should be disabled. This is required because the concatenated results in the primes vector need to be in the same order as in the locally executable version.

%cloudfor('stepsperjob',1e4)

The control parameter above states that 10,000 iterations should be performed in each Job. This will means that the Project will consist of 40 Jobs, as the total number of iterations performed is 400,000.

3.4.3. Running the example

The cloudfor version can be executed by changing your current working directory in MATLAB to the directory containing the material for this example and executing the command shown below:

[pi_value, primes]=run_managing_results_dist;

Return values received from the Jobs will be managed differently, depending on which control parameter was used. The pi_counter values will be summed and the primes values will be concatenated. After the return values have been summed and concatenated, the final results will be displayed in the MATLAB Command Window and should resemble the ones received in the locally executable version. Please note that small deviations in the approximated value of Pi are expected, because the mcpi function uses random numbers and no fixed random number generator seeds are used.

3.5. Active Directory Impersonation

The walkthrough in this Chapter is intended to provide an introduction on how to use Active Directory (AD) impersonation. Using AD impersonation will allow you to execute code on the Techila Workers so that the entire code is executed using your own AD user account.

The material discussed in this example is located in the following folder in the Techila SDK:

techila\examples\Matlab\cloudfor\ad_impersonate

Note! Using AD impersonation requires that the Techila Workers are configured to use an AD account and that the AD account has been configured correctly. These configurations can only be done by persons with administrative permissions to the computing environment.

More general information about this feature can be found in Introduction to Techila Distributed Computing Engine.

Please consult your local Techila administrator for information about whether or not AD impersonation can be used in your Techila Distributed Computing Engine environment.

AD impersonation in cloudfor is enabled by adding the following control parameter:

%peach('ProjectParameters',{{'techila_ad_impersonate','true'}})

This control parameter will add the techila_ad_impersonate Project parameter to the Project. No other code modifications are needed.

When AD impersonation is enabled, the entire computational process will be executed under the user’s own AD account.

3.5.1. Example material walkthrough

The source code of the example discussed here can be found in the following file in the Techila SDK:

techila\examples\Matlab\cloudfor\ad_impersonate\run_impersonate.m

The code used in this example is also illustrated below for convenience.

function run_impersonate()
% This function contains the cloudfor-loop, which will be used to distribute
% computations to the Techila environment.
%
% During the computational Project, Active Directory impersonation will be
% used to run the Job under the End-User's own AD user account.
%
% Syntax:
%
% run_impersonate()

% Copyright 2015 Techila Technologies Ltd.

% Check which user account is used locally
[s,local_username]=dos('whoami');

% The keywords 'cloudfor' and 'cloudend' have been used to mark the
% beginning and end of the block of code that will be executed on Workers.
%
% AD impersonation has been enabled by setting the value of the
% 'techila_ad_impersonate' Project parameter to true.
cloudfor x=1:1
    %peach('ProjectParameters',{{'techila_ad_impersonate','true'}})

    % Check which user account is used to run the computational Job.
    [s,worker_username]=dos('whoami');
cloudend

% Print the user account information
fprintf('Username on local computer: %s\n',local_username);
fprintf('Username on Worker computer: %s\n',worker_username);
end

In this example, the whoami command is used to display the domain and user name. When the whoami is executed for the first time (before the cloudfor-loop), it is executed on the End-User’s computer, meaning the command will return the End-User’s own AD user name. The user name will be stored in the local_username variable.

The cloudfor-loop used in this example sets the number of iterations to one. This means the Project will consist of one Job.

AD impersonation is enabled by setting the value of Project parameter techila_ad_impersonate to 'true'. This means all commands during the Job will be executed using the End-User’s own AD user account.

Inside the cloudfor-loop, the whoami command is used to retrieve the user identity. This code line will be executed on the Techila Worker, during the Job. Because AD impersonation has been enabled, this command should return the End-User’s own AD user name and domain. If AD impersonation would be disabled (e.g. by removing the techila_ad_impersonate Project parameter, this command would return the Techila Worker’s AD user name.

After Project completion, information will be displayed about what AD user account was used locally and during the computational Job.

3.5.2. Running the example

This example can be executed by changing your current working directory in MATLAB to the directory containing the material for this example and executing the command shown below:

result=run_impersonate();

After the Project has been completed, information about the AD user accounts will be displayed. Please note that the output generated by the program will change based on your domain and AD account user names. The example screenshot below illustrates the program output when the End-User’s own AD account name is techila and the domain name is testdomain.

image7
Figure 6. The highlighted output will contain information about which user accounts were used.

3.6. Intermediate Data

The walkthrough in this Chapter is intended to provide an introduction on how to transfer intermediate data to and from Jobs.

The material discussed in this example is located in the following folder in the Techila SDK:

techila\examples\Matlab\cloudfor\intermediate_data

More general information about this feature can be found in Introduction to Techila Distributed Computing Engine.

In the computational Job, intermediate data is managed by using the following MATLAB functions.

  • saveIMData - Executed in the Job. Sends data from the Job to End-User.

  • loadIMData - Executed in the Job. Loads data received from End-User into the Job’s workspace.

On the End-User’s computer, intermediate data can be transferred to the Job by using the following function.

  • sendIMData - Executed on the End-User’s computer. Sends data to Job.

This sendIMData function will need to be executed in an intermediate callback function, which is automatically executed each time intermediate data is received from a Job. Intermediate callback functions can be enabled with a cloudfor control parameter.

These functions and the concept of an intermediate callback function are explained in more detail below.

saveIMData can be executed on the Techila Worker and is used to send workspace variables from a Job to the End-User. When this function is executed in a Job, the specified workspace variables will be saved to a mat-file, which will be automatically transferred to the End-User via the Techila Server. For example, the following syntax could be used to send variables called var1 and var2 from a Job to the End-User.

saveIMData('var1', 'var2')
imdata1
Figure 7. The saveIMData function will need to be executed on the Techila Worker, during the computational Job. This function is used to send intermediate result data from the Job to the End-User.

After an intermediate data file has been transferred to the End-User’s computer, the most convenient way to process the contents of the file is use an intermediate callback function. Intermediate callback functions can be enabled by using the imcallback control parameter for cloudfor to define which function will be executed when new intermediate data is received. For example, the following cloudfor control parameter could be used to define that a function named myfunction will be used to process each intermediate data file.

%cloudfor('imcallback','myfunction(TECHILA_FOR_IMRESULT)')

The TECHILA_FOR_IMRESULT keyword shown in the above syntax will automatically be replaced with a structure containing the results in the intermediate data file.

The intermediate callback function also provides a convenient way to transfer data back to the Job. This can be done by placing the sendIMData function call inside the callback function to send updated data to the Job.

When executing the sendIMData function to send data, you will need to define a target Job Id, followed by a comma separated list of variable names you want to transfer. For example, the following syntax could be used to send variables b and c to Job #2.

sendIMData(2,'b','c')

The example code snippet below shows an example intermediate callback function named myfunction, which could be used increase the value of variable a by 2. The updated value of variable a will be sent to the same Job from which it was received (imresult.TechilaJobId always contains the Job ID from which the intermediate data was received).

function result = myfunction(imresult)
a=imresult.a;
a=a+2;
sendIMData(imresult.TechilaJobId,'a')
end

After intermediate data has been sent to a Job (by using the sendIMData), the loadIMData can be executed on the Techila Worker, during the computational Job. This function will wait for intermediate data and load the intermediate data after it has been received from the End-User. This function can be executed without any input arguments, in which case the function will wait indefinitely for intermediate data. Code execution will continue immediately after data has been received and loaded.

loadIMData(); % Executed on Techila Worker, will wait indefinitely until intermediate data has been received.

If you do not want the function to wait indefinitely, you can define a timeout (in seconds) by using an input argument. For example, the following syntax could be used to wait for intermediate data for a maximum of 60 seconds before allowing code execution to continue. Code execution will be allowed to continue after 60 seconds, even if no intermediate data has been received. Code execution will also continue immediately after data has been received and loaded.

loadIMData(60); % Executed on Techila Worker, will wait a maximum of 60 seconds for intermediate data before continuing.

The image below illustrates how functions saveIMData, sendIMData and loadIMData can be used in conjunction to update variable values in a computational Job.

imdata2
Figure 8. During the Job, function saveIMData is used to save the value of variable a, which will be transferred back to the End-User’s computer. This intermediate data file will then be processed in an intermediate callback function. This intermediate callback function will update the value of variable a and transfer the updated variable to the Job using function sendIMData. Intermediate data received from the End-User’s computer can be read on the Techila Worker by executing the loadIMData function during the Job. After executing function, updated variable values will be available in the Job’s workspace.
Note
When using the saveIMData and loadIMData functions inside cloudfor, you will need to use wrap the contents of the cloudfor loop inside an if isdeployed clause as shown below. If you do not do this, the loadIMData function will be executed locally on your computer before the Project is created and can prevent further code execution.
cloudfor x = 1:10
if isdeployed
% computational code goes here
loadIMData();
end
cloudend

3.6.1. Example material walkthrough

The source code of the example discussed here can be found in the following file in the Techila SDK:

techila\examples\Matlab\cloudfor\intermediate_data\run_intermediate.m

The code used in this example is also illustrated below for convenience.

function result = run_intermediate()
% This function will create a Project consisting of 2 Jobs. Each Job will
% use intermediate data helper functions to update the value of a variable.
%
% To run, use command:
%
% result = run_intermediate()
%
% Copyright 2017 Techila Technologies Ltd.

jobs = 2; % Number of Jobs
result = zeros(1,jobs);

% The cloudfor 'imcallback' parameter defines that function 'myfunction'
% will be called each time new intermediate data has been received.
% TECHILA_FOR_IMRESULT keyword will be automatically replaced with a
% structure containing the intermediate data that was received.
cloudfor x = 1:jobs
%cloudfor('imcallback','myfunction(TECHILA_FOR_IMRESULT);')
if isdeployed
 a = 10 + x; % Set an arbitrary value to 'a' based on the loop index
 saveIMData('a'); % Send variable 'a' to the End-User as intermediate data
 loadIMData; % Wait until intermediate data has been received from End-User
 result(x) = a; % Return the updated value of 'a' as the result.
end
cloudend
end

In this example, the cloudfor loop will create a Project consisting of two Jobs. Each Job will generate a variable a and transfer the value of variable a as intermediate data back to the End-User’s computer. After the intermediate data has been received on the End-User’s computer, the data will be processed using an intermediate callback function named myfunction.

Function myfunction will display information about the data that was received from a Job, increase the value of variable a by 2 and send the updated value back to the same Job that sent the data by using function sendIMData. This updated value will be loaded by the loadIMData function call.

Each Job will return the updated value of the variable as the result. These results will be printed after the Project has been completed.

function myfunction(imdata)
% Intermediate callback function. Called each time new intermediate data
% has been received.
%
% Copyright 2017 Techila Technologies Ltd.

jobidx = imdata.TechilaJobId; % The source Job Id
disp(['Received intermediate data from Job #' num2str(jobidx)])
a = imdata.a; % Get value of variable 'a' that was received from the Job
disp(['Received variable "a" from Job. Value of variable is: ' num2str(a)])
a = a + 2;  % Increase value so we know the data has been modified by this function
disp(['Increased value of "a" to: ' num2str(a)])
disp(['Sending variable updated value of "a" as intermediate data to Job #' num2str(jobidx)])
sendIMData(jobidx, 'a'); % Send the updated value of 'a' back to the same Job
disp(['Finished sending intermediate data to Job #' num2str(jobidx)])
end

3.6.2. Running the example

This example can be executed by changing your current working directory in MATLAB to the directory containing the material for this example and executing the command shown below:

result=run_intermediate()

The screenshot below illustrates what the output of the example looks like.

imdata3

3.7. Using Semaphores

Semaphores can be used to limit the number of simultaneous operations performed in a Project. There are two different types of semaphores:

  • Project-specific semaphores

  • Global semaphores

The walkthrough in this Chapter is intended to provide an introduction on how to create Project-specific semaphores, which can be used to limit the number of simultaneous operations.

The material discussed in this example is located in the following folder in the Techila SDK:

techila\examples\Matlab\cloudfor\semaphores

More general information about this feature can be found in Introduction to Techila Distributed Computing Engine.

Project-specific semaphores will need to be created in the code that is executed on the End-User’s computer. Respectively, in order to limit the number of simultaneous processes, the semaphore tokens will need to be reserved in the code executed on the Techila Workers. Global semaphores can only be created by Techila administrators.

The example figure below illustrates one way of using Project-specific semaphores. The semaphore is created by setting the semaphore properties with the Semaphore control parameter. The parameters used in the example will create a Project-specific semaphore called examplesema with two semaphore tokens.

The functions used for reserving and releasing the semaphore tokens are intended to be executed on the Techila Worker. If these functions are executed on the End-User’s computer, they will generate an error, because the End-User’s computer does not have all the necessary Techila Distributed Computing Engine components. For this reason, the code inside the cloudfor-loop has been encapsulated in an if isdeployed statement. This will prevent the code from being executed locally on the End-User’s computer.

The semaphore token will be reserved by the techilaSemaphoreReserve('examplesema') function call. This function call will return when the semaphore token has been reserved from the Project-specific semaphore called examplesema. If no tokens are available, the function will wait until a token becomes available.

The semaphore token will be released by the techilaSemaphoreRelease('examplesema') function call.

image8

As illustrated in the above figure, semaphores are created by using the Semaphore control parameter. The following syntaxes can be used when creating the semaphore.

%peach('Semaphore',{'name'}
%peach('Semaphore',{'name', size}
%peach('Semaphore',{'name', size, expiration}

The name parameter defines the name of the Project-specific semaphore that will be created and linked to the Project. For example, the following syntax could be used to create a semaphore with name examplesema with one token.

%peach('Semaphore',{'examplesema'}

The size parameter defines the number of tokens in the semaphore. Each time a Job requests a semaphore token, the amount of free tokens on the Techila Server is reduced by one. The number of reserved tokens cannot exceed the number defined in size. For example, the following syntax could be used to create a semaphore called examplesema with two tokens

%peach('Semaphore',{'examplesema',2}

The expiration parameter can be used to define an expiration time (in seconds) for the token. If a Job reserves a semaphore token for a longer time period than the one defined in the expiration parameter, the Project-specific semaphore token will be automatically released and made available for other Jobs in the Project. The process that exceeded the expiration time will be allowed to continue normally. For example, the following syntax could be used to define a 10 second expiration time for the examplesema semaphore.

%peach('Semaphore',{'examplesema',2,10}

Semaphores are reserved by calling techilaSemaphoreReserve with one of the syntaxes shown below.

techilaSemaphoreReserve(name)
techilaSemaphoreReserve(name, isglobal)
techilaSemaphoreReserve(name, isglobal, timeout)
techilaSemaphoreReserve(name, isglobal, timeout, ignoreerror)

The techilaSemaphoreReserve(name) function can be used to reserve a token from a Project-specific semaphore with name specified in name. This function will return the value true, when the semaphore token has been successfully reserved. For example, the following syntax could be used to reserve a token belonging to the examplesema semaphore.

techilaSemaphoreReserve('examplesema')

The techilaSemaphoreReserve(name, isglobal) function can be used to reserve a token from a Project-specific semaphore or a global semaphore. When isglobal is set to true, it defines that the token should be reserved from a global semaphore. Respectively, when the value is set to false, it defines that the token should be reserved from a Project-specific semaphore.

For example, the following syntax could be used to reserve one token from a global semaphore called globalsema.

techilaSemaphoreReserve('globalsema',true)

The techilaSemaphoreReserve(name, isglobal, timeout) function can be used to define a timeout period (in seconds) for the reservation process. When a timeout period is defined with the timeout parameter, a timer is started when the constructor requests a semaphore token. If no semaphore token can be reserved within the specified time window, the Job will be terminated and the Job will generate an error.

For example, the following syntax could be used to reserve one token from Project-specific semaphore called projectsema. The syntax also defines a 10 second timeout value for token. This means that the call will wait for a maximum of 10 seconds for a semaphore token to become available. If no token is available in 10 seconds, the code will generate an error, which will cause the Job to be terminated.

techilaSemaphoreReserve('globalsema', false, 10)

The techilaSemaphoreReserve(name, isglobal, timeout, ignoreerror) function can be used to ignore errors generated during the semaphore checkout process. When ignoreerror is set to true, the techilaSemaphoreReserve function will generate warning messages (instead of errors) and return the value false if there was a problem in the reservation process. This means that code execution will be allowed to continue on the Techila Worker.

Some of the typical reasons why this function returns a false value are:

  • The semaphore type on the Techila Server is different than the one specified in function (global vs Project-specific)

  • No semaphore with a matching name exists on the Techila Server

  • No semaphore token could be reserved in the time window specified with the timeout parameter

For example, the following syntax could be used to define that operations inside the first if-statement should be executed when a semaphore token was reserved successfully from a global semaphore named globalsema. Operations in the second if-statement will be executed if there was a problem when reserving the semaphore token.

cloudfor x=1:2
%cloudfor('stepsperjob', 1)
if isdeployed
    reservedok = techilaSemaphoreReserve('globalsema', true, 10, true)
    if reservedok
        % Execute this code block if the semaphore token was reserved
        % successfully.
        techilaSemaphoreRelease('globalsema');
    elseif ~reservedok
        % Execute this code block if there was a problem with the
        % reservation process.
    end

end
cloudend

As mentioned earlier and illustrated by the above code sample, each semaphore token that was reserved with a techilaSemaphoreReserve function call must be released by using the techilaSemaphoreRelease function with one of the syntaxes shown below.

techilaSemaphoreRelease(name)
techilaSemaphoreRelease(name, isglobal)

The techilaSemaphoreRelease(name) function can be used to release a semaphore token belonging to a Project-specific semaphore with name specified in name. This function cannot be used to release a token belonging to a global semaphore. The example syntax shown below could be used to release a token belonging to a Project-specific semaphore called examplesema.

techilaSemaphoreRelease('examplesema')

The techilaSemaphoreRelease(name, isglobal) function can be used to release tokens belonging to either Project-specific or global semaphores. When the value of isglobal is set to false, the function will release tokens from a Project-specific semaphore. Respectively, when the value of isglobal is set to true, tokens will be released from global semaphores.

For example, the following syntax could be used to release a token belonging to a global semaphore called globalsema.

techilaSemaphoreRelease('globalsema', true)

Note! If a Job is terminated on a Techila Worker, any semaphore tokens still reserved by the Job will be automatically released.

3.7.1. Example material walkthrough

The source code of the example discussed here can be found in the following file in the Techila SDK:

techila\examples\Matlab\Features\cloudfor\run_semaphore.m

The code used in this example is also illustrated below for convenience.

function result = run_semaphore()
% This function contains the cloudfor-loop, which will be used to distribute
% computations to the Techila environment.
%
% During the computational Project, semaphores will be used to limit the number
% of simultaneous operations in the Project.
%
% Syntax:
%
% result = run_semaphore()

% Copyright 2015 Techila Technologies Ltd.

% Set the number of jobs to 4
jobs = 4;

% Container for the results
result = cell(jobs,1);

% The keywords 'cloudfor' and 'cloudend' have been used to mark the
% beginning and end of the block of code that will be executed on Workers.
% ------------------------------------------------------------------------
% The %cloudfor(key,value) parameters used in this example are explained below:
% ------------------------------------------------------------------------
% ('stepsperjob',1)             Sets the amount of iterations performed in
%                               each Job to one (1)
% ('outputparam',result)        Define that only variable 'result' will be
%                               returned from the Job.
%
% ------------------------------------------------------------------------
% The %peach(key,value) parameters used in this example are explained below:
% ------------------------------------------------------------------------
% ('Semaphore', {'examplesema', 2})  Creates a Project-specific semaphore
%                                    named 'examplesema', which will have
%                                    two semaphore tokens.
cloudfor x=1:jobs
%cloudfor('stepsperjob', 1)
%peach('Semaphore', {'examplesema', 2})
%cloudfor('outputparam',result)
if isdeployed % Code inside this block will only be executed on Workers

    % Get current timestamp. This marks the start of the Job.
    jobStart = clock;

    % Reserve one token from the Project-specific semaphore 'examplesema'
    techilaSemaphoreReserve('examplesema');

    % Get current timestamp
    start = clock;

    % Generate CPU load for 30 seconds
    genload(30);

    % Calculate when the CPU load was generated relative to the start of the Job.
    twindowstart = etime(start, jobStart);
    twindowend = etime(clock, jobStart);

    % Store the time window in the result cell array.
    result{x}.pstatus = ['Project-specific semaphore reserved '...
        'for the following time window: '...
        num2str(twindowstart) '-'  num2str(twindowend)];

    % Release the 'examplesema' semaphore token
    techilaSemaphoreRelease('examplesema');

    % Attempt to reserve a token from the global semaphore 'globalsema'
    reservedok = techilaSemaphoreReserve('globalsema', true, 200, true);
    if reservedok % This block will be executed if the semaphore was reserved ok.
        start2 = clock;
        genload(5);
        twindowstart = etime(start2, jobStart);
        twindowend = etime(clock, jobStart);
        % Release the global semaphore token
        techilaSemaphoreRelease('globalsema', true);
        result{x}.gstatus = ['Global semaphore reserved '...
        'for the following time window: '  num2str(twindowstart)...
        '-'  num2str(twindowend)];
    elseif ~reservedok % This block will be executed a semaphore token could not be reserved
        result{x}.gstatus = 'Error when using global semaphore.';
    end
end
cloudend

% Print the results.
for x=1:jobs
    fprintf('Results from Job #%s\n',num2str(x))
    disp(result{x}.pstatus)
    disp(result{x}.gstatus)
end
end

function genload(duration)
% Simple function for generating CPU load for X seconds.
a=tic;
while (toc(a) < duration)
    rand;
end
end

Code summary: The code will create a Project consisting of four Jobs. Simultaneous processing in Jobs is limited by using Project-specific and global semaphores. After completing the Project, the information about the semaphore usages will be displayed.

Below is a more detailed overview of the code.

The value of the jobs variable is set to four, which will later be used to set the number of Jobs in the Project to four.

The semaphore is created by using the Semaphore control parameter. The syntax used in this example will create a Project-specific semaphore named examplesema. The number of tokens in the semaphore will be set to two. This means that a maximum of two tokens can be reserved at any given time.

The code inside the cloudfor-loop is wrapped inside an if isdeployed statement. This is done to prevent the code from being executed on the End-User’s (your) computer when you run the example.

The current time stamp is retrieved using jobStart = clock; and will be used to mark the start of the Job.

After getting the time stamp, the Job will reserve one token from the Project-specific semaphore, which was created by using the control parameter. This command will wait indefinitely, until a semaphore token has been reserved. This means that the first two Jobs that will execute this function, will reserve the tokens. The remaining Jobs will wait until semaphore tokens are released by the Jobs that reserved them.

After getting a semaphore token, the Job gets the current time stampwith techilaSemaphoreReserve('examplesema');. This is used to mark the start of the semaphore reservation time.

After this, the Job calls genload(30);, which will generate CPU load for 30 seconds by generating random numbers.

After generating CPU load, elapsed time between the start of the Job (jobStart variable) and the return of the genload function call is calculated with the following two lines:

twindowstart = etime(start, jobStart);
twindowend = etime(clock, jobStart);

If a Job was able to reserve a token immediately, this value should be close to 0. If the Job had to wait for a semaphore token to become available (i.e. some other Jobs reserved the tokens), this value will be close to 30. Please note that if the Jobs were not started at the same time, you will get different values.

Information about the reservation time slot will be stored with:

result{x}.pstatus = ['Project-specific semaphore reserved '...
    'for the following time window: '...
    num2str(twindowstart) '-'  num2str(twindowend)];

After marking the reservation time slot, the token belonging to the Project-specific semaphore is released using techilaSemaphoreRelease('examplesema');.

After processing the code that uses the Project-specific semaphore, the Job attempts to reserve a token from a global semaphore called globalsema by using:

reservedok = techilaSemaphoreReserve('globalsema', true, 20, true);

The syntax used in the call also defines that if the token is reserved for over 20 seconds, the Job should be terminated. The syntax also defines that the function should return, even if there was a problem with the semaphore reservation process.

If your Techila Distributed Computing Engine environment has a global semaphore called globalsema, then the function will return the value true. If your Techila Distributed Computing Engine environment does not have a global semaphore called globalsema, then the function will return the value false. Please note that global semaphores will need to be created by your local Techila administrator. This means that unless your local Techila administrator has created a semaphore named globalsema, the value returned by the function will be false.

Depending on whether or not the global semaphore could be reserved, the if-elseif branches will be executed respectively.

If the reservedok variable contains value true, the following code block will be executed.

start2 = clock;
genload(5);
twindowstart = etime(start2, jobStart);
twindowend = etime(clock, jobStart);
% Release the global semaphore token
techilaSemaphoreRelease('globalsema', true);
result{x}.gstatus = ['Global semaphore reserved '...
'for the following time window: '  num2str(twindowstart)...
'-'  num2str(twindowend)];

During these lines of code, five seconds of CPU load will be generated and the token reservation time window will be calculated. After this, the token belonging to the global semaphore named globalsema will be released. After this, information about the time window when the global semaphore token was reserved by the Job will be stored in the result array..

If the reservedok variable contains value false, the code block will be executed.

result{x}.gstatus = 'Error when using global semaphore.';

In this case, a simple string containing an error message will be stored in the result variable.

The remaining code lines are outside the cloudfor-loop, meaning they will be executed after the Project has been completed. During this part, information about the semaphore reservation times will be displayed on the screen by printing the strings stored during Jobs.

The example figure below illustrates how Jobs in this example are processes in an environment where all Jobs can be started at the same time. In this example figure, the global semaphore globalsema is assumed to exist and that it only contains one token.

The activities taking place during the example Project are explained below.

After the Jobs have been assigned to Techila Workers, two of the Jobs are able to reserve a Project-specific semaphore token and begin generating CPU load. This processing is illustrated by the 'Computing, Project-specific semaphore reserved' bars. During this time, the remaining two Jobs will wait until semaphore tokens become available. After the first Jobs have released the Project-specific semaphores (i.e. after generating CPU load for 30 seconds), Jobs #3 and #4 can reserve semaphore tokens and start processing the generating CPU load.

The global semaphore only contains one token, meaning only one Job can reserve a token at any given time. In the example figure below, Job #1 reserves the token and starts generating CPU load. This processing is represented by the 'Computing, global semaphore reserved' bars. After Job #1 has completed generating CPU load (i.e. after 5 seconds), the global semaphore is released and Job #2 can start processing.

After Jobs #3 and #4 finish generating CPU load, the Jobs will start reserving tokens from the global semaphore.

image9
Figure 9. Computing is performed only when a semaphore can be reserved. The Project-specific semaphore contains two tokens, meaning two Jobs can reserve a token without waiting. The number of Jobs able to simultaneously reserve global semaphore tokens depends on the number of tokens in the global semaphore. This example assumes that there is only one token in the global semaphore.

3.7.2. Running the example

This example can be executed by changing your current working directory in MATLAB to the directory containing the material for this example and executing the command shown below:

result=run_semaphore();

Please note that the output generated by the program will change based on whether or not the global semaphore named globalsema is available. The two example screenshots below illustrate the output in both scenarios.

Please also note that there might be overlap in the reported time windows. This is because the time windows are measured from the timestamp generated at the start of the if isdeployed block, which means that e.g. initialization delays can cause the reported times to overlap.

The example screenshot below illustrates the generated output when the global semaphore exists.

image10
Figure 10. Example output when the global semaphore exists.

The example screenshot below illustrates the generated output when the global semaphore does not exist.

Note! If the global semaphore does not exist, please contact your local Techila administrator for assistance. Creating global semaphore requires administrative permissions, meaning only a Techila administrator can create them.

image11
Figure 11. Example output when the global semaphore does not exist.

4. Peach Tutorial Examples

This Chapter contains minimalistic examples on how to implement and control the core features of the peach-function. The example material used this section, including m-files and data files can be found under the following folder in the Techila SDK:

techila\examples\Matlab\Tutorial

Each of the examples contains three pieces of code:

  • A locally executable function. The locally executable function can be executed locally and will not communicate with the distributed computing environment in any way.

  • A function containing the Local Control Code. This function is executed locally and will be used to distribute the computations in the Techila Worker Code to the distributed computing environment

  • A function containing the Techila Worker Code. This function will be compiled in to a binary and executed on the Techila Workers. This function contains the computationally intensive part of the locally executable function.

Please note that the example material in this Chapter is only intended to illustrate the core mechanics related to distributing computation with the peach-function. More information on available features can be found in Peach Feature Examples and by executing the following command in MATLAB.

doc peach

4.1. Executing a MATLAB Program on Techila Workers

This example is intended to provide an introduction on distributed computing using the peach-function. The purpose of this example is to:

  • Demonstrate how to modify a simple, locally executable function to a distributed version, where computational operations will take place on the Techila Workers.

  • Demonstrate the difference between Local Control Code and Techila Worker Code in MATLAB environment

  • Demonstrate the basic syntax of the peach-function in MATLAB environment

The material used in this example is located in the following folder in the Techila SDK:

techila\examples\Matlab\Tutorial\1_distribution

4.1.1. Locally executable function

The locally executable function called local_function contains a simple algorithm that consists of a single for-loop. The algorithm of the locally executable function used in this example is shown below.

function result = local_function(loops)
% This function can be executed locally on the End-Users computer.
%
% To use: result = local_function(loops)
%
% loops = number of iterations

% Copyright 2010-2013 Techila Technologies Ltd.

for i = 1:loops
    result(i) = 1+1;
end

The program requires one input argument called loops, which defines the number of iterations that will performed in the loop structure. Each iteration performs the same arithmetic operation: 1+1. The result of the latest iteration will get appended to the result vector. The result vector for five iterations is shown below.

loops=5

index

1 2 3 4 5

result

2 2 2 2 2

4.1.2. Distributed version of the program

All arithmetic operations in the locally executable function are performed in the for-loop. There are no recursive data dependencies between iterations, meaning that the all the iterations can be performed simultaneously. This is done by placing the computational instructions in the Techila Worker Code in a file called distribution_dist.m.

Local Control Code (in the file run_distribution.m) will used to create the computational Project. The Techila Worker Code in the distribution_dist.m file is automatically compiled to a binary, which will be placed in the Executor Bundle and transferred to the Techila Workers where the function distribution_dist will be executed.

4.1.3. Local Control Code

The Local Control Code used to control the distribution process is shown in below.

function result = run_distribution(jobs)
% This file contains the Local Control Code, which will be used to distribute
% computations to the Techila environment.
%
% Note! Before running the example, please ensure that the path
% techila\lib\Matlab is included in the matlabpath. The path can be added by
% executing the installsdk function from the techila\lib\Matlab directory.
% Instructions for this are provided in the document Techila with
% MATLAB
%
% To use: result = run_distribution(jobs)
%
% jobs = the number of Jobs
% The computational Project is created with PEACH. The PEACH parameters are
% explained below:
% 'distribution_dist' =   The name of the m-file (no suffix) that will be
%                         compiled and distributed to Workers.
%                         In this example, the code in the m-file named
%                         "distribution_dist.m" will be compiled and
%                         distributed.
% {} =     The parameters array. Parameters inside the cell array will be transferred
%          to Jobs and can be used as input parameters by the Worker Code. In
%          this example, the cell array is empty, which indicates that no
%          parameters are transferred to Jobs.
% 1:jobs = The peachvector. The length of the peachvector will determine the
%          number of Jobs in the Project. When applicable, elements of the
%          peachvector will be transferred to Jobs, each Job receiving a different
%          element. In this example, the peachvector is only used to
%          determine the number of jobs, no parameters are transferred.
% result = PEACH result vector. Results of individual jobs are stored in an
%          cell array, each cell element storing the result of one (1) Job.

% Copyright 2010-2013 Techila Technologies Ltd.

result = peach('distribution_dist',{},1:jobs);  % Create the computational project

result = cell2mat(result);  % Convert cell array to a single vector
end

The function run_distribution requires one input parameter. This input parameter will be used to specify the number of Jobs into which the Project should be split. This performed by using the value of the jobs parameter to determine the length of the peachvector. Please see an illustration of the parameter dependencies in Figure 11 below. In this example, the params array is empty, which indicates that no parameters will be transferred to the Techila Worker Code.

At the last line of the result vector will be converted to matrix format by using the cell2mat function. This conversion will take place after all Jobs have been completed and the results have been transferred back to the End-Users computer.

image12
Figure 12. The peach-function call in the Local Control Code. The input variable received from the End-User determines the values of the jobs, variable. This variable is used to define the length of the peachvector. The params array is empty, which indicates that no parameters will be transferred to the Techila Worker Code in the distribution_dist function

4.1.4. Techila Worker Code

The Techila Worker Code that is executed on the Techila Workers is shown below.

function result = distribution_dist()
% This m-file contains the Worker Code, which will be compiled and distributed
% to the Workers. The value of the sum is stored in the "result" variable,
% which is returned as the Job result.

% Copyright 2010-2013 Techila Technologies Ltd.

result = 1 + 1;
end

Operations performed in the Techila Worker Code are equivalent to one iteration of the locally executable loop structure. As no input parameters will be transferred to the Techila Worker Code example, identical arithmetic operations are performed during all Jobs. This is illustrated below in Figure 12.

image13
Figure 13. The Techila Worker Code is executed on the Techila Workers without any input parameters as indicated by the empty brackets in the peach function call.

4.1.5. Creating the Project

The Project can be created by executing the Local Control Code using command:

result = run_distribution(5)

This command will create a computational Project that will consist of five Jobs. Because the params array in the peach-function is represented by empty curly brackets, no input parameters will be transferred to the Techila Workers. The Techila Workers will execute the computational operations in the distribution_dist function without any input parameters and return results to the Techila Server. The interaction between the Local Control Code and Techila Worker Code is illustrated below in Figure 13.

image14
Figure 14. The Local Control Code is executed on the End-Users computer. The params array of the peach-function call is empty. This indicates that no parameters will be transferred to the Techila Worker Code. The Techila Worker Code is executed on the Techila Workers without any input parameters.

When the Local Control Code is executed using the syntax run_distribution(5), computational operations illustrated in Figure 14 will take place on Techila Workers.

image15
Figure 15. The input parameter to the Local Control Code is used to determine the number of Jobs. The same arithmetic operation, 1+1, is performed in each Job. Results are delivered back to the End-Users computer where they are stored in the result vector.

4.2. Using Input Parameters

This example will demonstrate:

  • How to define input arguments to the program that will be executed on Techila Workers

In this example, input arguments will be transferred to the Techila Workers using the params array, which is the second input argument of the peach-function.

Generally speaking, several input parameters can be given to the executable program by defining parameters as a comma separated list, which is enclosed in curly brackets. For example, the syntax below defines that variables called var1 and var2 will be given to the executable program as input arguments.

peach('funcname',{var1,var2},1:10);

Elements of the peachvector can be given as input arguments by using the <param> notation. For example, the syntax shown below defines that third input argument of the executable program (funcname) should be an element of the peachvector.

peach(`funcname`,{var1,var2,`<param>`},1:10);

The material used in this example is located in the following folder in the Techila SDK:

techila\examples\Matlab\Tutorial\2_parameters

4.2.1. Locally executable function

The algorithm for the locally executable function used in this example is shown below.

function result = local_function(multip,loops)
% This function can be executed locally on the End-Users computer. The
% function consists of a loop structure, where the value of the loop
% counter is multiplied with a fixed value.
%
% To use: result = local_function(multip,loops)
%
% multip = value of the multiplicator
% loops  = number of iterations

% Copyright 2010-2013 Techila Technologies Ltd.

for i = 1:loops
    result(i) = multip * i;
end

This function requires two input parameters; multip and loops;`loops` determines the number of iterations that are performed and multip is a number, which will be multiplied by the iteration number i. The result of this arithmetic operation will then be appended to a vector called result, which will be returned as the output value of the function. The result vector when five iterations are performed is shown below.

multip = 2; loops=5

index

1 2 3 4 5

result

2 4 6 8 10

4.2.2. Distributed version of the program

All the computations in locally executable function are performed in the for-loop and there are no dependencies between the iterations. Because of this, the operations performed in the for-loop can be performed on the Techila Workers. This can be achieved by extracting the operations into a separate piece of code, which will be compiled in to an executable binary and sent to the Techila Workers for execution. Input parameters for the executable binary will be transferred with the params array (second input argument) of the peach-function.

4.2.3. Local Control Code

The Local Control Code used to control the distribution process is shown in below.

function result = run_parameters(multip,jobs)
% This function contains the Local Control Code and is used to distribute
% computations to the Techila environment with peach.
%
% To use: result = run_parameters(multip,jobs)
%
% multip = a static parameter, which is the same for all jobs
% jobs = the number of Jobs. Also defines the elements of the peachvector
%         which are transferred to the Jobs as input parameters with the
%         '<param>' notation.

% Copyright 2010-2013 Techila Technologies Ltd.

result = peach('parameter_dist',{multip,'<param>'},1:jobs);  % Create the Project.
result = cell2mat(result); % Convert cell array to a vector.
end

The run_parameters function takes two input parameters; multip and jobs. The value of the multip parameter will be identical on all Techila Workers. The value of the jobs parameter will be used to determine the length of the peachvector, meaning that the parameter also determines the number of Jobs in the Project. Elements of the peachvector are used as a dynamic input parameter as indicated by the <param> notation in the params array. The peach-function syntax in the Local Control Code is illustrated below in Figure 15

image16
Figure 16. The peach-function syntax in the Local Control Code. Parameters listed inside the curly brackets will be transferred to the Techila Worker Code. The ‘<param>` notation is used to give elements of the peachvector to the Techila Worker Code as input arguments. The value of this parameter will be different in each Job. The value of the jobs variable is defined by the End-User and it is used to define the length of the peachvector. The value of the jobs parameter therefore defines the number of Jobs.

4.2.4. Techila Worker Code

The Techila Worker Code that is executed on the Techila Workers is shown below.

function result =  parameter_dist(multip,jobidx)
% This m-file contains the Worker Code, which will be compiled and distributed
% to the Workers. The value of the jobidx parameter is received from the
% peachvector, which was defined in the Local Control Code. The value of the
% multip paramater is the same for each Job

% Copyright 2010-2013 Techila Technologies Ltd.

result = multip * jobidx;
end

The Local Control Code discussed earlier in this Chapter defined two parameters in the params array. One of these parameters was a static parameter and the other was a dynamic parameter. In the Techila Worker Code, the static parameter is being represented by a parameter called multip. multip is constant across all Jobs. The dynamic parameter in the Local Control Code is represented by jobidx parameter, which will get replaced by a different element of the peachvector in each Job. As a result we can say that jobidx parameter simulates the iteration number of the locally executable function. Parameters transferred to the Techila Worker Code are illustrated in the image below.

image17
Figure 17. The Techila Worker Code requires two input parameters. These parameters are defined in the params array of the peach-function call in the Local Control Code.

4.2.5. Creating the Project

The Project will be created by executing the Local Control Code using command:

result = run_parameters(2,5)

This will create a computational Project that will consist of five Jobs. The parameters in the params array in the peach-function call will be given values based on the input arguments of the run_parameters function. The Techila Workers execute the parameter_dist function using one static and one dynamic input parameter as illustrated in Figure 17 below.

image18
Figure 18. Parameters defined in the params array of peach-function call in the Local Control Code. These parameters are transferred to the Techila Worker Code executed on the Techila Workers. The multip parameter is constant for all Jobs. The value of the jobidx parameter will be replaced by elements of the peachvector.

As mentioned above, the Local Control Code can be executed with the following syntax:

result = run_parameters(2,5)

This will set the value of the static parameter multip to two (2). The peachvector will contain the integers from one to five. These integers are used to define the value of the jobidx parameter in the Techila Worker Code. The computational operations resulting from the syntax shown above are illustrated below in Figure 18.

image19
Figure 19. Executing the Local Control Code with the syntax shown in the figure will create a computational Project that consists of five Jobs. The value of the multip parameter is constant, remaining the same for all Jobs. The jobidx parameter is replaced with elements of the peachvector, receiving a different element for each Job. Job results are stored in the result vector, which is returned as the output value of the Local Control Code.

4.3. Transferring Data Files

This example will demonstrate:

  • How to transfer data files to the Techila Workers

In this example, files will be transferred to the Techila Workers using the files array of the peach-function. The data file used in this example is a MAT file called datafile.mat. This file is located in the same directory as the m-files containing the Local Control Code and Techila Worker Code that are used in this example.

Generally speaking, data files can be transferred to all Techila Workers by defining the file names as comma separated list. For example, the syntax shown below defines that files called file1 and file2 will be placed in a Data Bundle transferred to all participating Techila Workers.

peach('funcname',{},{'file1','file2'}, 1:10);

Sub-arrays can be used to place several files in different Data Bundles. For example, the syntax shown below would transfer four files (file1,file2,file3 and file4) to all participating Techila Workers. The first two files would be placed in one Data Bundle and the last two files in a second Data Bundle.

peach('funcname',{}, {{'file1', 'file2'},{'file3', 'file4'}}, 1:10);

The material used in this example is located in the following folder in the Techila SDK:

techila\examples\Matlab\Tutorial\3_datafiles

4.3.1. Locally executable function

The algorithm of the locally executable function used in this example is shown in below.

function result = local_function()
% This function can be executed locally on the End-Users computer. The
% function calculates the mean value of each column in the datafile matrix.
%
%To execute the function locally, use command:
%
%result = local_function()

% Copyright 2010-2013 Techila Technologies Ltd.

load datafile.mat
for i=1:10
    result(i)=mean(datafile(:,i));
end

The locally executable function local_function consists of two logical parts; loading input data into memory and performing analysis on this data. The input data is stored in a MAT-file called datafile.mat, which contains a 10x10 matrix of integers. The computational part consists of calculating the mean values of each column in the datafile matrix. Each iteration of the loop structure calculates the mean value of a single column vector, meaning that the number of iterations is fixed to ten (10).

4.3.2. Distributed version of the program

The distributed version consists of the same logical parts as the locally executable function; loading input data and performing some simple analysis on the data. This data is stored in the datafile.mat file, which will be transferred to Techila Workers with the files array, which is the third input argument of the peach-function.

4.3.3. Local Control Code

The Local Control Code that is used to control the distribution process is shown below.

function result = run_data_files()
% This file contains the Local Control Code and is used to distribute
% computations to the Techila environment with peach. A file named
% "datafile.mat" will be transferred with each Job. The datafile.mat file
% contains a 10x10 matrix and each Job will calculate the mean value of one
% column in this matrix.
%
% To create the computatational Project, use command:
%
% result = run_data_files()

% Copyright 2010-2013 Techila Technologies Ltd.

jobs=10; % Set the number of jobs to 10, which is equal to the number of
         % columns in the "datafile" matrix

result=peach('data_dist',{'<param>'},{'datafile.mat'},1:jobs); % Create the Project.
result = cell2mat(result); % Convert cell array to a vector.
end

The Local Control Code run_data_files requires no input parameters; the number of Jobs is defined in control code by the variable jobs. This is done by using the parameter to define the length of the peachvector. Elements of the peachvector are also used as a dynamic input parameter in the params array as indicated by the <param> notation. The files array contains the string datafile.mat. This is the name of the file that will be transferred to all Techila Workers. The peach-function syntax used in the Local Control Code is illustrated in Figure 19 below.

image20
Figure 20. The project is created by the peach-function call in the Local Control Code. The datafile.mat file is transferred to all Techila Workers participating in the Project. The Techila Worker Code will be provided one dynamic input parameter, which will be replaced with a different element of the peachvector for each Job.

4.3.4. Techila Worker Code

The Techila Worker Code that is executed on the Techila Workers is shown below.

function result=data_dist(jobidx)
% This m-file contains the Worker Code, which will be compiled and distributed
% to the Workers. The value of the jobidx parameter will be received from the
% peachvector, which is defined in the Local Control Code. Each job
% consists of calculating the mean value of one column in the datafile
% matrix.

% Copyright 2010-2013 Techila Technologies Ltd.

load('datafile.mat') % Load the contents of the datafile.mat file to the workspace
result=mean(datafile(:,jobidx)); % Calculate the mean value of a column.
end

The Local Control Code introduced earlier in this Chapter defines one dynamic input parameter. This is represented in the Techila Worker Code by jobidx parameter, which will get replaced by a different element of the peachvector in each Job. This means that the jobidx can be used to point to the correct column vector during each Job.

The Local Control Code also introduced one (1) filename in the files array. This file will be copied to the same temporary working directory at the Techila Worker with the executable binary, which means that the file datafile.mat can be loaded into memory using the same syntax as in a locally executable function.

image20
Figure 21. The Techila Worker Code. All the computational data required is copied to a temporary directory on the Techila Worker. Data files can be manipulated with the same instructions as in the locally executable function introduced earlier in this chapter.

4.3.5. Creating the computational project

The project can be created by executing the Local Control Code using command:

result = run_data_files()

The number of Jobs in the Project will be automatically fixed to ten as the value of the jobs parameter is defined in the Local Control Code. Parameters in the params array and the file specified in the files array will be transferred to the Techila Workers. During each Job, the executable binary will executed with one input argument, which will be a different element of the peachvector for each Job. The datafile.mat file can be accessed in a simolar manner as in the locally executable version, because the file has been copied to the same temporary working directory with the executable binary. The interaction between the Local Control Code and Techila Worker Code is illustrated in Figure 21 below.

image21
Figure 22. Parameters in the params array will be transferred to the Techila Worker Code. The datafile.mat file will be transferred to the same temporary directory with the Techila Worker Code. The syntax for loading the datafile.mat will be the same as in the locally executable function.

4.4. Distributing Perfectly Nested Loops

Locally executable programs can often contain perfectly nested for-loops, where the computationally intensive part is located in the innermost for-loop. In such scenarios, the peachvector can be used to as pointer to simulate the values of loop counters of inner and outer loops.

An example of a perfectly nested loop structure is shown below in pseudo-code:

for i = 1:x 		    % Outer Loop
    for j = 1:y		    % Inner Loop
       operation(i,j)	% Computation
    end
end

The perfectly nested loop structure in the example shown above contains two for-loops, an outer and an inner loop. The computationally intensive operations are located inside the inner for-loop and the values of the loop counters are used as input parameters in the computationally intensive operations. The combinations of the inner and outer loop counters is illustrated below in Figure 22

image22
Figure 23. Sample combinations of the loop counters in a perfectly nested loop structure.

As can be seen from the figure, the values of the inner and outer loop counters can also be thought to correspond to the row and column subscripts, i and j, of a 2-D matrix. The linear equivalent of these subscripts can be generated by using MATLAB`s sub2ind function. This converts the representation so it is expressed using a single value, meaning that the peachvector can be used to refer to the correct value. The linear indexes can also be converted back to subscript format with the ind2sub command.

The following example shows how to distribute a locally executable function that has a perfectly nested loop structure.

The material used in this example is located in the following folder in the Techila SDK:

techila\examples\Matlab\Tutorial\4_nestedloops

4.4.1. Locally executable function

The algorithm of the locally executable function used in this example is shown below.

function result = local_function()
% This function can be executed locally on the End-Users computer. The
% function multiplies each element in the matrix A = [2 4 6; 8 10 16; 14 16 18]
% individually.
%
% To use execute the function locally, use command:
%
% result = local_function()

% Copyright 2010-2013 Techila Technologies Ltd.

A = [2 4 6; 8 10 16; 14 16 18]; % Create matrix A
Imax=size(A,1); % Number of rows
Jmax=size(A,2); % Number of columns

for i = 1:Imax
    for j = 1:Jmax
        result(i,j) = A(i,j)*2; % Multiply each element individually
    end
end

The function requires no input parameters. Each element of the matrix A is multiplied separately inside a perfectly nested loop structure. The result of the operation will be stored in the result-matrix at the subscript indices determined by the values of the loop counters.

4.4.2. Local Control Code

The Local Control Code used to distribute computations that occur within a perfectly nested loop in this example is shown below.

function result = run_nested_loop()
% This file contains the Local Control Code and is used to distribute
% computations to the Techila environment with peach.
%
% To create the computational project, use command:
%
% result = run_nested_loop()

% Copyright 2010-2013 Techila Technologies Ltd.

A = [2 4 6; 8 10 16; 14 16 18]; % Create matrix A
siz=size(A); % Get the size of the matrix
jobs=siz(1)*siz(2); % Set number of jobs equal to the amount of elements

result=peach('nested_dist',{'<param>',siz,A}, 1:jobs); % Create the project

result=reshape(cell2mat(result),siz); %Reshape to a 2-D matrix
end

The params array contains three parameters; one of the parameters is dynamic and two of the parameters are static. Parameter siz contains the size of the matrix and will be used to convert jobidx to subscript format on the Techila Workers.

4.4.3. Techila Worker Code

The Techila Worker Code that is executed on the Techila Workers is shown below.

function result = nested_dist(jobidx,siz,A)
% This m-file contains the Worker Code, which will be compiled and distributed
% to Workers. The value of the jobidx parameter will be replaced by an
% element of the peachvector, which is defined in the Local Control Code. Other
% parameters include the size of the matrix (siz) and the matrix A (A).

% Copyright 2010-2013 Techila Technologies Ltd.

%Convert the jobidx value to column and row coordinates
[i,j] = ind2sub(siz, jobidx);

% Multiply the matrix element. This result is returned to the server.
result=2 * A(i,j);
end

Each Job will operate on one element of the two dimensional matrix. The value of the jobidx parameter will determine which matrix element will be operated on. This is will be done by converting the jobidx parameter to subscript format and using it to point to the correct matrix element.

4.4.4. Creating the computational project

The project can be created by executing the Local Control Code using command:

result = run_nested_loop()

The Project will automatically be divided into nine Jobs, as the value of the jobs parameter was defined in the Local Control Code. Parameters defined in the params array will be transferred to the Techila Workers. Elements of the peachvector (stored in the jobidx variable) parameter will be converted to subscript format on the Techila Workers by using the inbuilt ind2sub function.

4.4.5. Local Testing

It is possible to test Techila Worker Code locally. This means that it is not necessary to create a separate project for testing purposes. Local testing can be done as follows.

  1. Set a break point in the Local Control Code on the line containing the peach-function call

  2. Run the Local Control Code as you would when distributing computations to the distributed computing environment. The Local Control Code execution will break at the breakpoint. MATLAB will also automatically enter to debug mode at this point. The MATLAB workspace will now contain the same variables that are available, as the peach-function call will be performed.

  3. If you are using peachvector elements as input arguments (<param> notation), specify a value to the input arguments that it will correspond to an element of the peachvector.

  4. Execute the Techila Worker Code locally by calling the function using the desired parameters. Ensure that the code will function properly and produces expected results.

    This procedure can be tested for example using the code illustrated in Distributing Perfectly Nested Loops.

  5. Open the file run_nested_loop.m with the MATLAB Editor and set a break point on the line shown below:

    result=peach(`nested_dist`,{`<param>`,siz,A}, 1:jobs);
  6. Execute the following command in MATLAB:

    result = run_nested_loop

    Execution will break at the line containing the breakpoint. The workspace will contain the following variables:

    • A

    • jobs

    • siz

  7. Give a value for the jobidx parameter using command

    K>> jobidx=1
  8. Execute the Techila Worker Code using command:

    K>> result=nested_dist(jobidx,siz,A)

    Assuming jobidx was set to 1, this will produce following result:

    result =  4

    This corresponds to the computational operations that would take place on the Techila Worker that computes the first Job in the Project.

5. Peach Feature Examples

The basic methodology and syntax of distributing computations using the MATLAB peach-function was shown in Peach Tutorial Examples. In addition to the core features used in the tutorial, there are a wide range of optional features, such as Snapshotting, Streaming and Job Input Files.

The example material discussed in this Chapter can be found in example specific subfolders in the following Techila SDK folder:

techila\examples\Matlab\Features\<example specific subfolder>

Please note that the example material discussed in this Chapter does not contain examples on all available peach-features. For a complete list on available features, execute the following command in MATLAB:

doc peach

Monte Carlo Method

A Monte Carlo method is used in several of the examples for evaluating the value of Pi. This section contains a short introduction on the Monte Carlo method used in these examples.

The Monte Carlo method is a statistical simulation where random numbers are used to model and solve a computational problem. This method can also be used to approximate the value of Pi with the help of a unit circle and a random number generator.

unit

The area of the unit circle shown in the figure is determined by the equation π∙r^2 and the area of the square surrounding it by the equation (2 * r)^2. This means the ratio of areas is defined as follows:

ratio of areas = (area of the unit circle)/(area of the square) = (pi * r ^ 2 /( (2 * r) ^2 )=( pi * r ^ 2 / (4 * r ^ 2 )= pi / 4 = 0.7853981

When a random point will be generated, it can be located within or outside the unit circle. When a large number of points are being generated with a reliable random number generator, they will be spread evenly over the square. As more and more points are generated, the ratio of points within circle compared to the total number of points starts to approximate the ratio of the two areas.

ratio of points * ratio of areas

(points within the circle)/(total number of points) = (area of the unit circle)/(area of the square)

(points within the circle)/(total number of points) = pi / 4

For example, in a simulation of 1000 random points, the typical number of points within the circle is approximately 785. This means that the value of Pi is calculated in the following way.

785 / 1000 * pi / 4

pi * 4 * 785 / 1000 = 3.14

Algorithmic approaches are usually done only using one quarter of a circle with a radius of 1. This is simply because of the fact that number generating algorithms on many platforms generate random numbers with a uniform(0,1) distribution. This does not change the approximation procedure, because the ratios of the areas remain the same.

5.1. Distributing Monte Carlo Pi with the peach-Function

This example will demonstrate:

  • Approximation of the value of Pi using Monte Carlo method

  • Converting of a locally executable Monte Carlo method to a distributed version

The material used in this example is located in the following folder in the Techila SDK:

techila\examples\Matlab\Features\basic_monte_carlo_pi

5.1.1. Locally executable function

The locally executable function for approximating the value of Pi used in this example is shown below.

function result = local_mcpi(loops)
% This function can be executed locally on the End-Users computer. The function
% implements a Monte Carlo routine, which approximates the value of Pi. To
% execute the function locally, use command:
%
% result = local_mcpi(loops)
%
% loops = number of iterations performed in the Monte Carlo routine.

% Copyright 2010-2013 Techila Technologies Ltd.

count = 0; % Initialize the counter to zero as no points have been generated.
for i = 1:loops
    if ((sqrt(rand() ^ 2 + rand() ^ 2)) < 1) % Calculate the distance of the random point
        count = count + 1; % Increase counter if the distance is less than one.
    end
end

result = 4 * count/loops;  % Calculate the value of Pi based on the random number sampling.

end

The function requires one input argument that determines the number of iterations in the for-loop. During each iteration, two random values will be generated. These will be used as the coordinates of the random point. The coordinates of the point are then used to calculate the distance of the point from the center of the unit circle. If the distance is less than one, the point is located within the unit circle and the counter is incremented by one. As soon as all iterations have been completed, the value of Pi will be calculated.

The locally executable version of Monte Carlo Pi can be executed using command

pivalue = local_mcpi(10000000)

This will calculate the approximated value of Pi using 10,000,000 randomly generated points.

5.1.2. Distributed version of the program

The computationally intensive part in Monte Carlo methods is the random number sampling. The sampling is performed in the for-loop in the locally executable function. There are no dependencies between the iterations. This means that the sampling process can be divided into a separate function and executed simultaneously on several Techila Workers.

Note that when using the peach-function, the seed of the random number generator is initialized automatically on the Techila Workers by the peachclient-wrapper. If you wish to use a different seeding method, please seed the random number generator directly in the code you wish to execute on Techila Workers.

5.1.3. Local Control Code

The Local Control Code used in this example to control the distribution process is shown below.

function result = run_mcpi(jobs, loops)
% This function contains the Local Control Code, which will be used to distribute
% computations to the Techila environment.
%
% The m-file named "mcpi_dist.m" will be compiled and distributed to Workers.
% The "loops" parameter will be transferred to all Jobs with the params array.
% The peachvector will be used to control the number of Jobs in the Project.
% The "result" variable will contain all the individual Job results as
% elements of a cell array.
%
% To create the Project, use command:
%
% result = run_mcpi(jobs, loops)
%
% jobs = number of jobs
% loops = number of iterations performed in each Job

% Copyright 2010-2013 Techila Technologies Ltd.

result = peach('mcpi_dist', {loops}, 1:jobs);

% Elements of the vector are summed and scaled according to the number of Jobs and
% number of loops in each Job.
result = sum(cell2mat(result))* 4 / (loops * jobs);

end

The Local Control Code contains two lines of code that have distinctly different roles. The line containing the peach-function call is responsible for creating the computational Project to the Techila Distributed Computing Engine environment. The last line is executed after the Project has been completed and contains the instructions necessary for post-processing procedures.

The peach-function call defines that the function mcpi_dist will be deployed and executed on Techila Workers. The mcpi_dist function will receive one input argument called loops, which is defined in the params array. The peachvector is only used to control the number of Jobs in the Project.

5.1.4. Techila Worker Code

The code that is executed on Techila Workers in this example is shown below.

function result = mcpi_dist(loops)
% This m-file contains the Worker Code, which will be compiled and distributed
% to the Workers. The values of the input parameters will be received from the
% parameters defined in the Local Control Code.

% Copyright 2010-2013 Techila Technologies Ltd.

result = 0; %No random points generated yet, init to 0.

for i = 1:loops % Monte Carlo loop from 1 to loops
    if ((sqrt(rand() ^ 2 + rand() ^ 2)) < 1) % Point within the circle?
        result = result + 1; % Increment if the point is within the circle.
    end
end

The algorithm is very similar to the algorithm of the locally executable function. The function requires one input argument called 'loops' which is being used to determine the number of iterations. During each iteration, the distance of a randomly generated point from the centre will be calculated. If the distance is less than one, the point is within the unit circle and the count is incremented by one. The only differentiating factor is that the post-processing activities, which otherwise would take place after the for-loop, are not being implemented.

5.1.5. Creating the computational Project

The computational Project can be created with the command shown below:

result = run_mcpi(10, 1000000)

This will create a Project consisting of ten Jobs where each of the Jobs will perform 1,000,000 iterations. The Jobs are distributed to Techila Workers, where the Monte Carlo routine in the Techila Worker Code is executed.

When a Techila Worker finishes the Monte Carlo routine, it sends the results to Techila Server. After all the Techila Workers have transferred the results to the Techila Server, the results are transferred to the End-Users computer. After the results have been downloaded, the last line in the control code is executed which contains the post-processing operations, which in this case consist of scaling the results according to the number of performed iterations.

5.2. Snapshot

Snapshotting is a mechanism where intermediate results of computations are stored in snapshot files and transferred to the Techila Server at regular intervals. Snapshotting is used to improve the fault tolerance of computations and to reduce the amount of computational time lost due to interruptions.

Snapshotting is done by storing the state of the computation at regular intervals in snapshot files on the Techila Worker. The snapshot files will then be transferred over to the Techila Server at regular intervals from the Techila Workers. If an interruption should occur, these snapshot files will be transferred to other available Techila Workers, where the computational process can be resumed by using the intermediate results stored in the Snapshot file.

The material used in this example is located in the following folder in the Techila SDK:

techila\examples\Matlab\Features\snapshot

Snapshotting is enabled by default when using the peach-function. This means that the Local Control Code will not require any changes, if you use the default values set for the snapshot routine:

The default name for the snapshot file that will be transferred to the Techila Server is snapshot.mat. Using this default name will enable you to use the saveSnapshot and loadSnapshot helper functions without any additional parameters. If you choose to name your snapshot file differently, please see the saveSnapshot and loadSnapshot help for defining the file name. Help can be displayed with commands:

help loadSnapshot
help saveSnapshot

The default snapshot file transfer interval for from Techila Workers to Techila Server is 15 minutes.

If you wish to use custom filenames for the snapshot file, you can specify the name using following parameter pair in the peach-function call.

'SnapshotFiles', 'filename1, filename2'

If you wish to use a custom transfer interval, you can specify the interval using following parameter pair.

'SnapshotInterval', <minutes>

When using default name of the snapshot file, workspace variables can be stored using command:

saveSnapshot('var1',var2',...)

The saveSnapshot function also has a built-in control mechanism that sets the frequency often intermediate results will be stored in the snapshot file. This means that Snapshots will automatically be generated at a suitable frequency. If more control over the snapshot generation frequency is required, the saveSnapshot function can be placed in an if clause:

if condition is true
    saveSnapshot(‘var1',var2',...)
end

When using the default name for the Snapshot file, intermediate results stored in a Snapshot file can be loaded using command:

loadSnapshot()

The implementation of the Snapshot feature is demonstrated using the Monte Carlo Pi example.

5.2.1. Local Control Code

The Local Control Code to create a Project using Snapshotting with default values is shown below.

function result = run_snapshot(jobs, loops)
% This function contains the Local Control Code, which will be used to distribute
% computations to the Techila environment.
%
% The m-file named "snapshot_dist.m" will be compiled and distributed to Workers.
% The "loops" parameter will be transferred to all Jobs with the params array.
% The peachvector will be used to control the number of Jobs in the Project.
%
% Snapshotting will be implemented with the default values, as the Local Control Code
% does not specify otherwise.
%
% To create the Project, use command:
%
% result = run_snapshot(jobs, loops)
%
% jobs = number of jobs
% loops = number of iterations performed in each Job

% Copyright 2010-2013 Techila Technologies Ltd.

result = peach('snapshot_dist', {loops}, 1:jobs); % Create the computational Project

result = sum(cell2mat(result))* 4 / (loops * jobs);

end

When using the default values for Snapshotting, the Local Control Code will not require any changes. The two parameters controlling the Snapshotting process, the name of the snapshot file and the upload interval will be set to default values inside the peach-function.

5.2.2. Techila Worker Code

As the Local Control Code did not specify any custom settings for Snapshotting, the procedure will use default values. The upload procedure will be automatic, but the Techila Worker Code will need to be modified so that the program can initialize properly if resuming computations from a Snapshot file. The Techila Worker Code will also need to be modified to generate snapshot files at a frequency that serves the purposes of the code. Modified Techila Worker Code using Snapshotting is shown below.

function result = snapshot_dist(loops)
% This m-file contains the Worker Code, which will be compiled and distributed
% to the Workers.  The saveSnapshot helper function will be used to
% store intermediate results in the snapshot.mat file.

% Copyright 2010-2013 Techila Technologies Ltd.

result = 0;      %Init: No random points generated yet, init to 0.
iter=1;          %Init: No iterations have been performed yet, init to 1.

loadSnapshot; %Override Init values if snapshot exists

for iter = iter : loops; %Resume iterations from start or from snapshot

    if ((sqrt(rand() ^ 2 + rand() ^ 2)) < 1)
        result = result + 1;
    end

    if mod(iter,1e8)==0 %Snapshot every 1e8 iterations
       saveSnapshot('iter','result') % Save intermediate results
    end

end

Initialization of the Techila Worker Code will set values for two variables, result and iter. These are initialized values, which will be used if no Snapshot files can be found. If a Snapshot file exists, it will indicate that the Job is being resumed after an interruption. In this case, the content of the Snapshot file will be used to override the initialized values. This will be done using the loadSnapshot function, which automatically loads the contents of the Snapshot file to the workspace. Iterations will be resumed from the last value stored in the Snapshot file.

Intermediate results will be stored in the Snapshot by calling the saveSnapshot function every 1e8th iteration. The variables stored in the snapshot file are iter and result. Variable iter will contain the number of iterations performed until the snapshot generation occurred and result will contain the intermediate result.

5.2.3. Creating the computational Project

The Project can be created by executing the Local Control Code using command:

result = run_snapshot(10, 1e9)

This will create a Project consisting of 10 Jobs, where each Job will consist of 1e9 iterations. Intermediate results will be saved every 1e8th iteration. Snapshot files will be transferred every 15 minutes from the Techila Worker to Techila Server. If a Job is migrated to a new Techila Worker while the Job is being computed, the latest available Snapshot file will be automatically transferred from the Techila Server to the new Techila Worker.

Snapshot data can also be viewed and downloaded by using the Techila Web Interface. Instructions for this can be found in the Techila Web Interface End-User Guide.

Note that when using the syntax shown above to run the example, the execution time of single Job is relatively short. This might result in the Job being completed before a Snapshot file is transferred to the Techila Server. If Snapshot data is not visible in the Techila Web Interface, consider increasing the amount of iterations to increase the execution time of a Job.

5.3. Streaming & Callback Function

Streaming enables individual results to be transferred as soon as they become available. This is different from the default behavior, where all the results will be transferred in a single package after all of the Jobs have been completed.

Callback functions enable results to be handled as soon as they have been streamed from the Techila Server to End-User. The Callback function is called once for each result file that will be transferred from the Techila Server.

The material used in this example is located in the following folder in the Techila SDK:

techila\examples\Matlab\Features\streaming_callback

Streaming is disabled by default. Streaming can be enabled using following parameter pair:

'StreamResults', 'true'

A function can be used as a Callback function by defining the name of the function using following parameter pair:

'CallbackMethod', @name_of_the_function

The function will then be called every time a new result file has been streamed from the Techila Server to End-User.

By default, the Callback function will get the name of the result file as input parameter.

The input parameter can be defined to be a struct containing the contents of the result file using following parameter pair:

'CallbackParams', {'<*>'}

The input parameter can also be defined to be a value in the result file using the following syntax.

'CallbackParams', {'<parameter>'}

Where <parameter> is the name of a variable.

The Callback function can also be given input parameters directly from the Local Control Code. For example, when the function workspace of the Local Control Code contains the variables A and B, they can be defined as input parameters for the Callback function with the following syntax:

'CallbackParams', {A,B}

Values returned by the Callback Function will in turn be returned by the peach-function. Since new values are appended to the result vector in the order in which Jobs are being completed, values in the result vector will be in a random order.

The implementation of the Streaming and Callback features will be demonstrated using the Monte Carlo Pi method. In the distributed version of the program, Job results will be streamed as soon as they have become available. The Callback function is used to plot the error of the approximation in a continuous manner on a chart.

5.3.1. Local Control Code

The Local Control Code of the Monte Carlo Pi where a Callback function and Streaming are being used is shown below.

function result = run_stream(jobs,loops)
% This function contains the Local Control Code, which will be used to distribute
% computations to the Techila environment.
%
% The m-file named "mcpi_dist.m" will be compiled and distributed to Workers.
% The "loops" parameter will be transferred to all Jobs with the params array.
% The peachvector will be used to control the number of Jobs in the Project.
%
% Results will be streamed from the Workers in the order they will be completed.
% Results will be visualized by plotting them on a graph.
%
%
% To create the Project, use command:
%
% result = run_stream(jobs,loops)
%
% jobs = number of jobs
% loops = number of iterations performed in each Job

% Copyright 2010-2013 Techila Technologies Ltd.

global total;global rj;global data;global fig; % Create global variables to be used in the callback function

data = inf(1,jobs);
total = 0;
rj = 0;

figure(1);
fig=plot(data, 'YDataSource', 'data');
title('Amount of error in the Pi approximation');
ylabel('Amount of error');
xlabel('Number of Job result files processed');
drawnow;

result = peach('mcpi_dist', {loops}, 1:jobs, ...
    'StreamResults', 'true', ... % Enable streaming
    'CallbackMethod', @summc, ... % Name of the Callback function
    'CallbackParams', {loops, '<result>'}); % Parameters for the CB function

end

function result = summc(loops, val) % The Callback function

  global data; global fig; global rj; global total;

  rj = rj + 1; 		% One more result file received
  total = total + val;  % Add new results to old results
  pivalue = total * 4 / (rj * loops); % New approximate value of Pi
  error = pivalue - pi; % Calculate the error
  result = error;
  data(rj) = abs(result);
  if (mod(rj,10) == 0)   % Update figure when 10 more results are available
    refreshdata(fig, 'caller');
    drawnow;
  end
end

The Local Control Code here consists of two functions, run_stream and summc. The run_stream-function will distribute the computations using the peach-function. The summc-function is the Callback function that will be executed every time a new result will get streamed from the Techila Server to the End-User. The variables used in the Callback function are declared as global in both functions, meaning that all functions can access these variables.

CallbackMethod is used to define the name of the Callback function used in handling the results. This example will call summc-function for each result.

CallbackParams is used to define the input arguments of the Callback function. In this example, the Callback function will be given the value of the variable loops as the first argument, which will define the number of iterations that will be performed in each Job. The second input argument will be defined by '<result>'. This is a notation that tells the Callback function to use the output value of the Job as its input argument. In this example, ‘<result>' will be replaced by the value of the result variable, which is being returned by the Techila Worker Code.

The Callback function summc contains the arithmetic operations to continuously update the approximated value of Pi. This approximated value is then compared to the Pi value in MATLAB to determine the absolute error. The value of this error will be plotted on a graph every time when 10 new results have been received and have been processed.

5.3.2. Techila Worker Code

Streaming does not require any modifications to the Techila Worker Code that will be executed on the Techila Workers. The code is identical to the basic Monte Carlo Pi implementation presented Distributing Monte Carlo Pi with the peach-Function.

function result = mcpi_dist(loops)
% This m-file contains the Worker Code, which will be compiled and distributed
% to the Workers. The values of the input parameters will be received from the
% parameters defined in the Local Control Code.

% Copyright 2010-2013 Techila Technologies Ltd.

result = 0; %No random points generated yet, init to 0.

for i = 1:loops % Monte Carlo loop from 1 to loops
    if ((sqrt(rand() ^ 2 + rand() ^ 2)) < 1) % Point within the circle?
        result = result + 1; % Increment if the point is within the circle.
    end
end

5.3.3. Creating the computational Project

The computational Project can be created by using command:

result = run_stream(100,200000)

This will create a Project consisting of 100 Jobs, where every Job will perform 200,000 iterations. Results will be streamed from the Techila Server to End-User as they are completed and the graph will be updated every time 10 new results have been post-processed. The interaction between the Local Control Code and results received from the Techila Workers is illustrated in the figure below.

image26
Figure 24. The value of the loops-parameter is defined when the Local Control Code is called. The 'loops' parameter is also listed as a parameter in ‘callbackparams', meaning the parameter is transferred to the Callback function. The second input argument of the callback function 'summc' called 'val' is replaced with the value of the 'result' variable, which is received from Techila Workers.

5.4. Job Input Files

Job Input Files allow using Job-specific input files and can be used in scenarios, where individual Jobs only require access to some files within the dataset. Job-specific Input Files are stored in a Job Input Bundle and will be transferred to the Techila Server. Techila Server will transfer files from the Bundle to the Techila Workers requiring them. These files will be stored on the Techila Worker for the duration of the Job. The Job-specific Input Files will be removed from the Techila Worker as soon as the Job has completed.

The material used in this example is located in the following folder in the Techila SDK:

techila\examples\Matlab\Features\job_input_files

A list of Job-specific Input Files will be specified in JobInputFiles parameter as an array of cells:

'JobInputFiles', {{files_for_job_1}, {files_for_job_2}}

A Job can get a single Job-specific Input File as shown below:

'JobInputFiles', {{'job_1_input_1'},{' job_2_input_1'},...}

A Job can also get several Job-specific Input Files as demonstrated below:

'JobInputFiles', {{'job_1_input_1', 'job_1_input_2'},{'job_2_input_1', 'job_2_input_2'},...}

The names used for the Job-specific Input Files on a Techila Worker can be specified using the JobInputFileNames. If a single Job-specific Input File was defined with JobInputFiles, the name of the file is defined as shown below:

'JobInputFileNames', {'filename1'}

If a Job should get several Job-specific Input Files, their names will be specified as follows:

'JobInputFileNames', {'filename1','filename2',...}

JobInputFileNames is an optional parameter. If the parameter is not defined, the names will default to jobinputfile1.mat for the first file, jobinputfile2.mat for the second, and so on.

The use of Job input Files is illustrated using four images. Every image has a resolution of 500x500 pixels and features a quarter circle consisting of black and white pixels. The input files are being illustrated below.

image27

Each Job will analyze one input file by calculating the number of black pixels. The ratio of black and white pixels will then be used to approximate the value of Pi. The computational work performed in this example is trivial and is only intended to illustrate the mechanism of using Job-Specific Input Files.

5.4.1. Local Control Code

The Local Control Code for creating a Project that uses Job-Specific Input Files is shown below.

function result = run_inputfiles()
% This function contains the Local Control Code, which will be used to distribute
% computations to the Techila environment.
%
% The m-file named "inputfiles_dist" will be compiled and distributed to Workers.
% Job specific input files will be transferred with each Job, each Job receiving
% one input file.
%
% To create the Project, use command:
%
% result = run_inputfiles()
%
% Note: The number of Jobs in the Project will be automatically set to four.

% Copyright 2010-2013 Techila Technologies Ltd.

jobs = 4;
result=peach('inputfiles_dist',{},1:jobs,...
    'JobInputFiles', {{'input1.png'},{'input2.png'},{'input3.png'},{'input4.png'}},...
    'JobInputFileNames',{'quadrant.png'});

result = 4*(sum(cell2mat(result))/1e6);

end

The JobInputFiles parameter specifies files, which should be used in each Job. The syntax used in this example is shown below:

'JobInputFiles',{{'input1.png'},{'input2.png'},{'input_3.png'},{'input4.png'}}

This syntax assigns one input file for each Job. The file input1.png will be transferred to a Techila Worker together with Job #1, input2.png is transferred together with Job #2 and so on. The number of entries in the Job Input File list is equal to the number of elements in the peachvector.

The JobInputFileNames parameter specifies the names of the Job Input Files on the Techila Workers. The syntax used in this example is shown below:

'JobInputFileNames', {'quadrant.png'}

This syntax assigns the name quadrant.png to all Job-Specific Input Files.

5.4.2. Techila Worker Code

Techila Worker Code used to analyse the individual input files is shown below.

function result = inputfiles_dist()
% This m-file contains the Worker Code, which will be compiled and distributed
% to the Workers. The Jobs will access their Job-specific input files with the
% name "quadrant.png", which is defined in the Local Control Code

% Copyright 2010-2013 Techila Technologies Ltd.

    inputdata = imread('quadrant.png'); % Load the Job-specific input file to memory
    result = length(find(inputdata==0));% Calculate the amount of black pixels

end

In this example, all the Jobs access their input files by using the file name quadrant.png. Each Techila Worker then calculates the number of black pixels in their image by examining the intensity values of each pixel. The number of black pixels is returned as the result.

5.4.3. Creating the computational Project

The computational Project can be created by using command:

result = run_inputfiles

This will create a Project consisting of four Jobs. The system will automatically assign a Job-specific Input File to each Job, according to the file list specified in the Local Control Code. This is illustrated below in Figure 26.

image29
Figure 25. Transferring Job-specific Job Input files. All of the files are transferred to the Techila Server. The Techila Server transfers the requested Job Input File for each job. These files are renamed on the Techila Workers according to the parameters in the Local Control Code. In this example, the files are renamed to quadrant.png and copied to a temporary working directory on the Techila Workers.

5.5. Precompiled Binaries

The peach-function can also be used to distribute and execute precompiled binaries on the Techila Workers. When using precompiled binaries, the peachclient wrapper will not be used to transfer input parameters for the Jobs. Input parameters for the binaries will need to be defined in the Project parameters.

These input parameters will be passed directly to the executable binary using the %P() notation. The names of output files will also need to be specified separately and passed to the binary using the %O() notation.

The material used in this example is located in the following folder in the Techila SDK:

techila\examples\Matlab\Features\precompiled_binaries

The syntax for defining input parameters for precompiled binaries is shown below:

'ProjectParameters',{{'param_1', param_1},{'param_2', param_2}});

Parameters defined in ProjectParameters are given to the binary by referencing to them in the params array with the %P() notation. The jobidx parameter can be referenced without listing it in the Project parameters. This is because the jobidx parameter is created automatically (by the Job splitter) on the Techila Server and is included automatically with each Job.

The platform of the binary is defined with the Binaries parameter:

'Binaries',{{'binary_name','operating_system','processor_architecture'}}

The Binaries parameter can be used to define different binaries for different operating systems and processor architectures. For example, a different binary for 64-bit Windows and Linux Techila Workers can be defined with the syntax shown below:

'Binaries',{{'Windows_binary_name','Windows','amd64'},{'Linux_binary_name','Linux','amd64'}}

Note that when the Binaries parameter is used, the funcname parameter of the peach-function call will not define the name of the executable function.

The names of output files are defined with the following parameter pair.

'OutputFiles', {'List of Files'}

A single output file can be defined with:

'OutputFiles', {'name_of_outputfile'}

Output files defined in the OutputFiles parameter are given directly to the binary by referencing to them with the %O() notation in the params array.

The mechanism for distributing binaries is demonstrated with a precompiled version of the Monte Carlo Pi written in C. The binary is provided for two platforms: 64-bit Windows and Linux. The name of the binary is mcpi.exe for Windows and mcpi for Linux. The executable binary takes three input arguments; two of these will be used to control the Monte Carlo routine and the third will specify the name of the output file. The generic syntax is:

mcpi jobidx loops output

The input arguments are:

  • jobidx. Initializes the random number generator seed

  • loops. Determines the number of iterations

  • output. Determines the name of the output file

The binaries can also be executed locally. To execute the Windows binary locally on a computer having a Windows operating system, follow the steps listed below:

  1. Open a Command Prompt

  2. Change the working directory to the directory containing the mcpi.exe/mcpi files

  3. Execute the program using command:

    mcpi 1 100000 data

This executes the binary and performs 100,000 iterations of the Monte Carlo Pi routine. The results will be stored in a file called data. The file will store two values; the number of points that were located inside the unit circle and the number of iterations.

5.5.1. Local Control Code

The code used to control the distribution process of the precompiled binaries is shown below. Note that the funcname parameter can be used quite freely in this example. This is because the names of the executable binaries are defined with the Binaries parameter.

The Local Control Code consists of two functions; run_binary and getdata:

  • run_binary is used to distribute the computations. This function contains the peach-function call and returns the output value of the post-processed results.

  • getdata is a Callback function that is used read the contents of result files after they have been downloaded from the Techila Server.

The peach-function call contains the following parameters:

'Binaries', {{'mcpi.exe',Windows','amd64'},{'mcpi','Linux','amd64'}}

Above parameter specifies that the name of the binary for Windows Techila Workers is mcpi.exe and mcpi for Linux Techila Workers.

'Executable','true'

Above parameter specifies that funcname parameter refers to a precompiled binary

'MatlabRequired','false'

Above parameter specifies that a MATLAB Runtime Bundle will not be required.

'CallbackMethod', @getdata

Above parameter specifies that the name of the callback function is getdata. This function will be used to load the contents of the output files and retrieve the values returned from the Jobs.

'ProjectParameters',{{'loops',loops}}

Above parameter specifies the loops variable as a Project parameter, making it available for the executable binary as a Job input parameter. This input parameter is used by referring to it in the params array with the %P(loops) notation.

'OutputFiles',{'data'}

Above parameter specifies the name of the output file, making it available to the binary by referring to it in the params array.

The params array in the peach-function call is shown below:

{['%P(jobidx) %P(loops) %O(output1)']}

This defines two input parameters and one output file for the mcpi executable. The way in which these input parameters are transferred to the binary is illustrated in the Figure 27 below.

image30
Figure 26. The value of the loops parameter will be defined by the End-User when executing the Local Control Code. The loops parameter is also defined in ‘ProjectParameters', which means that it can be referenced to with the %P() notation in the params array. The name of the output file is defined with ‘OutputFiles' and given directly to the binary with %O() notation. The value of the jobidx parameter is received directly from the Techila Server, meaning it does not have to be defined in ‘ProjectParameters'.

5.5.2. Techila Worker Code

Each Techila Worker performs the Monte Carlo routine by executing the precompiled mcpi.exe or mcpi binary. The binary is executed according to the input arguments that were defined in the peach-function params array.

5.5.3. Creating the computational Project

The Project can be created by executing the Local Control Code

result = run_binary(10,100000)

This will create a Project consisting of 10 Jobs. During each Job, the mcpi binary will be executed and will perform a Monte Carlo routine that consists of 100,000 iterations. After the Monte Carlo routine has been completed, the result of the approximation will be stored a file called data. This file will be returned from the Techila Workers to the Techila Server. After all Jobs have been completed, the output files will be transferred to your computer.

After the output files have been transferred to your computer, each file will be processed by using the getdata-function. This function will be used to load each output file and retrieve the first value from the file, which will contain the number of points that were inside the unit circle for each Job. This value will be returned from the Callback-function, meaning it will also be returned by the peach-function as an element of the result-vector.

After all output files have been processed, the values in the result-vector will be used to calculate the approximated value of Pi.

5.6. MEX files

MEX files are MATLAB executables, which can be used to access a large number of existing C, C++ or FORTRAN routines directly from MATLAB, without having to rewrite them as M-files. MEX files can be included in the computational Project by defining the names of the source files during Project creation. The source files will then be automatically compiled in to MEX files and transferred to the Techila Workers.

The use of MEX files is illustrated using the Monte Carlo routine, where the computationally intensive part has been written in C and has been compiled into a MEX file called mcpi.c. The MEX accepts two input parameters; the first input parameter is used to specify the number of iterations, the second input parameter is used to seed the random number generator.

The material used in this example is located in the following folder in the Techila SDK:

techila\examples\Matlab\Features\mex_files

MEX files can be included in the compilation using following parameter pair:

'MexFiles', {{'file1.c', 'requirement1.c}, 'file2.c'}

This parameter compiles the listed source files into MEX files. The compiled files are automatically included with each Job in the Project.

5.6.1. Local Control Code

The Local Control Code to include MEX files in a computational Project is shown below.

function result = run_mex(jobs,loops)
% This function contains the Local Control Code, which will be used to distribute
% computations to the Techila environment.
%
% The m-file named "mcpi_wrapper.m" will be compiled and distributed to Workers.
% The "loops" parameter will be transferred to all Jobs with the params array.
% The peachvector will be used to control the number of Jobs in the Project.
% THe MEX file named "mcpi.c" will be compiled and transferred with each Job.
% This MEX function will be called from the Worker Code.
%
% To create the Project, use command:
%
% result = run_mex(jobs,loops)
%
% jobs = number of jobs
% loops = number of iterations performed in each Job

% Copyright 2010-2013 Techila Technologies Ltd.

result = peach('mcpi_wrapper',{loops,'<param>'},1:jobs,...
'MexFiles',{'mcpi.c'});

result = sum(cell2mat(result));
result = 4 * result / (jobs * loops);
end

The use of MEX files is defined with the following parameter:

'MexFiles',{'mcpi.c'}

The parameter pair defines that the file named mcpi.c is required in the computations and needs to be compiled and transferred with each Job. This file is located in the same directory as the mcpi_wrapper.m file and other files related to this example.

5.6.2. Techila Worker Code

The Techila Worker Code used in this example is shown below.

function result = mcpi_wrapper(loops,jobidx)
% This m-file contains the Worker Code, which will be compiled and distributed
% to the Workers. The values of the input parameters will be received from the
% parameters defined in the Local Control Code.

% Copyright 2010-2013 Techila Technologies Ltd.

result=mcpi(loops,jobidx); % Call the MEX function using the parameters received from the Local Control Code.
end

The executable function mcpi_wrapper acts as a wrapper for calling the MEX file. The syntax for the calling the MATLAB executable is the same as it would be calling a built-in function. After the MEX has been executed, the return value will be stored in the result variable which in turn will be returned from the Techila Worker.

5.6.3. MEX code

The MEX code is shown in below.

/* Copyright 2010-2018 Techila Technologies Ltd. */

#include <string.h>
#include <math.h>
#include "mex.h"

void mexFunction(int nlhs, mxArray *plhs[ ],int nrhs, const mxArray *prhs[ ]) {
  int j, loops, jobidx;
  double *output, x, y, c;

  /* Create the output array */
  plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL);
  output = mxGetPr(plhs[0]);

  /* Get input integer values */

  loops = (int)(mxGetScalar(prhs[0]));  /* The number of iterations */
  jobidx = (int)(mxGetScalar(prhs[1])); /* Used to initialize the RNG */

  /* Init the random number generator */
  srand(time(0) * jobidx * 12837);

  for (j = 0; j < loops; j++) { /* Monte Carlo approximation */
    x = ((float) rand() / RAND_MAX);
    y = ((float) rand() / RAND_MAX);
    c = sqrt(pow(x, 2) + pow(y, 2));
    if (c < 1) {
      output[0]++;
    }
  }
}

The algorithm in the MEX file requires using two input parameters: jobidx is used to initialize the random number generator seed and loops to determine the number of iterations done in the Monte Carlo routine. The results are stored in a variable named output, which will be returned as the output value of the mcpi_wrapper function.

5.6.4. Creating the computational Project

The Project can be created using command:

result = run_mex(10,1000000)

This will create a Project consisting of 10 Jobs, each Job performing 1,000,000 iterations. The mcpi.c file will be automatically compiled and transferred to Techila Workers. The Monte Carlo approximation will be done by executing the Monte Carlo algorithm in the MEX file according to the values defined in the params array.

5.6.5. Project Detaching

When a Project is detached, the peach-function returns immediately after all of the computational data has been transferred to the Server. This means that MATLAB does not remain in "busy" state for the duration of the Project and can be used for other purposes while the Project is being computed. Results of a Project can be downloaded after the Project has been completed.

The material used in this example is located in the following folder in the Techila SDK:

techila\examples\Matlab\Features\detached_projet

5.7. Project detaching in MATLAB

Projects can be detached using following parameter:

'DoNotwait', 'true'

This will cause the peach-function to return immediately after the Project has been created and all computational data transferred to the Techila Server. The peach-function call will return the Project ID number, which can be used in the download process.

Results can be downloaded by linking the peach-function call to an existing Project ID number using following parameter pair:

'ProjectId', projectid

It is also possible to download results of previously completed Project (assuming the results have not been removed from the Techila Server), even when the original Project as not detached with the DoNotwait parameter. Results belonging to such Projects can be downloaded by defining the Project ID number as the value of the projectid parameter. For example, the following syntax would link the peach-function call to Project 1234.

'ProjectId', 1234

Following example demonstrates detaching a Project and downloading results using a peach-function call.

5.7.1. Local Control Code

The Local Control Code for creating a Detached Project is shown below.

function projectid = run_detached(jobs,loops)
% This file contains the Local Control Code,
% which will be used to distribute computations to the Techila environment.
%
% The m-file named "mcpi_dist.m" will be compiled and distributed to Workers.
% The "loops" parameter will be transferred to all Jobs with the params array.
% The peachvector will be used to control the number of Jobs in the Project.
% The peach function will return immediately after the computational data has
% been transferred to the server. The function will return the Project ID of the Project
% that was created.
%
% To create the Project, use command:
%
% projectid = run_detached(jobs,loops)
%
% jobs = number of jobs
% loops = number of iterations performed in each Job

% Copyright 2010-2013 Techila Technologies Ltd.

projectid = peach('mcpi_dist', {loops}, 1:jobs, ...
    'DoNotwait', 'true');

end

The Project is detached with the parameter pair:

'DoNotwait', 'true'

This parameter pair causes the peach-function to return immediately after the Project has been created. The variable projectid will contain the Project ID number of the Project that has been created. This Project ID number can be used to download the results.

As soon as the Project has been completed the results can be downloaded by performing a peach-function call. The peach-function call is linked to an existing Project ID. The algorithm of the function used to download the results is shown below.

function result = download_pi_results(projectid)
% This function downloads the results of a previously created Project.
% To download results of a previously created Project, use command:
%
% result = download_pi_results(projectid)
%
% projectid = The Project ID number of the Project for which the results will be downloaded.

% Copyright 2010-2013 Techila Technologies Ltd.

 result=peach('',{},1,...
    'ProjectId', projectid); % Links to an existing project

result = cell2mat(result);	% Convert to a single matrix
result = 4*sum(result(:,1)) / (result(1,2) * size(result,1)); % Calculate the value of Pi using the downloaded results.

end

The function download_pi_results will download the results. The peach-function will only be used to contact the Techila Server and to request for the results. This means that funcname and params and parameters will not be required here.

The ProjectId parameter will specify the Project ID number to which the peach-function call should be linked to. The value of the parameter will be defined by the input argument of the download_pi_results function.

5.7.2. Techila Worker Code

The code that is executed on the Techila Workers is shown below.

function result = mcpi_dist(loops)
% This m-file contains the Worker Code, which will be compiled and distributed
% to the Workers. The values of the input parameters will be received from the
% parameters defined in the Local Control Code.

% Copyright 2010-2013 Techila Technologies Ltd.

result = 0; %No random points generated yet, init to 0.

for i = 1:loops %Monte Carlo loop from 1 to loops
    if ((sqrt(rand() ^ 2 + rand() ^ 2)) < 1) % Point within the circle?
        result = result + 1; % Increment if the point is within the circle.
    end
end
result = [result loops]; % Save result and value of the loops variable for post-processing.
end

The Techila Worker Code is similar to the basic implementation shown in Distributing Monte Carlo Pi with the peach-Function. The only difference is that the result also contains the number of iterations that were performed during the Monte Carlo routine. The number of iterations is stored in order to preserve information that is required in the post-processing. Embedding the variables required in post-processing in the result files means, that the post-processing activities can be performed correctly regardless of when the results are downloaded.

5.7.3. Creating the Project

The computational Project can be created by executing the following command:

projectid = run_detached(10,1000000)

This creates a Project consisting of ten Jobs. After all of the computational data has been transferred to the Techila Server, the Project ID number will be returned to the projectid variable. The Project ID number can be used to download the results of the Project after all the Project has been completed.

After the Project has been completed, the results can be downloaded from the Techila Server with the download_pi_results function using the syntax shown below:

pivalue = download_pi_results(projectid)

5.8. Iterative Projects

Using iterative Projects is not so much as a feature as it is a technique. Projects that require that use the output values of previous Projects as input values can be implemented by placing the peach-function inside a loop structure. This example illustrates this technique by creating several, consecutive Projects that perform the Monte Carlo Pi approximation. The iterative process will stop, as soon as the error of the approximated value of PI reaches below a threshold value.

The material used in this example is located in the following folder in the Techila SDK:

techila\examples\Matlab\Features\iterative_project

5.8.1. Local Control Code

The Local Control Code used to create several, consecutively created Projects is shown below.

function run_pi_iteration()
% This function contains the Local Control Code, which will be used to distribute
% computations to the Techila environment.
%
% The m-file named "mcpi_dist" will be compiled and distributed to Workers.
% Several consecutive Projects will be created, during which the value of Pi will
% be calculated using the Monte Carlo method. Results of the Projects will be used
% to improve the accuracy of the approximation. Projects will be created until
% the amount of error in the approximation is below the threshold value.
%
% To create the Projects, use command:
%
% run_pi_iteration()
%
% Note: The number of Jobs in the Project will be automatically set to 20.

% Copyright 2010-2013 Techila Technologies Ltd.

threshold = 2e-4;   % Maximum allowed error
n = 20;             % Number of Jobs
loops = 1e7;        % Number of iterations performed in each Job
total_result = 0;   % Initial result when no approximations have been performed.
iteration = 1;      % Project counter, first Project will
current_error = pi; % Initial error, no approximations have been performed

if exist('restorepoint.mat')    % Is the computations are being resumed?
   load restorepoint            % Load intermediate results
end

techilainit(); % Initialize the Techila environment once

while abs(current_error) >= threshold
    result = sum(cell2mat(peach('mcpi_dist', {'<param>',iteration,loops}, 1:n,...
        'Messages','false',...      % Turn off messages
        'DoNotInit','true',...      % Do not initilize the Techila environment
        'DoNotUninit','true')));    % Do not uninitalize the Techila environment

    total_result = total_result + result;   % Add results of the current project to total results
    approximated_pi = total_result * 4 / (loops * n * iteration); % Calculate the approximated value of Pi
    current_error = approximated_pi - pi; % Calculate the current error
    fprintf(1,'Amount of error in the approximation = %.16f\n',current_error); % Print the value of the current error
    iteration=iteration+1;
    save restorepoint iteration total_result % Save current computational results to a mat-file.
end
techilauninit(); % Uninitialize the Techila environment
fprintf('Error below threshold value, no more Projects required.\n')
fprintf('Approximated value of Pi = %g\n',approximated_pi) % Print the approximated value of Pi
delete('restorepoint.mat')
end

The peach-function call is placed inside a loop structure, which is implemented with a while statement. The while-clause is true, if the error of the approximated value of Pi exceeds the threshold value. When the error is greater than the threshold value, a new computational Project will be created to improve the accuracy of the approximation. Intermediate results will be saved locally every time the results of the latest Project have become available.

5.8.2. Techila Worker Code

The algorithm for the Techila Worker Code is shown below.

function result = mcpi_dist(jobidx,iteration,loops)
% This m-file contains the Worker Code, which will be compiled and distributed
% to the Workers. The values of the input parameters will be received from the
% parameters defined in the Local Control Code.

% Copyright 2010-2013 Techila Technologies Ltd.

result = 0; %No random points generated yet, init to 0.

rand('state',jobidx*iteration) %Seed the RNG based on the, jobidx and iteration value.

for i = 1:loops % Monte Carlo loop from 1 to loops
    if ((sqrt(rand() ^ 2 + rand() ^ 2)) < 1) % Point within the circle?
        result = result + 1; % Increment if the point is within the circle
    end
end

Apart from the random number seeding method, the code is identical to the one used in Distributing Monte Carlo Pi with the peach-Function. The random number seeding is done in order to ensure that the Jobs in the Projects generate such results that the error threshold is reached after a reasonable number of Projects.

5.8.3. Creating the computation Project

The Local Control Code can be executed using command:

run_pi_iteration()

The command shown above will create Projects consisting of 10 Jobs. Each Job will consist of 10 million iterations. Projects will be created until the error of the approximated value is smaller than the threshold value. The error of the approximation will be printed every time a Project has been completed.

6. Interconnect

The Techila interconnect feature allows solving parallel workloads in a Techila Distributed Computing Engine environment. Using Techila interconnect will allow you to solve computational Projects, where Jobs need to communicate with other Jobs in the Project.

This Chapter contains walkthroughs of simple examples, which illustrate how to use the Techila interconnect functions to transfer interconnect data in different scenarios.

Each of the following Chapters contains a walkthrough of one Techila interconnect example.

Below are some notes about additional requirements that need to be met when using the Techila interconnect feature with MATLAB.

General note: Prevent interconnect commands from executing on your computer


If Techila interconnect commands are executed on your computer, the commands will fail because the interconnect functions are not intended to be executed on the End-User’s computer, but on the Techila Workers.

When you are using the cloudfor-function to distribute computations to the Techila Distributed Computing Engine environment, the code inside the cloudfor-loop structure will be executed once on your computer. This code execution also means that if there are any interconnect function calls inside the cloudfor-loop structure, these will also be executed and will generate errors.

The errors can be prevented by wrapping the code inside the cloudfor-loop structure in an if isdeployed statement. Variable isdeployed is of boolean type and the value of the variable will be automatically generated by MATLAB. The value will be false when the code is executed in source code format in MATLAB, meaning the if isdeployed code block will not be executed on the End-User’s computer.

For more information about isdeployed, please execute the following command in MATLAB:

doc isdeployed

Below code snippet illustrates how the if isdeployed statement should be used when using the Techila interconnect functions.

cloudfor x=1:2
%cloudfor('stepsperjob',1)
if isdeployed
    if x == 1
        sendDataToJob(2,'Hi from Job 1');
        jobres{x} = recvDataFromJob(2);
    else
        jobres{x} = recvDataFromJob(1);
        sendDataToJob(1,'Hi from Job 2');
    end
end
cloudend

General note: All Jobs of an interconnect Project must be running at the same time


When using Techila interconnect functions in your code, all Jobs that execute these functions must be running at the same time. Additionally, all Techila Workers that are assigned Jobs from your Project must be able to transfer Techila interconnect data. For example, if you Project consists of 12 Jobs that execute interconnect functions, all 12 Jobs must be running at the same time.

If all Techila Workers in your Techila Distributed Computing Engine environment are not able to transfer interconnect data packages, it is recommended that you assign your Projects to run on Techila Worker Groups that support interconnect data transfers. If Jobs are assigned to Techila Workers that are unable to transfer interconnect data packages, your Project may fail due to network connection problems. Please note that before the interconnect Techila Worker Groups can be used, they will need to be configured by your local Techila Administrator.

You can specify that only Techila Workers belonging to specific Techila Worker Groups should be allowed to participate in the Project with the techila_worker_group Project parameter.

The example code snippet below illustrates how the Project could be limited to only allow Techila Workers belonging to Techila Worker Group called IC Group 1 to participate. This example assumes that administrator has configured a Techila Worker Group called IC Group 1 so it consists only of Techila Workers that are able to transfer interconnect data packages with other Techila Workers in the Techila Worker Group.

cloudfor x=1:2
%peach('ProjectParameters',{{'techila_worker_group','IC Group 1'}})
…
cloudend

Please ask your local Techila Administrator for more detailed information about how to use the Techila interconnect feature in your Techila Distributed Computing Engine environment.

6.1. Transferring Data between Specific Jobs

This example is intended to illustrate how to transfer data between specific Jobs in the Project. Executable code snippets are provided for the distributed version that uses the cloudfor-function.

The material used in this example is located in the following folder in the Techila SDK:

techila\examples\Matlab\Interconnect\1_cloudfor_jobtojob

Please note that before you can successfully run this example, your Techila Distributed Computing Engine environment needs to be configured to support Techila interconnect Projects. Please ask your local Techila Administrator for more information.

Transferring data between Jobs

Data can be transferred from one Job to another Job with the 'sendDataToJob' function:

sendDataToJob(<targetjobidx>,<data to be transferred>);

The notation <targetjobidx> should be replaced with the index of the Job you wish to send the data to. The notation <data to be transferred> should be replaced with the data you wish to send to the target Job. The transferred data can be for example a workspace variable or a simple string.

Any data that is transferred with the sendDataToJob function, must be received with the recvDataFromJob function in the target Job:

recvdata = recvDataFromJob(<sourcejobidx>);

The <sourcejobidx> notation should be replaced with the index of the Job from which you wish to receive data. Received data will be returned by the recvDataFromJob function and can be stored in a variable using the standard MATLAB syntax.

Example: The following syntax could be used to transfer the string Hello to Job #2.

sendDataToJob(2,'Hello');

If we assume that Job #1 was the Job that executed the above command, then the data could be received in Job #2 with the following syntax

recvdata = recvDataFromJob(2);

In this example, the variable recvdata would contain the string Hello.

Note! After interconnect data has been transferred between Jobs, the waitForOthers() command can be used to enforce a synchronization point. When this command is executed in Jobs, each Job in the Project will wait until all other Jobs in the Project have also executed the command before continuing.

6.1.1. Example code walkthrough

The code for the Techila SDK example that illustrates how to use the 'sendDataToJob' and 'recvDataFromJob' functions is shown below:

function jobres = run_jobtojob()
% This function contains the cloudfor-loop, which will be used to distribute
% computations to the Techila environment.
%
% This code will create a Project, which will have 2 Jobs. Each Job will send
% a short string to the other Job in the Project by using the Techila
% interconnect feature.
%
% To create the Project, use command:
%
% jobres = run_jobtojob()

% Copyright 2015 Techila Technologies Ltd.
steps=2; % Set total number of iterations to 2
cloudfor x=1:steps
%cloudfor('stepsperjob',1)
%%peach('ProjectParameters',{{'techila_worker_group','IC Group 1'}})
if isdeployed % Code inside this 'if' block will only be executed on Workers.
    if x == 1 % Job #1 will execute this block
        sendDataToJob(2,'Hi from Job 1'); % Send message to Job #2
        jobres{x} = recvDataFromJob(2);   % Receive message from Job #2
    end
    if x == 2 % Job #2 will execute this block
        jobres{x} = recvDataFromJob(1); % Receive message from Job #1
        sendDataToJob(1,'Hi from Job 2'); % Send message to Job #1
    end
    % Wait until all Jobs have reached this point before continuing
    waitForOthers()
end
cloudend
end

The above code will create a Project consisting of two Jobs, where each Job will consist of one iteration. Each Job will transfer a short string to the other Job in the Project. After both Jobs have sent (and received) the data, the Project will be completed.

Below is an illustration of the interconnect data transfer operations that will be performed in this Project when the Jobs are assigned to Techila Workers.

image30
Figure 27. Transferring simple message strings between two Jobs.

Below is a more detailed explanation on the effect of each line in the code sample.

The below line shows a control parameter, which is used to define that the number of iterations in each Job should be set to one:

%cloudfor('stepsperjob',1)

Note! If the stepsperjob parameter would be removed, the Project would only contain one Job (because iterations are extremely fast, meaning they would be grouped into a single Job). In this case, when the Job would be started on a Techila Worker, the Job would execute the first if-statement. This if-statement contains a SendDataToJob command, which would attempt to send data to Job #2. This transfer attempt would fail, because there would not be Job #2 to receive the data.

When performing interconnect computations in a Techila Distributed Computing Engine environment, it is recommended that you set the number of iterations per Job manually by using the stepsperjob parameter. This will help ensure that you are able to design your code so that every interconnect data transfer is performed in a predictable manner.

The line below shows the syntax for defining that only Techila Workers from Techila Worker Group called IC Group 1 are allowed to participate. Note! This parameter is commented out in the example, meaning the Techila Worker Group limitation will not be active. If you wish to activate the limitation that only Techila Workers from Techila Worker Group IC Group 1 are allowed to participate, remove the additional %-character from the start of the line.

%peach('ProjectParameters',{{'techila_worker_group','IC Group 1'}})

Note! If interconnect Techila Worker Groups are named differently in your Techila Distributed Computing Engine environment, replace IC Group 1 with the applicable name. Please contact your local Techila Administrator for more details.

The code that will be executed on Techila Workers is placed inside an if isdeployed statement. This is required in order to prevent the code from being executed locally on the End-User’s computer.

The computational code that is executed on the Techila Workers contain two if statements, which determine the operations that will be executed in each Job. Job #1 will execute the code inside the first if-statement (x==1) and Job #2 will execute the code inside the other code branch (x==2).

Job #1 will start by executing the sendDataToJob, which is used to transfer data to Job #2. Job #2 respectively starts by executing the recvDataFromJob command, which is used to read the data, which is being transferred by Job #1.

After Job #2 has received the data, the roles are reversed, meaning Job #2 will transfer data to Job #1. After Job #1 has received the data, each Job will continue execution.

Jobs will continue execution only after all Jobs have reached and executed the waitForOthers command.

In this example, the results will be stored in the cell array called jobres, where each cell element corresponds to the result generated in one Job. First element corresponds to the result generated in Job #1, and the second cell element contains the result from Job #2.

6.1.2. Running the example

This example can be can be executed by changing your current working directory in MATLAB to the directory containing the material for this example and executing the command shown below:

jobres = run_jobtojob()

After you have executed the command, the computational code will be compiled by using the MATLAB compiler. After the compilation is completed, the Project will be automatically created and will consist of two (2) Jobs.

After both Jobs have been assigned to Techila Workers, the interconnect network will be automatically established. After the interconnect network has been established, the Jobs will exchange messages. After messages have been exchanged, the Jobs will be marked as complete. The exchanged messages will be returned back to your computer and will be stored in the jobres cell array.

6.2. Broadcasting Data from one Job to all other Jobs

This example is intended to illustrate how to broadcast data from one Job to all other Jobs in the Project. An executable code snippet is provided for the distributed version that uses the cloudfor-function.

The material used in this example is located in the following folder in the Techila SDK:

techila\examples\Matlab\Interconnect\2_cloudfor_broadcast

Please note that before you can successfully run this example, your Techila Distributed Computing Engine environment needs to be configured to support Techila interconnect Projects. Please ask your local Techila Administrator for more information.

Broadcasting interconnect data

Data can be broadcasted from one Job to all other Jobs with the cloudbc function:

bcval = cloudbc(<datatobetransferred>, <sourcejobidx>);

The notation <datatobetransferred> should be replaced with the data you wish to broadcast to other Jobs in the Project. The notation <sourcejobidx> should be replaced with the index of the Job you wish to use for broadcasting the data. The function will return the broadcasted data and it can be stored in a workspace variable; in example syntax shown above it will be stored in the bcval variable.

The figure below illustrates how the cloudbc function could be used to broadcast the value of a local workspace variable x from Job #2 to other Jobs in the Project.

image31
Figure 28. Using the cloudbc function to broadcast the value of a local variable to other Jobs.

6.2.1. Example code walkthrough

The code for the Techila SDK example that illustrates how to use the cloudbc function is shown below:

function jobres = run_broadcast(sourcejob,jobcount)
% This function contains the cloudfor-loop, which will be used to distribute
% computations to the Techila environment.
%
% During the computational Project, data will be broadcasted from one Job
% to all other Jobs in the Project. The broadcasted data will be returned
% from all Jobs.
%
% Syntax:
%
% jobres = run_broadcast(sourcejob,jobcount)
%
% sourcejob = Defines which Job will broadcast the data.
% jobcount = Defines the number of Jobs in the Project.
%
% Example syntax (Job #2 broadcasts, 4 Jobs in total):
%
% jobres = run_broadcast(2,4)
%

% Copyright 2015 Techila Technologies Ltd.

cloudfor x=1:jobcount
%cloudfor('stepsperjob',1)
%%peach('ProjectParameters',{{'techila_worker_group','IC Group 1'}})
if isdeployed
    datatotransfer=['Hi from Job ' num2str(x)]; % Build the string that will be broadcasted
    jobres{x} = cloudbc(datatotransfer,sourcejob); % Broadcast the string to all other Jobs from 'sourcejob'
    waitForOthers() % Wait until all Jobs have reached this point before continuing
end
cloudend
end

The function run_broadcast takes two input arguments; the first input argument (sourcejob) defines which Job will broadcast the data; the second input argument (jobcount) defines how many Jobs will there be in the Project.

The Job starts by creating a workspace variable called datatotransfer:

datatotransfer = ['Hi from Job ' num2str(x)];

This datatotransfer variable will be a string and will always start with the fixed string `Hi from Job `. This fixed string will be concatenated with value of the cloudfor-loop counter for each Job. For example, the table below contains the values of the datatotransfer variable in each Job, in a Project consisting of 3 Jobs.

Job # Value of datatotransfer

1

Hi from Job 1

2

Hi from Job 2

3

Hi from Job 3

The following cloudbc function call will be used to broadcast the data from one Job to all other Jobs in the Project.

jobres{x} = cloudbc(datatotransfer,sourcejob);

The value of the variable sourcejob will determine which Job will broadcast data. The data that will be transferred is defined by the value of the datatotransfer variable. For example, if the value of the sourcejob variable is 2, then Job #2 will broadcast the string Hi from Job 2 to all other Jobs in the Project.

In each Job, the cloudbc function will return the string that was broadcasted and store it in the jobres cell array at the index specified by the cloudfor loop counter.

After data has been transferred, the waitForOthers()command will be executed which means that each Job in the Project will wait until all other Jobs have also executed this command before continuing.

6.2.2. Running the example

This example can be can be executed by changing your current working directory in MATLAB to the directory containing the material for this example and executing the command shown below:

jobres = run_broadcast(2,3)

When executed with the syntax shown above, the code will create a Project consisting of three (3) Jobs. Job #2 will broadcast data to other Jobs in the Project. Below figure illustrates the operations that take place when the code is executed with the syntax shown above.

image32
Figure 29. Operations performed when running the example.

Tip! Feel free to modify the values of the input arguments, but please note that there need to be enough available CPU cores to process each Job simultaneously. If all Jobs are not processed simultaneously, the Project will fail during the initialization phase because the interconnect network cannot be established.

6.3. Transferring Data from all Jobs to all other Jobs

This example is intended to illustrate how to broadcast data from all Jobs to all other Jobs in the Project.

The material used in this example is located in the following folder in the Techila SDK:

techila\examples\Matlab\Interconnect\3_cloudfor_alltoall

Please note that before you can successfully run this example, your Techila Distributed Computing Engine environment needs to be configured to support Techila interconnect Projects. Please ask your local Techila Administrator for more information.

Transferring data between all Jobs

Data can be transferred to all Jobs from all other Jobs by using the sendDataToJob and recvDataFromJob functions combined with regular for-loops and if-statements. These for-loops and if-statements will need to be implemented so that each Job that is sending data has a matching Job that is receiving data.

6.3.1. Example code walkthrough

The code for the Techila SDK example that illustrates how to use the sendDataToJob and recvDataFromJob functions to transfer data between all Jobs is shown below:

function dataall = run_alltoall()
% This function contains the cloudfor-loop, which will be used to distribute
% computations to the Techila environment.
%
% This code will create a Project, which will have 4 Jobs. Each Job will send
% a short string to all other Jobs in the Project by using the Techila
% interconnect feature.
%
% To create the Project, use command:
%
% dataall = run_alltoall()

% Copyright 2015 Techila Technologies Ltd.
cloudfor jobidx=1:4
%cloudfor('stepsperjob',1)
%%peach('ProjectParameters',{{'techila_worker_group','IC Group 1'}})
if isdeployed
    dataall=cell(1,4);
    jobcount=str2num(getenv('TECHILA_JOBCOUNT')); % Get the number of Jobs in the Project
    jobidx=str2num(getenv('TECHILA_JOBID_IN_PROJECT')); % Get the jobidx of the Job, values between 1-4.

    switch jobidx % Decide which string will be transferred from the Job
    case 1
         msg='Hello from Job #1';
    case 2
         msg='Hello from Job #2';
    case 3
         msg='Hello from Job #3';
    case 4
         msg='Hello from Job #4';
    end

    % For loops for sending the data to all other Jobs.
    for src = 1:jobcount
        for dst = 1:jobcount
            if src == jobidx && dst  ~= jobidx
                sendDataToJob(dst,msg);
            elseif src ~= jobidx && dst == jobidx
                data = recvDataFromJob(src);
                dataall{jobidx} = [dataall{jobidx} data ', '];
            else
                disp('Do nothing')
            end
        end
    end
    dataall{jobidx} = dataall{jobidx}(1:end-2);  % Trim the output
    % Wait until all Jobs have reached this point before continuing
    waitForOthers()
end
cloudend
end

The above code will create a Project with 4 Jobs where simple strings will be transferred from each Job to all other Jobs in the Project.

The Job is started by creating an empty cell array called dataall that will be used to store the strings that have been received from other Jobs in the Project.

The number of Jobs in the Project is retrieved by getting the value of the environment variable TECHILA_JOBCOUNT.

The Job’s index number is retrieved by getting the value of the environment variable TECHILA_JOBID_IN_PROJECT. This value will be stored in the jobidx variable and will be unique for each Job and will range from one to four.

The switch statement will use the value of the jobidx variable to determine what message the Job will transfer to other Jobs in the Project. The table below contains the messages transferred from each Job.

Job # Message Transferred

1

Hello from Job #1

2

Hello from Job #2

3

Hello from Job #3

4

Hello from Job #4

After deciding which message the Job should send, the Job will execute the for-loop structure which determines the order in which messages are transferred. The transferred messages will be concatenated to the dataall cell array, which will be returned to the End-User’s computer

The interconnect data transfers that take place during the Project are illustrated in the figure below. The arrows indicate that interconnect data is being transferred. The values in parentheses correspond to the values of the src and dst loop counters. For example, arrow with value (1,3) means that Job #1 is sending the msg string to Job #3. If src is equal to dst (e.g. (2,2)), no data is transferred because the source and target are the same.

image33
Figure 30. Order in which data is transferred between Jobs. Numbers in parentheses match the values of (src,dst) loop counters.

After all messages have been transferred, the trailing comma from the string stored in cell array dataall will be trimmed.

6.3.2. Running the example

This example can be can be executed by changing your current working directory in MATLAB to the directory containing the material for this example and executing the command shown below:

dataall = run_alltoall()

When the command is executed, the code will create a Project consisting of four (4) Jobs. Each Job will transfer a simple string to all other Jobs in the Project. These transferred strings will then be returned to the End-User’s computer. After completing the Project, the transferred messages can be viewed by accessing the cell elements. For example, the below syntax can be used to access messages transferred to Job #1.

dataall{1}

ans =

Hello from Job #2, Hello from Job #3, Hello from Job #4

6.4. Executing a Function by Using CloudOp

This example is intended to illustrate how to execute a function by using the cloudop-function.

The material used in this example is located in the following folder in the Techila SDK:

techila\examples\Matlab\Interconnect\4_cloudfor_cloudop

Please note that before you can successfully run this example, your Techila Distributed Computing Engine environment needs to be configured to support Techila interconnect Projects. Please ask your local Techila Administrator for more information.

The cloudop-function executes the given operation across all the Jobs and returns the result to all jobs, or the target job:

result=cloudop(@<op>, <data>, <target>)

The @<op> notation should be replaced with the operation you wish to execute on all Jobs. For example, if you wish to execute the MATLAB max function, the syntax @max would be used.

It is also possible to execute custom functions with cloudop. For example, if you have developed a custom function called simplesum, then you could execute this with cloudop with the following syntax.

result=cloudop(@simplesum, <data>, <target>)

Custom functions executed with cloudop will need to meet following requirements:

  • The custom function must accept two input arguments

  • The custom function must return one output value. The format of this output value must be such that it can be given as an input argument to the custom function. This is because the operations will be executed using a binary tree structure, which means that the output of the custom function will be also used as input for the function when function is called later in the tree structure.

The example code snippet below shows custom function called multiply, which meets the above requirements.

function result =multiply(a,b)
result=a*b;
end

The <data> notation needs to be replaced with the input data you want to give to the operation that will be executed.

The <target> notation is an optional input argument. When <target> is defined, the value defines which Job will receive the final result from the cloudop-function. Please note that when <target> is defined, the cloudop-function will return an empty array in all other Jobs.

Example 1: In the example code snippet below, the min function is used to find the minimum value of local workspace variables (variable x). The minimum value will then be transferred to Job #2, where it will be stored in a cell-array. Using a cell-array is required, because the cloudop-function will only return the minimum value in Job #2, all other Jobs will return an empty array as the result.

function xmin=example()

xmin = cell(1,3);
inputdata=[10 5 20];
cloudfor idx=1:3
%cloudfor('stepsperjob',1)
if isdeployed
     x= inputdata (idx);
     xmin{idx}=cloudop(@min, x,2);
end
cloudend
disp(xmin)
end

The operations that take place on the Techila Workers when the above code snippet is executed are illustrated in the figure below.

image34

Example 2: In the example code snippet below, the 'min' function is used to find the global minimum value of local workspace variables (variable 'x'). The minimum value will then be broadcasted to all Jobs and stored in an array. The code snippet would create a Project containing three (3) Jobs.

function xmin=example()

xmin = zeros(1,3);
inputdata =[10 5 20];
cloudfor idx=1:3
%cloudfor('stepsperjob',1)
if isdeployed
     x=inputdata(idx);
     xmin(idx)=cloudop(@min, x);
end
cloudend
disp(xmin)
end

The operations that take place on the Techila Workers when the above code snippet is executed are illustrated in the figure below.

image35
Figure 31. Process flow of finding the minimum value from a set of local workspace variables.

6.4.1. Example code walkthrough

The following code snippet illustrates how to create a Project, where the smallest random number is searched and broadcasted to all Jobs by using the cloudop-function.

function result=run_cloudop()
% This function contains the cloudfor-loop, which will be used to distribute
% computations to the Techila environment.
%
% This code will create a Project, which will have 4 Jobs. Each Job will
% start by generating a random number locally. The 'cloudop' function will
% then be used to find the minimum value from these local variables.
% To create the Project, use command:
%
% result=run_cloudop()

% Copyright 2015 Techila Technologies Ltd.

result=zeros(1,4);
cloudfor x=1:4
%cloudfor('stepsperjob',1)
%%peach('ProjectParameters',{{'techila_worker_group','IC Group 1'}})
if isdeployed
    inputdata=rand(1); % Generate a locally defined random number
    result(x)=cloudop(@min, inputdata) % Search and return the smallest number using 'min'.
    waitForOthers() % Wait until all Jobs have reached this point before continuing
end
cloudend
disp(result) % Display the result
end

The Job is started by generating one random number, which is stored in the inputdata variable. This is a local workspace variable and the value will be different in each Job.

After generating the random number, the cloudop function will be used to find the smallest value from the local inputdata variables by using the min function. The cloudop function syntax only specifies two input arguments, meaning the result of the operation will be broadcasted to all Jobs.

6.4.2. Running the example

This example can be can be executed by changing your current working directory in MATLAB to the directory containing the material for this example and executing the command shown below:

result = run_cloudop()

Executing the command will create a Project consisting of four (4) Jobs. Each Job will start by generating a local random number. The cloudop-function will then be used to search the smallest numeric value from the local 'inputdata' variables. The smallest value will be returned in each Job, and stored in the 'result' array, which will be returned to the End-User’s computer.

7. Troubleshooting

This chapter contains a troubleshooting section, which contains information on some of the most frequently encountered error messages. For more troubleshooting tips, please see Introduction to Techila Distributed Computing Engine.

Problem: Compilation fails with error: error: Error using localCompile Error in compiling cloudfor_getindex: errormessage=bad allocation , errorcode=1.

Solution: Add the line shown below to techila_settings.ini file. The techila_settings.ini file is typically located in the techila directory of the Techila SDK. After adding the line, please run the code again.

conf.matlab.peach.mccstandalone=false

Problem: Unable to compile/select compiler on 64bit Matlab (Windows)

Solution: Install Microsoft Visual Studio or another supported compiler. More information can be found on the Mathworks website: http://www.mathworks.com/support/compilers/

Problem: Project fails and Techila Workers generate an error message resembling the one shown here: Failed to create a directory required to extract the CTF file.

Solution: The path of some of the files included in the compilation is too long, causing the extraction process to fail on the Techila Worker. To solve this problem, copy the files to a location with a shorter path or use for example the "subst" command to substitute the path.

8. Appendix

8.1. Appendix 1: Examples of Cloudfor control parameter definitions

This Chapter contains a collection of examples on how to define additional parameters for the cloudfor function.

General syntax Example Explanation

%cloudfor('stepsperjob',<integer>)

%cloudfor('stepsperjob',2) Executes two iterations in each Job

%cloudfor('estimate',<numeric>)

%cloudfor('estimate',10) Sets the number of iterations performed in each Job so that the execution time will be 10 seconds. For example, if the execution time of 1 iteration is 0.5 seconds, each Job would execute 20 iterations.

%cloudfor('inputparam',<comma separated variables>)

%cloudfor('inputparam',in1,in2) Only Workspace variables 'in1' and 'in2' are transferred to Techila Workers.

%cloudfor('outputparam',<comma separated values>)

%cloudfor('outputparam',out1,out2) Only Workspace variables 'out1' and 'out2' are returned from Techila Workers.

%cloudfor('sum',<comma separated values>)

%cloudfor('sum',var1,var2) Sum return values 'var1' and 'var2'

%cloudfor('cat',<comma separated values>)

%cloudfor('cat',var1,var2) Concatenate return values 'var1' and 'var2'

%cloudfor('replace',<comma separated values>)

%cloudfor('replace',var1,var2) Replace return values 'var1' and 'var2' with the latest result

%cloudfor('dependency',<comma separated values>)

%cloudfor('dependency',ev_func,ev_func2) Defines that functions 'ev_func' and 'ev_func2' will be required during the Job.

%cloudfor('stream',<true/false>)

%cloudfor('stream','false') Disables streaming. Results returned in one package after all Jobs are completed.

%cloudfor('quiet')

%cloudfor('quiet') Disables messages.

%cloudfor('parameters',<string>)

%cloudfor('parameters','<param1>') Used when performing computations with a precompiled binary. <param1> gets values from the cloudfor loop counter values.

%cloudfor('force:loopcount')

%cloudfor('force:loopcount') Removes the 100,000 Job safety limit in a Project.

%cloudfor('force:largedata')

%cloudfor('force:largedata') Removes the 10 MB Workspace variable limit in a Project.

%cloudfor(callback, <string>)

%cloudfor('callback','disp('Test')') Displays the word 'Test' each time new results have been received.

%cloudfor('resultfilevar',<variable>)

%cloudfor('resultfilevar',filelist) Stores the location of the result files to the 'filelist' variable.

%cloudfor('importdatavar',<variable>)

%cloudfor('importdatavar',out_var) Import the result data from the result files to the 'out_var' variable.

%cloudfor('importdata',delimiter, nheaderlines)

%cloudfor('importdata',',',1) Defines a comma (,) as the column separator and one header line.

%cloudfor('datafile',<variable>/<csv>)

%cloudfor('datafile',file1,file2) Transfer files 'file1' and 'file2' to all participating Techila Workers.

%cloudfor('jobinputfile',<paramx>/<see peach>)

Example 1: %cloudfor('jobinputfile', JobFile={{'file1'},{'file2'}})
Example 2:cloudfor x={'file1','file2'}

%cloudfor('jobinputfile',<param1>)

Example 1: Transfers Job-specific input files for two Jobs. File 'file1' for Job #1 and file 'file2' for Job #2. Files will be renamed to 'JobFile' on Techila Workers.
Example 2: Transfers 'file1' to Job #1 and 'file2' to Job #2. Both files will be renamed to 'jobinputfile1.mat' on the Techila Worker.

%cloudfor('donotinit')

%cloudfor('donotinit') Do not initialize the Techila Distributed Computing Engine environment. Techilainit() needs to be called before cloudfor if this is specified.

%cloudfor('donotuninit')

%cloudfor('donotuninit') Do not uninitialize the Techila Distributed Computing Engine environment. Typically used with the 'donotinit' parameter.

%peach(<peachparam>,<peachvalue>)

Example 1: %peach('AllowPartial', 'true') Example 1. Allow some of the Jobs in the Project to fail.