MATLAB Compiler

Description

The MATLAB Compiler can be used to create a stand-alone executable from a MATLAB application. This executable can then be run on Biowulf or your local machine without utilizing a MATLAB license. Note that you do not need to compile your Matlab code to submit it as a batch job.

The compiler can also be used to incorporate MATLAB-based algorithms into applications built using C/C++, .NET, Java, or Python. See the Mathworks documentation for details. Most MATLAB functions can be compiled, but a few cannot. Check this list to see if your code can be compiled.

IMPORTANT: (November 2021) Biowulf users now have access to unlimited Matlab licenses and all toolboxes
The NIH HPC Staff is pleased to announce a new Matlab license model that provides the following advantages to Biowulf Matlab users: (1) access to all Matlab toolboxes, (2) unlimited number of Matlab licenses, (3) the ability to run batch jobs without using the Matlab compiler, and (4) the ability to submit large numbers of Matlab batch jobs. As before, interactive Matlab jobs are still possible, and are limited to two sinteractive sesssions.

A MATLAB program may produce different results after it has been compiled. Test your application again after compiling to be sure its behavior has not changed. See the articles listed under "Programming Considerations for Compiling MATLAB code" below to learn how to avoid these issues.

Starting with Matlab R2021a (v910) we provide the MCR Runtime in compressed format (e.g., v910.tar.gz) only. We recommend users copy this compressed MCR to local disk (lscratch) and uncompress and use locally.

Web sites

  • Mathworks Compiler documentation
  • Mathworks Compiler SDK documentation
  • Programming Considerations for Compiling MATLAB code


    MATLAB Component Runtime (MCR)
    back to top

    Once MATLAB code has been compiled, it is run using the MATLAB Component Runtime (MCR). There are several versions of the MCR available on the systems. The MCR version must match the version of MATLAB that was used to compile the code. On our systems, the MCR is located in /usr/local/matlab-compiler. Note that you do not need to compile your Matlab code to submit it as a batch job.
    MATLAB to MCR mapping
    MATLAB Version MCR Version
    R2021b v911
    R2021a v910
    R2020b v99
    R2020a v98
    R2019b v97
    R2019a v96
    R2018b v95
    R2018a v94
    R2017b v93
    R2017a v92
    R2016b v91
    R2016a v901
    R2015b v90
    R2015a v85
    R2014b v84
    R2014a v83
    R2013b v82
    R2013a v81
    R2012b v80
    R2012a v717
    R2011b v716
    R2011a v715
    R2010b v714
    R2010a v7.13
    R2009b v711

    Compiling a .m file to produce an executable
    back to top

    Note that you do not need to compile your Matlab code to submit it as a batch job. Compilation involves loading the matlab module and executing one simple command. (user input in bold):

    [user@biowulf ~]$ sinteractive
    [user@cn1234 ~]$ module load matlab/<ver>
    [user@cn1234 ~]$ mcc -m matlab_file.m
    [user@cn1234 ~]$ exit
    

    Note that these and following mcc commands can also be executed directly from within MATLAB.

    >> mcc -m matlab_file.m
    

    Several new files are produced by the compilation process, so it may be best to create a new directory in which to compile the executable. You may cd to that directory and issue the mcc command using the full path and file name of the .m file to be compiled, or you may send the new files to the directory of your choice using the -d argument like so:

    >> mcc -m -d /new/location matlab_file.m
    

    Users who wish to run compiled MATLAB code on Biowulf are strongly encouraged to add the singleCompThread runtime flag to their mcc command to ensure that compiled MATLAB jobs run a single thread per core.

    >> mcc -m -R singleCompThread matlab_file.m
    

    Other options and runtime flags are available. Type help mcc at the MATLAB command prompt to see more. These options identical for mcc.

    Compilation example

    The following demonstrates how to compile a .m file and then call the resulting executable.

    In this example, the user copies the magicsquare.m example file to a new directory in their home space. They then compile it into an executable using mcc. Several files are generated including a binary executable version of magicsquare and a shell script that sets up runtime libraries to make it easier to run the compiled executable (run_magicsquare.sh). Finally, the binary is executed using run_magicsquare.sh with arguments providing the location of the (appropriate) MATLAB MCR and the variable for generating the magic square (first 3, then 5).

    magicsquare.m contains the following code:

    function m = magicsquare(n)
    %MAGICSQUARE generates a magic square matrix of the size specified
    %    by the input parameter n.
    
    % Copyright 2003-2006 The MathWorks, Inc.
    
    if ischar(n)
        n=str2num(n);
    end
    m = magic(n);
    disp(m)
    

    First the user copies the .m file to a new directory in their home space.

    [user@cn1234 ~]$ mkdir ~/matlab_compiler_test
    [user@cn1234 ~]$ cd ~/matlab_compiler_test
    [user@cn1234 ~/matlab_compiler_test]$ cp /usr/local/matlab64/extern/examples/compiler/magicsquare.m ./
    [user@cn1234 ~/matlab_compiler_test]$ ls -l
    -r--r--r-- 1 user group   202 May 13 14:15 magicsquare.m
    

    Then the user executes mcc (here from within the shell) to compile the code.

    [user@cn1234 ~/matlab_compiler_test]$ module load matlab/2018b #or different version with different MCR below
    [user@cn1234 ~/matlab_compiler_test]$ mcc -m -R singleCompThread magicsquare.m 
    
                                                                  < M A T L A B (R) >
                                                        Copyright 1984-2018 The MathWorks, Inc.
                                                         R2018b (9.5.0.944444) 64-bit (glnxa64)
                                                                    August 28, 2018
    
     
    For online documentation, see https://www.mathworks.com/support
    For product information, visit www.mathworks.com.
    
    [user@cn1234 ~/matlab_compiler_test]$ ls -l
    total 108
    -rwxr--r-- 1 user        group 88922 Dec 13 15:32 magicsquare
    -rw-r--r-- 1 user        group   124 Jun 27 14:19 magicsquare.m
    -rw-r--r-- 1 user        group   102 Dec 13 15:32 mccExcludedFiles.log
    -rw-r--r-- 1 user        group  3546 Dec 13 15:32 readme.txt
    -rw-r--r-- 1 user        group     6 Dec 13 15:32 requiredMCRProducts.txt
    -rwxr--r-- 1 user        group   879 Dec 13 15:32 run_magicsquare.sh
    
    

    The two new files magicsquare and run_magicsquare.sh are most important for our purposes. Finally, the user runs the compiled code directly from the shell by entering the path and name of the run_*.sh shell script followed by the full path to the correct MCR for the version of matlab used to compile followed by the variable(s) needed by the compiled MATLAB function.

    [user@cn1234 ~/matlab_compiler_test]$ ./run_magicsquare.sh /usr/local/matlab-compiler/v95 3
    ------------------------------------------
    Setting up environment variables
    ---
    LD_LIBRARY_PATH is .:/usr/local/matlab-compiler/v95/runtime/glnxa64:/usr/local/matlab-compiler/v95/bin/glnxa64:/usr/local/matlab-compiler/v95/sys/os/glnxa64:/usr/local/matlab-compiler/v95/sys/opengl/lib/glnxa64
    
    m =
    
         8     1     6
         3     5     7
         4     9     2
    
    [user@cn1234 ~/matlab_compiler_test]$ ./run_magicsquare.sh /usr/local/matlab-compiler/v95 5
    ------------------------------------------
    Setting up environment variables
    ---
    LD_LIBRARY_PATH is .:/usr/local/matlab-compiler/v95/runtime/glnxa64:/usr/local/matlab-compiler/v95/bin/glnxa64:/usr/local/matlab-compiler/v95/sys/os/glnxa64:/usr/local/matlab-compiler/v95/sys/opengl/lib/glnxa64
    
    m =
    
        17    24     1     8    15
        23     5     7    14    16
         4     6    13    20    22
        10    12    19    21     3
        11    18    25     2     9
    
    

    A note on the deprecated command mcc2
    back to top

    The in-house function called mcc2 (originally written to minimize license usage) has been deprecated. Biowulf users now have access to unlimited number of compiler licenses and should use the compiler command mcc. mcc's usage is identical to mcc2.

    [user@cn1234 ~]$ module load matlab
    

    Within an interactive MATLAB session, mcc resides in the compiler toolbox. This function might not be visible to MATLAB if the toolbox cache is out of date. To test this enter:

    >> help mcc
    

    The following error shows that the toolbox cache is out of date and MATLAB does not recognize mcc2.

    mcc not found.
    
    Use the Help browser search field to search the documentation, or
    type "help help" for help command options, such as help for methods.
    

    To correct this error, enter:

    >> rehash toolbox
    

    The previous command should now return a few lines of help for mcc2.

    >> help mcc
    

    The change should persist across MATLAB sessions.

    Compiling a .m file to produce an executable via a MATLAB GUI
    back to top

    Open an sinteractive session on Biowulf and start up MATLAB. It is a good idea to test your MATLAB script before compilation by running it at the prompt.

    Type deploytool to start the Compiler GUI. In the window that appears, select (for the purposes of this example) 'Application Compiler' to get started. Of course, you can select 'Library Compiler' if you want to build a shared library. (See the Mathworks documentation for details.)

    The Application Compiler window will appear on your screen

    Select the plus sign beside 'Add main file' (highlighted in pink at the top) and in the resultant window, select the MATLAB file that you want to compile Add required files in the 'Files required for your application to run' section.

    Click the 'Package' button, which is the green check button at the top right.

    Once your build is complete, follow the instructions above or below on running your compiled code.

    Submitting the compiled executable as a batch job on the Biowulf computational nodes
    back to top

    Note that you do not need to compile your Matlab code to submit it as a batch job. Set up a batch script along the following lines:

    #!/bin/sh
    #SBATCH -J matjob
    
    # This file is my-mat-job.sh.
    # It assumes the code was compiled with MATLAB 2018b
    # see previous example
    cd ~/matlab_compiler_test \
    && ./run_magicsquare.sh /usr/local/matlab-compiler/v95 5
    

    Submit this job with:

    [user@biowulf ~]$ sbatch my-mat-job.sh
    

    The sbatch command has many options available. If you need to allocate more memory, cpus, or time for your job, want to run your job on another partition, or you have other special requirements, check the manual pages with:

    [user@biowulf ~]$ man sbatch
    

    More info can also be found in the Biowulf User Guide under Job Submission.

    Running a swarm of compiled jobs
    back to top

    The in-house swarm program is an easy and powerful way to run many processes in parallel on the cluster, also known as a job array. Note that is is not necessary to compile your matlab code to be able to use swarm.

    When running a job array, it helps to store the MATLAB runtime on the local file system (in /lscratch/$SLURM_JOB_ID) in order to relieve the central file system of the combined load of accessing the Matlab runtime tree from all of your subjobs.

    In the following example, the MATLAB program magicsquare takes 1 parameter as input. Once the program has been compiled either on the command line or using the GUI, a swarm file can be set up along the following lines:

    # This file is my-mat-jobs.swarm.
    # It assumes that the code was compiled with MATLAB 2018b
    tar -C /lscratch/$SLURM_JOB_ID -xf /usr/local/matlab-compiler/v95.tar.gz \
      && cd ~/matlab_compiler_test \
      && ./run_magicsquare.sh /lscratch/$SLURM_JOB_ID/v95 4
    tar -C /lscratch/$SLURM_JOB_ID -xf /usr/local/matlab-compiler/v95.tar.gz \
      && cd ~/matlab_compiler_test \
      && ./run_magicsquare.sh /lscratch/$SLURM_JOB_ID/v95 2
    tar -C /lscratch/$SLURM_JOB_ID -xf /usr/local/matlab-compiler/v95.tar.gz \
      && cd ~/matlab_compiler_test \
      && ./run_magicsquare.sh /lscratch/$SLURM_JOB_ID/v95 8
    tar -C /lscratch/$SLURM_JOB_ID -xf /usr/local/matlab-compiler/v95.tar.gz \
      && cd ~/matlab_compiler_test \
      && ./run_magicsquare.sh /lscratch/$SLURM_JOB_ID/v93 5
    tar -C /lscratch/$SLURM_JOB_ID -xf /usr/local/matlab-compiler/v93.tar.gz \
      && cd ~/matlab_compiler_test \
      && ./run_magicsquare.sh /lscratch/$SLURM_JOB_ID/v95 6
    tar -C /lscratch/$SLURM_JOB_ID -xf /usr/local/matlab-compiler/v95.tar.gz \
      && cd ~/matlab_compiler_test; \
      && ./run_magicsquare.sh /lscratch/$SLURM_JOB_ID/v95 3
    

    This swarm file can be submiited to the Biowulf cluster with:

    [user@biowulf ~]$ swarm --gres lscratch:10 -f my-mat-jobs.swarm
    138158
    

    You typically would not want to write swarm files manually. Instead, you should write code that will generate swarm files for you. That way, if you decide to rerun your analysis with some new parameters or on some new files, it will be trivial to generate a new swarm file even if it contains thousands of commands. Here's some example MATLAB code that will generate the swarm file above.

    % stick all the parameters in an array
    % (Note that they are strings)
    param_list = {'4' '2' '8' '5' '6' '3'};
    
    % make a command on a new line for each parameter
    command_list = [];
    for ii = 1:length(param_list)
        command_list = [command_list ...
            'tar -C /lscratch/$SLURM_JOB_ID -xf /usr/local/matlab-compiler/v95.tar.gz \\ \n'...
            '  && cd ~/matlab_compiler_test \\ \n'...
            '  && ./run_magicsquare.sh '...
            '/lscratch/$SLURM_JOB_ID/v95 '...
            param_list{ii}...
            '\n'];
    end
    
    % write the commands into a swarm file
    file_handle = fopen('my-mat-jobs.swarm','w+');
    fprintf(file_handle,command_list);
    fclose(file_handle);
    

    For more tips and tricks on automating the swarm submission process in MATLAB, see this recorded training session.

    MCR cache location can affect performance
    back to top

    When a user executes compiled MATLAB code, MATLAB creates a hidden cache containing binaries, links, scripts, etc. By default this cache will be located in a user's home directory (i.e. ~/.mcrCache9.0/). Performance of the compiled MATLAB code can be poor if the MCR cache directory is located on a network filesystem and a large number of parallel processes attempt to access it simultaneously.

    To address this issue the cache directory can be made local to each node in a swarm. The location of the directory can be determined by setting the MCR_CACHE_ROOT environmental variable. Local scratch space should be requested for this purpose in the swarm or sbatch command. See using local disk for more information.

    The following command could be incorporated into the wrapper script generated by the matlab compiler:

    export MCR_CACHE_ROOT=/lscratch/$SLURM_JOB_ID
    

    Setting the directory to the value of $SLURM_JOB_ID is important to prevent multiple jobs running on the same nodes from interfering with one another. Otherwise, one job may attempt to read from a file in the cache while another file is overwriting it. This means the variable must be set after a job has initiated and been assigned a job id. (This approach will work with swarm because each subjob in a job array actually has a unique job id.)

    If you don't want to manually edit the run_X.sh script generated by MATLAB upon compilation, another strategy would be to add this command to each line of you swarm file like so.

    export MCR_CACHE_ROOT=/lscratch/$SLURM_JOB_ID; \
      tar -C /lscratch/$SLURM_JOB_ID -xf /usr/local/matlab-compiler/v95.tar.gz \
      && cd ~/matlab_compiler_test \
      && ./run_magicsquare.sh /lscratch/$SLURM_JOB_ID/v95 4
    export MCR_CACHE_ROOT=/lscratch/$SLURM_JOB_ID; \
      tar -C /lscratch/$SLURM_JOB_ID -xf /usr/local/matlab-compiler/v95.tar.gz \
      && cd ~/matlab_compiler_test \
      && ./run_magicsquare.sh /lscratch/$SLURM_JOB_ID/v95 2
    export MCR_CACHE_ROOT=/lscratch/$SLURM_JOB_ID; \
      tar -C /lscratch/$SLURM_JOB_ID -xf /usr/local/matlab-compiler/v95.tar.gz \
      && cd ~/matlab_compiler_test \
      && ./run_magicsquare.sh /lscratch/$SLURM_JOB_ID/v95 8
    export MCR_CACHE_ROOT=/lscratch/$SLURM_JOB_ID; \
      tar -C /lscratch/$SLURM_JOB_ID -xf /usr/local/matlab-compiler/v95.tar.gz \
      && cd ~/matlab_compiler_test \
      && ./run_magicsquare.sh /lscratch/$SLURM_JOB_ID/v95 5
    export MCR_CACHE_ROOT=/lscratch/$SLURM_JOB_ID; \
      tar -C /lscratch/$SLURM_JOB_ID -xf /usr/local/matlab-compiler/v95.tar.gz \
      && cd ~/matlab_compiler_test \
      && ./run_magicsquare.sh /lscratch/$SLURM_JOB_ID/v95 3
    

    Of course, these commands could be added automatically by a script that generates the swarm file as explained above.

    Finally, you must remember to request the lscratch resource in your swarm command. For instance, the following command would allocate 10GB of local disk space for each job to use as the mcr cache and to hold the Matlab runtime. This should be more than enough.

    [user@biowulf ~]$ swarm --gres=lscratch:10 -f my-mat-jobs.swarm
    

    See this thread on MATLAB answers for more information.