Профилируйте MEX-функции при помощи профилировщика MATLAB

Можно профилировать времена выполнения для MEX-функций, сгенерированных MATLAB® Coder™ при помощи профилировщика MATLAB. Профиль для сгенерированного кода показывает количество вызовов и время, проведенное для каждой строки соответствующей функции MATLAB. Используйте Профилировщик, чтобы идентифицировать строки кода MATLAB, которые производят сгенерированный код, которые занимают большую часть времени. Эта информация может помочь вам идентифицировать и исправить проблемы производительности рано в цикле разработки. Для получения дополнительной информации о профилировщике MATLAB смотрите profile и Профиль, чтобы Улучшать Производительность (MATLAB).

Генерация профиля MEX

Можно использовать профилировщика MATLAB со сгенерированной MEX-функцией. Также, если у вас есть тестовый файл, который вызывает вашу функцию MATLAB, можно сгенерировать MEX-функцию и профилировать ее за один шаг. Можно выполнить эти операции в командной строке или в приложении MATLAB Coder.

Использовать Профилировщик со сгенерированной MEX-функцией:

  1. Включите профилирование MEX путем установки свойства объекта настройки EnableMexProfiling на true.

    Также можно использовать codegen с опцией -profile.

    Эквивалентной установкой в приложении MATLAB Coder является Enable execution profiling на шаге Generate.

  2. Сгенерируйте файл MEX MyFunction_mex.

  3. Запустите профилировщика MATLAB и просмотрите Сводный отчет по профилированию, который открывается в отдельном окне.

    profile on;
    MyFunction_mex;
    profile viewer;

    Убедитесь, что вы не изменили или переместили исходный файл MATLAB MyFunction.m. В противном случае Профилировщик не рассматривает MyFunction_mex для профилирования.

Если у вас есть тестовый файл MyFunctionTest.m, который вызывает вашу функцию MATLAB, вы можете:

  • Сгенерируйте MEX-функцию и профилируйте ее за один шаг при помощи codegen с -test и опциями -profile. Если вы включили профилировщика MATLAB прежде, выключите его, прежде чем вы будете использовать эти две опции вместе.

    codegen MyFunction -test MyFunctionTest -profile
  • Профилируйте MEX-функцию путем выбора Enable execution profiling на шаге Verify приложения. Если вы включили профилировщика MATLAB прежде, выключите его, прежде чем вы выполните это действие.

Пример

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

Рассмотрите функцию MATLAB:

function [y] = MyFunction(A,B) %#codegen

% Generated code uses row-major representation of matrices A and B
coder.rowMajor; 
length = size(A,1);

% Summing absolute values of all elements of A and B by traversing over the
% matrices row by row
sum_abs = 0;  
for row = 1:length 
   for col = 1:length  
       sum_abs = sum_abs + abs(A(row,col)) + abs(B(row,col));
   end
end

% Calling external C function 'foo.c' that returns the sum of all elements
% of A and B
sum = 0;
sum = coder.ceval('foo',coder.ref(A),coder.ref(B),length);

% Returning the difference of sum_abs and sum
y = sum_abs - sum;
end

Сгенерированный код для этой функции использует главное строкой представление квадратных матриц A и B. Код сначала вычисляет sum_abs (сумма абсолютных значений всех элементов A и B) путем пересечения по строке матриц строкой. Этот алгоритм оптимизирован для матриц, которые представлены в главном строкой размещении. Код затем использует coder.ceval, чтобы вызвать внешнюю функцию C foo.c:

#include <stdio.h>
#include <stdlib.h>
#include "foo.h"

double foo(double *A, double *B, double length)
{
 int i,j,s;
 double sum = 0;
 s = (int)length;
 
 /*Summing all the elements of A and B*/
 for(i=0;i<s*s;i++)
 {
         sum += A[i] + B[i];
 }
 return(sum);
}

Соответствующий заголовочный файл C foo.h:

#include "rtwtypes.h"

double foo(double *A, double *B, double length);

foo.c возвращает переменную sum, которая является суммой всех элементов A и B. Производительность функционального foo.c независима от того, представлены ли матрицы A и B в главных строкой или главных столбцом размещениях. MyFunction возвращает различие sum_abs и sum.

Можно измерить уровень MyFunction для больших входных матриц A и B, и затем оптимизировать его далее:

  1. Включите профилирование MEX и сгенерируйте код MEX для MyFunction. Запустите MyFunction_mex для двух больших случайных матриц A и B. Просмотрите Сводный отчет по профилированию.

    A = rand(20000);
    B = rand(20000);
    
    codegen MyFunction -args {A,B} foo.c foo.h -profile
    
    profile on; 
    MyFunction_mex(A,B);
    profile viewer;

    Отдельное окно открывает показ Сводного отчета по профилированию.

    Сводный отчет по профилированию показывает общее время и сам время для файла MEX и его дочернего элемента, который является сгенерированным кодом для исходной функции MATLAB.

  2. Под Именем функции щелкните по первой ссылке, чтобы просмотреть Детализированный отчет Профиля для сгенерированного кода для MyFunction. Вы видите строки, где большая часть времени была проведена:

  3. Строка, вызывая coder.ceval занимает большую часть времени (21,152 с). Эта строка имеет самое долгое время выполнения, потому что coder.ceval преобразовывает представление матриц A и B от главного строкой размещения до главного столбцом размещения прежде, чем передать их внешней функции C. Можно избежать этого преобразования при помощи дополнительного аргумента -layout:rowMajor в coder.ceval:

    sum = coder.ceval('-layout:rowMajor','foo',coder.ref(A),coder.ref(B),length);
  4. Сгенерируйте MEX-функцию и профилируйте снова использование измененного MyFunction.

    A = rand(20000);
    B = rand(20000);
    
    codegen MyFunction -args {A,B} foo.c foo.h -profile
    
    profile on; 
    MyFunction_mex(A,B);
    profile viewer;
    Детализированный отчет Профиля для MyFunction показывает, что строка, вызывая coder.ceval теперь занимает только 0,456 с:

Эффект складных выражений на покрытии кода MEX

Когда вы используете coder.const, чтобы свернуть выражения в константы, он вызывает различие в покрытии кода между функцией MATLAB и MEX-функцией. Например, рассмотрите функцию:

function y = MyFunction %#codegen
a = 1;
b = 2; 
c = a + b;
y = 5 + coder.const(c);
end

При профилировании функции MATLAB MyFunction показывает это покрытие кода в Детализированном отчете Профиля:

Однако профилируя MEX-функцию MyFunction_mex показывает различное покрытие кода:

Строки 2, 3, и 4 не выполняются в сгенерированном коде, потому что вы свернули выражение c = a + b в константу для генерации кода.

Этот пример использует пользовательское сворачивание выражения. Генератор кода иногда автоматически сворачивает определенные выражения, чтобы оптимизировать производительность сгенерированного кода. Такая оптимизация также заставляет покрытие MEX-функции отличаться от функции MATLAB.

Смотрите также

| | | | |

Похожие темы