If you run MATLAB single- or multi-processor jobs routinely, you may have had the experience of denied MATLAB access or having your MATLAB batch jobs killed due to unavailable MATLAB licenses. This can be avoided if you compile your MATLAB application into an executable with the MATLAB mcc compiler. The executable runs without MATLAB or license. A standalone example is available for your peruse. Even if you don’t plan to run the example, the shell scripting commands as well as some batch scripts included in the zip file are handy for SCC batch users.

How to build a standalone executable (on the SCC)

Requisites:

  • The starting, or “main,” program for a standalone must be a MATLAB command function, i.e., a function m-file with no output. It can either be your original main (then, it must be a command function) or you can create a command function wrapper as the new “main” which in turn calls the original main. A wrapper is more appealing as it enables MATLAB applications to be kept completely separate from corresponding standalone operations.
  • All runtime input parameters are always passed to the standalone as strings. Any passed string parameter intended as double in the code must be converted with str2double. Your wrapper will perform data type conversions (if any) and pass them to the original main for further processing.

Compilation:

>> mcc -mv -o myExecR2013a myStandalone.m myApp.m    % . . . 
  • -mv produces a standalone and shows actions taken
  • -o myExecR2013a specifies the executable name. Though not required, “R2013a” indicates MATLAB release used for compilation.
  • myApp.m is an example of your main program. The standalone procedure supports most toolboxes.

    myApp.m

    function s = myApp(n, nprocs)
    % Purpose: runs basic MATLAB commands; companion to a standalone demo
    %       n: size of simple arithmetic sequence; 1+2+3+ . . . +n
    %  nprocs: number of processors; matlabpool('local', nprocs)
    
    % Create a bar chart . . .
    fprintf(1,'\n First, a graphics test . . . . .\n');
    bar(magic(4));  % bar chart
    title('This demonstrates graphics usage.');
    
    % Compute with the Parallel Computing Toolbox
    fprintf(1,'\n Next, test the parallel computing toolbox . . . . .\n');
    fprintf(1,'Parfor will be used to compute the sum of the arithmetic sequence\n');
    fprintf(1,'s = 1 + 2 + 3 + . . . + n = n(n+1)/2\n\n');
    fprintf(1,'Will use maximum number of threads available for the parfor operations.\n');
    % Request thread recsources
    
    warning('off');
    disp(sprintf('\nNumber of threads available : %d\n\n', maxNumCompThreads))
    
    matlabpool('local', nprocs);
    spmd   % invoke spmd paradigm
      fprintf(1,'This is lab %d of %d\n', labindex, numlabs);
    end
    % testing parfor
    s = 0;    % initialize solution
    parfor i=1:n
        s = s + i;       % s = 1 + 2 + 3 + . . . + n
    end
    matlabpool close;  % return thread resources
    fprintf(1,'\n\n Iteration count n = %d\n', n);
    fprintf(1,'\nComputed s = %d   ;  Expected s =  %d \n\n', s, n*(n+1)/2);
    
    end   % end of function

    All supportive user m-files must be included for compilation.

    Consult the Restrictions and Limitations section for unsupported commands and toolboxes.

    If a wrapper is not used, myApp.m must be a command function.

  • myStandalone.m is an optional application-dependent wrapper and is a command function.
    • In this example, myStandalone inherits 2 run time input from myApp.m to preserve the original capability. To run it in MATLAB . . .
      >> myStandalone 2000 4   % parfor i=1:2000 on 4 cores

      Good to verify that myStandalone.m works before compiling. For this purpose only, you need to do this

      >> addpath codes2compile   % your m-files folder

      myStandalone.m

      function myStandalone(n, nprocs)
      function myStandalone(n, nprocs)
      % function myStandalone(n, nprocs)
      % Purpose: this optionally serves as the front m-file to your app
      %          so your app remain unchanged.
      %       n: size of simple arithmetic sequence [1+2+3+ . . . +n]
      %  nprocs: number of processors [ (matlabpool('local', nprocs) ]
      % Standalone Main Program Rules
      % a) It must be a function, and it must not have output
      %    >> myStandalone 2000 4       % command  syntax
      %    >> myStandalone(2000, 4)     % function syntax
      % b) The standalone runs in command syntax only 
      %    scc1$ ./myExecR2013a 2000 4
      % c) All commandline input (if any) are passed as strings
      %    Must be converted to double for used as double
      % In command syntax, both n and nprocs are strings
      if ischar(n) == 1
          disp('n needs conversion')
          n = str2double(n);             % convert string back to double
      end
      if ischar(nprocs) == 1
          disp('nprocs needs conversion')
          nprocs = str2double(nprocs);   % convert string back to double
      end
      
      % My application starts with myApp (can be script or function m-file)
      s = myApp(n, nprocs);
      
      % Handle the output (s) as intended
      disp(['Sum of Arithmetic sequence 1+2+3+...+n = ' num2str(s)])
      
      if isdeployed     % in standalone mode . . .
         exit;
      else
         close all
      end
      
      end   % end of function

  • Check out Research Computing’s Standalone Made Easy compiling tool.
  • For batch processing, mcc runtime flag (e.g., -R -singleCompThread) may be required.
  • Recompiling required whenever changes are made to one or more m-files.

How does the standalone find the MATLAB runtime library

Compiling your code to generate a standalone is only the first of two steps you need to take. The second step is to set the LD_LIBRARY_PATH environment variable to tell the system where to find the MATLAB Compiler Runtime library, or MCR. On the SCC, you can append the shell command files mycsh.txt and mybash.txt to your respective .cshrc and .bashrc shell scripts in your home directory

  • For tcsh shell users:
    scc1% cat mycsh.txt >> ~/.cshrc  <-- appends commands to ~/.cshrc
    scc1% source ~/.cshrc            <-- make shell effective immediately
  • For bash shell users:
    scc1$ cat mybash.txt >> ~/.bashrc <-- appends commands to ~/.bashrc
    scc1$ source ~/.bashrc            <-- make shell effective immediately

This recommended procedure need only be performed once as long as the standalones are compiled with this MATLAB release. On the other hand, the Run Standalone With Script method may be more appropriate if your standalones are compiled with multiple MATLAB releases.

How to run a standalone executable

To run standalone interactively on the SCC

scc1$ ./myExecR2013a 2000 4

To run a standalone batch job on the SCC

The standalone generated above is suitable for interactive applications. For batch processing however, additional runtime flags (-R) may be required. Let's say that you submitted a single-core batch job on the SCC. This job is dispatched to an available node (think of each node as a multicore desktop) at runtime. MATLAB's multithreading utility may decide to take advantage of multicore on your code's behalf (it has no knowledge of your asking for 1 core through the batch scheduler). When that happens, the batch scheduler aborts your job for using more cores than committed. To prevent core over usage, you can compile your application with

>> mcc -mv -o myExecR2013a myStandalone.m myApp.m ...
       -R -singleCompThread -R -nodisplay

The -R -singleCompThread turns off multithreading while -R -nodisplay disables graphics display.

The standalone built with these runtime switches will always run with single thread and will not display graphics — in batch or interactive. For standalone to run in interactive mode, omit -R -nodisplay to enable graphics.

scc1$ qsub -V -t 100 ./run_standalone_job

run_standalone_job

#!/bin/csh
# SGE script for MATLAB standalone (generated with mcc)
# Usage:
# scc1$ qsub -t 100 ./run_standalone_job          # SGE_TASK_ID=100
# scc1$ qsub -t 100-300:200 ./run_standalone_job  # SGE_TASK_ID=[100,300]
#
# Specify SGE batch scheduler options
# Merge output and error files in one
#$ -j y
# Send email to SCC userID when job finished or aborted
#$ -m ae
# Request 4 cores from omp queue (example needs multicores)
# For serial apps, prepend the line below with another #
##$ -pe omp 4

echo "\n\n********************************************"
echo "* This job runs on $HOSTNAME"
echo "********************************************\n\n"

set NODENAME = `echo $HOSTNAME | sed 's/.scc.bu.edu//'`

# Running MATLAB standalone results in creation of a cache folder in home dir
# This may cause runtime issues. Below is a workaround.
echo tmpdir is $TMPDIR
setenv MCR_CACHE_ROOT $TMPDIR
echo "\n\n********************************************"
echo "* Created local scratch folder /net/$NODENAME$TMPDIR"
echo "********************************************\n\n"

unsetenv DISPLAY

# Output to screen go to your ?.o$JOB_ID file

if ($SGE_TASK_ID == 'undefined') then
  echo "SGE_TASK_ID is undefined; use qsub -t to define it"
else
  @ n = $SGE_TASK_ID;
endif

if ($NSLOTS == 'undefined') then
  @ nprocs = 1;         # in absence of -pe . . .
else
  @ nprocs = $NSLOTS;   # -pe omp 4 ==> NSLOTS = 4
endif

# this standalone example expects n (parfor i=1:n) & nprocs (cores)
myExecR2014b $n $nprocs

To run a single batch job, this script uses n=100 with 4 cores to compute the sum of the arithmetic sequence: s = 1 + 2 + 3 + . . . + n

To submit multiple batch jobs with qsub, see Notes.

How to generate and run standalone on other systems

Generally, the above instructions are applicable to other situations; you can generate standalone on one Linux (or Windows, Macs) platform with MATLAB installed and run it on another Linux (or Windows, Macs) machine without an installed MATLAB. On the SCC, since MATLAB — and hence MCR — is available, only a couple of environment variables need to be set to help the executable find the necessary MATLAB library. To run the standalone on a system without MATLAB, an MCR library, freely downloadable from the Mathworks, will be needed.