2010-09-07 19 views
10

我有一個程序,我從教科書中複製,哪些時間在計算與未初始化,初始化的數組和矢量相同的事情時程序執行運行時的差異。在MATLAB中執行定時程序;奇怪的結果

但是,雖然程序運行有點像預期的那樣,如果每隔一段時間運行幾次,它會發出一個瘋狂的結果。請參閱下面的程序和瘋狂結果的例子。

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在哪裏「查找」這個數字?

+0

可能是當存儲在toc中的時鐘值翻轉時? – gary 2010-09-07 03:29:44

+0

您使用的是什麼MATLAB版本? – gnovice 2010-09-07 03:36:29

+0

@gnovice - 7.10.0.499(2010a) – Rook 2010-09-07 03:38:20

回答

1

至少有兩個可能的錯誤來源。你可以嘗試通過僅僅查看計算值而不用格式化來區分'tic/toc'和'fprintf'。

我不明白'toc'的大括號,但他們不應該有任何傷害。

+0

是的,averageX確實得到了很大的價值。所以,這個問題不在fprintf函數中。大括號只是我自己嘗試過的東西,之後我忘了刪除它們。他們沒有傷害。 – Rook 2010-09-07 12:22:24

+0

如果增加迭代次數(maxcount),會發生什麼情況。你在做什麼平臺? – zellus 2010-09-07 14:58:31

+0

@Rook:你也可以看看下面的文章。然後結尾的帖子以及評論都很有趣。 http://undocumentedmatlab.com/blog/tic-toc-undocumented-option/ – zellus 2010-09-07 15:35:12

3

這確實很瘋狂。不知道是什麼原因造成的,並且無法在我自己的Matlab R2010a上覆制幾次運行,按名稱或通過F5調用。

這是一個調試它的想法。

在腳本或函數中使用tic/toc時,使用捕獲輸出的「tstart = tic」表單。這可以安全地使用嵌套的tic/toc調用(例如,在內部調用函數),並讓您保持多個開始時間和耗用時間,並以編程方式檢查它們。

t0 = tic; 
% ... do some work ... 
te = toc(t0); % "te" for "time elapsed" 

您可以使用不同的「t0_label」後綴爲每個TIC和TOC的回報,或將它們存儲在一個矢量,所以你保留它們,直到你的腳本結束。

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/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 

基於MATLAB R2010b中(預發佈),其中有Int64的數學,你可以通過盤車拉坯抽動值的參考是「未來」重現了類似的荒謬TOC結果。看起來像一個int rollover效果,正如gary comtois所建議的那樣。

>> t0 = tic; toc(t0+999999) 
Elapsed time is 6148914691.236258 seconds. 

這表明,如果有在TOC使用定時器有些抖動,可能如果當你定時很短的操作發生時得到側翻。 (我假設toc()在內部做類似於tic()的值來獲得一個值來比較輸入值)。增加迭代次數可以使效果消失,因爲少量時鐘抖動作爲較長時間的一部分不太重要tic/toc時期。也可以解釋爲什麼你在沒有預先分配的測試中看不到這個,這需要更長的時間。


更新:我能夠重現此行爲。我正在研究一些不相關的代碼,發現在一臺我們以前沒有用過的CPU型號的特定臺式機上,Core 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一個錯誤,是與特定的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調用的操作系統功能。設置啓動參數可以解決它。

+0

雖然仍然不確定原因,但似乎增加...呃,如果你可以閱讀我的評論zellus不要在這裏重複。我現在也試試這個。 – Rook 2010-09-07 15:49:05

+0

很好的解釋,幫助我解決我的問題。 – Yasin 2015-04-21 20:29:24

2

這裏是我的什麼可能基於這兩個數據塊,我發現要發生的事情,理論:

  • 有一個功能maxNumCompThreads控制使用MATLAB來執行任務計算的最大線程數。引用文檔:

    默認情況下,MATLAB利用的 計算機上運行它的 多線程功能。

    這導致我認爲腳本的多個副本可能同時運行。

  • This newsgroup thread討論了舊版本MATLAB(R14)中的一個錯誤,「以MATLAB加速帶有全局結構變量的M代碼的方式」,它似乎可以使用函數TIC/TOC。該解決方案有使用無證FEATURE功能禁用加速器:

    feature accel off 
    

把這兩件事情一起,我想知道,如果在工作區中運行腳本的多個版本可以同時重置TIC/TOC函數使用的全局變量並相互擰緊。在將腳本轉換爲Amro功能時,這可能不是問題,因爲這會分離兩個程序運行的工作區(即它們不會同時在主工作區中運行)。

這也可以解釋你得到的數字非常大。正如加里和安德魯指出的那樣,這些數字似乎是由於整數滾動效應(即integer overflow),因此開始時間(來自TIC)大於結束時間(來自TOC)。由於TIC/TOC在內部使用未經簽名的 64位整數作爲時間度量,所以這將導致大數仍然爲正數。考慮以下可能的情況與在同一時間在不同的線程上運行兩個腳本:

  1. 第一個線程調用TIC,初始化的全局變量的開始時間測量(即當前時間)。
  2. 第一個線程然後調用TOC,並且TOC函數可能做出的即時動作是獲取當前時間度量。
  3. 第二個線程調用TIC,將全局開始時間度量重置爲當前時間,這是時間晚於剛剛由第一個線程的TOC函數測量的時間。
  4. 第一個線程的TOC函數訪問全局開始時間度量以獲取它與之前採取的度量之間的差異。這個差異導致負數,除了時間度量是無符號整數。這會導致整數溢出,給出時間差異的巨大正數。

那麼,你會如何避免這個問題呢?將腳本更改爲像Amro這樣的功能可能是最好的選擇,因爲這似乎規避了問題使工作空間變得混亂。另一種變通,你可以嘗試是計算的最大線程數設置爲一個:

maxNumCompThreads(1); 

這應該讓你的腳本的多個副本在主工作區中同時運行。

+0

我考慮過腳本和函數的影響,以及運行命令行上運行的東西時運行保存的m文件時JIT的影響。仍然我無法重現這個問題(我運行與OP相同的MATLAB版本和操作系統)..這可能是一個競爭條件錯誤確實 – Amro 2010-09-07 19:34:45

+0

@Amro:不幸的是,我沒有相同的MATLAB版本作爲OP,所以我不能嘗試重現它。我*可以*說我無法在R2009a中重現它。沒有R2010a,以上是我最好的猜測。 ;) – gnovice 2010-09-07 19:44:34

1

這是一個可測試的假設。 Matlab的tic()/ toc()必須使用一些高分辨率的定時器。在Windows上,因爲它們的返回值看起來像時鐘週期,所以我認爲它們使用的是Win32 QueryPerformanceCounter()調用,或者其他可能會碰到CPU的RDTSC時間戳計數器。這些顯然在一些多處理器系統上有問題,在鏈接文章中提到。也許你的機器就是其中之一,如果Matlab進程由進程調度器從核心轉移到核心,那麼可能會得到不同的結果。

http://msdn.microsoft.com/en-us/library/ms644904(VS.85).aspx

http://www.virtualdub.org/blog/pivot/entry.php?id=106

這將是硬件和操作系統配置相關,這可以解釋爲什麼其他的海報一直無法重現它。

嘗試使用Windows任務管理器將您的Matlab.exe進程的親和力設置爲單個CPU。 (在進程選項卡上,右鍵單擊MATLAB.exe,「設置關聯...」,取消選中除CPU 0以外的所有其他設置)。如果在設置親和性時瘋狂計時消失,看起來像找到原因。

無論如何,解決方法看起來像只是增加maxcount,因此您要計算更長時間的工作,並且顯然在tic()/ toc()中獲得的噪音與測量值相比較小。 (你不希望與CPU親和力混淆; Matlab應該很容易運行。)如果在那裏導致int溢出的問題,其他小的正數也有點可疑。此外,像Matlab這樣的高級語言的高分辨率時序有點問題。定時工作負載降至幾百微秒會使其受到機器狀態下其他瞬態條件的干擾。