| Filename | /home/micha/.plenv/versions/5.38.2/lib/perl5/site_perl/5.38.2/Test2/API/Instance.pm |
| Statements | Executed 140 statements in 2.22ms |
| Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
|---|---|---|---|---|---|
| 1 | 1 | 1 | 541µs | 2.30ms | Test2::API::Instance::BEGIN@13 |
| 1 | 1 | 1 | 400µs | 3.31ms | Test2::API::Instance::BEGIN@14 |
| 3 | 1 | 1 | 36µs | 485µs | Test2::API::Instance::load |
| 1 | 1 | 1 | 33µs | 113µs | Test2::API::Instance::set_exit |
| 1 | 1 | 1 | 11µs | 13µs | Test2::API::Instance::_finalize |
| 1 | 1 | 1 | 11µs | 13µs | Test2::API::Instance::BEGIN@2 |
| 1 | 1 | 1 | 10µs | 11µs | Test2::API::Instance::reset |
| 1 | 1 | 1 | 10µs | 12µs | Test2::API::Instance::BEGIN@53 |
| 1 | 1 | 1 | 8µs | 12µs | Test2::API::Instance::BEGIN@62 |
| 1 | 1 | 1 | 7µs | 232µs | Test2::API::Instance::BEGIN@16 |
| 2 | 2 | 1 | 6µs | 21µs | Test2::API::Instance::__ANON__[:60] |
| 1 | 1 | 1 | 5µs | 8µs | Test2::API::Instance::add_post_load_callback |
| 1 | 1 | 1 | 4µs | 35µs | Test2::API::Instance::BEGIN@11 |
| 1 | 1 | 1 | 4µs | 24µs | Test2::API::Instance::BEGIN@8 |
| 1 | 1 | 1 | 4µs | 28µs | Test2::API::Instance::BEGIN@63 |
| 1 | 1 | 1 | 4µs | 22µs | Test2::API::Instance::BEGIN@3 |
| 1 | 1 | 1 | 4µs | 16µs | Test2::API::Instance::BEGIN@9 |
| 1 | 1 | 1 | 4µs | 26µs | Test2::API::Instance::import |
| 1 | 1 | 1 | 3µs | 3µs | Test2::API::Instance::add_formatter |
| 1 | 1 | 1 | 2µs | 3µs | Test2::API::Instance::add_context_acquire_callback |
| 1 | 1 | 1 | 2µs | 3µs | Test2::API::Instance::add_exit_callback |
| 1 | 1 | 1 | 2µs | 13µs | Test2::API::Instance::init |
| 1 | 1 | 1 | 2µs | 2µs | Test2::API::Instance::pid |
| 1 | 1 | 1 | 1µs | 1µs | Test2::API::Instance::tid |
| 1 | 1 | 1 | 1µs | 1µs | Test2::API::Instance::has_ipc |
| 0 | 0 | 0 | 0s | 0s | Test2::API::Instance::__ANON__[:195] |
| 0 | 0 | 0 | 0s | 0s | Test2::API::Instance::__ANON__[:215] |
| 0 | 0 | 0 | 0s | 0s | Test2::API::Instance::__ANON__[:375] |
| 0 | 0 | 0 | 0s | 0s | Test2::API::Instance::__ANON__[:418] |
| 0 | 0 | 0 | 0s | 0s | Test2::API::Instance::_check_pid |
| 0 | 0 | 0 | 0s | 0s | Test2::API::Instance::_ipc_wait |
| 0 | 0 | 0 | 0s | 0s | Test2::API::Instance::add_context_init_callback |
| 0 | 0 | 0 | 0s | 0s | Test2::API::Instance::add_context_release_callback |
| 0 | 0 | 0 | 0s | 0s | Test2::API::Instance::add_ipc_driver |
| 0 | 0 | 0 | 0s | 0s | Test2::API::Instance::add_pre_subtest_callback |
| 0 | 0 | 0 | 0s | 0s | Test2::API::Instance::disable_ipc_polling |
| 0 | 0 | 0 | 0s | 0s | Test2::API::Instance::enable_ipc_polling |
| 0 | 0 | 0 | 0s | 0s | Test2::API::Instance::formatter_set |
| 0 | 0 | 0 | 0s | 0s | Test2::API::Instance::get_ipc_pending |
| 0 | 0 | 0 | 0s | 0s | Test2::API::Instance::ipc_disable |
| 0 | 0 | 0 | 0s | 0s | Test2::API::Instance::post_preload_reset |
| 0 | 0 | 0 | 0s | 0s | Test2::API::Instance::set_ipc_pending |
| 0 | 0 | 0 | 0s | 0s | Test2::API::Instance::start_preload |
| 0 | 0 | 0 | 0s | 0s | Test2::API::Instance::stop_preload |
| 0 | 0 | 0 | 0s | 0s | Test2::API::Instance::test2_disable_trace_stamps |
| 0 | 0 | 0 | 0s | 0s | Test2::API::Instance::test2_enable_trace_stamps |
| 0 | 0 | 0 | 0s | 0s | Test2::API::Instance::test2_trace_stamps_enabled |
| Line | State ments |
Time on line |
Calls | Time in subs |
Code |
|---|---|---|---|---|---|
| 1 | package Test2::API::Instance; | ||||
| 2 | 2 | 26µs | 2 | 14µs | # spent 13µs (11+2) within Test2::API::Instance::BEGIN@2 which was called:
# once (11µs+2µs) by Test2::API::BEGIN@51 at line 2 # spent 13µs making 1 call to Test2::API::Instance::BEGIN@2
# spent 2µs making 1 call to strict::import |
| 3 | 2 | 35µs | 2 | 40µs | # spent 22µs (4+18) within Test2::API::Instance::BEGIN@3 which was called:
# once (4µs+18µs) by Test2::API::BEGIN@51 at line 3 # spent 22µs making 1 call to Test2::API::Instance::BEGIN@3
# spent 18µs making 1 call to warnings::import |
| 4 | |||||
| 5 | 1 | 300ns | our $VERSION = '1.302198'; | ||
| 6 | |||||
| 7 | 1 | 900ns | our @CARP_NOT = qw/Test2::API Test2::API::Instance Test2::IPC::Driver Test2::Formatter/; | ||
| 8 | 2 | 17µs | 2 | 44µs | # spent 24µs (4+20) within Test2::API::Instance::BEGIN@8 which was called:
# once (4µs+20µs) by Test2::API::BEGIN@51 at line 8 # spent 24µs making 1 call to Test2::API::Instance::BEGIN@8
# spent 20µs making 1 call to Exporter::import |
| 9 | 2 | 21µs | 2 | 28µs | # spent 16µs (4+12) within Test2::API::Instance::BEGIN@9 which was called:
# once (4µs+12µs) by Test2::API::BEGIN@51 at line 9 # spent 16µs making 1 call to Test2::API::Instance::BEGIN@9
# spent 12µs making 1 call to Exporter::import |
| 10 | |||||
| 11 | 2 | 17µs | 2 | 66µs | # spent 35µs (4+31) within Test2::API::Instance::BEGIN@11 which was called:
# once (4µs+31µs) by Test2::API::BEGIN@51 at line 11 # spent 35µs making 1 call to Test2::API::Instance::BEGIN@11
# spent 31µs making 1 call to Exporter::import |
| 12 | |||||
| 13 | 2 | 82µs | 1 | 2.30ms | # spent 2.30ms (541µs+1.76) within Test2::API::Instance::BEGIN@13 which was called:
# once (541µs+1.76ms) by Test2::API::BEGIN@51 at line 13 # spent 2.30ms making 1 call to Test2::API::Instance::BEGIN@13 |
| 14 | 2 | 88µs | 1 | 3.31ms | # spent 3.31ms (400µs+2.91) within Test2::API::Instance::BEGIN@14 which was called:
# once (400µs+2.91ms) by Test2::API::BEGIN@51 at line 14 # spent 3.31ms making 1 call to Test2::API::Instance::BEGIN@14 |
| 15 | |||||
| 16 | 1 | 3µs | 1 | 225µs | # spent 232µs (7+225) within Test2::API::Instance::BEGIN@16 which was called:
# once (7µs+225µs) by Test2::API::BEGIN@51 at line 41 # spent 225µs making 1 call to Test2::Util::HashBase::import |
| 17 | _pid _tid | ||||
| 18 | no_wait | ||||
| 19 | finalized loaded | ||||
| 20 | ipc stack formatter | ||||
| 21 | contexts | ||||
| 22 | |||||
| 23 | add_uuid_via | ||||
| 24 | |||||
| 25 | -preload | ||||
| 26 | |||||
| 27 | ipc_disabled | ||||
| 28 | ipc_polling | ||||
| 29 | ipc_drivers | ||||
| 30 | ipc_timeout | ||||
| 31 | formatters | ||||
| 32 | |||||
| 33 | exit_callbacks | ||||
| 34 | post_load_callbacks | ||||
| 35 | context_acquire_callbacks | ||||
| 36 | context_init_callbacks | ||||
| 37 | context_release_callbacks | ||||
| 38 | pre_subtest_callbacks | ||||
| 39 | |||||
| 40 | trace_stamps | ||||
| 41 | 1 | 139µs | 1 | 232µs | }; # spent 232µs making 1 call to Test2::API::Instance::BEGIN@16 |
| 42 | |||||
| 43 | sub DEFAULT_IPC_TIMEOUT() { 30 } | ||||
| 44 | |||||
| 45 | sub test2_enable_trace_stamps { $_[0]->{+TRACE_STAMPS} = 1 } | ||||
| 46 | sub test2_disable_trace_stamps { $_[0]->{+TRACE_STAMPS} = 0 } | ||||
| 47 | sub test2_trace_stamps_enabled { $_[0]->{+TRACE_STAMPS} } | ||||
| 48 | |||||
| 49 | 1 | 2µs | # spent 2µs within Test2::API::Instance::pid which was called:
# once (2µs+0s) by Test2::API::test2_set_is_end at line 35 of Test2/API.pm | ||
| 50 | 1 | 1µs | # spent 1µs within Test2::API::Instance::tid which was called:
# once (1µs+0s) by Test2::API::test2_set_is_end at line 36 of Test2/API.pm | ||
| 51 | |||||
| 52 | # Wrap around the getters that should call _finalize. | ||||
| 53 | # spent 12µs (10+2) within Test2::API::Instance::BEGIN@53 which was called:
# once (10µs+2µs) by Test2::API::BEGIN@51 at line 66 | ||||
| 54 | 1 | 2µs | for my $finalizer (IPC, FORMATTER) { | ||
| 55 | 2 | 6µs | 2 | 2µs | my $orig = __PACKAGE__->can($finalizer); # spent 2µs making 2 calls to UNIVERSAL::can, avg 1µs/call |
| 56 | # spent 21µs (6+14) within Test2::API::Instance::__ANON__[/home/micha/.plenv/versions/5.38.2/lib/perl5/site_perl/5.38.2/Test2/API/Instance.pm:60] which was called 2 times, avg 10µs/call:
# once (4µs+14µs) by Test2::API::test2_formatter at line 305 of Test2/API.pm
# once (2µs+700ns) by Test2::API::test2_ipc at line 282 of Test2/API.pm | ||||
| 57 | 2 | 200ns | my $self = shift; | ||
| 58 | 2 | 1µs | 1 | 13µs | $self->_finalize unless $self->{+FINALIZED}; # spent 13µs making 1 call to Test2::API::Instance::_finalize |
| 59 | 2 | 5µs | 2 | 1µs | $self->$orig; # spent 1µs making 2 calls to Test2::Util::HashBase::__ANON__[Test2/Util/HashBase.pm:84], avg 700ns/call |
| 60 | 2 | 2µs | }; | ||
| 61 | |||||
| 62 | 2 | 48µs | 2 | 17µs | # spent 12µs (8+5) within Test2::API::Instance::BEGIN@62 which was called:
# once (8µs+5µs) by Test2::API::BEGIN@51 at line 62 # spent 12µs making 1 call to Test2::API::Instance::BEGIN@62
# spent 5µs making 1 call to strict::unimport |
| 63 | 2 | 27µs | 2 | 51µs | # spent 28µs (4+24) within Test2::API::Instance::BEGIN@63 which was called:
# once (4µs+24µs) by Test2::API::BEGIN@51 at line 63 # spent 28µs making 1 call to Test2::API::Instance::BEGIN@63
# spent 24µs making 1 call to warnings::unimport |
| 64 | 2 | 2µs | *{$finalizer} = $new; | ||
| 65 | } | ||||
| 66 | 1 | 1.57ms | 1 | 12µs | } # spent 12µs making 1 call to Test2::API::Instance::BEGIN@53 |
| 67 | |||||
| 68 | 1 | 2µs | # spent 1µs within Test2::API::Instance::has_ipc which was called:
# once (1µs+0s) by Test2::API::test2_has_ipc at line 283 of Test2/API.pm | ||
| 69 | |||||
| 70 | # spent 26µs (4+23) within Test2::API::Instance::import which was called:
# once (4µs+23µs) by Test2::API::BEGIN@51 at line 51 of Test2/API.pm | ||||
| 71 | 1 | 300ns | my $class = shift; | ||
| 72 | 1 | 300ns | return unless @_; | ||
| 73 | 1 | 300ns | my ($ref) = @_; | ||
| 74 | 1 | 2µs | 1 | 23µs | $$ref = $class->new; # spent 23µs making 1 call to Test2::Util::HashBase::_new |
| 75 | } | ||||
| 76 | |||||
| 77 | 1 | 2µs | 1 | 11µs | # spent 13µs (2+11) within Test2::API::Instance::init which was called:
# once (2µs+11µs) by Test2::Util::HashBase::_new at line 155 of Test2/Util/HashBase.pm # spent 11µs making 1 call to Test2::API::Instance::reset |
| 78 | |||||
| 79 | sub start_preload { | ||||
| 80 | my $self = shift; | ||||
| 81 | |||||
| 82 | confess "preload cannot be started, Test2::API has already been initialized" | ||||
| 83 | if $self->{+FINALIZED} || $self->{+LOADED}; | ||||
| 84 | |||||
| 85 | return $self->{+PRELOAD} = 1; | ||||
| 86 | } | ||||
| 87 | |||||
| 88 | sub stop_preload { | ||||
| 89 | my $self = shift; | ||||
| 90 | |||||
| 91 | return 0 unless $self->{+PRELOAD}; | ||||
| 92 | $self->{+PRELOAD} = 0; | ||||
| 93 | |||||
| 94 | $self->post_preload_reset(); | ||||
| 95 | |||||
| 96 | return 1; | ||||
| 97 | } | ||||
| 98 | |||||
| 99 | sub post_preload_reset { | ||||
| 100 | my $self = shift; | ||||
| 101 | |||||
| 102 | delete $self->{+_PID}; | ||||
| 103 | delete $self->{+_TID}; | ||||
| 104 | |||||
| 105 | $self->{+ADD_UUID_VIA} = undef unless exists $self->{+ADD_UUID_VIA}; | ||||
| 106 | |||||
| 107 | $self->{+CONTEXTS} = {}; | ||||
| 108 | |||||
| 109 | $self->{+FORMATTERS} = []; | ||||
| 110 | |||||
| 111 | $self->{+FINALIZED} = undef; | ||||
| 112 | $self->{+IPC} = undef; | ||||
| 113 | $self->{+IPC_DISABLED} = $ENV{T2_NO_IPC} ? 1 : 0; | ||||
| 114 | |||||
| 115 | $self->{+IPC_TIMEOUT} = DEFAULT_IPC_TIMEOUT() unless defined $self->{+IPC_TIMEOUT}; | ||||
| 116 | |||||
| 117 | $self->{+LOADED} = 0; | ||||
| 118 | |||||
| 119 | $self->{+STACK} ||= Test2::API::Stack->new; | ||||
| 120 | } | ||||
| 121 | |||||
| 122 | # spent 11µs (10+1) within Test2::API::Instance::reset which was called:
# once (10µs+1µs) by Test2::API::Instance::init at line 77 | ||||
| 123 | 1 | 100ns | my $self = shift; | ||
| 124 | |||||
| 125 | 1 | 1µs | delete $self->{+_PID}; | ||
| 126 | 1 | 100ns | delete $self->{+_TID}; | ||
| 127 | |||||
| 128 | 1 | 600ns | $self->{+TRACE_STAMPS} = $ENV{T2_TRACE_STAMPS} || 0; | ||
| 129 | |||||
| 130 | 1 | 300ns | $self->{+ADD_UUID_VIA} = undef; | ||
| 131 | |||||
| 132 | 1 | 400ns | $self->{+CONTEXTS} = {}; | ||
| 133 | |||||
| 134 | 1 | 200ns | $self->{+IPC_DRIVERS} = []; | ||
| 135 | 1 | 200ns | $self->{+IPC_POLLING} = undef; | ||
| 136 | |||||
| 137 | 1 | 200ns | $self->{+FORMATTERS} = []; | ||
| 138 | 1 | 500ns | $self->{+FORMATTER} = undef; | ||
| 139 | |||||
| 140 | 1 | 200ns | $self->{+FINALIZED} = undef; | ||
| 141 | 1 | 200ns | $self->{+IPC} = undef; | ||
| 142 | 1 | 300ns | $self->{+IPC_DISABLED} = $ENV{T2_NO_IPC} ? 1 : 0; | ||
| 143 | |||||
| 144 | 1 | 900ns | $self->{+IPC_TIMEOUT} = DEFAULT_IPC_TIMEOUT() unless defined $self->{+IPC_TIMEOUT}; | ||
| 145 | |||||
| 146 | 1 | 100ns | $self->{+NO_WAIT} = 0; | ||
| 147 | 1 | 200ns | $self->{+LOADED} = 0; | ||
| 148 | |||||
| 149 | 1 | 200ns | $self->{+EXIT_CALLBACKS} = []; | ||
| 150 | 1 | 100ns | $self->{+POST_LOAD_CALLBACKS} = []; | ||
| 151 | 1 | 100ns | $self->{+CONTEXT_ACQUIRE_CALLBACKS} = []; | ||
| 152 | 1 | 200ns | $self->{+CONTEXT_INIT_CALLBACKS} = []; | ||
| 153 | 1 | 100ns | $self->{+CONTEXT_RELEASE_CALLBACKS} = []; | ||
| 154 | 1 | 200ns | $self->{+PRE_SUBTEST_CALLBACKS} = []; | ||
| 155 | |||||
| 156 | 1 | 2µs | 1 | 1µs | $self->{+STACK} = Test2::API::Stack->new; # spent 1µs making 1 call to Test2::API::Stack::new |
| 157 | } | ||||
| 158 | |||||
| 159 | # spent 13µs (11+2) within Test2::API::Instance::_finalize which was called:
# once (11µs+2µs) by Test2::API::Instance::__ANON__[/home/micha/.plenv/versions/5.38.2/lib/perl5/site_perl/5.38.2/Test2/API/Instance.pm:60] at line 58 | ||||
| 160 | 1 | 100ns | my $self = shift; | ||
| 161 | 1 | 300ns | my ($caller) = @_; | ||
| 162 | 1 | 3µs | $caller ||= [caller(1)]; | ||
| 163 | |||||
| 164 | confess "Attempt to initialize Test2::API during preload" | ||||
| 165 | 1 | 200ns | if $self->{+PRELOAD}; | ||
| 166 | |||||
| 167 | 1 | 200ns | $self->{+FINALIZED} = $caller; | ||
| 168 | |||||
| 169 | 1 | 300ns | $self->{+_PID} = $$ unless defined $self->{+_PID}; | ||
| 170 | 1 | 200ns | $self->{+_TID} = get_tid() unless defined $self->{+_TID}; | ||
| 171 | |||||
| 172 | 1 | 300ns | unless ($self->{+FORMATTER}) { | ||
| 173 | 1 | 200ns | my ($formatter, $source); | ||
| 174 | 1 | 2µs | if ($ENV{T2_FORMATTER}) { | ||
| 175 | $source = "set by the 'T2_FORMATTER' environment variable"; | ||||
| 176 | |||||
| 177 | if ($ENV{T2_FORMATTER} =~ m/^(\+)?(.*)$/) { | ||||
| 178 | $formatter = $1 ? $2 : "Test2::Formatter::$2" | ||||
| 179 | } | ||||
| 180 | else { | ||||
| 181 | $formatter = ''; | ||||
| 182 | } | ||||
| 183 | } | ||||
| 184 | elsif (@{$self->{+FORMATTERS}}) { | ||||
| 185 | 1 | 600ns | ($formatter) = @{$self->{+FORMATTERS}}; | ||
| 186 | 1 | 200ns | $source = "Most recently added"; | ||
| 187 | } | ||||
| 188 | else { | ||||
| 189 | $formatter = 'Test2::Formatter::TAP'; | ||||
| 190 | $source = 'default formatter'; | ||||
| 191 | } | ||||
| 192 | |||||
| 193 | 1 | 5µs | 1 | 2µs | unless (ref($formatter) || $formatter->can('write')) { # spent 2µs making 1 call to UNIVERSAL::can |
| 194 | my $file = pkg_to_file($formatter); | ||||
| 195 | my ($ok, $err) = try { require $file }; | ||||
| 196 | unless ($ok) { | ||||
| 197 | my $line = "* COULD NOT LOAD FORMATTER '$formatter' ($source) *"; | ||||
| 198 | my $border = '*' x length($line); | ||||
| 199 | die "\n\n $border\n $line\n $border\n\n$err"; | ||||
| 200 | } | ||||
| 201 | } | ||||
| 202 | |||||
| 203 | 1 | 400ns | $self->{+FORMATTER} = $formatter; | ||
| 204 | } | ||||
| 205 | |||||
| 206 | # Turn on IPC if threads are on, drivers are registered, or the Test2::IPC | ||||
| 207 | # module is loaded. | ||||
| 208 | 1 | 200ns | return if $self->{+IPC_DISABLED}; | ||
| 209 | 1 | 2µs | return unless USE_THREADS || $INC{'Test2/IPC.pm'} || @{$self->{+IPC_DRIVERS}}; | ||
| 210 | |||||
| 211 | # Turn on polling by default, people expect it. | ||||
| 212 | $self->enable_ipc_polling; | ||||
| 213 | |||||
| 214 | unless (@{$self->{+IPC_DRIVERS}}) { | ||||
| 215 | my ($ok, $error) = try { require Test2::IPC::Driver::Files }; | ||||
| 216 | die $error unless $ok; | ||||
| 217 | push @{$self->{+IPC_DRIVERS}} => 'Test2::IPC::Driver::Files'; | ||||
| 218 | } | ||||
| 219 | |||||
| 220 | for my $driver (@{$self->{+IPC_DRIVERS}}) { | ||||
| 221 | next unless $driver->can('is_viable') && $driver->is_viable; | ||||
| 222 | $self->{+IPC} = $driver->new or next; | ||||
| 223 | return; | ||||
| 224 | } | ||||
| 225 | |||||
| 226 | die "IPC has been requested, but no viable drivers were found. Aborting...\n"; | ||||
| 227 | } | ||||
| 228 | |||||
| 229 | sub formatter_set { $_[0]->{+FORMATTER} ? 1 : 0 } | ||||
| 230 | |||||
| 231 | # spent 3µs within Test2::API::Instance::add_formatter which was called:
# once (3µs+0s) by Test2::API::test2_formatter_add at line 309 of Test2/API.pm | ||||
| 232 | 1 | 100ns | my $self = shift; | ||
| 233 | 1 | 400ns | my ($formatter) = @_; | ||
| 234 | 1 | 900ns | unshift @{$self->{+FORMATTERS}} => $formatter; | ||
| 235 | |||||
| 236 | 1 | 4µs | return unless $self->{+FINALIZED}; | ||
| 237 | |||||
| 238 | # Why is the @CARP_NOT entry not enough? | ||||
| 239 | local %Carp::Internal = %Carp::Internal; | ||||
| 240 | $Carp::Internal{'Test2::Formatter'} = 1; | ||||
| 241 | |||||
| 242 | carp "Formatter $formatter loaded too late to be used as the global formatter"; | ||||
| 243 | } | ||||
| 244 | |||||
| 245 | # spent 3µs (2+300ns) within Test2::API::Instance::add_context_acquire_callback which was called:
# once (2µs+300ns) by Test2::API::test2_add_callback_context_aquire at line 263 of Test2/API.pm | ||||
| 246 | 1 | 200ns | my $self = shift; | ||
| 247 | 1 | 100ns | my ($code) = @_; | ||
| 248 | |||||
| 249 | 1 | 2µs | 1 | 300ns | my $rtype = reftype($code) || ""; # spent 300ns making 1 call to Scalar::Util::reftype |
| 250 | |||||
| 251 | 1 | 200ns | confess "Context-acquire callbacks must be coderefs" | ||
| 252 | unless $code && $rtype eq 'CODE'; | ||||
| 253 | |||||
| 254 | 1 | 2µs | push @{$self->{+CONTEXT_ACQUIRE_CALLBACKS}} => $code; | ||
| 255 | } | ||||
| 256 | |||||
| 257 | sub add_context_init_callback { | ||||
| 258 | my $self = shift; | ||||
| 259 | my ($code) = @_; | ||||
| 260 | |||||
| 261 | my $rtype = reftype($code) || ""; | ||||
| 262 | |||||
| 263 | confess "Context-init callbacks must be coderefs" | ||||
| 264 | unless $code && $rtype eq 'CODE'; | ||||
| 265 | |||||
| 266 | push @{$self->{+CONTEXT_INIT_CALLBACKS}} => $code; | ||||
| 267 | } | ||||
| 268 | |||||
| 269 | sub add_context_release_callback { | ||||
| 270 | my $self = shift; | ||||
| 271 | my ($code) = @_; | ||||
| 272 | |||||
| 273 | my $rtype = reftype($code) || ""; | ||||
| 274 | |||||
| 275 | confess "Context-release callbacks must be coderefs" | ||||
| 276 | unless $code && $rtype eq 'CODE'; | ||||
| 277 | |||||
| 278 | push @{$self->{+CONTEXT_RELEASE_CALLBACKS}} => $code; | ||||
| 279 | } | ||||
| 280 | |||||
| 281 | # spent 8µs (5+3) within Test2::API::Instance::add_post_load_callback which was called:
# once (5µs+3µs) by Test2::API::test2_add_callback_post_load at line 267 of Test2/API.pm | ||||
| 282 | 1 | 200ns | my $self = shift; | ||
| 283 | 1 | 200ns | my ($code) = @_; | ||
| 284 | |||||
| 285 | 1 | 6µs | 1 | 3µs | my $rtype = reftype($code) || ""; # spent 3µs making 1 call to Scalar::Util::reftype |
| 286 | |||||
| 287 | 1 | 500ns | confess "Post-load callbacks must be coderefs" | ||
| 288 | unless $code && $rtype eq 'CODE'; | ||||
| 289 | |||||
| 290 | 1 | 800ns | push @{$self->{+POST_LOAD_CALLBACKS}} => $code; | ||
| 291 | 1 | 2µs | $code->() if $self->{+LOADED}; | ||
| 292 | } | ||||
| 293 | |||||
| 294 | sub add_pre_subtest_callback { | ||||
| 295 | my $self = shift; | ||||
| 296 | my ($code) = @_; | ||||
| 297 | |||||
| 298 | my $rtype = reftype($code) || ""; | ||||
| 299 | |||||
| 300 | confess "Pre-subtest callbacks must be coderefs" | ||||
| 301 | unless $code && $rtype eq 'CODE'; | ||||
| 302 | |||||
| 303 | push @{$self->{+PRE_SUBTEST_CALLBACKS}} => $code; | ||||
| 304 | } | ||||
| 305 | |||||
| 306 | # spent 485µs (36+449) within Test2::API::Instance::load which was called 3 times, avg 162µs/call:
# 3 times (36µs+449µs) by Test2::API::test2_load at line 204 of Test2/API.pm, avg 162µs/call | ||||
| 307 | 3 | 800ns | my $self = shift; | ||
| 308 | 3 | 1µs | unless ($self->{+LOADED}) { | ||
| 309 | confess "Attempt to initialize Test2::API during preload" | ||||
| 310 | 1 | 300ns | if $self->{+PRELOAD}; | ||
| 311 | |||||
| 312 | 1 | 2µs | $self->{+_PID} = $$ unless defined $self->{+_PID}; | ||
| 313 | 1 | 500ns | $self->{+_TID} = get_tid() unless defined $self->{+_TID}; | ||
| 314 | |||||
| 315 | # This is for https://github.com/Test-More/test-more/issues/16 | ||||
| 316 | # and https://rt.perl.org/Public/Bug/Display.html?id=127774 | ||||
| 317 | # END blocks run in reverse order. This insures the END block is loaded | ||||
| 318 | # as late as possible. It will not solve all cases, but it helps. | ||||
| 319 | 1 | 21µs | eval "END { Test2::API::test2_set_is_end() }; 1" or die $@; # spent 3µs executing statements in string eval # includes 2µs spent executing 1 call to 1 sub defined therein. | ||
| 320 | |||||
| 321 | 1 | 2µs | $self->{+LOADED} = 1; | ||
| 322 | 1 | 2µs | 1 | 449µs | $_->() for @{$self->{+POST_LOAD_CALLBACKS}}; # spent 449µs making 1 call to Test::Builder::__ANON__[Test/Builder.pm:148] |
| 323 | } | ||||
| 324 | 3 | 4µs | return $self->{+LOADED}; | ||
| 325 | } | ||||
| 326 | |||||
| 327 | # spent 3µs (2+200ns) within Test2::API::Instance::add_exit_callback which was called:
# once (2µs+200ns) by Test2::API::test2_add_callback_exit at line 266 of Test2/API.pm | ||||
| 328 | 1 | 100ns | my $self = shift; | ||
| 329 | 1 | 100ns | my ($code) = @_; | ||
| 330 | 1 | 2µs | 1 | 200ns | my $rtype = reftype($code) || ""; # spent 200ns making 1 call to Scalar::Util::reftype |
| 331 | |||||
| 332 | 1 | 500ns | confess "End callbacks must be coderefs" | ||
| 333 | unless $code && $rtype eq 'CODE'; | ||||
| 334 | |||||
| 335 | 1 | 1µs | push @{$self->{+EXIT_CALLBACKS}} => $code; | ||
| 336 | } | ||||
| 337 | |||||
| 338 | sub ipc_disable { | ||||
| 339 | my $self = shift; | ||||
| 340 | |||||
| 341 | confess "Attempt to disable IPC after it has been initialized" | ||||
| 342 | if $self->{+IPC}; | ||||
| 343 | |||||
| 344 | $self->{+IPC_DISABLED} = 1; | ||||
| 345 | } | ||||
| 346 | |||||
| 347 | sub add_ipc_driver { | ||||
| 348 | my $self = shift; | ||||
| 349 | my ($driver) = @_; | ||||
| 350 | unshift @{$self->{+IPC_DRIVERS}} => $driver; | ||||
| 351 | |||||
| 352 | return unless $self->{+FINALIZED}; | ||||
| 353 | |||||
| 354 | # Why is the @CARP_NOT entry not enough? | ||||
| 355 | local %Carp::Internal = %Carp::Internal; | ||||
| 356 | $Carp::Internal{'Test2::IPC::Driver'} = 1; | ||||
| 357 | |||||
| 358 | carp "IPC driver $driver loaded too late to be used as the global ipc driver"; | ||||
| 359 | } | ||||
| 360 | |||||
| 361 | sub enable_ipc_polling { | ||||
| 362 | my $self = shift; | ||||
| 363 | |||||
| 364 | $self->{+_PID} = $$ unless defined $self->{+_PID}; | ||||
| 365 | $self->{+_TID} = get_tid() unless defined $self->{+_TID}; | ||||
| 366 | |||||
| 367 | $self->add_context_init_callback( | ||||
| 368 | # This is called every time a context is created, it needs to be fast. | ||||
| 369 | # $_[0] is a context object | ||||
| 370 | sub { | ||||
| 371 | return unless $self->{+IPC_POLLING}; | ||||
| 372 | return unless $self->{+IPC}; | ||||
| 373 | return unless $self->{+IPC}->pending(); | ||||
| 374 | return $_[0]->{hub}->cull; | ||||
| 375 | } | ||||
| 376 | ) unless defined $self->ipc_polling; | ||||
| 377 | |||||
| 378 | $self->set_ipc_polling(1); | ||||
| 379 | } | ||||
| 380 | |||||
| 381 | sub get_ipc_pending { | ||||
| 382 | my $self = shift; | ||||
| 383 | return -1 unless $self->{+IPC}; | ||||
| 384 | $self->{+IPC}->pending(); | ||||
| 385 | } | ||||
| 386 | |||||
| 387 | sub _check_pid { | ||||
| 388 | my $self = shift; | ||||
| 389 | my ($pid) = @_; | ||||
| 390 | return kill(0, $pid); | ||||
| 391 | } | ||||
| 392 | |||||
| 393 | sub set_ipc_pending { | ||||
| 394 | my $self = shift; | ||||
| 395 | return unless $self->{+IPC}; | ||||
| 396 | my ($val) = @_; | ||||
| 397 | |||||
| 398 | confess "value is required for set_ipc_pending" | ||||
| 399 | unless $val; | ||||
| 400 | |||||
| 401 | $self->{+IPC}->set_pending($val); | ||||
| 402 | } | ||||
| 403 | |||||
| 404 | sub disable_ipc_polling { | ||||
| 405 | my $self = shift; | ||||
| 406 | return unless defined $self->{+IPC_POLLING}; | ||||
| 407 | $self->{+IPC_POLLING} = 0; | ||||
| 408 | } | ||||
| 409 | |||||
| 410 | sub _ipc_wait { | ||||
| 411 | my ($timeout) = @_; | ||||
| 412 | my $fail = 0; | ||||
| 413 | |||||
| 414 | $timeout = DEFAULT_IPC_TIMEOUT() unless defined $timeout; | ||||
| 415 | |||||
| 416 | my $ok = eval { | ||||
| 417 | if (CAN_FORK) { | ||||
| 418 | local $SIG{ALRM} = sub { die "Timeout waiting on child processes" }; | ||||
| 419 | alarm $timeout; | ||||
| 420 | |||||
| 421 | while (1) { | ||||
| 422 | my $pid = CORE::wait(); | ||||
| 423 | my $err = $?; | ||||
| 424 | last if $pid == -1; | ||||
| 425 | next unless $err; | ||||
| 426 | $fail++; | ||||
| 427 | |||||
| 428 | my $sig = $err & 127; | ||||
| 429 | my $exit = $err >> 8; | ||||
| 430 | warn "Process $pid did not exit cleanly (wstat: $err, exit: $exit, sig: $sig)\n"; | ||||
| 431 | } | ||||
| 432 | |||||
| 433 | alarm 0; | ||||
| 434 | } | ||||
| 435 | |||||
| 436 | if (USE_THREADS) { | ||||
| 437 | my $start = time; | ||||
| 438 | |||||
| 439 | while (1) { | ||||
| 440 | last unless threads->list(); | ||||
| 441 | die "Timeout waiting on child thread" if time - $start >= $timeout; | ||||
| 442 | sleep 1; | ||||
| 443 | for my $t (threads->list) { | ||||
| 444 | # threads older than 1.34 do not have this :-( | ||||
| 445 | next if $t->can('is_joinable') && !$t->is_joinable; | ||||
| 446 | $t->join; | ||||
| 447 | # In older threads we cannot check if a thread had an error unless | ||||
| 448 | # we control it and its return. | ||||
| 449 | my $err = $t->can('error') ? $t->error : undef; | ||||
| 450 | next unless $err; | ||||
| 451 | my $tid = $t->tid(); | ||||
| 452 | $fail++; | ||||
| 453 | chomp($err); | ||||
| 454 | warn "Thread $tid did not end cleanly: $err\n"; | ||||
| 455 | } | ||||
| 456 | } | ||||
| 457 | } | ||||
| 458 | |||||
| 459 | 1; | ||||
| 460 | }; | ||||
| 461 | my $error = $@; | ||||
| 462 | |||||
| 463 | return 0 if $ok && !$fail; | ||||
| 464 | warn $error unless $ok; | ||||
| 465 | return 255; | ||||
| 466 | } | ||||
| 467 | |||||
| 468 | # spent 113µs (33+80) within Test2::API::Instance::set_exit which was called:
# once (33µs+80µs) by Test2::API::END at line 56 of Test2/API.pm | ||||
| 469 | 1 | 300ns | my $self = shift; | ||
| 470 | |||||
| 471 | 1 | 400ns | return if $self->{+PRELOAD}; | ||
| 472 | |||||
| 473 | 1 | 600ns | my $exit = $?; | ||
| 474 | 1 | 300ns | my $new_exit = $exit; | ||
| 475 | |||||
| 476 | 1 | 1µs | if ($INC{'Test/Builder.pm'} && $Test::Builder::VERSION ne $Test2::API::VERSION) { | ||
| 477 | print STDERR <<" EOT"; | ||||
| 478 | |||||
| 479 | ******************************************************************************** | ||||
| 480 | * * | ||||
| 481 | * Test::Builder -- Test2::API version mismatch detected * | ||||
| 482 | * * | ||||
| 483 | ******************************************************************************** | ||||
| 484 | Test2::API Version: $Test2::API::VERSION | ||||
| 485 | Test::Builder Version: $Test::Builder::VERSION | ||||
| 486 | |||||
| 487 | This is not a supported configuration, you will have problems. | ||||
| 488 | |||||
| 489 | EOT | ||||
| 490 | } | ||||
| 491 | |||||
| 492 | 1 | 2µs | for my $ctx (values %{$self->{+CONTEXTS}}) { | ||
| 493 | next unless $ctx; | ||||
| 494 | |||||
| 495 | next if $ctx->_aborted && ${$ctx->_aborted}; | ||||
| 496 | |||||
| 497 | # Only worry about contexts in this PID | ||||
| 498 | my $trace = $ctx->trace || next; | ||||
| 499 | next unless $trace->pid && $trace->pid == $$; | ||||
| 500 | |||||
| 501 | # Do not worry about contexts that have no hub | ||||
| 502 | my $hub = $ctx->hub || next; | ||||
| 503 | |||||
| 504 | # Do not worry if the state came to a sudden end. | ||||
| 505 | next if $hub->bailed_out; | ||||
| 506 | next if defined $hub->skip_reason; | ||||
| 507 | |||||
| 508 | # now we worry | ||||
| 509 | $trace->alert("context object was never released! This means a testing tool is behaving very badly"); | ||||
| 510 | |||||
| 511 | $exit = 255; | ||||
| 512 | $new_exit = 255; | ||||
| 513 | } | ||||
| 514 | |||||
| 515 | 1 | 3µs | if (!defined($self->{+_PID}) or !defined($self->{+_TID}) or $self->{+_PID} != $$ or $self->{+_TID} != get_tid()) { | ||
| 516 | $? = $exit; | ||||
| 517 | return; | ||||
| 518 | } | ||||
| 519 | |||||
| 520 | 1 | 2µs | 1 | 2µs | my @hubs = $self->{+STACK} ? $self->{+STACK}->all : (); # spent 2µs making 1 call to Test2::API::Stack::all |
| 521 | |||||
| 522 | 1 | 700ns | if (@hubs and $self->{+IPC} and !$self->{+NO_WAIT}) { | ||
| 523 | local $?; | ||||
| 524 | my %seen; | ||||
| 525 | for my $hub (reverse @hubs) { | ||||
| 526 | my $ipc = $hub->ipc or next; | ||||
| 527 | next if $seen{$ipc}++; | ||||
| 528 | $ipc->waiting(); | ||||
| 529 | } | ||||
| 530 | |||||
| 531 | my $ipc_exit = _ipc_wait($self->{+IPC_TIMEOUT}); | ||||
| 532 | $new_exit ||= $ipc_exit; | ||||
| 533 | } | ||||
| 534 | |||||
| 535 | # None of this is necessary if we never got a root hub | ||||
| 536 | 1 | 800ns | if(my $root = shift @hubs) { | ||
| 537 | 1 | 3µs | 1 | 7µs | my $trace = Test2::EventFacet::Trace->new( # spent 7µs making 1 call to Test2::Util::HashBase::_new |
| 538 | frame => [__PACKAGE__, __FILE__, 0, __PACKAGE__ . '::END'], | ||||
| 539 | detail => __PACKAGE__ . ' END Block finalization', | ||||
| 540 | ); | ||||
| 541 | 1 | 800ns | 1 | 8µs | my $ctx = Test2::API::Context->new( # spent 8µs making 1 call to Test2::Util::HashBase::_new |
| 542 | trace => $trace, | ||||
| 543 | hub => $root, | ||||
| 544 | ); | ||||
| 545 | |||||
| 546 | 1 | 300ns | if (@hubs) { | ||
| 547 | $ctx->diag("Test ended with extra hubs on the stack!"); | ||||
| 548 | $new_exit = 255; | ||||
| 549 | } | ||||
| 550 | |||||
| 551 | 1 | 4µs | 2 | 2µs | unless ($root->no_ending) { # spent 1µs making 1 call to Test2::Util::HashBase::__ANON__[Test2/Util/HashBase.pm:84]
# spent 600ns making 1 call to Test2::API::Context::DESTROY |
| 552 | 1 | 600ns | local $?; | ||
| 553 | 1 | 2µs | 1 | 1µs | $root->finalize($trace) unless $root->ended; # spent 1µs making 1 call to Test2::Util::HashBase::__ANON__[Test2/Util/HashBase.pm:84] |
| 554 | 1 | 14µs | 1 | 58µs | $_->($ctx, $exit, \$new_exit) for @{$self->{+EXIT_CALLBACKS}}; # spent 58µs making 1 call to Test::Builder::__ANON__[Test/Builder.pm:156] |
| 555 | 1 | 1µs | 1 | 300ns | $new_exit ||= $root->failed; # spent 300ns making 1 call to Test2::Util::HashBase::__ANON__[Test2/Util/HashBase.pm:84] |
| 556 | 1 | 1µs | 1 | 2µs | $new_exit ||= 255 unless $root->is_passing; # spent 2µs making 1 call to Test2::Hub::is_passing |
| 557 | } | ||||
| 558 | } | ||||
| 559 | |||||
| 560 | 1 | 300ns | $new_exit = 255 if $new_exit > 255; | ||
| 561 | |||||
| 562 | 1 | 300ns | if ($new_exit && eval { require Test2::API::Breakage; 1 }) { | ||
| 563 | my @warn = Test2::API::Breakage->report(); | ||||
| 564 | |||||
| 565 | if (@warn) { | ||||
| 566 | print STDERR "\nYou have loaded versions of test modules known to have problems with Test2.\nThis could explain some test failures.\n"; | ||||
| 567 | print STDERR "$_\n" for @warn; | ||||
| 568 | print STDERR "\n"; | ||||
| 569 | } | ||||
| 570 | } | ||||
| 571 | |||||
| 572 | 1 | 2µs | $? = $new_exit; | ||
| 573 | } | ||||
| 574 | |||||
| 575 | 1 | 3µs | 1; | ||
| 576 | |||||
| 577 | __END__ |