Generate Reentrant C Code from MATLAB Code - MATLAB & Simulink (original) (raw)
About This Tutorial
Learning Objectives
This tutorial shows you how to:
- Generate reentrant code from MATLAB® code that does not use persistent or global data.
- Automatically generate C code from your MATLAB code.
- Define function input properties at the command line.
- Specify code generation properties.
- Generate a code generation report that you can use to view and debug your MATLAB code.
Note
This example requires libraries that are specific to the Microsoft® Windows® operating system and, therefore, runs only on Windows platforms.
Prerequisites
To complete this example, install the following products:
- MATLAB
- MATLAB Coder™
- C compiler
MATLAB Coder locates and uses a supported installed compiler. For the current list of supported compilers, see Supported and Compatible Compilers on the MathWorks® website.
You can usemex -setup
to change the default compiler. See Change Default Compiler.
Required Files
Type | Name | Description |
---|---|---|
Function code | matrix_exp.m | MATLAB function that computes matrix exponential of the input matrix using Taylor series and returns the computed output. |
C main function | main.c | Calls the reentrant code. |
About the Example
This example is a simple, multithreaded example that does not use persistent or global data. Two threads call the MATLAB function matrix_exp
with different sets of input data.
In your current working folder, create a file matrix_exp.m
that contains this code:
function Y = matrix_exp(X) %#codegen % % The function matrix_exp computes matrix exponential of % the input matrix using Taylor series and returns the % computed output. E = zeros(size(X)); F = eye(size(X)); k = 1; while norm(E+F-E,1) > 0 E = E + F; F = X*F/k; k = k+1; end Y = E;
When you generate reusable, reentrant code, MATLAB Coder supports dynamic allocation of:
- Function variables that are too large for the stack
- Persistent variables
- Global variables
MATLAB Coder generates a header file, _primaryfunctionname_
_types.h
, that you must include when using the generated code. This header file contains the following structures:
_primaryfunctionname_
StackData
Contains the user allocated memory. Pass a pointer to this structure as the first parameter to functions that use it:- Directly (the function uses a field in the structure)
- Indirectly (the function passes the structure to a called function)
If the algorithm uses persistent or global data, the_primaryfunctionname_
StackData
structure also contains a pointer to the_primaryfunctionname_
PersistentData
structure. If you include this pointer, you have to pass only one parameter to each calling function.
_primaryfunctionname_
PersistentData
If your algorithm uses persistent or global variables, MATLAB Coder provides a separate structure for them. The memory allocation structure contains a pointer to this persistent data structure. Because you have a separate structure for persistent and global variables, you can allocate memory for these variables once and share them with all threads. However, if the threads do not communicate, you can allocate memory for these variables per thread.
Providing a C main Function
To call the reentrant code, provide a main
function that:
- Includes the generated header file
matrix_exp.h
. This file includes the generated header file,matrix_exp_types.h
. - For each thread, allocates memory for stack data.
- Calls the
matrix_exp_initialize
housekeeping function. For more information, see Deploy Generated Code. - Calls
matrix_exp
. - Calls
matrix_exp_terminate
. - Frees up the for stack data memory.
In your current working folder, create a file main.c
that contains this code:
#include <stdio.h> #include <stdlib.h> #include <windows.h> #include "matrix_exp.h" #include "matrix_exp_initialize.h" #include "matrix_exp_terminate.h" #include "rtwtypes.h" #define NUMELEMENTS (160*160) typedef struct { real_T in[NUMELEMENTS]; real_T out[NUMELEMENTS]; matrix_expStackData* spillData; } IODATA; /* The thread_function calls the matrix_exp function written in MATLAB */ DWORD WINAPI thread_function(PVOID dummyPtr) { IODATA *myIOData = (IODATA*)dummyPtr; matrix_exp_initialize(); matrix_exp(myIOData->spillData, myIOData->in, myIOData->out); matrix_exp_terminate(); return 0; } void main() { HANDLE thread1, thread2; IODATA data1; IODATA data2; int32_T i; /*Initializing data for passing to the 2 threads*/ matrix_expStackData* sd1 = (matrix_expStackData*)calloc(1,sizeof(matrix_expStackData)); matrix_expStackData* sd2 = (matrix_expStackData*)calloc(1,sizeof(matrix_expStackData)); data1.spillData = sd1; data2.spillData = sd2; for (i=0;i<NUMELEMENTS;i++) { data1.in[i] = 1; data1.out[i] = 0; data2.in[i] = 1.1; data2.out[i] = 0; } /*Initializing the 2 threads and passing data to the thread functions*/ printf("Starting thread 1...\n"); thread1 = CreateThread(NULL , 0, thread_function, (PVOID) &data1, 0, NULL); if (thread1 == NULL){ perror( "Thread 1 creation failed."); exit(EXIT_FAILURE); } printf("Starting thread 2...\n"); thread2 = CreateThread(NULL, 0, thread_function, (PVOID) &data2, 0, NULL); if (thread2 == NULL){ perror( "Thread 2 creation failed."); exit(EXIT_FAILURE); } /*Wait for both the threads to finish execution*/ if (WaitForSingleObject(thread1, INFINITE) != WAIT_OBJECT_0){ perror( "Thread 1 join failed."); exit(EXIT_FAILURE); } if (WaitForSingleObject(thread2, INFINITE) != WAIT_OBJECT_0){ perror( "Thread 2 join failed."); exit(EXIT_FAILURE); } free(sd1); free(sd2); printf("Finished Execution!\n"); exit(EXIT_SUCCESS); } |
---|
Configuring Build Parameters
You can enable generation of reentrant code using a code generation configuration object.
- Create a configuration object.
cfg = coder.config('exe'); - Enable reentrant code generation.
cfg.MultiInstanceCode = true;
Generating the C Code
Call the codegen
function to generate C code, with the following options:
-config
to pass in the code generation configuration objectcfg
.main.c
to include this file in the compilation.-report
to create a code generation report.-args
to specify the class, size, and complexity of input arguments using example data.
codegen -config cfg main.c -report matrix_exp.m -args ones(160,160)
codegen
generates a C executable, matrix_exp.exe
, in the current folder and C code in the /codegen/exe/matrix_exp
subfolder. Because you selected report generation, codegen
provides a link to the report.
Viewing the Generated C Code
codegen
generates a header file matrix_exp_types.h
, which defines the matrix_expStackData
global structure. This structure contains local variables that are too large to fit on the stack.
To view this header file:
- Click the View report link to open the code generation report.
- In the list of generated files, click
matrix_exp_types.h
.
/* * matrix_exp_types.h * * Code generation for function 'matrix_exp' * */ #ifndef __MATRIX_EXP_TYPES_H__ #define __MATRIX_EXP_TYPES_H__ /* Include files */ #include "rtwtypes.h" /* Type Definitions */ #ifndef typedef_matrix_expStackData #define typedef_matrix_expStackData typedef struct { struct { double F[25600]; double Y[25600]; double X[25600]; } f0; } matrix_expStackData; #endif /*typedef_matrix_expStackData*/ #endif /* End of code generation (matrix_exp_types.h) */ |
---|
Running the Code
Verify that the example is running on Windows platforms and call the code.
% This example can only be run on Windows platforms if ~ispc error('This example requires Windows-specific libraries and can only be run on Windows.'); end system('matrix_exp.exe') |
---|
The executable runs and reports completion.
Key Points to Remember
- Create a
main
function that:- Includes the generated header file,
_primaryfunctionname_
_types.h
. This file defines the_primaryfunctionname_StackData
global structure. This structure contains local variables that are too large to fit on the stack. - For each thread, allocates memory for stack data.
- Calls
_primaryfunctionname__initialize
. - Calls
_primaryfunctionname_
. - Calls
_primaryfunctionname__terminate
. - Frees the stack data memory.
- Includes the generated header file,
- Use the
-config
option to pass the code generation configuration object to thecodegen
function. - Use the
-args
option to specify input parameters at the command line. - Use the
-report
option to create a code generation report.