使用 MATLAB 探查器探查 MEX 函数
您可以使用 MATLAB® 探查器来探查 MATLAB Coder™ 生成的 MEX 函数的执行时间。所生成代码的探查文件显示对应 MATLAB 函数的调用次数和运行每行代码所花费的时间。使用探查器可识别产生耗时最长的生成代码的 MATLAB 代码行。这些信息可以帮助您在开发周期的早期确定和更正性能问题。有关 MATLAB 探查器的详细信息,请参阅 profile 和探查您的代码以改善性能。
MATLAB Online™ 不支持探查器的图形界面。
生成 MEX 探查文件
您可以在命令行中以交互方式使用生成的 MEX 函数运行 MATLAB 探查器。或者,如果您有调用 MATLAB 函数的测试文件,您可以使用 codegen 命令或 MATLAB Coder 生成 MEX 函数并一步完成探查。
如果探查器正在运行,您必须在生成新探查之前将其关闭。要关闭探查器,请使用以下命令:
profile off;以交互方式运行 MATLAB 探查器
如果您没有编写调用 MATLAB 函数的测试文件,则必须以交互方式运行探查器。要生成适合探查的 MEX 函数,请使用以下方法之一:
在命令行上,创建一个 MEX 代码配置对象。将
EnableMexProfiling属性设置为true。使用codegen命令生成代码并指定配置对象。例如:cfg = coder.config("mex"); cfg.EnableMexProfiling = true; codegen -config cfg MyFunction
在命令行上,使用
codegen命令与-profile选项生成代码。例如:codegen MyFunction -profile
如果您使用 MATLAB Coder,请在工具条的 MATLAB Coder 选项卡中,点击输出类型 > MEX 以指示代码生成器生成 MEX 函数。在工具条上,点击设置以打开“代码生成设置”对话框。在调试窗格中,选中启用执行探查复选框。然后,在工具条上,点击生成代码并编译以生成 MEX 函数。
一旦您生成适合探查的 MEX 函数,请使用以下命令运行 MATLAB 探查器并查看探查摘要报告:
profile on; MyFunction_mex; profile viewer; profile off;
确保您没有更改或移动原始 MATLAB 文件 MyFunction.m。否则,探查器无法为 MyFunction_mex 生成探查。
一步生成并探查 MEX 函数
如果您有调用 MATLAB 函数的测试文件,您可以在命令行上或使用 MATLAB Coder 一步生成 MEX 函数并对其进行探查。使用以下方法之一:
在命令行中,使用带
-test和-profile选型的codegen命令生成 MEX 函数。例如:codegen MyFunction -test MyFunctionTest -profile
在工具条的 MATLAB Coder 选项卡中,点击输出类型 > MEX 以指示代码生成器生成 MEX 函数。在工具条上,点击设置以打开“代码生成设置”对话框。在调试窗格中,选中启用执行探查复选框。在工具条上,点击运行生成的 MEX > 运行文件并选择
MyFunctionTest.m。
MATLAB 在 MEX 生成后打开探查器窗口。
示例
您使用探查器来识别产生耗时最长的生成代码的函数或 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