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

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

Графический интерфейс Профилировщику не поддержан в MATLAB Online™.

Генерация профиля 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.

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

| | | | |

Похожие темы