数组布局对于集成、可用性和性能非常重要。代码生成器生成默认使用列主布局的代码。然而,许多设备、传感器和库使用行主阵列布局来处理它们的数据。您可以通过生成使用行主布局的代码,将代码直接应用于该数据。数组布局也会影响性能。对于一个特定的数组布局,许多算法可以更有效地执行内存访问。
可以在命令行使用代码生成配置属性指定行主数组布局,或者使用MATLAB®编码器™你也可以为单个函数和类指定行主布局或列主布局。入口点(顶级)函数的输入和输出必须使用相同的数组布局。
考虑这个函数对两个矩阵相加。该算法通过显式的行和列遍历执行加法。
函数[S] = addMatrix (A, B)% # codegenS = 0(大小(A));为行= 1:尺寸(1)为坳= 1:尺寸(2)年代(行,坳)=(行,上校)+ B(行,坳);结束结束
生成C代码addMatrix
通过使用-rowmajor
选择。属性指定输入参数的形式arg游戏
选项并启动代码生成报告。
codegenaddMatrixarg游戏{的(20、10)的(20、10)}配置:自由-launchreport-rowmajor
或者,通过修改RowMajor
参数在代码生成配置对象中。你可以对任何类型的配置对象使用这个参数:自由
,墨西哥人
,dll
,或exe
.
cfg = coder.config (“自由”);cfg。RowMajor = true;codegenaddMatrixarg游戏{的(20、10)的(20、10)}配置cfg-launchreport
代码生成结果如下:
.../*使用row-major生成addMatrix的代码*/ for (row = 0;行< 20;Row ++) {for (col = 0;坳< 10;{S[col + 10 * row] = A[col + 10 * row] + B[col + 10 * row];}}…
控件指定行主布局MATLAB编码器应用:
打开生成对话框。在生成代码页面,点击生成箭头.
点击更多的设置.
在内存选项卡,设置阵列布局:行
.
要验证生成的代码是否使用行主布局,请将生成代码中的数组索引与使用列主布局的代码中的数组索引进行比较。您还可以生成使用n维索引的代码。n维索引可以使数组布局的差异更加明显。有关更多信息,请参见生成使用n维索引的代码.
MATLAB默认以列主布局存储数据。当您调用生成的使用行主布局的MEX函数时,软件会自动将输入数据从列主布局转换为行主布局。从MEX函数返回的输出数据被转换回列主布局。为独立的自由
,dll
,exe
代码生成时,代码生成器假设入口点函数的输入和输出存储在与函数相同的数组布局中。
对于某些算法,行主布局提供了更有效的内存访问。考虑下面的C代码addMatrix
它使用行主布局。生成的代码使用公式对数组进行索引:
[color = # 0000ff] [color = # 0000ff]
因为数组是以行主布局存储的,所以相邻的内存元素由单个列增量分隔。的步幅对于算法等于1。步幅是连续的内存访问之间在内存元素中的距离。更短的步长提供更有效的内存访问。
对数据使用列主布局会导致更长的步长和更低的内存访问效率。要查看这个比较,请生成使用列主布局的代码:
codegenaddMatrixarg游戏{的(20、10)的(20、10)}配置:自由-launchreport
代码生成生成以下C代码:
.../*使用column-major生成addMatrix的代码*/ for (row = 0;行< 20;Row ++) {for (col = 0;坳< 10;{S[row + 20 * col] = A[row + 20 * col] + B[row + 20 * col];}}…
在列主布局中,在生成的代码中,列元素在内存中是连续的。相邻的内存元素由单行增量隔开,并按公式索引:
[row + 20 * col]
但是,该算法遍历内部for循环中的列。因此,column-major C代码在每次连续的内存访问中必须跨越20个元素。
提供最有效内存访问的数组布局取决于算法。对于这个算法,数据的行主布局提供了更有效的内存访问。算法逐行遍历数据。行主存储因此更有效。
可以对n维数组使用行主布局。当数组以行主布局存储时,来自最后一个(最右边)维度或索引的元素在内存中是连续的。在列主布局中,来自第一个维度(最左边)或索引的元素是连续的。
考虑下面的示例函数addMatrix3D
,它接受三维输入。
函数[S] = addMatrix3D (A, B)% # codegenS = 0(大小(A));为i = 1:尺寸(1)为j = 1:尺寸(2)为S(i,j,k) = A(i,j,k) + B(i,j,k);结束结束结束结束
生成使用行主布局的代码:
codegenaddMatrix3Darg游戏{(20、10、5)、人(20、10、5)}配置:自由-launchreport-rowmajor
代码生成器生成以下C代码:
.../* row-major layout */ for (i = 0;我< 20;i++) {for (j = 0;j < 10;J ++) {for (k = 0;k < 5;k + +) {S [(k + 5 * j) + 50 *我]= [(k + 5 * j) + 50 *我]+ B [(k + 5 * j) + 50 *我);}}}…
在行主布局中,相邻的内存元素由最后一个索引的单个增量隔开,k
.内部的for循环在内存中只被一个位置分隔的相邻元素上迭代。比较使用栏主布局生成的代码的差异:
.../* column-major layout */ for (i = 0;我< 20;i++) {for (j = 0;j < 10;J ++) {for (k = 0;k < 5;k + +) {S [(i + 20 * j) + 200 * k] = [(i + 20 * j) + 200 * k) + B [(i + 20 * j) + 200 * k);}}}…
在列主布局中,相邻的元素由第一个索引的一个增量分隔,我
.内部for循环现在在内存中由200个位置分隔的相邻元素上迭代。长步长可能会由于缓存未命中而导致性能下降。
因为算法遍历最后一个索引,k
,在内部for循环中,对于使用列主布局的生成代码,步长要长得多。对于这个算法,数据的行主布局提供了更有效的内存访问。
要调用外部C/ c++函数,需要使用特定的布局存储数据,请使用coder.ceval
与布局
语法。如果不使用此语法,则默认情况下假定外部函数输入和输出使用列主布局。
考虑一个用于使用行主布局的外部C函数myCFunctionRM
.要将此函数集成到代码中,请使用“布局:rowMajor”
或“行”
选择。此选项确保输入和输出数组以行主顺序存储。代码生成器根据需要自动插入数组布局转换。
coder.ceval (“布局:rowMajor”,“myCFunctionRM”, coder.ref coder.ref ())
在使用行主布局的MATLAB函数中,您可以寻求调用一个外部函数,该函数设计用于使用列主布局。在本例中,使用the“布局:columnMajor”
或“上校”
选择。
coder.ceval (“布局:columnMajor”,“myCFunctionCM”, coder.ref coder.ref ())
可以在同一代码中执行行主函数和列主函数调用。考虑到功能myMixedFn1
作为一个例子:
函数[E] = myMixedFn1 (x, y)% # codegen%指定ceval调用的返回参数类型D = 0(大小(x));E = 0(大小(x));%包括使用行主和列主的外部C函数coder.cinclude (“addMatrixRM.h”);coder.updateBuildInfo (“addSourceFiles”,“addMatrixRM.c”);coder.cinclude (“addMatrixCM.h”);coder.updateBuildInfo (“addSourceFiles”,“addMatrixCM.c”);%调用C函数,该函数使用行主顺序coder.ceval (“布局:rowMajor”,“addMatrixRM”,...coder.rref (x) coder.rref (y), coder.wref (D));%调用C函数,使用列主顺序coder.ceval (“布局:columnMajor”,“addMatrixCM”,...coder.rref (x) coder.rref (D), coder.wref (E));结束
外部文件是:
要生成代码,输入:
codegen配置:自由myMixedFn1arg游戏{的(20、10)的(20、10)}-rowmajor-launchreport
codegen
|coder.ceval
|coder.columnMajor
|coder.isColumnMajor
|coder.isRowMajor
|coder.rowMajor