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 429031FFA1 for ; Fri, 18 Dec 2020 12:09:52 +0000 (UTC) From: Eric Wong To: meta@public-inbox.org Subject: [PATCH 16/26] lei: micro-optimize startup time Date: Fri, 18 Dec 2020 12:09:40 +0000 Message-Id: <20201218120950.23272-17-e@80x24.org> In-Reply-To: <20201218120950.23272-1-e@80x24.org> References: <20201218120950.23272-1-e@80x24.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit List-Id: We'll use lower-level Socket and avoid IO::Socket::UNIX, use Cwd::fastcwd(*), avoid IO::Handle->autoflush by using the select operator, and reuse buffer for reading the socket while avoiding unnecessary $/ localization in a tiny script. All these things adds up to ~5-10 ms savings on my loaded system. (*) caveats about fastcwd won't apply since lei won't work in removed directories. --- lib/PublicInbox/LEI.pm | 13 ++++++------- lib/PublicInbox/TestCommon.pm | 1 + script/lei | 33 +++++++++++++++++---------------- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/lib/PublicInbox/LEI.pm b/lib/PublicInbox/LEI.pm index f5824c59..5399fade 100644 --- a/lib/PublicInbox/LEI.pm +++ b/lib/PublicInbox/LEI.pm @@ -10,9 +10,9 @@ use strict; use v5.10.1; use parent qw(PublicInbox::DS); use Getopt::Long (); +use Socket qw(AF_UNIX SOCK_STREAM pack_sockaddr_un); use Errno qw(EAGAIN ECONNREFUSED ENOENT); use POSIX qw(setsid); -use IO::Socket::UNIX; use IO::Handle (); use Sys::Syslog qw(syslog openlog); use PublicInbox::Config; @@ -585,18 +585,17 @@ sub noop {} # lei(1) calls this when it can't connect sub lazy_start { my ($path, $err) = @_; + require IO::FDPass; # require this early so caller sees it if ($err == ECONNREFUSED) { unlink($path) or die "unlink($path): $!"; } elsif ($err != ENOENT) { + $! = $err; # allow interpolation to stringify in die die "connect($path): $!"; } - require IO::FDPass; umask(077) // die("umask(077): $!"); - my $l = IO::Socket::UNIX->new(Local => $path, - Listen => 1024, - Type => SOCK_STREAM) or - $err = $!; - $l or return die "bind($path): $err"; + socket(my $l, AF_UNIX, SOCK_STREAM, 0) or die "socket: $!"; + bind($l, pack_sockaddr_un($path)) or die "bind($path): $!"; + listen($l, 1024) or die "listen $!"; my @st = stat($path) or die "stat($path): $!"; my $dev_ino_expect = pack('dd', $st[0], $st[1]); # dev+ino pipe(my ($eof_r, $eof_w)) or die "pipe: $!"; diff --git a/lib/PublicInbox/TestCommon.pm b/lib/PublicInbox/TestCommon.pm index c236c589..338e760c 100644 --- a/lib/PublicInbox/TestCommon.pm +++ b/lib/PublicInbox/TestCommon.pm @@ -261,6 +261,7 @@ sub run_script ($;$$) { my $orig_io = _prepare_redirects($fhref); _run_sub($sub, $key, \@argv); _undo_redirects($orig_io); + select STDOUT; } # slurp the redirects back into user-supplied strings diff --git a/script/lei b/script/lei index e59e4316..2b041fb4 100755 --- a/script/lei +++ b/script/lei @@ -3,8 +3,7 @@ # License: AGPL-3.0+ use strict; use v5.10.1; -use Cwd qw(cwd); -use IO::Socket::UNIX; +use Socket qw(AF_UNIX SOCK_STREAM pack_sockaddr_un); if (eval { require IO::FDPass; 1 }) { # use daemon to reduce load time my $path = do { @@ -13,14 +12,15 @@ if (eval { require IO::FDPass; 1 }) { # use daemon to reduce load time require File::Spec; $runtime_dir = File::Spec->tmpdir."/lei-$<"; } - unless (-d $runtime_dir && -w _) { + unless (-d $runtime_dir) { require File::Path; File::Path::mkpath($runtime_dir, 0, 0700); } "$runtime_dir/sock"; }; - my $sock = IO::Socket::UNIX->new(Peer => $path, Type => SOCK_STREAM); - unless ($sock) { # start the daemon if not started + my $addr = pack_sockaddr_un($path); + socket(my $sock, AF_UNIX, SOCK_STREAM, 0) or die "socket: $!"; + unless (connect($sock, $addr)) { # start the daemon if not started my $err = $! + 0; my $env = { PERL5LIB => join(':', @INC) }; my $cmd = [ $^X, qw[-MPublicInbox::LEI @@ -31,13 +31,14 @@ if (eval { require IO::FDPass; 1 }) { # use daemon to reduce load time warn "lei-daemon exited with \$?=$?\n" if $?; # try connecting again anyways, unlink+bind may be racy - $sock = IO::Socket::UNIX->new(Peer => $path, - Type => SOCK_STREAM) // die + connect($sock, $addr) or die "connect($path): $! (after attempted daemon start)"; } - my $pwd = $ENV{PWD}; - my $cwd = cwd(); - if ($pwd) { # prefer ENV{PWD} if it's a symlink to real cwd + require Cwd; + my $cwd = Cwd::fastcwd() // die "fastcwd: $!"; + my $pwd = $ENV{PWD} // ''; + if ($pwd eq $cwd) { # likely, all good + } elsif ($pwd) { # prefer ENV{PWD} if it's a symlink to real cwd my @st_cwd = stat($cwd) or die "stat(cwd=$cwd): $!\n"; my @st_pwd = stat($pwd); # make sure st_dev/st_ino match for {PWD} to be valid @@ -47,16 +48,16 @@ if (eval { require IO::FDPass; 1 }) { # use daemon to reduce load time $pwd = $cwd; } local $ENV{PWD} = $pwd; - $sock->autoflush(1); - IO::FDPass::send(fileno($sock), $_) for (0..2); my $buf = "$$\0\0>" . join("]\0[", @ARGV) . "\0\0>"; while (my ($k, $v) = each %ENV) { $buf .= "$k=$v\0" } $buf .= "\0\0"; + select $sock; + $| = 1; # unbuffer selected $sock + IO::FDPass::send(fileno($sock), $_) for (0..2); print $sock $buf or die "print(sock, buf): $!"; - local $/ = "\n"; - while (my $line = <$sock>) { - $line =~ /\Aexit=([0-9]+)\n\z/ and exit($1 + 0); - die $line; + while ($buf = <$sock>) { + $buf =~ /\Aexit=([0-9]+)\n\z/ and exit($1 + 0); + die $buf; } } else { # for systems lacking IO::FDPass require PublicInbox::LEI;