mwrap (Perl version) user+dev discussion/patches/pulls/bugs/help
 help / color / mirror / code / Atom feed
From: Eric Wong <e@80x24.org>
To: mwrap-perl@80x24.org
Subject: [PATCH 4/4] rproxy: cache addr2line output
Date: Wed, 28 Dec 2022 10:05:35 +0000	[thread overview]
Message-ID: <20221228100535.2252158-5-e@80x24.org> (raw)
In-Reply-To: <20221228100535.2252158-1-e@80x24.org>

We'll hoist out exe resolution into its own sub and rely on
reusing stat info (via `stat(_)') to give us ctime + size info
to use as a cache key.
---
 lib/Devel/Mwrap/Rproxy.pm | 78 ++++++++++++++++++++++++---------------
 1 file changed, 48 insertions(+), 30 deletions(-)

diff --git a/lib/Devel/Mwrap/Rproxy.pm b/lib/Devel/Mwrap/Rproxy.pm
index 43c1372..9b12405 100644
--- a/lib/Devel/Mwrap/Rproxy.pm
+++ b/lib/Devel/Mwrap/Rproxy.pm
@@ -59,17 +59,53 @@ sub list {
 }
 
 our %addr2line; # { exe|lib => Devel::Mwrap::Rproxy::A2L }
+my %cache; # "$exe\0$addr$st_ctime$st_size" => $line
+my $cache_exp = 0;
+my $cache_time = 1800;
+
+sub resolve_exe ($$) {
+	my ($exe, $st) = @_;
+	# n.b. this assumes PATH is identical across the rproxy and
+	# mwrap-httpd process, which may not always be the case:
+	if (index($exe, '/') < 0 && !-r $exe) {
+		for my $p (split(/:/, $ENV{PATH})) {
+			$p .= "/$exe";
+			if (-x $p) {
+				$exe = $p;
+				last;
+			}
+		}
+	}
+	my $fh;
+	if (-T $exe && open($fh, '<', $exe)) { # is it text? use shebang
+		my $l = readline($fh);
+		$exe = ($l =~ /\A\#\![ \t]*(\S+)/) ? $1 : $^X;
+	}
+	return unless -e $exe;
+
+	# Debian `perl-debug' is special:
+	($exe eq '/usr/bin/perl' && -x '/usr/bin/debugperl') and
+		$exe = '/usr/bin/debugperl';
+	my @st = stat(_);
+	$$st = pack('dd', $st[10], $st[7]); # ctime + size
+	$exe;
+}
 
 # addr2line bidirectional pipe wrapper
 sub a2l {
 	my ($exe, $addr) = @_;
-	my $a2l = $addr2line{$exe} //=
-		Devel::Mwrap::Rproxy::A2L->new($exe) //
-		return "$exe $addr";
-	chomp(my $line = $a2l->lookup($addr));
-	$line = Plack::Util::encode_html($line);
-	$line =~ /\?\?/ ? "$line $exe $addr" :
-		($line =~ /\S/ ? $line : "$exe $addr");
+	$exe = resolve_exe($exe, \(my $st)) // return "$exe($addr)";
+	$cache{"$addr\0$exe$st"} //= do {
+		my $a2l = $addr2line{$exe} //=
+			Devel::Mwrap::Rproxy::A2L->new($exe);
+
+		$a2l ? do {
+			chomp(my $line = $a2l->lookup($addr));
+			$line = Plack::Util::encode_html($line);
+			$line =~ /\?\?/ ? "$line $exe($addr)" :
+				($line =~ /\S/ ? $line : "$exe($addr)");
+		} : "$exe($addr)"
+	}
 }
 
 sub call { # PSGI entry point
@@ -97,6 +133,11 @@ sub call { # PSGI entry point
 	sub {
 		my ($wcb) = @_;
 		my $http_out = $wcb->([$code, \@hdr]);
+		my $now = time;
+		if ($now > $cache_exp) {
+			undef %cache;
+			$cache_exp = $now + $cache_time;
+		}
 		eval {
 			local %addr2line;
 			# extract executable|library(address)
@@ -134,29 +175,6 @@ use v5.12;
 
 sub new {
 	my ($cls, $exe) = @_;
-	# n.b. this assumes PATH is identical across the rproxy and
-	# mwrap-httpd process, which may not always be the case:
-	if (index($exe, '/') < 0 && !-r $exe) {
-		for my $p (split(/:/, $ENV{PATH})) {
-			$p .= "/$exe";
-			if (-x $p) {
-				$exe = $p;
-				last;
-			}
-		}
-	}
-	my $fh;
-	if (-T $exe && open($fh, '<', $exe)) { # is it text? use shebang
-		my $l = readline($fh);
-		$exe = ($l =~ /\A\#\![ \t]*(\S+)/) ? $1 : $^X;
-	}
-	return unless -e $exe;
-
-	# Debian `perl-debug' is special:
-	if ($exe eq '/usr/bin/perl' && -x '/usr/bin/debugperl') {
-		$exe = '/usr/bin/debugperl';
-	}
-
 	pipe(my ($rd, $_wr)) or die "pipe: $!";
 	pipe(my ($_rd, $wr)) or die "pipe: $!";
 	# -f/--functions needs -p/--pretty-print to go with it

      parent reply	other threads:[~2022-12-28 10:05 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-12-28 10:05 [PATCH 0/4] rproxy: addr2line support improvements Eric Wong
2022-12-28 10:05 ` [PATCH 1/4] rproxy: bail out early on errors reading /proc/$$/cmdline Eric Wong
2022-12-28 10:05 ` [PATCH 2/4] rproxy: close pipes in deterministic order Eric Wong
2022-12-28 10:05 ` [PATCH 3/4] rproxy: improve addr2line support Eric Wong
2022-12-28 10:05 ` Eric Wong [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20221228100535.2252158-5-e@80x24.org \
    --to=e@80x24.org \
    --cc=mwrap-perl@80x24.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://80x24.org/mwrap-perl.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).