【问题标题】:MATLAB JIT for-loop optimizationMATLAB JIT for 循环优化
【发布时间】:2020-10-19 16:26:32
【问题描述】:

设置 - 从以下测试代码看来,如果迭代次数超过六次,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 次迭代后的振荡:

【问题讨论】:

  • 1) 我认为您测量错误,但我看不到这种效果 2) JIT 取决于代码,您的结果不适用于所有 for 循环。 3)你达到了测量的极限,我在我的机器上多次迭代得到 0us。
  • 4) 如果你是对的,那么答案很可能是专有的......
  • 1) 奇怪的是你得到 0us。不幸的是,我现在只有一台机器要测试。 2)为了规避 tic/toc 的测量限制,我尝试在 for 循环中添加一些虚拟计算并具有相同的输出。 3)我有另一个测试模拟代码,其中嵌套的 for 循环在第二次运行时显示优化(这与 MATLAB JIT 所做的一致)。 4)你说得对,它必须是专有的,MATLAB JIT文档也没有详细说明这一点
  • 是的,你或多或少是对的。我得到不同的结果,但通常在第 5 次或第 6 次迭代之后,代码要快得多。可能是 JIT 的手动启发式阈值
  • 鉴于循环迭代是预先确定的,JIT 不太可能在给定次数的迭代后“决定”做某事。在循环开始之前,已知它将运行 30 次。 JIT 可以在第一次运行之前决定是否有足够的迭代来实际编译。如果将代码放在函数中,那么整个代码将在函数开始之前编译,并且每次循环迭代应该同样快。 [续]

标签: matlab for-loop optimization iteration jit


【解决方案1】:

鉴于循环迭代是预先确定的,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 来计时码,除非它运行很长时间。 timeit 始终是更好的选择:它多次运行代码,因此它可以丢弃存在不相关延迟的运行。

【讨论】:

  • 您对 tic/toc 的使用是正确的。我错误地在 tic 之后包含了 N、a 和 b 的初始化。 tic/toc 对于小的精确时间测量非常不稳定。在您(以及我的)代码上使用 diff(a) 会显示时序抖动。感谢您的详细回答。也请检查我的答案,我发现前 5 次迭代中的高时间延迟问题是因为我使用测试代码作为 man 脚本中的一个部分,并在 MATLAB 中使用“运行部分”选项来执行代码.
【解决方案2】:

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

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-17
    • 1970-01-01
    • 1970-01-01
    • 2022-11-18
    • 1970-01-01
    • 1970-01-01
    • 2019-05-31
    相关资源
    最近更新 更多