Profile of Test2/API/Instance.pm

← Index
NYTProf Performance Profile «line view»
For t/bug-md-11.t
Run on Fri Mar 8 13:27:24 2024
Reported on Fri Mar 8 13:30:23 2024

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

Subroutines
Calls | P | F | Exclusive Time | Inclusive Time | Subroutine
--- | --- | --- | --- | --- | ---
1 | 1 | 1 | 541µs | 2.30ms | Test2::API::Instance::::BEGIN@13Test2::API::Instance::BEGIN@13
1 | 1 | 1 | 400µs | 3.31ms | Test2::API::Instance::::BEGIN@14Test2::API::Instance::BEGIN@14
3 | 1 | 1 | 36µs | 485µs | Test2::API::Instance::::loadTest2::API::Instance::load
1 | 1 | 1 | 33µs | 113µs | Test2::API::Instance::::set_exitTest2::API::Instance::set_exit
1 | 1 | 1 | 11µs | 13µs | Test2::API::Instance::::_finalizeTest2::API::Instance::_finalize
1 | 1 | 1 | 11µs | 13µs | Test2::API::Instance::::BEGIN@2Test2::API::Instance::BEGIN@2
1 | 1 | 1 | 10µs | 11µs | Test2::API::Instance::::resetTest2::API::Instance::reset
1 | 1 | 1 | 10µs | 12µs | Test2::API::Instance::::BEGIN@53Test2::API::Instance::BEGIN@53
1 | 1 | 1 | 8µs | 12µs | Test2::API::Instance::::BEGIN@62Test2::API::Instance::BEGIN@62
1 | 1 | 1 | 7µs | 232µs | Test2::API::Instance::::BEGIN@16Test2::API::Instance::BEGIN@16
2 | 2 | 1 | 6µs | 21µs | Test2::API::Instance::::__ANON__[:60]Test2::API::Instance::__ANON__[:60]
1 | 1 | 1 | 5µs | 8µs | Test2::API::Instance::::add_post_load_callbackTest2::API::Instance::add_post_load_callback
1 | 1 | 1 | 4µs | 35µs | Test2::API::Instance::::BEGIN@11Test2::API::Instance::BEGIN@11
1 | 1 | 1 | 4µs | 24µs | Test2::API::Instance::::BEGIN@8Test2::API::Instance::BEGIN@8
1 | 1 | 1 | 4µs | 28µs | Test2::API::Instance::::BEGIN@63Test2::API::Instance::BEGIN@63
1 | 1 | 1 | 4µs | 22µs | Test2::API::Instance::::BEGIN@3Test2::API::Instance::BEGIN@3
1 | 1 | 1 | 4µs | 16µs | Test2::API::Instance::::BEGIN@9Test2::API::Instance::BEGIN@9
1 | 1 | 1 | 4µs | 26µs | Test2::API::Instance::::importTest2::API::Instance::import
1 | 1 | 1 | 3µs | 3µs | Test2::API::Instance::::add_formatterTest2::API::Instance::add_formatter
1 | 1 | 1 | 2µs | 3µs | Test2::API::Instance::::add_context_acquire_callbackTest2::API::Instance::add_context_acquire_callback
1 | 1 | 1 | 2µs | 3µs | Test2::API::Instance::::add_exit_callbackTest2::API::Instance::add_exit_callback
1 | 1 | 1 | 2µs | 13µs | Test2::API::Instance::::initTest2::API::Instance::init
1 | 1 | 1 | 2µs | 2µs | Test2::API::Instance::::pidTest2::API::Instance::pid
1 | 1 | 1 | 1µs | 1µs | Test2::API::Instance::::tidTest2::API::Instance::tid
1 | 1 | 1 | 1µs | 1µs | Test2::API::Instance::::has_ipcTest2::API::Instance::has_ipc
0 | 0 | 0 | 0s | 0s | Test2::API::Instance::::__ANON__[:195]Test2::API::Instance::__ANON__[:195]
0 | 0 | 0 | 0s | 0s | Test2::API::Instance::::__ANON__[:215]Test2::API::Instance::__ANON__[:215]
0 | 0 | 0 | 0s | 0s | Test2::API::Instance::::__ANON__[:375]Test2::API::Instance::__ANON__[:375]
0 | 0 | 0 | 0s | 0s | Test2::API::Instance::::__ANON__[:418]Test2::API::Instance::__ANON__[:418]
0 | 0 | 0 | 0s | 0s | Test2::API::Instance::::_check_pidTest2::API::Instance::_check_pid
0 | 0 | 0 | 0s | 0s | Test2::API::Instance::::_ipc_waitTest2::API::Instance::_ipc_wait
0 | 0 | 0 | 0s | 0s | Test2::API::Instance::::add_context_init_callbackTest2::API::Instance::add_context_init_callback
0 | 0 | 0 | 0s | 0s | Test2::API::Instance::::add_context_release_callbackTest2::API::Instance::add_context_release_callback
0 | 0 | 0 | 0s | 0s | Test2::API::Instance::::add_ipc_driverTest2::API::Instance::add_ipc_driver
0 | 0 | 0 | 0s | 0s | Test2::API::Instance::::add_pre_subtest_callbackTest2::API::Instance::add_pre_subtest_callback
0 | 0 | 0 | 0s | 0s | Test2::API::Instance::::disable_ipc_pollingTest2::API::Instance::disable_ipc_polling
0 | 0 | 0 | 0s | 0s | Test2::API::Instance::::enable_ipc_pollingTest2::API::Instance::enable_ipc_polling
0 | 0 | 0 | 0s | 0s | Test2::API::Instance::::formatter_setTest2::API::Instance::formatter_set
0 | 0 | 0 | 0s | 0s | Test2::API::Instance::::get_ipc_pendingTest2::API::Instance::get_ipc_pending
0 | 0 | 0 | 0s | 0s | Test2::API::Instance::::ipc_disableTest2::API::Instance::ipc_disable
0 | 0 | 0 | 0s | 0s | Test2::API::Instance::::post_preload_resetTest2::API::Instance::post_preload_reset
0 | 0 | 0 | 0s | 0s | Test2::API::Instance::::set_ipc_pendingTest2::API::Instance::set_ipc_pending
0 | 0 | 0 | 0s | 0s | Test2::API::Instance::::start_preloadTest2::API::Instance::start_preload
0 | 0 | 0 | 0s | 0s | Test2::API::Instance::::stop_preloadTest2::API::Instance::stop_preload
0 | 0 | 0 | 0s | 0s | Test2::API::Instance::::test2_disable_trace_stampsTest2::API::Instance::test2_disable_trace_stamps
0 | 0 | 0 | 0s | 0s | Test2::API::Instance::::test2_enable_trace_stampsTest2::API::Instance::test2_enable_trace_stamps
0 | 0 | 0 | 0s | 0s | Test2::API::Instance::::test2_trace_stamps_enabledTest2::API::Instance::test2_trace_stamps_enabled

Call graph for these subroutines as a Graphviz dot language file.

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 use strict; # 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 use warnings; # 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 use Carp qw/confess carp/; # 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 use Scalar::Util qw/reftype/; # 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 use Test2::Util qw/get_tid USE_THREADS CAN_FORK pkg_to_file try CAN_SIGSYS/; # 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 use Test2::EventFacet::Trace(); # 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 use Test2::API::Stack(); # 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 use Test2::Util::HashBase qw{ # 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 sub pid { $_[0]->{+_PID} }
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 sub tid { $_[0]->{+_TID} }
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 BEGIN {
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 my $new = sub {
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 no strict 'refs'; # 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 no warnings 'redefine'; # 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 sub has_ipc { !!$_[0]->{+IPC} }
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 sub import {
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 sub init { $_[0]->reset } # 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 sub reset {
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 sub _finalize {
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 sub add_formatter {
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 sub add_context_acquire_callback {
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 sub add_post_load_callback {
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 sub load {
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 sub add_exit_callback {
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 sub set_exit {
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__