使用MATLAB编译器时,为什么看不到明显的加速?

时间:2020-03-06 14:45:29  来源:igfitidea点击:

我有很多不错的MATLAB代码,它们运行得太慢,用C编写会很痛苦。C语言的MATLAB编译器似乎并没有多大帮助。是否应该进一步加快执行速度?我搞砸了吗?

解决方案

以我的经验,缓慢的MATLAB代码通常是由于不对代码进行矢量化处理(即编写for循环而不是仅对数组进行乘法运算(简单的示例))。

如果要执行文件I / O,请一次读取一份数据。在帮助文件中查找fscanf的矢量化版本。

不要忘记,MATLAB也包括一个探查器!

对于Matlab编译器,我们可能指的是mcc命令,它通过绕过Matlab解释器确实加快了代码的速度。可以显着加快MAtlab代码速度(提高50-200倍)的原因是使用由mex命令编译的实际C代码。

我会回声dwj所说的话:如果MATLAB代码很慢,那可能是因为它没有足够的矢量化。如果我们在对整个数组执行操作时正在执行显式循环,那是罪魁祸首。

这同样适用于所有面向数组的动态语言:Perl数据语言,Numeric Python,MATLAB / Octave等。在已编译的C和FORTRAN编译代码中,甚至在某种程度上都是如此:专门设计的矢量化库通常使用经过仔细手工编码的内部语言循环和SIMD指令(例如MMX,SSE,AltiVec)。

正如其他人指出的那样,缓慢的Matlab代码通常是矢量化不足的结果。

但是,有时即使是完美的矢量化代码也很慢。然后,我们还有其他几种选择:

  • 查看是否可以使用任何库/工具箱。这些通常被编写为非常优化的。
  • 分析代码,找到关键点,然后用纯C语言重写。将C代码(例如DLL)连接到Matlab很容易,并且在文档中进行了介绍。

如果我们正在使用MATLAB编译器(在最新版本的MATLAB上),那么几乎可以肯定根本看不到任何加速。这是因为编译器实际上所做的只是给我们打包代码的一种方式,以便可以将其分发给没有MATLAB的人。它不会将其转换为更快的内容(例如机器代码或者C),而只是将其包装在C中,因此我们可以调用它。

它通过使代码在MATLAB编译器运行时(MCR)上运行来实现此目的,该运行时实质上是仍在解释代码的MATLAB计算内核。由于必须调用MCR导致的损失,我们可能会发现,与仅在MATLAB上运行相比,编译后的代码运行得更慢。

换句话说,我们可能会说,编译器实际上至少没有在传统意义上进行编译。

较早版本的编译器以不同的方式工作,在某些情况下可能会加速。对于Mathwork的看法,请转到

http://www.mathworks.com/support/solutions/data/1-1ARNS.html

mcc根本不会加快代码的速度-它实际上不是编译器。

放弃之前,我们需要运行探查器并弄清楚所有工作都在哪里("工具"->"打开探查器")。同样,明智地使用" tic"和" toc"也可以有所帮助。在知道时间之前,不要优化代码(不要试图猜测)。

请记住,在matlab中:

  • 位级操作真的很慢
  • 文件I / O缓慢
  • 循环通常很慢,但是矢量化很快(如果我们不知道矢量语法,请学习它)
  • 核心运算速度非常快(例如:矩阵乘法,fft)
  • 如果我们认为可以在C / Fortran / etc中更快地执行操作,则可以编写MEX文件
  • 有将matlab转换为C的商业解决方案(google,将" matlab转换为c"),并且它们可以正常工作

首先,我对上述所有有关概要分析和向量化的评论都发表第二个意见。

从历史的角度来看...

较旧的Matlab版本允许用户通过预解析m代码并将其转换为一组matlab库调用来将m个文件转换为mex函数。这些调用具有解释器所做的所有错误检查,但是解释器和/或者联机分析器的旧版本很慢,因此编译m文件有时会有所帮助。通常,当我们遇到循环时它会有所帮助,因为Matlab足够聪明,可以在C语言中内联某些代码。如果我们拥有Matlab的那些版本之一,则可以尝试告诉mex脚本保存.c文件,然后可以确切地看到它的含义。正在做。

在较新的版本中(可能是2006a及更高版本,但我不记得了),Mathworks开始使用即时编译器作为解释器。实际上,此JIT编译器会自动编译所有mex函数,因此显式脱机执行完全没有帮助。从那时起,在每个版本中,他们还付出了很多努力来提高解释器的速度。我相信,较新版本的Matlab甚至不允许我们将m文件自动编译为mex文件,因为它不再有意义。

我们是否尝试过分析代码?我们无需向量化所有代码,只需控制运行时间的函数即可。 MATLAB profiler将为我们提供一些提示,说明代码在哪里花费最多的时间。

我们还应该在MathWorks手册中的"提高性能的提示"部分中阅读许多其他内容。

我们可以将代码移植到"嵌入式Matlab",然后使用Realtime-Workshop将其转换为C。

嵌入式Matlab是Matlab的子集。它不支持单元数组,图形,动态大小的Marices或者某些矩阵寻址模式。移植到嵌入式Matlab可能需要花费大量精力。

Realtime-Workshop是代码生成产品的核心。它吐出通用C语言,或者可以针对一系列嵌入式平台进行优化。我们最感兴趣的也许是xPC-Target,它将通用硬件视为嵌入式目标。

MATLAB编译器会包装m代码,并将其分派到MATLAB运行时。因此,我们在MATLAB中看到的性能应该是我们在编译器中看到的性能。

对于其他答案,向量化代码很有帮助。但是,如今,MATLAB JIT相当不错,许多事情在矢量化方面的表现都差不多。这并不是说矢量化不会带来性能上的好处,这并不是曾经的魔术。真正告诉我们的唯一方法是使用探查器来找出代码在哪里遇到瓶颈。很多时候,我们可以在某些地方进行本地重构以真正提高代码的性能。

我们还可以采用其他两种硬件方法来提高性能。首先,许多线性代数子系统是多线程的。如果我们在多核或者多处理器平台上工作,则可能要确保已根据自己的喜好启用了该功能。其次,我们也许可以使用并行计算工具箱来充分利用多个处理器。最后,如果我们是Simulink用户,则可以使用emlmex将m代码编译为c。这对于定点工作特别有效。

我会投票支持概要分析,然后看一下瓶颈。

如果瓶颈是矩阵数学,那么我们可能不会做得更好……除了一个大难题是数组分配。例如如果有循环:

s = [];
for i = 1:50000
  s(i) = 3;
end

这必须继续调整数组的大小。预先调整数组大小(从零或者NaN开始)并从那里填充它要快得多:

s = zeros(50000,1);
for i = 1:50000
  s(i) = 3;
end

如果瓶颈是很多函数调用的重复执行,那将是一个艰难的过程。

如果瓶颈是MATLAB不能快速完成的工作(某些类型的解析,XML或者类似的工作),那么我将使用Java,因为MATLAB已经在JVM上运行,并且可以很容易地连接到任意JAR文件。我看过与C / C ++的接口,这确实很丑陋。 Microsoft COM可以(仅在Windows上)可以,但是学习Java之后,我认为我永远也不会再这样做了。