Сгенерируйте код для данных переменного размера

Данные переменного размера - это данные, размер которых может измениться во время выполнения. Можно использовать MATLAB® Coder™ для генерации кода C/C + + из кода MATLAB, который использует данные переменного размера. MATLAB поддерживает ограниченные и неограниченные данные переменного размера для генерации кода. Bounded variable-size data имеет фиксированные верхние границы. Эти данные могут быть выделены статически в стеке или динамически в куче. Unbounded variable-size data не имеет фиксированных верхних границ. Эти данные должны быть выделены на куче. По умолчанию для генерации кода MEX и C/C + + включена поддержка данных переменного размера и включено динамическое выделение памяти для массивов переменного размера, размер которых больше или равен конфигурируемому порогу.

Отключите поддержку данных переменного размера

По умолчанию для генерации кода MEX и C/C + + включена поддержка данных переменного размера. Вы изменяете параметры переменных размеров из диалогового окна параметров проекта, командной строки или с помощью диалоговых окон.

Использование приложения MATLAB Coder

  1. Чтобы открыть диалоговое окно Generate, на странице Generate Code щелкните стрелу Generate.

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

  3. На вкладке Memory выберите или очистите Enable variable-sizing.

В командной строке

  1. Создайте объект строения для генерации кода. Для примера, для библиотеки:

    cfg = coder.config('lib');

  2. Установите EnableVariableSizing опция:

    cfg.EnableVariableSizing = false;

  3. Использование -config опция, передайте объект строения в codegen :

    codegen -config cfg foo
    

Управление динамическим выделением памяти

По умолчанию динамическое выделение памяти разрешено для массивов переменного размера, размер которых больше или равен конфигурируемому порогу. Если вы отключаете поддержку данных переменного размера (см. «Отключить поддержку данных переменного размера»), вы также отключаете динамическое выделение памяти. Вы можете изменить настройки динамического выделения памяти из диалогового окна параметров проекта или командной строки.

Использование приложения MATLAB Coder

  1. Чтобы открыть диалоговое окно Generate, на странице Generate Code щелкните стрелу Generate.

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

  3. На вкладке Memory установите Dynamic memory allocation одну из следующих опций:

    НастройкаДействие
    NeverДинамическое выделение памяти отключено. Данные переменного размера выделяются статически в стеке.
    For all variable-sized arraysДинамическое выделение памяти включено для массивов переменного размера. Данные переменного размера распределяются динамически на куче.
    For arrays with max size at or above thresholdДинамическое выделение памяти разрешено для массивов переменного размера, размер которых больше или равен Dynamic memory allocation threshold. Массивы переменного размера, размер которых меньше этого порога, выделяются в стеке.

  4. Если вы задаете Dynamic memory allocation равным For arrays with maximum size at or above threshold, сконфигурируйте Dynamic memory allocation threshold, чтобы настроить выделение памяти.

В командной строке

  1. Создайте объект строения для генерации кода. Для примера, для MEX-функции:

    mexcfg = coder.config('mex');

  2. Установите DynamicMemoryAllocation опция:

    НастройкаДействие
    mexcfg.DynamicMemoryAllocation='Off';
    Динамическое выделение памяти отключено. Данные переменного размера выделяются статически в стеке.
    mexcfg.DynamicMemoryAllocation='AllVariableSizeArrays';
    Динамическое выделение памяти включено для массивов переменного размера. Данные переменного размера распределяются динамически на куче.
    mexcfg.DynamicMemoryAllocation='Threshold';
    Динамическое выделение памяти разрешено для массивов переменного размера, размер которых (в байтах) больше или равен значению, заданному с помощью DynamicMemoryAllocationThreshold параметр. Массивы переменного размера, размер которых меньше этого порога, выделяются в стеке.

  3. Опционально, если вы задаете DynamicMemoryAllocation на 'Threshold', сконфигурируйте DynamicMemoryAllocationThreshold для точной настройки выделения памяти.

  4. Использование -config опция, передайте объект строения в codegen:

    codegen -config mexcfg foo
    

Генерация кода для функций MATLAB с данными переменного размера

Вот базовый рабочий процесс, который сначала генерирует код MEX для проверки сгенерированного кода, а затем генерирует автономный код после того, как вы удовлетворены результатом прототипа.

Чтобы пройти через эти шаги с простым примером, см. «Генерация кода для функции MATLAB, которая расширяет вектор в цикле»

  1. В РЕДАКТОРА MATLAB добавьте директиву компиляции %#codegen в верхней части вашей функции.

    Эта директива:

    • Указывает, что вы намерены сгенерировать код для алгоритма MATLAB

    • Включает проверку в анализаторе кода MATLAB, чтобы обнаружить потенциальные ошибки во время генерации кода

  2. Устраните проблемы, обнаруженные анализатором кода.

    В некоторых случаях анализатор КОДА MATLAB предупреждает вас, когда ваш код присваивает данным фиксированный размер, но позже увеличивает данные, например, путем назначения или конкатенации в цикле. Если эти данные должны варьироваться в размере во время исполнения, можно игнорировать эти предупреждения.

  3. Сгенерируйте MEX-функцию используя codegen для проверки сгенерированного кода. Используйте следующие опции командной строки:

    • -args {coder.typeof...} если у вас есть входы переменного размера

    • -report чтобы сгенерировать отчет генерации кода

    Для примера:

    codegen -report foo -args {coder.typeof(0,[2 4],1)}
    
    Эта команда использует coder.typeof чтобы задать один вход переменного размера для функции foo. Первый аргумент, 0, указывает тип входных данных (double) и сложности (real). Второй аргумент, [2 4], указывает размер, матрица с двумя размерностями. Третий аргумент, 1, указывает, что вход имеет переменный размер. Верхняя граница равна 2 для первой размерности и 4 для второго измерения.

    Примечание

    Во время компиляции, codegen обнаруживает переменные и поля структуры, которые изменяют размер после их определения, и сообщает об этих вхождениях как об ошибках. В сложение, codegen выполняет проверку во время выполнения, чтобы сгенерировать ошибки, когда данные превышают верхние границы.

  4. Исправьте ошибки несоответствия размера:

    ПричинаКак исправитьДля получения дополнительной информации
    Вы пытаетесь изменить размер данных после того, как его размер был заблокирован.Объявите данные переменным размером.См. «Диагностика и исправление ошибок несоответствия размеров».
  5. Исправьте ошибки верхних границ

    ПричинаКак исправитьДля получения дополнительной информации
    MATLAB не может определить или вычислить верхнюю границуЗадайте верхнюю границу.См. Определение верхних границ для массивов переменного размера и диагностика и исправление ошибок несоответствия размеров.
    MATLAB пытается вычислить верхнюю границу для неограниченных данных переменного размера.Если данные не ограничены, включите динамическое выделение памяти. См. Раздел «Управление динамическим выделением памяти»
  6. Сгенерируйте код C/C + + с помощью codegen функция.

Сгенерируйте код для функции MATLAB, которая расширяет вектор в цикле

О функции MATLAB myuniquetol

Этот пример использует функцию myuniquetol. Эта функция возвращается в векторном B версию входа вектора A, где элементы являются уникальными для в пределах допуска tol друг от друга. В векторных B, abs(B(i) - B(j))> tol для всех i и j. Первоначально предположим, что входной вектор A может хранить до 100 элементов.

function B = myuniquetol(A, tol)
A = sort(A);
B = A(1);
k = 1;
for i = 2:length(A)
   if abs(A(k) - A(i)) > tol
      B = [B A(i)];
      k = i;
   end
end

Шаг 1: Добавьте директиву компиляции для генерации кода

Добавьте %#codegen директива компиляции в верхней части функции:

function B = myuniquetol(A, tol) %#codegen
A = sort(A);
B = A(1);
k = 1;
for i = 2:length(A)
   if abs(A(k) - A(i)) > tol
      B = [B A(i)];
      k = i;
   end
end

Шаг 2. Устранение проблем, обнаруженных анализатором кода

Анализатор кода обнаруживает эту переменную B может изменить размер for-цикл. Оно выдает это предупреждение:

The variable 'B' appears to change size on every loop iteration.
Consider preallocating for speed.

В этой функции вы ожидаете векторную B чтобы расширить размер, поскольку он добавляет значения из векторных A. Поэтому можно игнорировать это предупреждение.

Шаг 3: Сгенерируйте код MEX

Это лучшая практика, чтобы сгенерировать код MEX, прежде чем вы генерируете код C/C + +. Генерация кода MEX может идентифицировать проблемы генерации кода, которые труднее обнаружить во время исполнения.

  1. Сгенерируйте MEX-функцию для myuniquetol:

    codegen -report myuniquetol -args {coder.typeof(0,[1 100],1),coder.typeof(0)}

     Что означают эти опции командной строки?

    Генерация кода выполнена успешно. codegen не обнаруживает проблемы. В текущей папке, codegen генерирует MEX-функцию для myuniquetol и предоставляет ссылку на отчет генерации кода.

  2. Щелкните ссылку View report.

  3. В отчете генерации кода выберите вкладку Variables.

    Размер A является 1x:100 потому что вы указали, что A - размер переменной с верхней границей 100. Размер переменной B является 1x:?, что указывает, что это размер переменной без верхних границ.

Шаг 4: Сгенерируйте код С

Сгенерируйте код С для входов переменного размера. По умолчанию, codegen статически выделяет память для данных, размер которых меньше динамического порога выделения памяти в 64 килобайта. Если размер данных больше или равен порогу или не ограничен, codegen динамически выделяет память на куче.

  1. Создайте опцию строения для генерации библиотеки на C:

    cfg=coder.config('lib');
    
  2. Выполните следующую команду:

    codegen -config cfg -report myuniquetol -args {coder.typeof(0,[1 100],1),coder.typeof(0)}

    codegen генерирует статическую библиотеку в расположении по умолчанию, codegen\lib\myuniquetol и предоставляет ссылку на отчет генерации кода.

  3. Щелкните ссылку View report.

  4. В списке сгенерированных файлов нажмите myuniquetol.h.

    Объявление функции:

    extern void myuniquetol(const double A_data[], const int A_size[2], double tol,
      emxArray_real_T *B);

    codegen вычисляет размер A и, поскольку его максимальный размер меньше порога динамического выделения памяти по умолчанию в 64 тыс. байт, выделяет эту память статически. Сгенерированный код содержит:

    • double A_data[]определение A.

    • int A_size[2]: фактический размер входа.

    Генератор кода определяет, что B - размер переменной с неизвестными верхними границами. Он представляет B как emxArray_real_T. MATLAB обеспечивает служебные функции для создания и взаимодействия с emxArrays в вашем сгенерированном коде. Для получения дополнительной информации смотрите Использование массивов C в Сгенерированных Функциональных Интерфейсах.

Шаг 5: Задайте верхнюю границу для вектора Выхода

Вы указали, что вход A - размер переменной с верхней границей 100. Поэтому вы знаете, что выход B не может быть больше 100 элементы.

  • Использовать coder.varsize чтобы указать, что B - размер переменной с верхней границей 100.

    function B = myuniquetol(A, tol) %#codegen
    A = sort(A);
    coder.varsize('B', [1 100], [0 1]);
    B = A(1);
    k = 1;
    for i = 2:length(A)
       if abs(A(k) - A(i)) > tol
          B = [B A(i)];
          k = i;
       end
    end

  • Сгенерируйте код.

    codegen -config cfg -report myuniquetol -args {coder.typeof(0,[1 100],1),coder.typeof(0)}  

    Объявление функции:

    extern void myuniquetol(const double A_data[], const int A_size[2], double tol,
      double B_data[], int B_size[2]);

    Генератор кода статически выделяет память для B. Он хранит размер B в int B_size[2].

Шаг 6: Изменение порога динамического выделения памяти

На этом этапе вы уменьшаете порог динамического выделения памяти и генерируете код для входа, который превышает этот порог. Этот шаг задает, что второе измерение A имеет верхнюю границу 10000.

  1. Измените верхнюю границу B чтобы соответствовать верхней границе A.

    function B = myuniquetol(A, tol) %#codegen
    A = sort(A);
    coder.varsize('B', [1 10000], [0 1]);
    B = A(1);
    k = 1;
    for i = 2:length(A)
       if abs(A(k) - A(i)) > tol
          B = [B A(i)];
          k = i;
       end
    end

  2. Установите динамический порог выделения памяти в 4 килобайта и сгенерируйте код, где вход размер A превышает этот порог.

    cfg.DynamicMemoryAllocationThreshold=4096;
    codegen -config cfg -report myuniquetol -args {coder.typeof(0,[1 10000],1),coder.typeof(0)} 

  3. Просмотрите сгенерированный код в отчете. Потому что максимальный размер A и B теперь превысите динамический порог выделения памяти, codegen выделяет A и B динамически на куче. В сгенерированном коде A и B иметь тип emxArray_real_T.

    extern void myuniquetol(const emxArray_real_T *A, double tol, emxArray_real_T *B);

Похожие темы