Сгенерируйте код, который использует размещение массива Row-Major

Размещение массива может быть важным для интегрирования, удобства использования и эффективности. Генератор кода производит код, который по умолчанию использует размещение основного столбца. Однако многие устройства, датчики и библиотеки используют для своих данных размещение массива с основной строкой. Можно применить код непосредственно к этим данным путем генерации кода, который использует размещение основной строки. Размещение массива также может повлиять на эффективность. Многие алгоритмы выполняют доступ к памяти более эффективно для одного определенного размещения массива.

Вы можете задать размещение массива основной строки в командной строке, с свойствами строения генерации кода или с помощью 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

Сгенерируйте код С для 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

Генерация кода приводит к этому коду С:

... 
/* 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:

  1. Откройте диалоговое окно Generate. На странице Generate Code щелкните стрелу Generate.

  2. Нажмите More Settings.

  3. На вкладке Memory установите Array layout: Row-major.

Чтобы убедиться, что ваш сгенерированный код использует размещение основной строки, сравните индексацию массива в вашем сгенерированном коде с индексацией массива в коде, который использует размещение основной столбца. Можно также сгенерировать код, который использует N-мерную индексацию. N-мерная индексация может сделать различия в размещении массива более очевидными. Для получения дополнительной информации смотрите Сгенерировать код, который использует N-размерную индексацию.

По умолчанию MATLAB хранит данные в размещении основного столбца. При вызове сгенерированной MEX-функции, которая использует размещение основной строки, программа автоматически преобразует входные данные из размещения основной строки в размещение основной строки. Выходные данные, возвращенные из MEX-функции, преобразуются назад в размещение основного столбца. Для автономных lib, dll, и exe Генерация кода генератор кода принимает, что входные параметры функции и выходы точек входа сохранены с того же размещения массива, что и функция.

Размещение массива и алгоритмическая эффективность

Для некоторых алгоритмов размещение основной строки обеспечивает более эффективный доступ к памяти. Рассмотрим код С, показанный для 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-loop. Поэтому основной по столбцу код С должен сделать шаг из 20 элементов для каждого последовательного доступа к памяти.

Размещение массива, который обеспечивает наиболее эффективный доступ к памяти, зависит от алгоритма. Для этого алгоритма основная строка размещения данных обеспечивает более эффективный доступ к памяти. Алгоритм идёт по строке данных за строкой. Поэтому основная система хранения данных является более эффективной.

Основная строка Размещения для N-мерных массивов

Можно использовать основное размещение для 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

Генератор кода производит этот код С:

... 
/* 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

Внешние файлы:

 addMatrixRM.h

 addMatrixRM.c

 addMatrixCM.h

 addMatrixCM.c

Чтобы сгенерировать код, введите:

codegen -config:lib myMixedFn1 -args {ones(20,10),ones(20,10)} -rowmajor -launchreport

См. также

| | | | |

Похожие темы