目錄

名稱

Benchmark - Perl 程式碼執行時間基準測試

語法

    use Benchmark qw(:all) ;

    timethis ($count, "code");

    # Use Perl code in strings...
    timethese($count, {
	'Name1' => '...code1...',
	'Name2' => '...code2...',
    });

    # ... or use subroutine references.
    timethese($count, {
	'Name1' => sub { ...code1... },
	'Name2' => sub { ...code2... },
    });

    # cmpthese can be used both ways as well
    cmpthese($count, {
	'Name1' => '...code1...',
	'Name2' => '...code2...',
    });

    cmpthese($count, {
	'Name1' => sub { ...code1... },
	'Name2' => sub { ...code2... },
    });

    # ...or in two stages
    $results = timethese($count,
        {
	    'Name1' => sub { ...code1... },
	    'Name2' => sub { ...code2... },
        },
	'none'
    );
    cmpthese( $results ) ;

    $t = timeit($count, '...other code...')
    print "$count loops of other code took:",timestr($t),"\n";

    $t = countit($time, '...other code...')
    $count = $t->iters ;
    print "$count loops of other code took:",timestr($t),"\n";

    # enable hires wallclock timing if possible
    use Benchmark ':hireswallclock';

說明

Benchmark 模組封裝了許多例程,協助您找出執行某些程式碼所需的時間。

timethis - 多次執行一段程式碼

timethese - 多次執行多段程式碼

cmpthese - 將 timethese 的結果列印為比較圖表

timeit - 執行一段程式碼並查看執行時間

countit - 查看一段程式碼在特定時間內執行次數

方法

new

傳回目前時間。範例

use Benchmark;
$t0 = Benchmark->new;
# ... your code here ...
$t1 = Benchmark->new;
$td = timediff($t1, $t0);
print "the code took:",timestr($td),"\n";
debug

透過設定 $Benchmark::Debug 旗標來啟用或停用除錯

Benchmark->debug(1);
$t = timeit(10, ' 5 ** $Global ');
Benchmark->debug(0);
iters

傳回反覆運算次數。

標準匯出

如果您使用 Benchmark 模組,下列常式將會匯出至您的名稱空間

timeit(COUNT, CODE)

引數:COUNT 是執行迴圈的次數,而 CODE 是要執行的程式碼。CODE 可以是程式碼參照或要評估的字串;不論哪一種,都會在呼叫者的套件中執行。

傳回:Benchmark 物件。

timethis ( COUNT, CODE, [ TITLE, [ STYLE ]] )

計時 CODE 的 COUNT 次反覆運算。CODE 可以是字串以評估或程式碼參照;不論哪一種,CODE 都會在呼叫者的套件中執行。結果將會印出至 STDOUT,格式為 TITLE 後接時間。如果未提供 TITLE,預設為「timethis COUNT」。STYLE 決定輸出的格式,如下方 timestr() 所述。

COUNT 可以為零或負數:這表示執行所需的最少 CPU 秒數。零表示預設值 3 秒。例如,至少執行 10 秒

timethis(-10, $code)

或至少執行 3 秒的兩個程式碼測試

timethese(0, { test1 => '...', test2 => '...'})

在 UNIX 術語中,CPU 秒數是使用者時間加上處理程序本身的系統時間,與真實 (牆上時鐘) 時間和子處理程序所花費的時間相反。不接受小於 0.1 秒 (例如,-0.01 作為計數會導致執行時期發生致命例外)。

請注意,CPU 秒數是最少時間:CPU 排程和其他作業系統因素可能會使嘗試複雜化,導致花費更多一點時間。不過,基準輸出也會顯示 $code 執行/秒的次數,這應該會比實際花費的秒數更有趣。

傳回 Benchmark 物件。

timethese ( COUNT, CODEHASHREF, [ STYLE ] )

CODEHASHREF 是對雜湊的參照,其中包含名稱作為鍵,以及對每個值的字串以評估或程式碼參照。對於 CODEHASHREF 中的每個 (KEY, VALUE) 配對,此常式會呼叫

timethis(COUNT, VALUE, KEY, STYLE)

常式會依據 KEY 的字串比較順序呼叫。

COUNT 可以為零或負數,請參閱 timethis()。

傳回 Benchmark 物件的雜湊參照,以名稱為鍵。

timediff ( T1, T2 )

傳回兩個 Benchmark 時間的差異,作為 Benchmark 物件,適合傳遞給 timestr()。

timestr ( TIMEDIFF, [ STYLE, [ FORMAT ] ] )

傳回一個字串,以要求的 STYLE 格式化 TIMEDIFF 物件中的時間。TIMEDIFF 預期為 Benchmark 物件,類似於 timediff() 傳回的物件。

STYLE 可為「all」、「none」、「noc」、「nop」或「auto」。「all」顯示 5 個可用的時間(「wallclock」時間、使用者時間、系統時間、子項目的使用者時間和子項目的系統時間)。「noc」顯示所有時間,但兩個子項目時間除外。「nop」僅顯示 wallclock 和兩個子項目時間。「auto」(預設值)會作用為「all」,除非子項目時間皆為零,則會作用為「noc」。「none」會防止輸出。

FORMAT 是 printf(3)-style 格式規範符號(不含開頭的「%」),用於列印時間。預設值為「5.2f」。

選用匯出

如果您特別要求匯入下列常式,它們會匯出到您的命名空間

clearcache ( COUNT )

清除 null 迴圈 COUNT 輪的快取時間。

clearallcache ( )

清除所有快取時間。

cmpthese ( COUNT, CODEHASHREF, [ STYLE ] )
cmpthese ( RESULTSHASHREF, [ STYLE ] )

選擇性地呼叫 timethese(),然後輸出比較圖表。這

cmpthese( -1, { a => "++\$i", b => "\$i *= 2" } ) ;

會輸出類似於

       Rate    b    a
b 2831802/s   -- -61%
a 7208959/s 155%   --

此圖表從最慢到最快排序,並顯示每對測試之間的百分比速度差異。

cmpthese 也可傳遞 timethese() 傳回的資料結構

$results = timethese( -1,
    { a => "++\$i", b => "\$i *= 2" } ) ;
cmpthese( $results );

以防您想要看到兩組結果。如果第一個引數是未加祝福的雜湊參照,那就是 RESULTSHASHREF;否則那就是 COUNT。

傳回對應到列的陣列參照,每列都是陣列,包含來自上述圖表的儲存格,包括標籤。這

my $rows = cmpthese( -1,
    { a => '++$i', b => '$i *= 2' }, "none" );

會傳回類似於

[
    [ '',       'Rate',   'b',    'a' ],
    [ 'b', '2885232/s',  '--', '-59%' ],
    [ 'a', '7099126/s', '146%',  '--' ],
]

注意:此結果值與回傳 timethese() 結果結構的先前版本不同。如果您想要這樣,請使用上面顯示的兩個陳述式 timethese...cmpthese 慣用語。

順便一提,請注意兩個範例之間的結果值差異;這是基準測試的典型情況。如果這是真正的基準測試,您可能需要執行更多次反覆運算。

countit(TIME, CODE)

參數:TIME 是執行 CODE 的最短時間,而 CODE 是要執行的程式碼。CODE 可以是程式碼參考或要評估的字串;無論如何,它都將在呼叫者的套件中執行。

TIME 不是負數。countit() 將執行迴圈多次,以計算 CODE 的速度,然後再執行 TIME。實際執行的時間通常會大於 TIME,這是因為系統時脈解析度,因此最好查看反覆運算次數除以您關注的時間,而不仅仅是反覆運算次數。

傳回:Benchmark 物件。

disablecache ( )

停用空迴圈計時的快取。這將強制 Benchmark 重新計算這些計時,以針對每個計時的新程式碼片段進行計時。

enablecache ( )

啟用空迴圈計時的快取。空迴圈的 COUNT 回合所花費的時間將僅針對每個不同的 COUNT 使用計算一次。

timesum ( T1, T2 )

將兩個 Benchmark 時間的總和傳回,作為適合傳遞給 timestr() 的 Benchmark 物件。

:hireswallclock

如果已安裝 Time::HiRes 模組,您可以為 Benchmark 指定特殊標籤 :hireswallclock(如果 Time::HiRes 不可用,則標籤將被靜默忽略)。此標籤將導致以微秒為單位測量時鐘時間,而不是整數秒。但請注意,速度計算仍以 CPU 時間進行,而不是時鐘時間。

Benchmark 物件

此模組中的許多函數傳回 Benchmark 物件,或者在 timethese() 的情況下,傳回雜湊的參考,其值為 Benchmark 物件。如果您想要儲存或進一步處理 Benchmark 函數的結果,這會很有用。

在內部,Benchmark 物件會保留計時值,如下面的 "NOTES" 所述。可以使用下列方法來存取它們

cpu_p

主體 (父) 程序的總 CPU (使用者 + 系統)。

cpu_c

任何子程序的總 CPU(使用者 + 系統)。

cpu_a

父程序和任何子程序的總 CPU。

real

真實經過時間「時鐘秒數」。

iters

執行的迭代次數。

以下說明 Benchmark 物件的使用方式

$result = timethis(100000, sub { ... });
print "total CPU = ", $result->cpu_a, "\n";

NOTES

資料儲存為 time 和 times 函數的值清單

($real, $user, $system, $children_user, $children_system, $iters)

以秒為單位計算整個迴圈(未除以回合數)。

計時使用 time(3) 和 times(3)。

程式碼在呼叫者的套件中執行。

空迴圈的時間(回合數相同但迴圈主體為空的迴圈)會從真實迴圈的時間中減去。

空迴圈時間可以快取,關鍵是回合數。快取可以使用類似以下的呼叫控制

clearcache($key);
clearallcache();

disablecache();
enablecache();

預設關閉快取,因為它(通常會稍微)降低準確度,而且通常不會明顯影響執行時間。

EXAMPLES

例如,

use Benchmark qw( cmpthese ) ;
$x = 3;
cmpthese( -5, {
    a => sub{$x*$x},
    b => sub{$x**2},
} );

輸出類似以下內容

Benchmark: running a, b, each for at least 5 CPU seconds...
       Rate    b    a
b 1559428/s   -- -62%
a 4152037/s 166%   --

use Benchmark qw( timethese cmpthese ) ;
$x = 3;
$r = timethese( -5, {
    a => sub{$x*$x},
    b => sub{$x**2},
} );
cmpthese $r;

輸出類似以下內容

Benchmark: running a, b, each for at least 5 CPU seconds...
         a: 10 wallclock secs ( 5.14 usr +  0.13 sys =  5.27 CPU) @ 3835055.60/s (n=20210743)
         b:  5 wallclock secs ( 5.41 usr +  0.00 sys =  5.41 CPU) @ 1574944.92/s (n=8520452)
       Rate    b    a
b 1574945/s   -- -59%
a 3835056/s 144%   --

INHERITANCE

Benchmark 沒有繼承其他類別,當然除了 Exporter 之外。

CAVEATS

比較已評估的字串和程式碼參考會產生不準確的結果:程式碼參考會顯示比等效已評估字串稍慢的執行時間。

真實時間計時使用 time(2),因此粒度僅為一秒。

短測試可能會產生負數,因為 Perl 執行空迴圈的時間似乎比短測試長;請嘗試

timethis(100,'1');

空迴圈的系統時間可能略長於執行實際程式碼的迴圈的系統時間,因此差異可能最終會小於 0。

SEE ALSO

Devel::NYTProf - Perl 程式碼剖析器

AUTHORS

Jarkko Hietaniemi <jhi@iki.fi>、Tim Bunce <Tim.Bunce@ig.co.uk>

MODIFICATION HISTORY

1994 年 9 月 8 日;Tim Bunce。

1997 年 3 月 28 日;Hugo van der Sanden:新增對程式碼參考和已記錄的「偵錯」方法的支援;改寫文件。

1997 年 4 月 4 日至 7 日:Jarkko Hietaniemi,新增執行一段時間的功能。

1999 年 9 月;Barrie Slaymaker:數學修正,以及準確度和效率調整。新增 cmpthese()。現在會從 timethese() 傳回結果。公開 countit()(為 runfor())。

2001 年 12 月;Nicholas Clark:讓 timestr() 辨識「none」樣式並傳回空字串。如果 cmpthese 呼叫 timethese,讓它傳入樣式。(因此「none」會抑制輸出)。讓 sub new 將其偵錯輸出傾印到 STDERR,以與其他所有內容一致。在撰寫回歸測試時發現的所有錯誤。

2002 年 9 月,由 Jarkko Hietaniemi:新增 ':hireswallclock' 特殊標籤。

2004 年 2 月,由 Chia-liang Kao:當樣式為 'nop' 時,讓 cmpthese 和 timestr 使用子項的時間統計資料,而非父項。

2007 年 11 月,由 Christophe Grosjean:讓 cmpthese 和 timestr 計算時間與樣式參數一致,預設值不再是 'noc',而是 'all'。