How fast system calls are?

システムコールは遅い」とよくいわれるけれども、実際どのくらい遅いのかというのは測定したことがなかった。しかし実際に測ってみると、システムコールだからといって、Perlの他の操作と比較して必ずしも遅いとは限らないようだ。特に、time(2)*1は非常に高速で、配列リファレンスの生成("[42]")よりも速い。システムコールはあまねく遅いと思いこんでいたので、この結果は意外だ。
結果(CentOS 5):

Perl/5.10.1 on i686-linux
Benchmark: running ArrayRef, eval, for/1, open, stat, time for at least 1 CPU seconds...
  ArrayRef:  0 wallclock secs ( 1.18 usr +  0.00 sys =  1.18 CPU) @ 3332338.98/s (n=3932160)
      eval:  1 wallclock secs ( 1.05 usr +  0.00 sys =  1.05 CPU) @ 182043.81/s (n=191146)
     for/1:  0 wallclock secs ( 1.06 usr +  0.00 sys =  1.06 CPU) @ 2885232.08/s (n=3058346)
      open:  1 wallclock secs ( 0.62 usr +  0.39 sys =  1.01 CPU) @ 202770.30/s (n=204798)
      stat:  1 wallclock secs ( 0.85 usr +  0.30 sys =  1.15 CPU) @ 498642.61/s (n=573439)
      time:  1 wallclock secs ( 0.62 usr +  0.49 sys =  1.11 CPU) @ 5834682.88/s (n=6476498)
              Rate     eval     open     stat    for/1 ArrayRef     time
eval      182044/s       --     -10%     -63%     -94%     -95%     -97%
open      202770/s      11%       --     -59%     -93%     -94%     -97%
stat      498643/s     174%     146%       --     -83%     -85%     -91%
for/1    2885232/s    1485%    1323%     479%       --     -13%     -51%
ArrayRef 3332339/s    1731%    1543%     568%      15%       --     -43%
time     5834683/s    3105%    2777%    1070%     102%      75%       --

スクリプト:

#!perl -w
use strict;
use Benchmark qw(:all);
use POSIX ();
use Config;
printf "Perl/%vd on %s\n", $^V, $Config{archname};

cmpthese timethese -1, {
    # non-syscalls
    'ArrayRef' => sub {
        my $x = [42];
    },
    'eval' => sub {
        my $x = eval '';
    },
    'for/1' => sub {
        for my $i(42) {
            ; # noop
        }
    },

    # syscalls
    'stat' => sub {
        my @st = stat(__FILE__) or die $!;
    },
    'open' => sub {
        open my $fh, '<', __FILE__ or die $!;
    },
    'time' => sub {
        my $x = time();
    },
};
__END__

*1:正確にはtime(2)のラッパーであるPerl_pp_time()だが、これは非常に薄いラッパーなのでtime(2)とほぼ変わらない。