Main Content

本页翻译不是最新的。点击此处可查看最新英文版本。

使用 MATLAB 探查器探查 MEX 函数

您可以使用 MATLAB® 探查器来探查 MATLAB Coder™ 生成的 MEX 函数的执行时间。所生成代码的探查文件显示对应 MATLAB 函数的调用次数和运行每行代码所花费的时间。使用探查器可识别产生耗时最长的生成代码的 MATLAB 代码行。这些信息可以帮助您在开发周期的早期确定和更正性能问题。有关 MATLAB 探查器的详细信息,请参阅 profile探查您的代码以改善性能

MATLAB Online™ 不支持探查器的图形界面。

生成 MEX 探查文件

您可以将 MATLAB 探查器与生成的 MEX 函数结合使用。如果您有调用您的 MATLAB 函数的测试文件,也可以一步生成 MEX 函数并对其进行探查。您可以在命令行上或 MATLAB Coder 中执行这些操作。

要将探查器与生成的 MEX 函数结合使用,请执行以下操作:

  1. 通过将配置对象属性 EnableMexProfiling 设置为 true 启用 MEX 探查。

    您也可以将 codegen-profile 选项结合使用。

    MATLAB Coder 中的等效设置是生成步骤中的启用执行探查

  2. 生成 MEX 文件 MyFunction_mex

  3. 运行 MATLAB 探查器,并查看探查摘要报告,该报告将在单独窗口中打开。

    profile on;
    MyFunction_mex;
    profile viewer;

    确保您没有更改或移动原始 MATLAB 文件 MyFunction.m。否则,探查器不会将 MyFunction_mex 视为探查对象。

如果您有调用您的 MATLAB 函数的测试文件 MyFunctionTest.m,您可以:

  • 通过将 codegen-test-profile 选项结合使用,一步生成 MEX 函数并对其进行探查。如果您以前打开过 MATLAB 探查器,请在结合使用这两个选项之前将其关闭。

    codegen MyFunction -test MyFunctionTest -profile
  • 通过在 App 的验证步骤中选择启用执行探查来探查 MEX 函数。如果您以前打开过 MATLAB 探查器,请在执行此操作之前将其关闭。

示例

您使用探查器来识别产生耗时最长的生成代码的函数或 MATLAB 代码行。下面是 MATLAB 函数的示例,该函数在一个代码行中将其输入矩阵 AB 的表示从行优先布局转换为列优先布局。对于大型矩阵,这种转换需要很长的执行时间。通过修改特定代码行来避免这种转换会使函数更加高效。

以 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

为该函数生成的代码使用方阵 AB 的行优先表示。该代码首先通过逐行遍历矩阵来计算 sum_absAB 的所有元素的绝对值之和)。该算法针对以行优先布局方式表示的矩阵进行了优化。然后,代码使用 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,它是 AB 的所有元素的总和。函数 foo.c 的性能与矩阵 AB 以行优先布局还是列优先布局表示无关。MyFunction 返回 sum_abssum 的差值。

您可以针对大型输入矩阵 AB 测量 MyFunction 的性能,然后进一步对该函数进行优化:

  1. MyFunction 启用 MEX 探查并生成 MEX 代码。对两个大型随机矩阵 AB 运行 MyFunction_mex。查看探查摘要报告。

    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 将矩阵 AB 的表示从行优先布局转换为列优先布局,然后将其传递给外部 C 函数。您可以通过在 coder.ceval 中使用附加参数 -layout:rowMajor 来避免此转换:

    sum = coder.ceval('-layout:rowMajor','foo',coder.ref(A),coder.ref(B),length);
  4. 使用修改后的 MyFunction 再次生成 MEX 函数和探查。

    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 函数。

另请参阅

| | | | |

相关主题