MATLAB compiler notes for Solaris at SLAC

last update: 19 Nov 2002

This web page documents the first uses of the Matlab compiler for control systems applications at SLAC. It does not attempt to replace the official compiler documentation from the Mathworks. Rather this document should be viewed as a supplement that distills the minimum required knowledge to compile a simple Matlab function, export it to a target system, and run it on that target. In addition to these simple instructions, this page also documents the various difficulties encountered in this process. These range from incorrect documentation to awkward implementation of the compiler to significant flaws in the implementation of Matlab 6.5 on Solaris.

Motivation

The low level RF (LLRF) system of PEP-II used Matlab scripts in its design stage, and these scripts have been carried over to be used in operational mode. These scripts require the invocation of a Matlab session every time they are called. Operations will benefit in several ways if they can be compiled. The execution speed will be faster, since the user will no longer need to wait for Matlab to launch, and there will be no need to have Matlab run-time licenses on the control system computers to run these scripts. The compiler will have to be purchased, of course, but this compiler can be shared by the entire SLAC community. Since the LLRF runs on a Solaris platform, the compiler of interest, and that tested, is one for a Solaris target.

Compiler installation and user setup

Since the compiler is another in the suite of Matlab products, listed as an Application Development Tool, the installation of the software itself is straightforward.

Environment variables

The user must also set individual environment variables. The Matlab distribution must be added to the path.

    set path=(${path} <MATLAB>/bin)
and the LD_LIBRARY_PATH environment variable must also be set.
    setenv LD_LIBRARY_PATH <MATLAB>/extern/lib/sol2:<MATLAB>/bin/sol2:${LD_LIBRARY_PATH}
where <MATLAB> is the name of the directory in which Matlab is installed. Note that two directories must be added to LD_LIBRARY_PATH. The documentation incorrectly states that only one of these directories is required.

Compiler path

While running the Matlab compiler from within the Matlab desktop, the compiler inherits the Matlab path for use in, among other things, its search for Matlab functions that are called by other functions it is trying to compile. Since the Set Path pull-down menu changes the path for all users, only the system manager can use this feature to change the path. During a Matlab session, one can add a directory to the end of the path with the command

    addpath( 'afs/slac/g/spear/epics/extensions/matlab', '-end' );
This addition lasts for the duration of the session. This command can be automated by creating a startup.m file in the ~/matlab directory and adding this (and other) commands to the file.

While running the compiler from the unix prompt, outside of the Matlab environment, the locations of these functions must be made visible in an alternate way. The Matlab compiler, mcc, searches in several directories for an ascii file mccpath that lists directories to include in the path. One such directory, that Matlab creates, is

    ~/.matlab/R13
This is the directory that contains the preferences (prefdir) for Matlab R13. The correct mccpath in the correct directory can be created from the Matlab desktop by first changing to the preferences directory and then generating the correct mccpath.
    >> cd( prefdir )
    >> mccsavepath

Preparation of Matlab .m files for compilation

The Matlab compiler will not compile all possible Matlab code. Some, but definitely not all, of the main exceptions are detailed in the documentation under the headings

    Introducing the MATLAB Compiler
      Limitations and Restrictions

Beware of Matlab functions bearing objects

Table 1-2 in this section, Unsupported Functions in Stand-Alone Mode, details more than 70 Matlab functions that are not supported by the compiler. However this is far from a complete list. There are two reasons that I have found for this. First, the compiler does not support C++, or any other object-oriented code. The section on compiler limitations explicitly states that the compiler cannot compile

    M-files that use objects
However, Matlab increasingly incorporates objects into many of its functions, and, as advertised, these cannot be compiled.

These functions are not listed in Table 1-2. The user (hopefully more sophisticated in discovering these functions than I) needs to insure that the functions they include in their Matlab code do not use objects. In fairness, it seems that the help pages do refer to objects in many, if not all, of the functions that use objects. One should carefully read the help page for the function of interest to look for such references. Of course, there are references in the help to "objects" that can be compiled. For example, the term "objects" seems to have a different, and in this case benign, meaning in Matlab graphics. Fortunately, I have not run across graphical functions which do not compile because they are object-oriented.

The second reason for encountering Matlab functions which cannot be compiled is that certain Matlab functions have calls to other Matlab functions that are not compilable. And some of these calling functions may have more than one personality. Depending on how the function is called, it may or may not branch to a path that uses the forbidden function.

There is no documentation that lists all of the functions that are either always unable to be compiled, or unable to be compiled depending on their use. I have told the Mathworks that I would consider it valuable to have such documentation, but was told that this would not happen. The only advice I was given about verifying the ability of the Matlab compiler to correctly compile my code was to periodically try to compile my project and look for compiler errors caused by the use of forbidden functions.

Functions and not scripts

The compiler only compiles Matlab functions, and not Matlab scripts. The code that I compiled was composed primarily of scripts, so I needed to make these modifications often. The simplest form of this modification is trivial, of course. One just needs to start the former script with a function declaration

    function myMatlabFunction

One side effect of the use of scripts I encountered was the liberal use of global variables that passed information between the scripts. I chose to replace the global variables with local variables passed between the functions. The hardest part of this procedure was finding all of the global variables that were accessed by these scripts. Once they were found, the required function call was

    function [ out1, out2 ] = myMatlabFunction( in1, in2, in3 )

System calls

System calls made from a Matlab function run under the Matlab shell can behave differently when executed in a stand-alone compiled function. An example that I encountered was a system call that invoked an external program running in the unix shell (caput and caget). These functions return a status value that signals the success or failure of the function call. The output in which the Matlab function is interested, however, is a message that is written to stdout. Executed from within the Matlab shell the stdout is redirected to the second output argument of a shell (unix()) command. The compiled code will not put this string into the second argument. This feature is not documented in the manual, but there is a reference to it on the Mathworks website. I modified the unix commands with a global search/replace to caShell, a function that I had written to incorporate these changes.

After debugging caShell on the development platform, I encountered further problems with this code in the production environment. The permissions in the latter were more restrictive than those of the development platform. System requests on the production machine elicited queries back from the system which the compiled version did not expect and therefore to which the code did not respond. A straightforward alternative method to accomplish the function of the system call solved this problem, but for some unexplained reason it now requires the use of -B sgl compiler flag to compile.

Compiling Matlab functions

The compilation of the code can be accomplished either from within Matlab at its command line or outside of Matlab at the unix prompt. Because Matlab 6.5 on SLAC Solaris is flawed my choice was to run the compiler from the unix prompt. Matlab has its own setup files for compilation that are installed at

    <MATLAB>/bin/mexopts.sh
    <MATLAB>/bin/gccopts.sh
for the native and gcc compilers, respectively. The syntax for invoking the compiler is the same whether it is run from within Matlab or at the unix prompt. There is one difference that I found between mcc used at the Matlab and unix prompts. The help command for mcc is invoked by the command
    mcc -?
In unix under tcsh, the "?" character must be escaped in order for it to be recognized by mcc, so that the correct unix call is
    mcc -\?

I used two simple forms of the compiler. If I had no graphics applications that needed to be referenced during compilation or execution I used the call

    mcc -m secondca caShell
to compile, link, and create a stand-alone executable from the Matlab functions secondca.m and caShell.m. For an application in which I used the Matlab graphics functions, I needed to link against the graphics libraries, so the call to mcc changed to
    mcc -B sgl plot_noise caShell
where the -B option invokes the Matlab generated script sgl, which is located in
    <MATLAB>/toolbox/compiler/bundles
Since a Matlab GUI program also needs the graphics library, the call to compile it is
    mcc -B sgl faultFile plot_COMBS caShell
Compilation and linking of simple programs took between one and two minutes.

Matlab compiler performance

Solaris compiler version

SLAC has set the default Solaris compiler in /usr/local/bin to be

    Sun WorkShop 6 update 1 C 5.2 2000/09/11
This was done for compatibility reasons within the BaBar collaboration. This compiler generates error-free executables, but it also generates an incomplete type warning message for almost all, if not all, of the Matlab variables defined in the header files in the Matlab distribution. For even a small program this means thousands of such messages, making finding any important warning or error message tedious, at best. This problem does not exist for the latest Solaris compiler
    Sun Workshop 6 update 2 C 5.3 2001/05/15
so this is the C compiler to be used with the Matlab compiler. SLAC has this compiler installed. To access it one needs to modify the path appropriately
    set path=(/afs/slac/package/sunworkshop/6u2/SUNWspro/bin ${path})
The unix command
    cc -V
returns the version information of the C compiler that will be used.

Matlab compiler features

In terms of generating executable code the compiler performed very well. In my short test I did not uncover any cases in which a function working from the Matlab prompt did not compile into a working function from the unix prompt. The compiler was useful in finding variables in Matlab functions that had been global in the original code and which I needed to localize in the compiled code. The compiler issued warning messages for variables that were used but not initialized, which pointed to the global variables the function needed but did not have. From these warnings I knew how to change the prototype of the function in question.

I would have liked more warning messages, however. In some cases I had neglected to use the correct function syntax in the calling function, which now needed to pass all of the newly localized variables in the function call. The compiler did not issue warnings in this case and I had to wait for a run-time error to discover these errors. I also encountered one case in which there were no compilation warnings or errors, but an error at runtime when the compiled code tried to access a standard Matlab function (in this case the function was delete). The compiler found the correct code when I recompiled it with the -B sgl option that invokes the graphics library, even though this application used no graphics at all.

Distributing Stand-Alone Applications

Packaging the compiled application for distribution and execution on a target machine is a straightforward process, explained well by the documentation. The target needs to have three pieces for the standard application that uses graphics. It needs the compiled executable, the contents of a bin subdirectory created to handle the graphics features of the executable, and the necessary Matlab libraries. The bin subdirectory contains the files

    FigureMenuBar.fig
    FigureToolBar.fig
    Matlab
These files configure the menu bar and toolbar for the standard Matlab graphics window and are independent of the particular application that is compiled. This bin subdirectory is placed in the target directory of the executable. Executables which do not utilize the graphics capabilities neither produce nor require the files in this subdirectory.

The necessary Matlab libraries for the target are contained in the file

    <MATLAB>/extern/lib/sol2/mglinstaller
This file is a self-extracting archive file which must be copied over to over to the target machine and executed. It prompts for a directory in which to install itself and then extracts the necessary shared object libraries needed by any executable compiled by Matlab. The location of these libraries needs to be made visible to the target user by setting the environment variable
    setenv LD_LIBRARY_PATH <MATLABRuntimeDir>/bin/sol2:${LD_LIBRARY_PATH}

Compiling Functions Which Use Matlab Channel Access

Some of the Matlab functions to be compiled, especially those that communicate with a real-time controls system, use elements of the EPICS toolbox. Matlab Channel Access is an interface, developed by Andrei Terebilo on Win and ported to several other operating systems used at SLAC, that was designed to provide an efficient means of communication between Matlab and Channel Access on EPICS. The functions that are supported at SLAC have been compiled into a shared object library. These functions can then be accessed by any compiled Matlab function with the inclusion of the Matlab Channel Access library in the command line of the Matlab compiler.

Creating the Matlab Channel Access Library

The commands necessary for creating the library are included here both as documentation of this library and as a guide for the creation of other libraries. (Currently these files are located in directories in my unix account, but I expect that if this library is considered to be both useful and stable, these files will be moved to a more appropriate place within the control system.)

The library is created by supplying the appropriate options to the mcc compiler on the command line. The command used is

    mcc -B libMcaMccCmdFile -v > & libMca.log
where libMcaMccCmdFile is a script file that contains the necessary flags and file names needed to create the library. The options line contains
    -t -W lib:libMca -T link:lib -h
These options are documented in the mcc reference manual, and details of their meaning can be found there, but, in brief, the purpose of each is In particular, the -h option is required to eliminate the need to find all of the Matlab functions called by any of the functions to be compiled and explicitly include these "helper" functions in the mcc call.

Following the option line is a list of both all of the .m functions that will be included in the library and the mcamain.mexsol executable. The last line consists of -M -lrt. The C compiler needs to search the library librt.so to resolve the timer_delete symbol used in mcamain.mexsol and -M -lrt passes this information to the C compiler. No explicit paths need be given in this script file for the .m files because the paths are inherited from mccpath, which was set after the directories containing these files were added to the matlabpath from within Matlab. This command produces four files

    libMca.so
    libMca.mlib
    libMca.h
    libMca.exports

Using the Matlab Channel Access Library

In order to use this library, one needs just to call the Matlab compiler with the library on the command line

    mcc -m fourthca libMca.mlib -v
In addition to libMca.mlib, one also needs to have visible in the working directory the files
    libMca.so
    libMca.h

MATLAB 6.5 on SLAC Solaris is flawed

The biggest surprise and the biggest disappointment in the entire experience with this compiler has been the implementation of Matlab 6.5 in the SLAC Solaris environment. Although technically the product works, the response of the interface to any commands issued from the keyboard or mouse is so slow as to make the product unusable. Even the calculational performance, as measured by bench is worse on 6.5 as compared to 6.1. The interface only works at normal speed when the desktop is disabled. The calculational performance improves in this mode, but it is still worse than that of 6.1. I found the performance of 6.5 on Solaris so unacceptable, that I worked outside of it whenever possible. I used another editor, the Matlab editor on NT, and compiled from the unix command line.

My report of this problem to the Mathworks was not the first; they had earlier reports of this behavior from other customers, but have been silent in response to my question asking if they observe it on their own test platforms. (I mainly run Matlab on NT, and there is no such performance problem for 6.5 on that system.) The Mathworks said that it is a problem with the Java interface on Solaris. They say they are working on the problem, but don't know if there will be a fix for this release or if it will be postponed until the next release. They suggest an "unsupported" solution of forcing Matlab to use an earlier version of Java, but when I tried this "solution", Matlab died while attempting to launch its Desktop. The Mathworks has yet to respond as to what causes this failure and what can be done to correct it.

GUI programming in Matlab

Although not part of the compiler installation, one test that I made was to verify that the compiler would work on the GUIs built in Matlab. I used the recommended Matlab development tool, guide, which is launched at the Matlab prompt. (Again, I built this not on 6.5 running on Solaris, but on 6.5 running on NT.) guide creates a Matlab function file (faultFile.m in my case) that contains both the code needed to launch the GUI and a template for the user supplied code that associates the appropriate callback functions with the elements of the GUI. guide also generates a .fig file (faultFile.fig in my case).

The good news is that the compiler and guide worked together flawlessly, at least for my sample program. There was some bad news in that guide seems to be a little buggy on NT. The Property Editor screen did not always refresh and Matlab froze on me a number of times. (I have not pursued these issues with the Mathworks.) My workaround was to save frequently and use the Task Manager to kill Matlab when it froze.

Passing parameters between GUI elements and functions

I followed the guide reference manual in the method I used to pass parameters. guide creates a function that initializes the GUI and a set of template functions that are accessed by the actions of the GUI elements. These functions pass between them a handles object. Matlab recommends making handles a structure with all of the data that needs to be shared between functions. This structure is attached to the handle of the top level figure. The first object of the handles structure is set to be a pointer to the figure handle. Each function then has access to this structure since it is an argument in all of the template functions. The functions can also write to and update this structure using the Matlab guidata function. This method worked well as advertised.

Software tools

The solution that may fix the current problem you are having with the Matlab code you are trying to compile may be documented in this list of significant software changes
James J. Sebek

sebek@slac.stanford.edu