MATLAB JIT for 循环优化

MATLAB JIT for-loop optimization

设置-从下面的测试代码来看,如果迭代次数超过6次,MATLAB JIT似乎优化了for循环。
在第 6 次和第 7 次迭代之后,性能有了巨大的提升。差异在第 7 次迭代后保持振荡(来自输出图)。

疑问 - 我无法理解 MATLAB JIT 如何以及为何在最小迭代次数后进行优化?还有这个最小数量可以更改吗?

测试代码-

clearvars
clc

tic
N = 30;
a = NaN(1,N);
b = NaN(1,N);

for i=1:1:N
a(i)= toc;
end

(a.*1000000)' % time stamps in microseconds
diff(a.*1000000)' % difference in successive time stamps in microseconds
plot(diff(a.*1000000)')

输出 -(显示前 10 个值)

ans =

  154.1000
  196.4000
  223.2000
  249.1000
  553.6000
  760.9000
  762.9000
  763.3000
  763.6000
  764.0000


ans =

   42.3000
   26.8000
   25.9000
  304.5000
  207.3000
    2.0000
    0.4000
    0.3000
    0.4000
    0.3000

输出图-第7次迭代后的振荡:

看来问题出在我如何执行代码。在查询中,代码是一个部分,它是脚本文件的一部分。我运行特定部分只执行测试代码。这就是 JIT 搞砸的地方。

但是,以下场景提供了快速且一致的执行 -

  1. 执行代码是一个单独的脚本文件
  2. 在命令行中执行代码
  3. 通过封装在一个函数中来执行代码

问题中的实际问题已解决,但还有另一个怪癖 - 如果在相同的场景中(在本节中),如果我使用嵌套的 for 循环,则优化从第 2 次迭代开始。所以这部分JIT优化一直没有答案。

鉴于循环迭代是预先确定的,JIT 不太可能在给定的迭代次数后“决定”做某事。在循环开始之前,已知它将 运行 30 次。 JIT 可以在第一个 运行 之前决定它是否足以实际编译的迭代。如果你把你的代码放在一个函数中(或者现在显然也是一个脚本文件,这在旧版本的 MATLAB 中不是这样),那么整个代码将在函数启动之前编译,并且每个循环迭代应该同样快. 运行 代码部分或将代码复制粘贴到命令行,不允许 JIT 执行它的操作。

另请注意,您的计时代码是奇数:在第一次循环迭代中测量的时间包括初始化代码(创建 Nab,以及创建将循环的数组),因此将始终大于其他迭代时间。

尝试使用此代码,它将代码 运行 置于 循环中:

N = 30;
a = NaN(1,N);
for ii=1:N
   tic;
   for jj=1:1e4
      1;
   end
   a(ii) = toc;
end
a

一个典型的 运行 显示此输出:

a =

   1.0e-03 *

  Columns 1 through 11

    0.4317    0.4348    0.4375    0.4327    0.4250    0.4494    0.4355    0.4361    0.4198    0.4180    0.5554

  Columns 12 through 22

    0.6504    0.5350    0.8944    0.5387    0.4208    0.4554    0.4868    0.5484    0.4167    0.4143    0.5975

  Columns 23 through 30

    0.4196    0.4157    0.4157    0.4157    0.4158    0.4157    0.4163    0.4166

如您所见,第一个循环迭代与所有其他循环迭代花费的时间相同。对于某些迭代,时间会增加一点,这是由计算机上同时发生的其他事情引起的。 tic/toc 计算挂钟时间,而不是处理时间。这说明了为什么不应该使用 tic/toc 来计时代码,除非它 运行s 很长一段时间。 timeit 始终是一个更好的选择:它多次 运行s 代码,因此它可以丢弃存在不相关延迟的 运行s。