Skip Menu |

Preferred bug tracker

Please visit the preferred bug tracker to report your issue.

This queue is for tickets about the Exception-Class CPAN distribution.

Report information
The Basics
Id: 26489
Status: resolved
Priority: 0/
Queue: Exception-Class

People
Owner: Nobody in particular
Requestors: alech [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Wishlist
Broken in: 1.23
Fixed in: 1.26



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;
A while ago (April 28, 2007) I released a new version of Devel::StackTrace (1.15) which sped up object construction by a factor of 3x or so. Does this ameliorate the problem you were having?