Optimization Code Generation for Real-Time Applications
Time Limits on Generated Code
Embedded applications might have requirements that limit how long code can run before returning an answer. Such requirements can be problematic, because solvers give no time guarantees for optimization. This topic outlines techniques for estimating how long your embedded code will run before returning a result, and describes changes you can make to your code to shorten the time requirement.
For general advice on writing efficient code for code generation, see MATLAB Code Design Considerations for Code Generation (MATLAB Coder).
Match the Target Environment
To estimate the execution time of generated code before code generation, set your MATLAB® environment to match the target environment as closely as possible.
Check the clock speeds of your target hardware and your computer. Scale your benchmarking results accordingly.
maxNumCompThreadsin MATLAB to 1, because the default LAPACK and BLAS libraries generated by MATLAB Coder™ are single-threaded.
lastN = maxNumCompThreads(1);
After you finish benchmarking, reset the
N = maxNumCompThreads(lastN); % Alternatively, % N = maxNumCompThreads('automatic');
If your target hardware has multiple cores and you use custom multithreaded LAPACK and BLAS libraries, then set
maxNumCompThreadsto the number of threads on the target hardware. See Speed Up Linear Algebra in Generated Standalone Code by Using LAPACK Calls (MATLAB Coder).
If you have an Embedded Coder® license, see these topics for details on reliable ways to evaluate the resulting performance of your embedded code: Speed Up Linear Algebra in Code Generated from a MATLAB Function Block (Embedded Coder), Speed Up Matrix Operations in Code Generated from a MATLAB Function Block (Embedded Coder), Verification (Embedded Coder), and Performance (Embedded Coder).
Set Coder Configuration
To set the configuration for code generation, call
cfg = coder.config('mex');
To save time in the generated code, turn off integrity checks and checks for integer saturation. Solvers do not rely on these checks to function properly, assuming that the objective function and nonlinear constraint function do not require them. For details, see Control Run-Time Checks (MATLAB Coder).
cfg.IntegrityChecks = false; cfg.SaturateOnIntegerOverflow = false;
Typically, generated code runs faster when using static memory allocation, although this allocation can increase the amount of generated code. Also, some hardware does not support dynamic memory allocation. To use static memory allocation, specify this setting.
cfg.DynamicMemoryAllocation = 'Off';
You can improve the performance of your code by selecting different types of BLAS, the underlying linear algebra subprograms. To learn how to set the BLAS for your generated code, see Speed Up Matrix Operations in Generated Standalone Code by Using BLAS Calls (MATLAB Coder). If you want the embedded application to run in parallel, you must supply BLAS or LAPACK libraries that support parallel computation on your system. Similarly, when you have parallel hardware, you can improve the performance of your code by setting custom LAPACK calls. See Speed Up Linear Algebra in Generated Standalone Code by Using LAPACK Calls (MATLAB Coder).
Benchmark the Solver
Run your MEX generated code in a loop of 1000 evaluations using a set of input parameters that is typical of your application. Find both the total time and the maximum of the evaluation times. Try the parameters that you think might cause the solver to take too long, and test them and other parameters. If the MEX application returns satisfactory results in reasonable time frames, then you can expect that the deployed application will do the same.
Set Initial Point
One of the most important factors affecting both runtime and solution quality is
the initial point for the optimization
x0. When parameters change
slowly between solver calls, the solution from the previous call is typically a good
starting point for the next call. See Follow Equation Solution as a Parameter Changes, which also
shows how a jump in the solution time can occur because the solution switches Basins of Attraction.
If your optimization problem does not have parameters changing slowly, and includes only a few control variables, then trying to estimate a response from previous solutions can be worthwhile. Construct a model of the solution as a function of the parameters, either as a quadratic in the parameters or as a low-dimensional interpolation, and use the predicted solution point as a starting point for the solver.
Set Options Appropriately
You can sometimes speed a solution by adjusting parameters. If you set the
MaxIterations option to allow only a few iterations, then the
solver stops quickly. For example, if the solver is
enter this code.
opts = optimoptions('fmincon','Algorithm','sqp','MaxIterations',50); [x,fval,exitflag] = fmincon(fun,x0,A,b,Aeq,beq,lb,ub,nonlcon,options)
However, the result can be far from an optimum. Ensure that an inaccurate result
does not overly affect your system. Set
MaxIterations as large as
possible while still meeting your time constraint. You can estimate this value by
measuring how long an iteration takes, or by measuring how long a function
evaluation takes, and then either setting the
MaxFunctionEvaluations option or the
MaxIterations option. For an example, see Code Generation for Optimization Basics.
For further suggestions on settings that can speed the solver, see Solver Takes Too Long. Note that some suggestions in this topic do not apply because of limitations in code generation. See Code Generation in fmincon Background or Code Generation for quadprog Background.
You might want a global minimum, not just a local minimum, as a solution. Searching for a global minimum can take a great deal of time, and is not guaranteed to work. For suggestions, see Searching for a Smaller Minimum.