我有一个从教科书中复制的程序,当使用未初始化的,初始化的数组和向量计算相同内容时,它将计算程序执行时间的差异。

但是,尽管该程序按预期运行,但如果偶尔运行几次,则会产生令人抓狂的结果。有关程序和疯狂结果的示例,请参见下文。

clear all; clc;

% Purpose:
% This program calculates the time required to calculate the squares of
% all integers from 1 to 10000 in three different ways:
% 1. using a for loop with an uninitialized output array
% 2. Using a for loop with a pre-allocated output array
% 3. Using vectors

% PERFORM CALCULATION WITH AN UNINITIALIZED ARRAY
% (done only once because it is so slow)

maxcount = 1;
tic;
for jj = 1:maxcount
    clear square
    for ii = 1:10000
        square(ii) = ii^2;
    end
end
average1 = (toc)/maxcount;

% PERFORM CALCULATION WITH A PRE-ALLOCATED ARRAY
% (averaged over 10 loops)

maxcount = 10;
tic;
for jj = 1:maxcount
    clear square
    square = zeros(1,10000);
    for ii = 1:10000
        square(ii) = ii^2;
    end
end
average2 = (toc)/maxcount;

% PERFORM CALCULATION WITH VECTORS
% (averaged over 100 executions)

maxcount = 100;
tic;
for jj = 1:maxcount
    clear square
    ii = 1:10000;
    square = ii.^2;
end
average3 = (toc)/maxcount;

% Display results
fprintf('Loop / uninitialized array = %8.6f\n', average1)
fprintf('Loop / initialized array =   %8.6f\n', average2)
fprintf('Vectorized =                 %8.6f\n', average3)

结果-正常:
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在哪里“找到”该数字?

最佳答案

确实是疯了。不知道是什么原因导致的,并且无法在我自己的Matlab R2010a副本上通过名称或通过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

在具有int64数学的Matlab R2010b(预发行版)上,您可以通过将引用tic值设置为“将来”来重现类似的可笑toc结果。就像gary comtois所建议的那样,它看起来像一个int滚动效果。
>> t0 = tic; toc(t0+999999)
Elapsed time is 6148914691.236258 seconds.

这表明,如果在使用toc的计时器中存在一些抖动,则在对非常短的操作进行计时时可能会发生翻转。 (我假设toc()内部执行tic()之类的操作来获取与输入进行比较的值。)增加迭代次数可以消除这种影响,因为随着时间的延长,少量的时钟抖动将变得不那么重要。抽签/抽签期间。还将说明为什么在您的非预分配测试中看不到这一点,这需要花费更长的时间。

更新:我能够重现此行为。我正在处理一些无关的代码,发现在一个以前没有使用过的CPU模型的特定台式机上,Core 2 Q8400 2.66GHz四核,tic给出的结果不准确。看起来像是tic/toc中与系统有关的bug。

在这台特定的计算机上,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中的错误,与特定的CPU模型(或特定于系统配置的其他事物)相关。我已将该错误报告给MathWorks。

这意味着tic/toc可能不会为您提供不准确的结果,即使它不会产生那些疯狂的数字。解决方法是,在此计算机上,改用etime(),并且仅花费较长的时间来补偿etime的较低分辨率。您可以将其包装在自己的tick/tock函数中,该函数使用for i = 1:50000测试来检测tic在当前计算机上何时中断,正常使用tic/toc并警告它们并退回到使用etime()在残破的系统上。

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

10-07 19:07