MATLAB中的定时程序执行;奇怪的结果

MATLAB中的定时程序执行;奇怪的结果,matlab,Matlab,我有一个从教科书上复制的程序,当用未初始化、初始化的数组和向量计算同一事物时,它乘以程序执行运行时的差异 然而,尽管程序的运行有点像预期的那样,但如果每隔一段时间运行几次,它将给出一个疯狂的结果。参见下面的程序和疯狂结果示例 结果-正常: Loop / uninitialized array = 0.195286 Loop / initialized array = 0.000339 Vectorized = 0.000079 结果-疯狂: Loop / u

我有一个从教科书上复制的程序,当用未初始化、初始化的数组和向量计算同一事物时,它乘以程序执行运行时的差异

然而,尽管程序的运行有点像预期的那样,但如果每隔一段时间运行几次,它将给出一个疯狂的结果。参见下面的程序和疯狂结果示例

结果-正常:

Loop / uninitialized array = 0.195286
Loop / initialized array =   0.000339
Vectorized =                 0.000079
结果-疯狂:

Loop / uninitialized array = 0.203350
Loop / initialized array =   973258065.680879
Vectorized =                 0.000102
为什么会发生这种情况? (有时疯狂数字是矢量化的,有时是循环初始化的)


MATLAB在哪里“找到”了那个数字?

至少有两个可能的错误源。您是否可以通过只查看计算值而不设置格式来区分“tic/toc”和“fprintf”


我不理解“toc”周围的括号,但它们不应该造成任何伤害。

这真是太疯狂了。我不知道是什么原因导致了这种情况,并且无法在我自己的MatlabR2010A上通过多次运行(通过名称或F5调用)复制副本

这里有一个调试它的想法

在脚本或函数中使用tic/toc时,请使用捕获输出的“tstart=tic”表单。这样可以安全地使用嵌套的tic/toc调用(例如,在调用的函数内部),并允许您保留多个开始时间和经过的时间,并以编程方式检查它们

t0 = tic;
% ... do some work ...
te = toc(t0); % "te" for "time elapsed"
您可以为每个tic和toc返回使用不同的“t0_label”后缀,或者将它们存储在向量中,以便将它们保留到脚本结束

t0_uninit = tic;
% ... do the uninitialized-array test ...
te_uninit = toc(t0_uninit);

t0_prealloc = tic;
% ... test the preallocated array ...
te_prealloc = toc(t0_prealloc);
当脚本找到一个较大的值时,让它进入调试器

if any([te_uninit te_prealloc te_vector] > 5)
    keyboard
end
然后,您可以检查工作区和tic的返回值,这可能会提供一些线索


编辑:您也可以尝试单独测试tic(),看看您的系统时钟是否有问题,或者tic/toc正在调用什么。tic()的返回值看起来像某种本机时间戳。尝试在一行中多次调用它并比较后续的值。如果它倒退,那将是令人惊讶的

function test_tic

t0 = tic;
for i = 1:1000000
    t1 = tic;
    if t1 <= t0
        fprintf('tic went backwards: %s to %s\n', num2str(t0), num2str(t1));
    end
    t0 = t1;
end
这表明,如果toc正在使用的计时器中存在一些抖动,那么当您对非常短的操作计时时,可能会发生翻转。(我假设toc()在内部执行类似于tic()的操作,以获得一个值来比较输入。)增加迭代次数可能会使效果消失,因为少量时钟抖动作为较长的tic/toc周期的一部分将不太重要。还可以解释为什么在非预分配测试中看不到这一点,这需要更长的时间


更新:我能够重现这种行为。我当时正在研究一些不相关的代码,发现在一个我们以前从未使用过的CPU型号的特定桌面上,一个核心2 Q8400 2.66GHz四核,tic给出了不准确的结果。看起来像是tic/toc中的系统相关错误

在这台特殊的机器上,tic/toc会定期报告像您这样的异常高的值

>> for i = 1:50000; t0 = tic; te = toc(t0); if te > 1; fprintf('elapsed: %.9f\n', te); end; end
elapsed: 6934787980.471930500
elapsed: 6934787980.471931500
elapsed: 6934787980.471899000
>> for i = 1:50000; t0 = tic; te = toc(t0); if te > 1; fprintf('elapsed: %.9f\n', te); end; end
>> for i = 1:50000; t0 = tic; te = toc(t0); if te > 1; fprintf('elapsed: %.9f\n', te); end; end
elapsed: 6934787980.471928600
elapsed: 6934787980.471913300
>> 
这已经过去了。在这台机器上,tic/toc会定期报告操作的运行时间,尤其是CPU使用率低的任务

>> t0 = tic; c0 = clock; pause(4); toc(t0); fprintf('Wall    time is %.6f seconds.\n', etime(clock, c0));
Elapsed time is 0.183467 seconds.
Wall    time is 4.000000 seconds.
因此,这看起来像是tic/toc中的一个bug,它与特定的CPU型号(或与系统配置相关的其他东西)有关。我已经向MathWorks报告了这个错误

这意味着tic/toc可能会给你不准确的结果,即使它不会产生那些疯狂的大数字。作为一种解决方法,在这台机器上,改用etime(),并且只花更长的时间来补偿etime较低的分辨率。您可以将其封装在自己的tick/tock函数中,该函数使用for i=1:50000测试来检测当前机器上的tic何时损坏,正常使用tic/toc,并让它们发出警告,然后在损坏的tic系统上使用etime()


更新2012-03-28:我已经在野外看到了一段时间,这很可能是由于与CPU的高分辨率性能计时器和速度缩放以及(在Windows上)QueryPerformanceCounter的交互,如下所述:。这不是tic/toc中的bug,问题在于tic/toc调用的操作系统特性。设置启动参数可以解决这一问题。

以下是我关于可能发生的情况的理论,基于我发现的这两条数据:

  • 有一个函数控制MATLAB用于执行任务的最大计算线程数。引用文件:

    默认情况下,MATLAB使用 的多线程功能 它正在运行的计算机

    这让我想到,也许您的脚本的多个副本正在同时运行

  • 讨论了旧版本MATLAB(R14)中的一个bug,“以MATLAB使用全局结构变量加速M代码的方式”,看起来函数可能会使用这个bug。解决方案是使用未记录的功能禁用加速器:

    feature accel off
    
把这两件事放在一起,我想知道在工作区中运行的脚本的多个版本是否会同时重置函数所使用的全局变量,并将彼此搞糟。在将脚本转换为Amro所做的函数时,这可能不是问题,因为这将分隔两个程序运行的工作区(即,它们不会同时在主工作区中运行)

这也可以解释你得到的巨大数字。正如gary和Andrew所指出的,这些数字似乎是由于整数滚动效应(即an),即开始时间(从TIC)大于结束时间(从TOC)。这将导致一个仍然是正数的巨大数字,因为TIC/TOC在内部使用无符号64位整数作为时间度量。考虑以下两种脚本在不同线程上同时运行的可能场景:

  • 第一个线程调用TIC,将全局变量初始化为星形
    >> t0 = tic; c0 = clock; pause(4); toc(t0); fprintf('Wall    time is %.6f seconds.\n', etime(clock, c0));
    Elapsed time is 0.183467 seconds.
    Wall    time is 4.000000 seconds.
    
    feature accel off
    
    maxNumCompThreads(1);