Profile of lib/Data/DPath/Path.pm

← Index
NYTProf Performance Profile «line view»
For t/optimization.t
Run on Thu Jan 8 22:47:42 2015
Reported on Thu Jan 8 22:48:05 2015

Filename | /home/ss5/local/projects/data-dpath/lib/Data/DPath/Path.pm
Statements | Executed 395 statements in 2.32ms

Subroutines
Calls | P | F | Exclusive Time | Inclusive Time | Subroutine
--- | --- | --- | --- | --- | ---
1 | 1 | 1 | 5.51ms | 12.0ms | Data::DPath::Path::::BEGIN@11Data::DPath::Path::BEGIN@11
1 | 1 | 1 | 4.24ms | 19.4ms | Data::DPath::Path::::BEGIN@7Data::DPath::Path::BEGIN@7
1 | 1 | 1 | 646µs | 3.77ms | Data::DPath::Path::::BEGIN@8Data::DPath::Path::BEGIN@8
4 | 1 | 1 | 448µs | 1.50ms | Data::DPath::Path::::_build__stepsData::DPath::Path::_build__steps
16 | 1 | 1 | 92µs | 103µs | Data::DPath::Path::::unescapeData::DPath::Path::unescape
4 | 1 | 1 | 87µs | 1.58ms | Data::DPath::Path::::newData::DPath::Path::new
46 | 3 | 1 | 80µs | 80µs | Data::DPath::Path::::CORE:matchData::DPath::Path::CORE:match (opcode)
16 | 1 | 1 | 80µs | 99µs | Data::DPath::Path::::quotedData::DPath::Path::quoted
4 | 1 | 1 | 78µs | 4.46ms | Data::DPath::Path::::matchData::DPath::Path::match
4 | 4 | 1 | 26µs | 4.49ms | Data::DPath::Path::::op_matchData::DPath::Path::op_match
1 | 1 | 1 | 17µs | 71µs | Data::DPath::Path::::BEGIN@4Data::DPath::Path::BEGIN@4
1 | 1 | 1 | 15µs | 196µs | Data::DPath::Path::::BEGIN@14Data::DPath::Path::BEGIN@14
1 | 1 | 1 | 15µs | 149µs | Data::DPath::Path::::BEGIN@21Data::DPath::Path::BEGIN@21
1 | 1 | 1 | 13µs | 27µs | Data::DPath::Path::::BEGIN@115Data::DPath::Path::BEGIN@115
32 | 2 | 1 | 11µs | 11µs | Data::DPath::Path::::CORE:substData::DPath::Path::CORE:subst (opcode)
1 | 1 | 1 | 11µs | 16µs | Data::DPath::Path::::BEGIN@5Data::DPath::Path::BEGIN@5
1 | 1 | 1 | 11µs | 46.6ms | Data::DPath::Path::::BEGIN@10Data::DPath::Path::BEGIN@10
1 | 1 | 1 | 9µs | 551µs | Data::DPath::Path::::BEGIN@9Data::DPath::Path::BEGIN@9
1 | 1 | 1 | 7µs | 7µs | Data::DPath::Path::::pathData::DPath::Path::path (xsub)
2 | 2 | 2 | 2µs | 2µs | Data::DPath::Path::::_stepsData::DPath::Path::_steps (xsub)
1 | 1 | 1 | 700ns | 700ns | Data::DPath::Path::::give_referencesData::DPath::Path::give_references (xsub)
0 | 0 | 0 | 0s | 0s | Data::DPath::Path::::unquoteData::DPath::Path::unquote

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

Line | State ments | Time on line | Calls | Time in subs | Code
--- | --- | --- | --- | --- | ---
1 |  |  |  |  | package Data::DPath::Path;
2 |  |  |  |  | # ABSTRACT: Abstraction for a DPath
3 |  |  |  |  |
4 | 2 | 36µs | 2 | 124µs | # spent 71µs (17+54) within Data::DPath::Path::BEGIN@4 which was called: # once (17µs+54µs) by Data::DPath::BEGIN@12 at line 4 use strict; # spent 71µs making 1 call to Data::DPath::Path::BEGIN@4 # spent 54µs making 1 call to strict::import
5 | 2 | 25µs | 2 | 22µs | # spent 16µs (11+5) within Data::DPath::Path::BEGIN@5 which was called: # once (11µs+5µs) by Data::DPath::BEGIN@12 at line 5 use warnings; # spent 16µs making 1 call to Data::DPath::Path::BEGIN@5 # spent 5µs making 1 call to warnings::import
6 |  |  |  |  |
7 | 2 | 128µs | 2 | 19.5ms | # spent 19.4ms (4.24+15.2) within Data::DPath::Path::BEGIN@7 which was called: # once (4.24ms+15.2ms) by Data::DPath::BEGIN@12 at line 7 use Data::Dumper; # spent 19.4ms making 1 call to Data::DPath::Path::BEGIN@7 # spent 42µs making 1 call to Exporter::import
8 | 2 | 135µs | 2 | 6.84ms | # spent 3.77ms (646µs+3.13) within Data::DPath::Path::BEGIN@8 which was called: # once (646µs+3.13ms) by Data::DPath::BEGIN@12 at line 8 use aliased 'Data::DPath::Step'; # spent 3.77ms making 1 call to Data::DPath::Path::BEGIN@8 # spent 3.07ms making 1 call to aliased::import
9 | 2 | 31µs | 2 | 1.09ms | # spent 551µs (9+542) within Data::DPath::Path::BEGIN@9 which was called: # once (9µs+542µs) by Data::DPath::BEGIN@12 at line 9 use aliased 'Data::DPath::Point'; # spent 551µs making 1 call to Data::DPath::Path::BEGIN@9 # spent 542µs making 1 call to aliased::import
10 | 2 | 40µs | 2 | 93.1ms | # spent 46.6ms (11µs+46.6) within Data::DPath::Path::BEGIN@10 which was called: # once (11µs+46.6ms) by Data::DPath::BEGIN@12 at line 10 use aliased 'Data::DPath::Context'; # spent 46.6ms making 1 call to Data::DPath::Path::BEGIN@10 # spent 46.6ms making 1 call to aliased::import
11 | 3 | 160µs | 3 | 12.1ms | # spent 12.0ms (5.51+6.49) within Data::DPath::Path::BEGIN@11 which was called: # once (5.51ms+6.49ms) by Data::DPath::BEGIN@12 at line 11 use Text::Balanced 2.02 'extract_delimited', 'extract_codeblock'; # spent 12.0ms making 1 call to Data::DPath::Path::BEGIN@11 # spent 74µs making 1 call to Exporter::import # spent 12µs making 1 call to UNIVERSAL::VERSION
12 |  |  |  |  |
13 |  |  |  |  | use Class::XSAccessor
14 | 1 | 11µs | 1 | 181µs | # spent 196µs (15+181) within Data::DPath::Path::BEGIN@14 which was called: # once (15µs+181µs) by Data::DPath::BEGIN@12 at line 19 chained => 1, # spent 181µs making 1 call to Class::XSAccessor::import
15 |  |  |  |  | accessors => {
16 |  |  |  |  | path => 'path',
17 |  |  |  |  | _steps => '_steps',
18 |  |  |  |  | give_references => 'give_references',
19 | 1 | 45µs | 1 | 196µs | }; # spent 196µs making 1 call to Data::DPath::Path::BEGIN@14
20 |  |  |  |  |
21 | 1 | 11µs | 1 | 134µs | # spent 149µs (15+134) within Data::DPath::Path::BEGIN@21 which was called: # once (15µs+134µs) by Data::DPath::BEGIN@12 at line 29 use constant { ROOT => 'ROOT', # spent 134µs making 1 call to constant::import
22 |  |  |  |  | ANYWHERE => 'ANYWHERE',
23 |  |  |  |  | KEY => 'KEY',
24 |  |  |  |  | ANYSTEP => 'ANYSTEP',
25 |  |  |  |  | NOSTEP => 'NOSTEP',
26 |  |  |  |  | PARENT => 'PARENT',
27 |  |  |  |  | ANCESTOR => 'ANCESTOR',
28 |  |  |  |  | ANCESTOR_OR_SELF => 'ANCESTOR_OR_SELF',
29 | 1 | 460µs | 1 | 149µs | }; # spent 149µs making 1 call to Data::DPath::Path::BEGIN@21
30 |  |  |  |  |
31 |  |  |  |  | # spent 1.58ms (87µs+1.50) within Data::DPath::Path::new which was called 4 times, avg 396µs/call: # 4 times (87µs+1.50ms) by Data::DPath::__ANON__[lib/Data/DPath.pm:19] at line 18 of lib/Data/DPath.pm, avg 396µs/call sub new {
32 | 4 | 2µs |  |  | my $class = shift;
33 | 4 | 66µs |  |  | my $self = bless { @_ }, $class;
34 | 4 | 6µs | 4 | 1.50ms | $self->_build__steps; # spent 1.50ms making 4 calls to Data::DPath::Path::_build__steps, avg 374µs/call
35 | 4 | 11µs |  |  | return $self;
36 |  |  |  |  | }
37 |  |  |  |  |
38 |  |  |  |  | # spent 103µs (92+11) within Data::DPath::Path::unescape which was called 16 times, avg 6µs/call: # 16 times (92µs+11µs) by Data::DPath::Path::_build__steps at line 112, avg 6µs/call sub unescape {
39 | 16 | 9µs |  |  | my ($str) = @_;
40 |  |  |  |  |
41 | 16 | 4µs |  |  | return unless defined $str;
42 | 16 | 38µs | 16 | 7µs | $str =~ s/(?<!\\)\\(["'])/$1/g; # '"$ # spent 7µs making 16 calls to Data::DPath::Path::CORE:subst, avg 444ns/call
43 | 16 | 28µs | 16 | 4µs | $str =~ s/\\{2}/\\/g; # spent 4µs making 16 calls to Data::DPath::Path::CORE:subst, avg 250ns/call
44 | 16 | 35µs |  |  | return $str;
45 |  |  |  |  | }
46 |  |  |  |  |
47 |  |  |  |  | sub unquote {
48 |  |  |  |  | my ($str) = @_;
49 |  |  |  |  | $str =~ s/^"(.*)"$/$1/g;
50 |  |  |  |  | return $str;
51 |  |  |  |  | }
52 |  |  |  |  |
53 | 16 | 119µs | 16 | 20µs | # spent 99µs (80+20) within Data::DPath::Path::quoted which was called 16 times, avg 6µs/call: # 16 times (80µs+20µs) by Data::DPath::Path::_build__steps at line 77, avg 6µs/call sub quoted { shift =~ m,^/["'],; } # " # spent 20µs making 16 calls to Data::DPath::Path::CORE:match, avg 1µs/call
54 |  |  |  |  |
55 | 1 | 39µs |  |  | eval 'use overload "~~" => \&op_match' if $] >= 5.010; # spent 40µs executing statements in string eval # includes 14µs spent executing 1 call to 1 sub defined therein.
56 |  |  |  |  |
57 |  |  |  |  | # spent 4.49ms (26µs+4.46) within Data::DPath::Path::op_match which was called 4 times, avg 1.12ms/call: # once (8µs+2.22ms) by main::RUNTIME at line 73 of t/optimization.t # once (5µs+1.92ms) by main::RUNTIME at line 39 of t/optimization.t # once (7µs+217µs) by main::RUNTIME at line 36 of t/optimization.t # once (6µs+99µs) by main::RUNTIME at line 70 of t/optimization.t sub op_match {
58 | 4 | 4µs |  |  | my ($self, $data, $rhs) = @_;
59 |  |  |  |  |
60 | 4 | 24µs | 4 | 4.46ms | return [ $self->match( $data ) ]; # spent 4.46ms making 4 calls to Data::DPath::Path::match, avg 1.12ms/call
61 |  |  |  |  | }
62 |  |  |  |  |
63 |  |  |  |  | # essentially the Path parser
64 |  |  |  |  | # spent 1.50ms (448µs+1.05) within Data::DPath::Path::_build__steps which was called 4 times, avg 374µs/call: # 4 times (448µs+1.05ms) by Data::DPath::Path::new at line 34, avg 374µs/call sub _build__steps {
65 | 4 | 3µs |  |  | my ($self) = @_;
66 |  |  |  |  |
67 | 4 | 21µs | 1 | 7µs | my $remaining_path = $self->path; # spent 7µs making 1 call to Data::DPath::Path::path
68 | 4 | 800ns |  |  | my $extracted;
69 | 4 | 1µs |  |  | my @steps;
70 |  |  |  |  |
71 | 4 | 56µs | 3 | 14µs | push @steps, Step->new->part('')->kind(ROOT); # spent 9µs making 1 call to Data::DPath::Step::new # spent 4µs making 1 call to Data::DPath::Step::part # spent 900ns making 1 call to Data::DPath::Step::kind
72 |  |  |  |  |
73 | 4 | 2µs |  |  | while ($remaining_path) {
74 | 16 | 3µs |  |  | my $plain_part;
75 | 16 | 2µs |  |  | my $filter;
76 | 16 | 2µs |  |  | my $kind;
77 | 16 | 26µs | 16 | 99µs | if ( quoted($remaining_path) ) { # spent 99µs making 16 calls to Data::DPath::Path::quoted, avg 6µs/call
78 |  |  |  |  | ($plain_part, $remaining_path) = extract_delimited($remaining_path, q/'"/, "/"); # '
79 |  |  |  |  | ($filter, $remaining_path) = extract_codeblock($remaining_path, "[]");
80 |  |  |  |  | $plain_part = unescape unquote $plain_part;
81 |  |  |  |  | $kind = KEY; # quoted is always a key
82 |  |  |  |  | }
83 |  |  |  |  | else
84 |  |  |  |  | {
85 | 16 | 5µs |  |  | my $filter_already_extracted = 0;
86 | 16 | 44µs | 16 | 760µs | ($extracted, $remaining_path) = extract_delimited($remaining_path,'/'); # spent 760µs making 16 calls to Text::Balanced::extract_delimited, avg 47µs/call
87 |  |  |  |  |
88 | 16 | 11µs |  |  | if (not $extracted) {
89 |  |  |  |  | ($extracted, $remaining_path) = ($remaining_path, undef); # END OF PATH
90 |  |  |  |  | } else {
91 |  |  |  |  |
92 |  |  |  |  | # work around to recognize slashes in filter expressions and handle them:
93 |  |  |  |  | #
94 |  |  |  |  | # - 1) see if key unexpectedly contains opening "[" but no closing "]"
95 |  |  |  |  | # - 2) use the part before "["
96 |  |  |  |  | # - 3) unshift the rest to remaining
97 |  |  |  |  | # - 4) extract_codeblock() explicitely
98 | 12 | 50µs | 14 | 18µs | if ($extracted =~ /(.*)((?<!\\)\[.*)/ and $extracted !~ m|\]/\s*$|) { # spent 18µs making 14 calls to Data::DPath::Path::CORE:match, avg 1µs/call
99 |  |  |  |  | $remaining_path = $2 . $remaining_path;
100 |  |  |  |  | ( $plain_part = $1 ) =~ s|^/||;
101 |  |  |  |  | ($filter, $remaining_path) = extract_codeblock($remaining_path, "[]");
102 |  |  |  |  | $filter_already_extracted = 1;
103 |  |  |  |  | } else {
104 | 12 | 13µs |  |  | $remaining_path = (chop $extracted) . $remaining_path;
105 |  |  |  |  | }
106 |  |  |  |  | }
107 |  |  |  |  |
108 | 16 | 91µs | 16 | 42µs | ($plain_part, $filter) = $extracted =~ m,^/ # leading / # spent 42µs making 16 calls to Data::DPath::Path::CORE:match, avg 3µs/call
109 |  |  |  |  | (.*?) # path part
110 |  |  |  |  | (\[.*\])?$ # optional filter
111 |  |  |  |  | ,xg unless $filter_already_extracted;
112 | 16 | 28µs | 16 | 103µs | $plain_part = unescape $plain_part; # spent 103µs making 16 calls to Data::DPath::Path::unescape, avg 6µs/call
113 |  |  |  |  | }
114 |  |  |  |  |
115 | 2 | 250µs | 2 | 41µs | # spent 27µs (13+14) within Data::DPath::Path::BEGIN@115 which was called: # once (13µs+14µs) by Data::DPath::BEGIN@12 at line 115 no warnings 'uninitialized'; # spent 27µs making 1 call to Data::DPath::Path::BEGIN@115 # spent 14µs making 1 call to warnings::unimport
116 | 16 | 16µs |  |  | if ($plain_part eq '') { $kind ||= ANYWHERE }
117 |  |  |  |  | elsif ($plain_part eq '*') { $kind ||= ANYSTEP }
118 |  |  |  |  | elsif ($plain_part eq '.') { $kind ||= NOSTEP }
119 |  |  |  |  | elsif ($plain_part eq '..') { $kind ||= PARENT }
120 |  |  |  |  | elsif ($plain_part eq '::ancestor') { $kind ||= ANCESTOR }
121 |  |  |  |  | elsif ($plain_part eq '::ancestor-or-self') { $kind ||= ANCESTOR_OR_SELF }
122 | 8 | 3µs |  |  | else { $kind ||= KEY }
123 |  |  |  |  |
124 | 16 | 96µs | 4 | 4µs | push @steps, Step->new->part($plain_part)->kind($kind)->filter($filter); # spent 2µs making 1 call to Data::DPath::Step::new # spent 1µs making 1 call to Data::DPath::Step::part # spent 700ns making 1 call to Data::DPath::Step::filter # spent 700ns making 1 call to Data::DPath::Step::kind
125 |  |  |  |  | }
126 | 4 | 8µs | 1 | 2µs | pop @steps if $steps[-1]->kind eq ANYWHERE; # ignore final '/' # spent 2µs making 1 call to Data::DPath::Step::kind
127 | 4 | 20µs | 1 | 1µs | $self->_steps( \@steps ); # spent 1µs making 1 call to Data::DPath::Path::_steps
128 |  |  |  |  | }
129 |  |  |  |  |
130 |  |  |  |  | # spent 4.46ms (78µs+4.38) within Data::DPath::Path::match which was called 4 times, avg 1.12ms/call: # 4 times (78µs+4.38ms) by Data::DPath::Path::op_match at line 60, avg 1.12ms/call sub match {
131 | 4 | 3µs |  |  | my ($self, $data) = @_;
132 |  |  |  |  |
133 | 4 | 74µs | 6 | 14µs | my $context = Context # spent 6µs making 1 call to Data::DPath::Point::new # spent 5µs making 1 call to Data::DPath::Context::new # spent 1µs making 1 call to Data::DPath::Point::ref # spent 800ns making 1 call to Data::DPath::Context::current_points # spent 700ns making 1 call to Data::DPath::Path::give_references # spent 600ns making 1 call to Data::DPath::Context::give_references
134 |  |  |  |  | ->new
135 |  |  |  |  | ->current_points([ Point->new->ref(\$data) ])
136 |  |  |  |  | ->give_references($self->give_references);
137 | 4 | 17µs | 4 | 4.37ms | return $context->match($self); # spent 4.37ms making 4 calls to Data::DPath::Context::match, avg 1.09ms/call
138 |  |  |  |  | }
139 |  |  |  |  |
140 | 1 | 4µs |  |  | 1;
141 |  |  |  |  |
142 |  |  |  |  | __END__
|  |  |  |  | # spent 80µs within Data::DPath::Path::CORE:match which was called 46 times, avg 2µs/call: # 16 times (42µs+0s) by Data::DPath::Path::_build__steps at line 108, avg 3µs/call # 16 times (20µs+0s) by Data::DPath::Path::quoted at line 53, avg 1µs/call # 14 times (18µs+0s) by Data::DPath::Path::_build__steps at line 98, avg 1µs/call sub Data::DPath::Path::CORE:match; # opcode
|  |  |  |  | # spent 11µs within Data::DPath::Path::CORE:subst which was called 32 times, avg 347ns/call: # 16 times (7µs+0s) by Data::DPath::Path::unescape at line 42, avg 444ns/call # 16 times (4µs+0s) by Data::DPath::Path::unescape at line 43, avg 250ns/call sub Data::DPath::Path::CORE:subst; # opcode
|  |  |  |  | # spent 2µs within Data::DPath::Path::_steps which was called 2 times, avg 900ns/call: # once (1µs+0s) by Data::DPath::Path::_build__steps at line 127 # once (700ns+0s) by Data::DPath::Context::_search at line 418 of lib/Data/DPath/Context.pm sub Data::DPath::Path::_steps; # xsub
|  |  |  |  | # spent 700ns within Data::DPath::Path::give_references which was called: # once (700ns+0s) by Data::DPath::Path::match at line 133 sub Data::DPath::Path::give_references; # xsub
|  |  |  |  | # spent 7µs within Data::DPath::Path::path which was called: # once (7µs+0s) by Data::DPath::Path::_build__steps at line 67 sub Data::DPath::Path::path; # xsub