Компоновка массива может иметь важное значение для интеграции, удобства использования и производительности. Генератор кода создает код, который по умолчанию использует компоновку «основной столбец». Однако во многих устройствах, датчиках и библиотеках для своих данных используется макет массива с основными строками. Код можно применить непосредственно к этим данным, создав код, использующий макет основной строки. Макет массива также может влиять на производительность. Многие алгоритмы обеспечивают более эффективный доступ к памяти для одной конкретной структуры массива.
Макет основной строки массива можно задать в командной строке, с помощью свойств конфигурации генерации кода или с помощью приложения MATLAB ® Coder™. Можно также задать макет основной строки или макет основной строки для отдельных функций и классов. Входы и выходы функций начального уровня (верхнего уровня) должны иметь одинаковую структуру массива.
Рассмотрим эту функцию для добавления двух матриц. Алгоритм выполняет сложение через явный обход строки и столбца.
function [S] = addMatrix(A,B) %#codegen S = zeros(size(A)); for row = 1:size(A,1) for col = 1:size(A,2) S(row,col) = A(row,col) + B(row,col); end end
Создать код C для addMatrix с помощью -rowmajor вариант. Укажите форму входных параметров с помощью -args и запустите отчет о создании кода.
codegen addMatrix -args {ones(20,10),ones(20,10)} -config:lib -launchreport -rowmajor
Либо настройте код для макета основной строки, изменив RowMajor в объекте конфигурации генерации кода. Этот параметр можно использовать с любым типом объекта конфигурации: lib, mex, dll, или exe.
cfg = coder.config('lib'); cfg.RowMajor = true; codegen addMatrix -args {ones(20,10),ones(20,10)} -config cfg -launchreport
Результатом создания кода является код C:
...
/* generated code for addMatrix using row-major */
for (row = 0; row < 20; row++) {
for (col = 0; col < 10; col++) {
S[col + 10 * row] = A[col + 10 * row] + B[col + 10 * row];
}
}
...Чтобы задать макет основной строки с помощью приложения MATLAB Coder, выполните следующие действия.
Откройте диалоговое окно «Создание». На странице «Создать код» щелкните стрелку «Создать».![]()
Щелкните Дополнительные параметры.
На вкладке «Память» задайте формат массива:
Row-major.
Чтобы убедиться, что созданный код использует макет основной строки, сравните индексацию массива в созданном коде с индексацией массива в коде, использующем макет основной столбец. Можно также создать код, использующий N-мерное индексирование. N-мерная индексация может сделать различия в компоновке массива более очевидными. Дополнительные сведения см. в разделе Создание кода, использующего N-мерное индексирование.
По умолчанию MATLAB сохраняет данные в формате «основной столбец». При вызове сгенерированной функции MEX, использующей макет основной строки, программа автоматически преобразует входные данные из макета основной строки в макет основной строки. Выходные данные, возвращаемые функцией MEX, преобразуются обратно в формат «основной столбец». Для автономного lib, dll, и exe при формировании кода генератор кода предполагает, что входы и выходы функции точки входа сохраняются с той же самой компоновкой массива, что и функция.
Для некоторых алгоритмов компоновка основных строк обеспечивает более эффективный доступ к памяти. Рассмотрим код C, показанный для addMatrix используется макет основной строки. Массивы индексируются сгенерированным кодом по формуле:
[col + 10 * row]
Поскольку массивы хранятся в макете основной строки, соседние элементы памяти разделяются приращениями одного столбца. Длина шага для алгоритма равна единице. Длина шага - это расстояние в элементах памяти между последовательными доступами к памяти. Более короткая длина шага обеспечивает более эффективный доступ к памяти.
Использование макета «основной столбец» для данных приводит к увеличению длины шага и снижению эффективности доступа к памяти. Чтобы увидеть это сравнение, создайте код, использующий макет «основной столбец»:
codegen addMatrix -args {ones(20,10),ones(20,10)} -config:lib -launchreport
При создании кода создается код C:
...
/* generated code for addMatrix using column-major */
for (row = 0; row < 20; row++) {
for (col = 0; col < 10; col++) {
S[row + 20 * col] = A[row + 20 * col] + B[row + 20 * col];
}
}
...В макете «основной столбец» элементы столбца являются смежными в памяти в сгенерированном коде. Соседние элементы памяти разделены приращениями одной строки и индексируются по формуле:
[row + 20 * col]
Однако алгоритм выполняет итерацию по столбцам во внутреннем for-цикле. Поэтому основной C-код столбца должен выполнять шаг из 20 элементов для каждого последовательного доступа к памяти.
Компоновка массива, обеспечивающая наиболее эффективный доступ к памяти, зависит от алгоритма. Для этого алгоритма компоновка основных строк данных обеспечивает более эффективный доступ к памяти. Алгоритм проходит по строке данных за строкой. Таким образом, хранение основных строк является более эффективным.
Для N-мерных массивов можно использовать макет основной строки. Когда массив хранится в макете основной строки, элементы последнего (крайнего правого) измерения или индекса являются смежными в памяти. В компоновке «основной столбец» элементы из первого (крайнего слева) измерения или индекса являются смежными.
Рассмотрим функцию-пример addMatrix3D, которая принимает трехмерные входные данные.
function [S] = addMatrix3D(A,B) %#codegen S = zeros(size(A)); for i = 1:size(A,1) for j = 1:size(A,2) for k = 1:size(A,3) S(i,j,k) = A(i,j,k) + B(i,j,k); end end end end
Создать код, использующий макет основной строки:
codegen addMatrix3D -args {ones(20,10,5),ones(20,10,5)} -config:lib -launchreport -rowmajor
Генератор кода создает код C:
...
/* row-major layout */
for (i = 0; i < 20; i++) {
for (j = 0; j < 10; j++) {
for (k = 0; k < 5; k++) {
S[(k + 5 * j) + 50 * i] = A[(k + 5 * j) + 50 * i]
+ B[(k + 5 * j) + 50 * i];
}
}
}
...В макете основной строки смежные элементы памяти разделяются одиночными приращениями последнего индекса, k. Внутренний for-loop выполняет итерацию по смежным элементам, разделенным только одной позицией в памяти. Сравните различия с созданным кодом, использующим формат «основной столбец»:
...
/* column-major layout */
for (i = 0; i < 20; i++) {
for (j = 0; j < 10; j++) {
for (k = 0; k < 5; k++) {
S[(i + 20 * j) + 200 * k] = A[(i + 20 * j) + 200 * k]
+ B[(i + 20 * j) + 200 * k];
}
}
}
...При компоновке «основной столбец» смежные элементы разделяются единичными приращениями первого индекса, i. Внутренний for-loop теперь выполняет итерацию по смежным элементам, разделенным 200 позициями в памяти. Большая длина шага может привести к снижению производительности из-за пропусков кэш-памяти.
Поскольку алгоритм выполняет итерацию по последнему индексу, kво внутреннем for-loop длина шага значительно больше для сгенерированного кода, который использует компоновку «основной столбец». Для этого алгоритма компоновка основных строк данных обеспечивает более эффективный доступ к памяти.
Для вызова внешних функций C/C + +, которые ожидают данных, сохраненных с определенным форматом, используйтеcoder.ceval с layout синтаксис. Если этот синтаксис не используется, предполагается, что входные и выходные данные внешних функций по умолчанию используют компоновку «основной столбец».
Рассмотрим внешнюю функцию C, предназначенную для использования основного макета строки. myCFunctionRM. Чтобы интегрировать эту функцию в код, вызовите функцию с помощью '-layout:rowMajor' или '-row' вариант. Этот параметр гарантирует, что входные и выходные массивы хранятся в основном порядке строк. Генератор кода автоматически вставляет преобразования компоновки массива по мере необходимости.
coder.ceval('-layout:rowMajor','myCFunctionRM',coder.ref(in),coder.ref(out))
В рамках функции MATLAB, использующей макет основной строки, можно попытаться вызвать внешнюю функцию, предназначенную для использования макета основной строки. В этом случае используйте '-layout:columnMajor' или '-col' вариант.
coder.ceval('-layout:columnMajor','myCFunctionCM',coder.ref(in),coder.ref(out))
В одном коде можно выполнять вызовы основных функций строк и столбцов. Рассмотрим функцию myMixedFn1 в качестве примера:
function [E] = myMixedFn1(x,y) %#codegen % specify type of return arguments for ceval calls D = zeros(size(x)); E = 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 row-major order coder.ceval('-layout:rowMajor','addMatrixRM', ... coder.rref(x),coder.rref(y),coder.wref(D)); % call C function that uses column-major order coder.ceval('-layout:columnMajor','addMatrixCM', ... coder.rref(x),coder.rref(D),coder.wref(E)); end
Внешние файлы:
Для создания кода введите:
codegen -config:lib myMixedFn1 -args {ones(20,10),ones(20,10)} -rowmajor -launchreport
codegen | coder.ceval | coder.columnMajor | coder.isColumnMajor | coder.isRowMajor | coder.rowMajor