使用 MATLAB 探查器探查 MEX 函数
您可以使用 MATLAB® 探查器来探查 MATLAB Coder™ 生成的 MEX 函数的执行时间。所生成代码的探查文件显示对应 MATLAB 函数的调用次数和运行每行代码所花费的时间。使用探查器可识别产生耗时最长的生成代码的 MATLAB 代码行。这些信息可以帮助您在开发周期的早期确定和更正性能问题。有关 MATLAB 探查器的详细信息,请参阅 profile
和探查您的代码以改善性能。
MATLAB Online™ 不支持探查器的图形界面。
生成 MEX 探查文件
您可以将 MATLAB 探查器与生成的 MEX 函数结合使用。如果您有调用您的 MATLAB 函数的测试文件,也可以一步生成 MEX 函数并对其进行探查。您可以在命令行上或 MATLAB Coder 中执行这些操作。
要将探查器与生成的 MEX 函数结合使用,请执行以下操作:
通过将配置对象属性
EnableMexProfiling
设置为true
启用 MEX 探查。您也可以将
codegen
与-profile
选项结合使用。MATLAB Coder 中的等效设置是生成步骤中的启用执行探查。
生成 MEX 文件
MyFunction_mex
。运行 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 函数的示例,该函数在一个代码行中将其输入矩阵 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
的差值。
您可以针对大型输入矩阵 A
和 B
测量 MyFunction
的性能,然后进一步对该函数进行优化:
对
MyFunction
启用 MEX 探查并生成 MEX 代码。对两个大型随机矩阵A
和B
运行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;
将打开单独的窗口,显示探查摘要报告。
探查摘要报告显示 MEX 文件及其子文件(为原始 MATLAB 函数生成的代码)的总时间和自用时间。
在函数名称下,点击第一个链接查看为
MyFunction
生成的代码的探查详细信息报告。您可以查看耗时最多的代码行:调用
coder.ceval
的代码行需要很长时间(16.914 秒)。此代码行的执行时间很长,因为coder.ceval
将矩阵A
和B
的表示从行优先布局转换为列优先布局,然后将其传递给外部 C 函数。您可以通过在coder.ceval
中使用附加参量-layout:rowMajor
来避免此转换:sum = coder.ceval('-layout:rowMajor','foo',coder.ref(A),coder.ref(B),length);
使用修改后的
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 秒:
折叠表达式对 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 函数。
另请参阅
profile
| codegen
| coder.MexCodeConfig
| coder.rowMajor
| coder.ceval
| coder.const