Subject: | (Optionally) prevent generation of Devel::StackTrace objects if not needed |
Dear Dave,
in the OpenXPKI project, we use exceptions a lot. While profiling our
server today, we noticed that a huge amount of time was spent in
Devel::StackTrace, which is called every time we created an exception.
As we don't need those stack traces, I've patched Exception::Class to
support a no_stack_trace parameter to throw() (and new()) which prevents
them from being instantiated in the first place. This has actually sped
up a typical operation in our application by a factor of 7 or so.
Attached is the patch, it would be great if you could implement it in an
upcoming version so that we don't have to patch Exception::Class locally
ourselves.
Best regards,
Alex
Subject: | Exception-Class-no_stack_trace.patch |
Only in Exception-Class-1.23: Makefile
Only in Exception-Class-1.23: blib
diff -ru Exception-Class-1.23.orig/lib/Exception/Class.pm Exception-Class-1.23/lib/Exception/Class.pm
--- Exception-Class-1.23.orig/lib/Exception/Class.pm 2006-01-14 19:19:34.000000000 +0100
+++ Exception-Class-1.23/lib/Exception/Class.pm 2007-04-19 16:57:46.000000000 +0200
@@ -272,6 +272,11 @@
$self->{message} = $p{message} || $p{error} || $! || '';
$self->{show_trace} = $p{show_trace} if exists $p{show_trace};
+ if ($p{no_stack_trace}) {
+ # if stack traces have been disabled, show_trace
+ # does not make any sense
+ $self->{show_trace} = 0;
+ }
# CORE::time is important to fix an error with some versions of
# Perl
@@ -282,37 +287,42 @@
$self->{gid} = $(;
$self->{egid} = $);
- my @ignore_class = (__PACKAGE__);
- my @ignore_package = 'Exception::Class';
-
- if ( my $i = delete $p{ignore_class} )
- {
- push @ignore_class, ( ref($i) eq 'ARRAY' ? @$i : $i );
- }
-
- if ( my $i = delete $p{ignore_package} )
- {
- push @ignore_package, ( ref($i) eq 'ARRAY' ? @$i : $i );
- }
-
- $self->{trace} =
- Devel::StackTrace->new( ignore_class => \@ignore_class,
- ignore_package => \@ignore_package,
- no_refs => $self->NoRefs,
- respect_overload => $self->RespectOverload,
- );
-
- if ( my $frame = $self->trace->frame(0) )
- {
- $self->{package} = $frame->package;
- $self->{line} = $frame->line;
- $self->{file} = $frame->filename;
+ if (! $p{no_stack_trace}) {
+ # if stack traces have been disabled, there is no need to
+ # create a Devel::StackTrace object, as this takes up a lot
+ # of time ...
+ my @ignore_class = (__PACKAGE__);
+ my @ignore_package = 'Exception::Class';
+
+ if ( my $i = delete $p{ignore_class} )
+ {
+ push @ignore_class, ( ref($i) eq 'ARRAY' ? @$i : $i );
+ }
+
+ if ( my $i = delete $p{ignore_package} )
+ {
+ push @ignore_package, ( ref($i) eq 'ARRAY' ? @$i : $i );
+ }
+
+ $self->{trace} =
+ Devel::StackTrace->new( ignore_class => \@ignore_class,
+ ignore_package => \@ignore_package,
+ no_refs => $self->NoRefs,
+ respect_overload => $self->RespectOverload,
+ );
+
+ if ( my $frame = $self->trace->frame(0) )
+ {
+ $self->{package} = $frame->package;
+ $self->{line} = $frame->line;
+ $self->{file} = $frame->filename;
+ }
}
my %fields = map { $_ => 1 } $self->Fields;
while ( my ($key, $value) = each %p )
{
- next if $key =~ /^(?:error|message|show_trace)$/;
+ next if $key =~ /^(?:error|message|show_trace|no_stack_trace)$/;
if ( $fields{$key})
{
@@ -659,6 +669,12 @@
and C<ignore_package> parameters. These are passed directly to
Devel::Stacktrace's constructor. See C<Devel::Stacktrace> for more details.
+Additionally, a C<no_stack_trace> parameter can be passed, so that the
+stacktrace object is not created. If you throw a huge amount of exceptions,
+this will save you a good deal of time. C<no_stack_trace> resets the
+C<show_trace> parameter, as it makes no sense to pass C<no_stack_trace> => 1
+and C<show_trace> => 1.
+
If only a single value is given to the constructor it is assumed to be
the message parameter.
Only in Exception-Class-1.23: pm_to_blib
diff -ru Exception-Class-1.23.orig/t/basic.t Exception-Class-1.23/t/basic.t
--- Exception-Class-1.23.orig/t/basic.t 2006-01-14 19:19:34.000000000 +0100
+++ Exception-Class-1.23/t/basic.t 2007-04-19 17:07:52.000000000 +0200
@@ -4,7 +4,7 @@
use File::Spec;
-use Test::More tests => 56;
+use Test::More tests => 60;
use_ok('Exception::Class');
@@ -334,6 +334,27 @@
::is( $e->package, __PACKAGE__, 'package matches current package' );
}
+# 54-57 - no_stack_trace
+{
+ eval { YAE->throw( message => 'foo', no_stack_trace => 1 ) };
+
+ ok( $@,
+ "Passing no_stack_trace should work" );
+
+ is( $@->trace, undef,
+ "trace should be undef if no_stack_trace is passed" );
+}
+
+{
+ eval { YAE->throw( message => 'foo', no_stack_trace => 1, show_trace => 1 ) };
+
+ ok( $@,
+ "Passing no_stack_trace and show_trace should work" );
+
+ is( $@->show_trace, 0,
+ "show_trace should be reset to 0 if no_stack_trace is passed" );
+}
+
{
package BarBaz;