Code Design for Row-Major Array Layout - MATLAB & Simulink (original) (raw)

Outside of code generation, MATLAB® uses column-major layout by default. Array layout specifications do not affect self-contained MATLAB code. To test the efficiency of your generated code or your MATLAB Function block, create separate versions with row-major layout and column-major layout. Then, compare their performance.

You can design your MATLAB code to avoid potential inefficiencies related to array layout. Inefficiencies can be caused by:

Array layout conversions are necessary when you mix row-major and column-major specifications in the same code or model, or when you use linear indexing on data that is stored in row-major. When you simulate a model or generate code for a model that uses column-major, and that contains a MATLAB Function block that uses row-major, then the software converts input data to row-major and output data back to column-major as needed, and vice versa.

Inefficiencies can be caused by functions or algorithms that are less optimized for a given choice of array layout. If a function or algorithm is more efficient for a different layout, you can enforce that layout by embedding it in another function with acoder.rowMajor or coder.columnMajor call.

Understand Potential Inefficiencies Caused by Array Layout

Consider the code for myMixedFn2, which usescoder.ceval to pass data with row-major and column-major layout:

function [B, C] = myMixedFn2(x,y) %#codegen % specify type of return arguments for ceval calls A = zeros(size(x)); B = zeros(size(x)); C = zeros(size(x));

% include external C functions that use row-major & column-major coder.cinclude('addMatrixRM.h'); coder.updateBuildInfo('addSourceFiles', 'addMatrixRM.c'); coder.cinclude('addMatrixCM.h'); coder.updateBuildInfo('addSourceFiles', 'addMatrixCM.c');

% call C function that uses column-major order coder.ceval('-layout:columnMajor','addMatrixCM', ... coder.rref(x),coder.rref(y),coder.wref(A));

% compute B for i = 1:numel(A) B(i) = A(i) + 7; end

% call C function that uses row-major order coder.ceval('-layout:rowMajor','addMatrixRM', ... coder.rref(y),coder.rref(B),coder.wref(C)); end

The external files are:

addMatrixRM.h

extern void addMatrixRM(const double x[200], const double y[200], double z[200]);

addMatrixRM.c

#include "addMatrixRM.h"

void addMatrixRM(const double x[200], const double y[200], double z[200]) { int row; int col;

/* add two matrices / for (row = 0; row < 20; row++) { / row by row / for (col = 0; col < 10; col++) { / each element in current row */ z[col + 10 * row] = x[col + 10 * row] + y[col + 10 * row]; } } }

addMatrixCM.h

extern void addMatrixCM(const double x[200], const double y[200], double z[200]);

addMatrixCM.c

#include "addMatrixCM.h"

void addMatrixCM(const double x[200], const double y[200], double z[200]) { int row; int col;

/* add two matrices / for (row = 0; row < 20; row++) { / row by row / for (col = 0; col < 10; col++) { / each element in current row */ z[row + 20 * col] = x[row + 20 * col] + y[row + 20 * col]; } } }

Declare the configuration object, cfg. Generate code that uses row-major layout by using the -rowmajor option.

cfg = coder.config('lib'); cfg.HighlightPotentialRowMajorIssues = true; codegen myMixedFn2 -args {ones(20,10),ones(20,10)} -config cfg -launchreport -rowmajor

Highlighted issues are displayed in the code generation report, on the Code Insights tab, under the Potential row major issues section.

This image shows the code generation report for myMixedFn2. It displays the highlighted issues at the bottom of the report.

Array layout inefficiencies occur here because:

Linear Indexing Uses Column-Major Array Layout

The code generator follows MATLAB column-major semantics for linear indexing. For more information on linear indexing in MATLAB, see Array Indexing.

To use linear indexing on row-major data, the code generator must first recalculate the data representation in column-major layout. This additional processing can slow performance. To improve code efficiency, avoid using linear indexing on row-major data, or use column-major layout for code that uses linear indexing.

For example, consider the function sumShiftedProducts, which accepts a matrix as an input and outputs a scalar value. The function uses linear indexing on the input matrix to sum up the product of each matrix element with an adjacent element. The output value of this operation depends on the order in which the input elements are stored.

function mySum = sumShiftedProducts(A) %#codegen mySum = 0; % create linear vector of A elements B = A(:); % multiply B by B with elements shifted by one, and take sum mySum = sum( B.*circshift(B,1) ); end

For MATLAB Coderâ„¢, to generate code that uses row-major layout, enter:

codegen -config:mex sumShiftedProducts -args {ones(2,3)} -launchreport -rowmajor

For an example input, consider the matrix:

which yields:

If you pass this matrix as input to the generated code, the elements of A are stored in the order:

In contrast, because the vector B is obtained by linear indexing, it is stored in the order:

The code generator must insert a reshaping operation to rearrange the data from row-major layout for A to column-major layout for B. This additional operation reduces the efficiency of the function for row-major layout. The inefficiency increases with the size of the array. Because linear indexing always uses column-major layout, the generated code for sumShiftedProducts produces the same output result whether generated with row-major layout or column-major layout.

In general, functions that compute indices or subscripts also use linear indexing, and produce results corresponding to data stored in column-major layout. These functions include:

See Also

coder.ceval | coder.columnMajor | coder.rowMajor | coder.isRowMajor | coder.isColumnMajor