From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on dcvr.yhbt.net X-Spam-Level: X-Spam-Status: No, score=-4.0 required=3.0 tests=ALL_TRUSTED,BAYES_00 shortcircuit=no autolearn=ham autolearn_force=no version=3.4.2 Received: from localhost (dcvr.yhbt.net [127.0.0.1]) by dcvr.yhbt.net (Postfix) with ESMTP id 08EBA1F4B4 for ; Sun, 3 Jan 2021 20:58:30 +0000 (UTC) From: Eric Wong To: meta@public-inbox.org Subject: [PATCH] lei: prefer IO::FDPass over our Inline::C recv_3fds Date: Sun, 3 Jan 2021 20:58:29 +0000 Message-Id: <20210103205829.8964-1-e@80x24.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit List-Id: While our recv_3fds() implementation is more efficient syscall-wise, loading Inline takes nearly 50ms on my machine even after Inline::C memoizes the build. The current ~20ms in the fast path is barely acceptable to me, and 50ms would be unusable. Eventually, script/lei may invoke tcc(1) or cc(1) directly in the fast path, but it needs @INC for the slow path, at least. We'll encode the number of FDs into the socket name allow parallel installations, for now. --- lib/PublicInbox/LEI.pm | 12 +++++++++--- lib/PublicInbox/Spawn.pm | 11 ----------- script/lei | 18 ++++++++++++------ t/lei.t | 10 ++++++---- 4 files changed, 27 insertions(+), 24 deletions(-) diff --git a/lib/PublicInbox/LEI.pm b/lib/PublicInbox/LEI.pm index 6f21da35..f41f63ed 100644 --- a/lib/PublicInbox/LEI.pm +++ b/lib/PublicInbox/LEI.pm @@ -660,7 +660,7 @@ sub noop {} # lei(1) calls this when it can't connect sub lazy_start { - my ($path, $errno) = @_; + my ($path, $errno, $nfd) = @_; if ($errno == ECONNREFUSED) { unlink($path) or die "unlink($path): $!"; } elsif ($errno != ENOENT) { @@ -675,8 +675,14 @@ sub lazy_start { my $dev_ino_expect = pack('dd', $st[0], $st[1]); # dev+ino pipe(my ($eof_r, $eof_w)) or die "pipe: $!"; my $oldset = PublicInbox::Sigfd::block_signals(); - $recv_3fds = PublicInbox::Spawn->can('recv_3fds') or die - "Inline::C not installed/configured or IO::FDPass missing\n"; + if ($nfd == 1) { + require IO::FDPass; + $recv_3fds = sub { map { IO::FDPass::recv($_[0]) } (0..2) }; + } elsif ($nfd == 3) { + $recv_3fds = PublicInbox::Spawn->can('recv_3fds'); + } + $recv_3fds or die + "IO::FDPass missing or Inline::C not installed/configured\n"; require PublicInbox::Listener; require PublicInbox::EOFpipe; (-p STDOUT) or die "E: stdout must be a pipe\n"; diff --git a/lib/PublicInbox/Spawn.pm b/lib/PublicInbox/Spawn.pm index 61e95433..cd94ba96 100644 --- a/lib/PublicInbox/Spawn.pm +++ b/lib/PublicInbox/Spawn.pm @@ -315,17 +315,6 @@ unless ($set_nodatacow) { *nodatacow_fd = \&PublicInbox::NDC_PP::nodatacow_fd; *nodatacow_dir = \&PublicInbox::NDC_PP::nodatacow_dir; } -unless (__PACKAGE__->can('recv_3fds')) { - eval { # try the XS IO::FDPass package - require IO::FDPass; - no warnings 'once'; - *recv_3fds = sub { map { IO::FDPass::recv($_[0]) } (0..2) }; - *send_3fds = sub ($$$$) { - my $sockfd = shift; - IO::FDPass::send($sockfd, shift) for (0..2); - }; - }; -} undef $set_nodatacow; undef $vfork_spawn; diff --git a/script/lei b/script/lei index 029881f8..2ea98da4 100755 --- a/script/lei +++ b/script/lei @@ -4,11 +4,17 @@ use strict; use v5.10.1; use Socket qw(AF_UNIX SOCK_STREAM pack_sockaddr_un); -my $send_3fds; +my ($send_3fds, $nfd); if (my ($sock, $pwd) = eval { - require PublicInbox::Spawn; - $send_3fds = PublicInbox::Spawn->can('send_3fds') or die - "Inline::C not installed/configured or IO::FDPass missing\n"; + $send_3fds = eval { + require IO::FDPass; + $nfd = 1; # 1 FD per-sendmsg + sub { IO::FDPass::send($_[0], $_[$_]) for (1..3) } + } // do { + require PublicInbox::Spawn; # takes ~50ms even if built *sigh* + $nfd = 3; # 3 FDs per-sendmsg(2) + PublicInbox::Spawn->can('send_3fds'); + } // die "IO::FDPass missing or Inline::C not installed/configured\n"; my $path = do { my $runtime_dir = ($ENV{XDG_RUNTIME_DIR} // '') . '/lei'; if ($runtime_dir eq '/lei') { @@ -19,7 +25,7 @@ if (my ($sock, $pwd) = eval { require File::Path; File::Path::mkpath($runtime_dir, 0, 0700); } - "$runtime_dir/sock"; + "$runtime_dir/$nfd.sock"; }; my $addr = pack_sockaddr_un($path); socket(my $sock, AF_UNIX, SOCK_STREAM, 0) or die "socket: $!"; @@ -27,7 +33,7 @@ if (my ($sock, $pwd) = eval { local $ENV{PERL5LIB} = join(':', @INC); open(my $daemon, '-|', $^X, qw[-MPublicInbox::LEI -E PublicInbox::LEI::lazy_start(@ARGV)], - $path, $! + 0) or die "popen: $!"; + $path, $! + 0, $nfd) or die "popen: $!"; while (<$daemon>) { warn $_ } # EOF when STDERR is redirected close($daemon) or warn <<""; lei-daemon could not start, exited with \$?=$? diff --git a/t/lei.t b/t/lei.t index 42c0eb8f..5afb8351 100644 --- a/t/lei.t +++ b/t/lei.t @@ -193,12 +193,14 @@ if ($ENV{TEST_LEI_ONESHOT}) { SKIP: { # real socket require_mods(qw(Cwd), my $nr = 46); - require PublicInbox::Spawn; - skip "Inline::C not installed/configured or IO::FDPass missing", $nr - unless PublicInbox::Spawn->can('send_3fds'); + my $nfd = eval { require IO::FDPass; 1 } // do { + require PublicInbox::Spawn; + PublicInbox::Spawn->can('send_3fds') ? 3 : undef; + } // + skip 'IO::FDPass missing or Inline::C not installed/configured', $nr; local $ENV{XDG_RUNTIME_DIR} = "$home/xdg_run"; - my $sock = "$ENV{XDG_RUNTIME_DIR}/lei/sock"; + my $sock = "$ENV{XDG_RUNTIME_DIR}/lei/$nfd.sock"; ok($lei->('daemon-pid'), 'daemon-pid'); is($err, '', 'no error from daemon-pid');