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

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

Графический интерфейс Профилировщику не поддерживается в 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;

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

    Profile summary exhibiting a table with field Function Name Calls, Total Time in seconds, Self Time in seconds and total time plot. A flame graph is present, representing the table in a bar graph.

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

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

    Table with fields Line Number, Code, Cells, Total time in seconds, Percentage of time and time plot with relevant data entries from example code. Important to point out that the total time for coder.ceval is relatively high.

  3. Линия, вызывая coder.ceval занимает много времени (16,914 с). Эта линия имеет значительное время выполнения потому что 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,653 с:

    Same image as mentioned above, here coder.ceval has a reduced total time of 0.653s.

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

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

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

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

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

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

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

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

| | | | |

Похожие темы