| Filename | /home/lbr/project/petal-tiny/lib/Petal/Tiny.pm |
| Statements | Executed 454786 statements in 463ms |
| Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
|---|---|---|---|---|---|
| 14960 | 1 | 1 | 70.2ms | 169ms | Petal::Tiny::tag2node |
| 4430 | 3 | 1 | 60.1ms | 70.2ms | Petal::Tiny::resolve (recurses: max depth 1, inclusive time 15.2ms) |
| 4050 | 1 | 1 | 59.5ms | 82.2ms | Petal::Tiny::extract_attributes |
| 50 | 1 | 1 | 48.4ms | 233ms | Petal::Tiny::xml2nodes |
| 34050 | 7 | 1 | 46.1ms | 46.1ms | Petal::Tiny::CORE:match (opcode) |
| 1870 | 3 | 1 | 39.5ms | 229ms | Petal::Tiny::makeitso (recurses: max depth 11, inclusive time 1.48s) |
| 2810 | 2 | 1 | 38.7ms | 228ms | Petal::Tiny::makeitso_node (recurses: max depth 11, inclusive time 1.43s) |
| 1980 | 6 | 1 | 29.5ms | 108ms | Petal::Tiny::resolve_expression |
| 2630 | 1 | 1 | 26.2ms | 26.2ms | Petal::Tiny::node2txt |
| 24140 | 14 | 1 | 19.1ms | 19.1ms | Petal::Tiny::CORE:subst (opcode) |
| 4520 | 1 | 1 | 14.2ms | 15.5ms | Petal::Tiny::_interpolate_dollar |
| 7440 | 2 | 1 | 4.73ms | 4.73ms | Petal::Tiny::reftype |
| 1 | 1 | 1 | 2.89ms | 3.10ms | Petal::Tiny::BEGIN@5 |
| 1960 | 1 | 1 | 2.81ms | 3.22ms | Petal::Tiny::xmlencode |
| 50 | 1 | 1 | 558µs | 462ms | Petal::Tiny::process |
| 150 | 2 | 1 | 471µs | 2.36ms | Petal::Tiny::modifier_true |
| 50 | 1 | 1 | 462µs | 628µs | Petal::Tiny::new |
| 10 | 1 | 1 | 269µs | 1.25ms | Petal::Tiny::_do_repeat |
| 3 | 3 | 1 | 210µs | 210µs | Petal::Tiny::CORE:regcomp (opcode) |
| 60 | 1 | 1 | 190µs | 1.18ms | Petal::Tiny::modifier_false |
| 10 | 1 | 1 | 92µs | 92µs | Petal::Tiny::_deep_copy |
| 10 | 1 | 1 | 47µs | 517µs | Petal::Tiny::__ANON__[lib/Petal/Tiny.pm:127] |
| 20 | 1 | 1 | 18µs | 18µs | Petal::Tiny::CORE:substcont (opcode) |
| 1 | 1 | 1 | 11µs | 16µs | Petal::Tiny::BEGIN@3 |
| 1 | 1 | 1 | 7µs | 16µs | Petal::Tiny::BEGIN@4 |
| 1 | 1 | 1 | 2µs | 2µs | Petal::Tiny::CORE:qr (opcode) |
| 0 | 0 | 0 | 0s | 0s | Petal::Tiny::modifier_string |
| Line | State ments |
Time on line |
Calls | Time in subs |
Code |
|---|---|---|---|---|---|
| 1 | package Petal::Tiny; | ||||
| 2 | |||||
| 3 | 2 | 16µs | 2 | 21µs | # spent 16µs (11+5) within Petal::Tiny::BEGIN@3 which was called:
# once (11µs+5µs) by main::BEGIN@2 at line 3 # spent 16µs making 1 call to Petal::Tiny::BEGIN@3
# spent 5µs making 1 call to warnings::import |
| 4 | 2 | 14µs | 2 | 25µs | # spent 16µs (7+9) within Petal::Tiny::BEGIN@4 which was called:
# once (7µs+9µs) by main::BEGIN@2 at line 4 # spent 16µs making 1 call to Petal::Tiny::BEGIN@4
# spent 9µs making 1 call to strict::import |
| 5 | 2 | 2.23ms | 2 | 3.16ms | # spent 3.10ms (2.89+211µs) within Petal::Tiny::BEGIN@5 which was called:
# once (2.89ms+211µs) by main::BEGIN@2 at line 5 # spent 3.10ms making 1 call to Petal::Tiny::BEGIN@5
# spent 56µs making 1 call to Exporter::import |
| 6 | |||||
| 7 | # REX/Perl 1.0 | ||||
| 8 | # Robert D. Cameron "REX: XML Shallow Parsing with Regular Expressions", | ||||
| 9 | # Technical Report TR 1998-17, School of Computing Science, Simon Fraser | ||||
| 10 | # University, November, 1998. | ||||
| 11 | # Copyright (c) 1998, Robert D. Cameron. | ||||
| 12 | # The following code may be freely used and distributed provided that | ||||
| 13 | # this copyright and citation notice remains intact and that modifications | ||||
| 14 | # or additions are clearly identified. | ||||
| 15 | 1 | 500ns | my $TextSE = "[^<]+"; | ||
| 16 | 1 | 100ns | my $UntilHyphen = "[^-]*-"; | ||
| 17 | 1 | 900ns | my $Until2Hyphens = "$UntilHyphen(?:[^-]$UntilHyphen)*-"; | ||
| 18 | 1 | 500ns | my $CommentCE = "$Until2Hyphens>?"; | ||
| 19 | 1 | 100ns | my $UntilRSBs = "[^\\]]*](?:[^\\]]+])*]+"; | ||
| 20 | 1 | 600ns | my $CDATA_CE = "$UntilRSBs(?:[^\\]>]$UntilRSBs)*>"; | ||
| 21 | 1 | 200ns | my $S = "[ \\n\\t\\r]+"; | ||
| 22 | 1 | 100ns | my $NameStrt = "[A-Za-z_:]|[^\\x00-\\x7F]"; | ||
| 23 | 1 | 100ns | my $NameChar = "[A-Za-z0-9_:.-]|[^\\x00-\\x7F]"; | ||
| 24 | 1 | 600ns | my $Name = "(?:$NameStrt)(?:$NameChar)*"; | ||
| 25 | 1 | 200ns | my $QuoteSE = "\"[^\"]*\"|'[^']*'"; | ||
| 26 | 1 | 2µs | my $DT_IdentSE = "$S$Name(?:$S(?:$Name|$QuoteSE))*"; | ||
| 27 | 1 | 500ns | my $MarkupDeclCE = "(?:[^\\]\"'><]+|$QuoteSE)*>"; | ||
| 28 | 1 | 100ns | my $S1 = "[\\n\\r\\t ]"; | ||
| 29 | 1 | 100ns | my $UntilQMs = "[^?]*\\?+"; | ||
| 30 | 1 | 700ns | my $PI_Tail = "\\?>|$S1$UntilQMs(?:[^>?]$UntilQMs)*>"; | ||
| 31 | 1 | 1µs | my $DT_ItemSE = "<(?:!(?:--$Until2Hyphens>|[^-]$MarkupDeclCE)|\\?$Name(?:$PI_Tail))|%$Name;|$S"; | ||
| 32 | 1 | 1µs | my $DocTypeCE = "$DT_IdentSE(?:$S)?(?:\\[(?:$DT_ItemSE)*](?:$S)?)?>?"; | ||
| 33 | 1 | 1µs | my $DeclCE = "--(?:$CommentCE)?|\\[CDATA\\[(?:$CDATA_CE)?|DOCTYPE(?:$DocTypeCE)?"; | ||
| 34 | 1 | 500ns | my $PI_CE = "$Name(?:$PI_Tail)?"; | ||
| 35 | 1 | 400ns | my $EndTagCE = "$Name(?:$S)?>?"; | ||
| 36 | 1 | 200ns | my $AttValSE = "\"[^<\"]*\"|'[^<']*'"; | ||
| 37 | 1 | 1µs | my $ElemTagCE = "$Name(?:$S$Name(?:$S)?=(?:$S)?(?:$AttValSE))*(?:$S)?/?>?"; | ||
| 38 | 1 | 1µs | my $ElemTagCE_Mod = "$S($Name)(?:$S)?=(?:$S)?($AttValSE)"; | ||
| 39 | 1 | 1µs | my $MarkupSPE = "<(?:!(?:$DeclCE)?|\\?(?:$PI_CE)?|/(?:$EndTagCE)?|(?:$ElemTagCE)?)"; | ||
| 40 | 1 | 2µs | my $XML_SPE = "$TextSE|$MarkupSPE"; | ||
| 41 | # REX END - thank you Robert for this 26 line XML parser - awesome ... | ||||
| 42 | |||||
| 43 | 1 | 44µs | 2 | 34µs | my $ATTR_RE = qr /$ElemTagCE_Mod/; # spent 33µs making 1 call to Petal::Tiny::CORE:regcomp
# spent 2µs making 1 call to Petal::Tiny::CORE:qr |
| 44 | |||||
| 45 | 1 | 200ns | my $DEFAULT_NS = 'petal'; | ||
| 46 | |||||
| 47 | # spent 628µs (462+167) within Petal::Tiny::new which was called 50 times, avg 13µs/call:
# 50 times (462µs+167µs) by main::RUNTIME at line 59 of opt.pl, avg 13µs/call | ||||
| 48 | 50 | 21µs | my $class = shift; | ||
| 49 | 50 | 27µs | $class = ref $class || $class; | ||
| 50 | 50 | 124µs | my $thing = shift; | ||
| 51 | 50 | 52µs | my $self = bless {}, $class; | ||
| 52 | 50 | 313µs | 50 | 167µs | if (defined $thing and $thing =~ /(\<|\n|\>)/) { # spent 167µs making 50 calls to Petal::Tiny::CORE:match, avg 3µs/call |
| 53 | $self->{xmldata} = $thing; | ||||
| 54 | } | ||||
| 55 | elsif (defined $thing) { | ||||
| 56 | open my $xmldatafile, "<", $thing or die "cannot read open $thing"; | ||||
| 57 | $self->{xmldata} = join '', <$xmldatafile>; | ||||
| 58 | close $xmldatafile; | ||||
| 59 | } | ||||
| 60 | 50 | 89µs | return $self; | ||
| 61 | } | ||||
| 62 | |||||
| 63 | |||||
| 64 | # spent 462ms (558µs+462) within Petal::Tiny::process which was called 50 times, avg 9.24ms/call:
# 50 times (558µs+462ms) by main::RUNTIME at line 60 of opt.pl, avg 9.24ms/call | ||||
| 65 | 50 | 14µs | my $self = shift; | ||
| 66 | 50 | 150µs | my $context = { @_ }; | ||
| 67 | 50 | 29µs | my $data = $self->{xmldata}; | ||
| 68 | 50 | 16µs | defined $data or return; # empty data, empty result. | ||
| 69 | 50 | 308µs | 100 | 462ms | return $self->makeitso($self->xml2nodes($data), $context); # earl grey. hot. # spent 233ms making 50 calls to Petal::Tiny::xml2nodes, avg 4.66ms/call
# spent 229ms making 50 calls to Petal::Tiny::makeitso, avg 4.57ms/call |
| 70 | } | ||||
| 71 | |||||
| 72 | # spent 233ms (48.4+185) within Petal::Tiny::xml2nodes which was called 50 times, avg 4.66ms/call:
# 50 times (48.4ms+185ms) by Petal::Tiny::process at line 69, avg 4.66ms/call | ||||
| 73 | 50 | 25µs | my ($self, $xml) = @_; | ||
| 74 | |||||
| 75 | 50 | 16.3ms | 51 | 15.2ms | my @flat = ( $xml =~ /$XML_SPE/og ); # spent 15.0ms making 50 calls to Petal::Tiny::CORE:match, avg 300µs/call
# spent 176µs making 1 call to Petal::Tiny::CORE:regcomp |
| 76 | |||||
| 77 | 50 | 98µs | my $top = { _kids => [], _ns => $DEFAULT_NS }; | ||
| 78 | 50 | 25µs | my @nest = ( $top ); | ||
| 79 | 50 | 39µs | for my $tag (@flat) { | ||
| 80 | 14960 | 9.28ms | 14960 | 169ms | my $node = tag2node($tag, $nest[-1]{_ns}); # if ns is not explicitly set, inherit parent ns # spent 169ms making 14960 calls to Petal::Tiny::tag2node, avg 11µs/call |
| 81 | |||||
| 82 | 14960 | 7.53ms | if ($node->{_close}) { | ||
| 83 | 3220 | 528µs | my $open = pop @nest; | ||
| 84 | 3220 | 804µs | confess "unbalanced close-tag '</$node->{_tag}>'" if $open == $top; | ||
| 85 | 3220 | 1.76ms | confess "wrong close-tag '</$node->{_tag}>' for '<$open->{_tag}>'" if lc($node->{_tag}) ne lc($open->{_tag}); | ||
| 86 | } | ||||
| 87 | else { | ||||
| 88 | 11740 | 4.04ms | push @{ $nest[-1]{_kids} }, $node; | ||
| 89 | 11740 | 2.68ms | push @nest, $node unless ($node->{_simple} or $node->{_selfclose}); | ||
| 90 | } | ||||
| 91 | } | ||||
| 92 | 50 | 28µs | confess "Unbalanced tree, more open than close nodes" if @nest > 1; | ||
| 93 | |||||
| 94 | 50 | 58µs | my @nodes = @{ $top->{_kids} }; | ||
| 95 | |||||
| 96 | 50 | 894µs | return \@nodes; | ||
| 97 | } | ||||
| 98 | |||||
| 99 | # spent 229ms (39.5+189) within Petal::Tiny::makeitso which was called 1870 times, avg 122µs/call:
# 1790 times (32.8ms+-32.8ms) by Petal::Tiny::makeitso_node at line 232, avg 0s/call
# 50 times (327µs+228ms) by Petal::Tiny::process at line 69, avg 4.57ms/call
# 30 times (6.36ms+-6.36ms) by Petal::Tiny::makeitso_node at line 227, avg 0s/call | ||||
| 100 | 1870 | 433µs | my ($self, $nodes, $context) = @_; | ||
| 101 | |||||
| 102 | 1870 | 1.24ms | return "" unless @$nodes; | ||
| 103 | |||||
| 104 | 1100 | 132µs | my @res; | ||
| 105 | 1100 | 453µs | for my $node (@$nodes) { | ||
| 106 | 7320 | 7.38ms | 4520 | 15.5ms | if ($node->{_simple}) { # spent 15.5ms making 4520 calls to Petal::Tiny::_interpolate_dollar, avg 3µs/call |
| 107 | push @res, $self->_interpolate_dollar($context, $node->{_elem}, 'resolve_expression'); | ||||
| 108 | } | ||||
| 109 | else { | ||||
| 110 | 2800 | 2.49ms | 2800 | 228ms | push @res, $self->makeitso_node($node, $context); # spent 1.66s making 2800 calls to Petal::Tiny::makeitso_node, avg 592µs/call, recursion: max depth 11, sum of overlapping time 1.43s |
| 111 | } | ||||
| 112 | } | ||||
| 113 | |||||
| 114 | 1100 | 3.48ms | return join "", @res; | ||
| 115 | } | ||||
| 116 | |||||
| 117 | # spent 15.5ms (14.2+1.28) within Petal::Tiny::_interpolate_dollar which was called 4520 times, avg 3µs/call:
# 4520 times (14.2ms+1.28ms) by Petal::Tiny::makeitso at line 106, avg 3µs/call | ||||
| 118 | 4520 | 1.27ms | my ($self, $context, $string, $method) = @_; | ||
| 119 | |||||
| 120 | 4520 | 11.0ms | 4520 | 710µs | if ($string =~ /\$/) { # spent 710µs making 4520 calls to Petal::Tiny::CORE:match, avg 157ns/call |
| 121 | # spent 517µs (47+470) within Petal::Tiny::__ANON__[lib/Petal/Tiny.pm:127] which was called 10 times, avg 52µs/call:
# 10 times (47µs+470µs) by Petal::Tiny::_interpolate_dollar at line 129, avg 52µs/call | ||||
| 122 | 10 | 7µs | my $what = shift; | ||
| 123 | 10 | 16µs | 10 | 470µs | my $res = $self->$method($what, $context); # spent 470µs making 10 calls to Petal::Tiny::resolve_expression, avg 47µs/call |
| 124 | 10 | 22µs | return $res if defined $res; | ||
| 125 | carp "'$what' in \$-interpolation resolved to undef"; | ||||
| 126 | return ""; | ||||
| 127 | 10 | 35µs | }; | ||
| 128 | |||||
| 129 | 20 | 134µs | 40 | 565µs | $string =~ s/(?<!\$) \$\{ ( [^{}]+ ) \} / $subst->($1) /xegi; # spent 517µs making 10 calls to Petal::Tiny::__ANON__[lib/Petal/Tiny.pm:127], avg 52µs/call
# spent 30µs making 10 calls to Petal::Tiny::CORE:subst, avg 3µs/call
# spent 18µs making 20 calls to Petal::Tiny::CORE:substcont, avg 900ns/call |
| 130 | 10 | 18µs | 10 | 3µs | $string =~ s/(?<!\$) \$\{? ( [a-z0-9-\/:_]+ ) \}? / $subst->($1) /xegi; # spent 3µs making 10 calls to Petal::Tiny::CORE:subst, avg 300ns/call |
| 131 | 10 | 50µs | 10 | 2µs | $string =~ s/\$\$/\$/g; # spent 2µs making 10 calls to Petal::Tiny::CORE:subst, avg 230ns/call |
| 132 | } | ||||
| 133 | 4520 | 20.5ms | return $string; | ||
| 134 | } | ||||
| 135 | |||||
| 136 | # spent 92µs within Petal::Tiny::_deep_copy which was called 10 times, avg 9µs/call:
# 10 times (92µs+0s) by Petal::Tiny::_do_repeat at line 263, avg 9µs/call | ||||
| 137 | 10 | 3µs | my $node = shift; | ||
| 138 | 10 | 51µs | my %copy = %$node; | ||
| 139 | 10 | 3µs | my @kids; | ||
| 140 | 10 | 12µs | for my $kid (@{ $node->{_kids} }) { | ||
| 141 | push @kids, _deep_copy($kid); | ||||
| 142 | } | ||||
| 143 | 10 | 6µs | $copy{_kids} = \@kids; | ||
| 144 | 10 | 31µs | return \%copy; | ||
| 145 | } | ||||
| 146 | |||||
| 147 | sub makeitso_node { | ||||
| 148 | 2810 | 559µs | my ($self, $node, $context) = @_; | ||
| 149 | |||||
| 150 | 2810 | 955µs | my $TAL = $node->{_ns}; | ||
| 151 | |||||
| 152 | 2810 | 396µs | my $STOP_RECURSE = 0; | ||
| 153 | |||||
| 154 | 2810 | 1.02ms | if ($node->{_has_tal}) { | ||
| 155 | 1530 | 512µs | $node->{_change} = 1; | ||
| 156 | |||||
| 157 | 1530 | 950µs | if (defined( my $stuff = delete $node->{"$TAL:on-error"} )) { | ||
| 158 | my $nodeCopy = { %$node }; | ||||
| 159 | my $res = eval { $self->makeitso_node($node, $context); }; | ||||
| 160 | if ($@) { | ||||
| 161 | for my $k (keys %$nodeCopy) { delete $nodeCopy->{$k} if $k =~ /^$TAL:/ } | ||||
| 162 | delete $nodeCopy->{_selfclose}; | ||||
| 163 | $nodeCopy->{_contents} = $self->resolve_expression($stuff, $context); | ||||
| 164 | return node2txt($nodeCopy); | ||||
| 165 | } | ||||
| 166 | return $res; | ||||
| 167 | } | ||||
| 168 | |||||
| 169 | 1530 | 4.37ms | $context = { %$context }; | ||
| 170 | |||||
| 171 | 1530 | 859µs | if (defined( my $stuff = delete $node->{"$TAL:define"} )) { | ||
| 172 | for my $def (split /;(?!;)/, $stuff) { | ||||
| 173 | my ($symbol, $expression) = split ' ', $def, 2; | ||||
| 174 | $context->{$symbol} = $self->resolve_expression($expression, $context); | ||||
| 175 | } | ||||
| 176 | } | ||||
| 177 | |||||
| 178 | 1530 | 937µs | if (defined( my $stuff = delete $node->{"$TAL:condition"} )) { | ||
| 179 | 150 | 140µs | for my $cond (split /;(?!;)/, $stuff) { | ||
| 180 | 150 | 344µs | 150 | 5.91ms | return '' unless $self->resolve_expression($cond, $context); # spent 5.91ms making 150 calls to Petal::Tiny::resolve_expression, avg 39µs/call |
| 181 | } | ||||
| 182 | } | ||||
| 183 | |||||
| 184 | 1440 | 710µs | if (defined( my $stuff = delete $node->{"$TAL:repeat"} )) { | ||
| 185 | 10 | 16µs | my @loops = split /;(?!;)/, $stuff; | ||
| 186 | 10 | 4µs | my $count = 0; | ||
| 187 | 10 | 57µs | 10 | 1.25ms | return join "", $self->_do_repeat(\$count, 1, \@loops, $node, $context); # spent 1.25ms making 10 calls to Petal::Tiny::_do_repeat, avg 125µs/call |
| 188 | } | ||||
| 189 | |||||
| 190 | 1430 | 1.20ms | if (defined( my $stuff = delete $node->{"$TAL:content"} )) { | ||
| 191 | 840 | 700µs | 840 | 39.8ms | my $res = $self->resolve_expression($stuff, $context); # spent 39.8ms making 840 calls to Petal::Tiny::resolve_expression, avg 47µs/call |
| 192 | 840 | 423µs | $node->{_contents} = defined $res ? $res : ""; | ||
| 193 | 840 | 373µs | delete $node->{_selfclose}; | ||
| 194 | |||||
| 195 | # set the stop recurse flag so that if content contains $foo and $bar, | ||||
| 196 | # those aren't interpolated as variables. | ||||
| 197 | 840 | 243µs | $STOP_RECURSE = 1; | ||
| 198 | } | ||||
| 199 | |||||
| 200 | 1430 | 747µs | if (defined( my $stuff = delete $node->{"$TAL:replace"} )) { | ||
| 201 | 50 | 44µs | 50 | 7.58ms | my $res = $self->resolve_expression($stuff, $context); # spent 7.58ms making 50 calls to Petal::Tiny::resolve_expression, avg 152µs/call |
| 202 | 50 | 127µs | return defined $res ? $res : ''; | ||
| 203 | } | ||||
| 204 | |||||
| 205 | 1380 | 1.22ms | if (defined( my $stuff = delete $node->{"$TAL:attributes"} )) { | ||
| 206 | 740 | 947µs | for my $att (split /;(?!;)/, $stuff) { | ||
| 207 | 920 | 783µs | my ($symbol, $expression) = split ' ', $att, 2; | ||
| 208 | 920 | 1.67ms | 920 | 536µs | my $add = ($symbol =~ s/^\+//); # spent 536µs making 920 calls to Petal::Tiny::CORE:subst, avg 583ns/call |
| 209 | 920 | 692µs | 920 | 54.3ms | my $new = $self->resolve_expression($expression, $context); # spent 54.3ms making 920 calls to Petal::Tiny::resolve_expression, avg 59µs/call |
| 210 | 920 | 690µs | if (defined $new) { | ||
| 211 | 320 | 53µs | if ($add) { | ||
| 212 | 50 | 25µs | my $old = $node->{$symbol}; | ||
| 213 | 50 | 18µs | $old = "" unless defined $old; | ||
| 214 | 50 | 28µs | $new = $old . $new; | ||
| 215 | } | ||||
| 216 | 320 | 206µs | $node->{$symbol} = $new; | ||
| 217 | } | ||||
| 218 | else { | ||||
| 219 | 600 | 147µs | delete $node->{$symbol} unless $add; | ||
| 220 | } | ||||
| 221 | } | ||||
| 222 | } | ||||
| 223 | |||||
| 224 | 1380 | 1.08ms | if (defined(my $stuff = delete $node->{"$TAL:omit-tag"})) { | ||
| 225 | 30 | 13µs | if ($stuff eq '' or $self->resolve_expression($stuff, $context)) { | ||
| 226 | 30 | 8µs | return $node->{_contents} if $STOP_RECURSE; | ||
| 227 | 30 | 130µs | 30 | 0s | return $self->makeitso($node->{_kids}, $context); # spent 165ms making 30 calls to Petal::Tiny::makeitso, avg 5.50ms/call, recursion: max depth 4, sum of overlapping time 165ms |
| 228 | } | ||||
| 229 | } | ||||
| 230 | } | ||||
| 231 | |||||
| 232 | 2630 | 2.18ms | 1790 | 0s | unless ($STOP_RECURSE) { # spent 1.32s making 1790 calls to Petal::Tiny::makeitso, avg 737µs/call, recursion: max depth 11, sum of overlapping time 1.32s |
| 233 | $node->{_contents} = $self->makeitso($node->{_kids}, $context); | ||||
| 234 | } | ||||
| 235 | 2630 | 10.8ms | 2630 | 26.2ms | return node2txt($node); # spent 26.2ms making 2630 calls to Petal::Tiny::node2txt, avg 10µs/call |
| 236 | } | ||||
| 237 | |||||
| 238 | # spent 1.25ms (269µs+982µs) within Petal::Tiny::_do_repeat which was called 10 times, avg 125µs/call:
# 10 times (269µs+982µs) by Petal::Tiny::makeitso_node at line 187, avg 125µs/call | ||||
| 239 | 10 | 6µs | my ($self, $count, $last, $loops_ref, $node, $context) = @_; | ||
| 240 | 10 | 9µs | my @loops = @$loops_ref; | ||
| 241 | 10 | 6µs | my $stuff = shift @loops; | ||
| 242 | 10 | 14µs | my ($symbol, $expression) = split ' ', $stuff, 2; | ||
| 243 | 10 | 12µs | 10 | 308µs | my $array = $self->resolve_expression($expression, $context); # spent 308µs making 10 calls to Petal::Tiny::resolve_expression, avg 31µs/call |
| 244 | 10 | 9µs | $array = [ $array ] unless ref $array; # we don't judge | ||
| 245 | 10 | 2µs | my @result; | ||
| 246 | 10 | 18µs | foreach my $idx (0 .. $#$array) { | ||
| 247 | 10 | 4µs | my $item = $array->[$idx]; | ||
| 248 | 10 | 9µs | $context->{$symbol} = $item; | ||
| 249 | 10 | 17µs | if (@loops) { | ||
| 250 | push @result, $self->_do_repeat($count, $last && $idx == $#$array, \@loops, $node, $context); | ||||
| 251 | } | ||||
| 252 | else { | ||||
| 253 | 10 | 5µs | $$count++; | ||
| 254 | 10 | 10µs | $context->{repeat} = {}; | ||
| 255 | 10 | 8µs | $context->{repeat}->{index} = $$count; | ||
| 256 | 10 | 7µs | $context->{repeat}->{number} = $$count; | ||
| 257 | 10 | 14µs | $context->{repeat}->{even} = $$count%2 ? 0 : 1; | ||
| 258 | 10 | 8µs | $context->{repeat}->{odd} = $$count%2 ? 1 : 0; | ||
| 259 | 10 | 11µs | $context->{repeat}->{start} = $$count == 1 ? 1 : 0; | ||
| 260 | 10 | 10µs | $context->{repeat}->{end} = $last && $idx == $#$array ? 1 : 0; | ||
| 261 | 10 | 16µs | $context->{repeat}->{inner} = $context->{repeat}->{start} || $context->{repeat}->{end} ? 0 : 1; | ||
| 262 | |||||
| 263 | 10 | 27µs | 20 | 92µs | push @result, $self->makeitso_node(_deep_copy($node), $context); # spent 92µs making 10 calls to Petal::Tiny::_deep_copy, avg 9µs/call
# spent 582µs making 10 calls to Petal::Tiny::makeitso_node, avg 58µs/call, recursion: max depth 4, sum of overlapping time 582µs |
| 264 | } | ||||
| 265 | } | ||||
| 266 | 10 | 24µs | return @result; | ||
| 267 | } | ||||
| 268 | |||||
| 269 | |||||
| 270 | # spent 108ms (29.5+78.9) within Petal::Tiny::resolve_expression which was called 1980 times, avg 55µs/call:
# 920 times (18.9ms+35.4ms) by Petal::Tiny::makeitso_node at line 209, avg 59µs/call
# 840 times (8.29ms+31.5ms) by Petal::Tiny::makeitso_node at line 191, avg 47µs/call
# 150 times (1.51ms+4.40ms) by Petal::Tiny::makeitso_node at line 180, avg 39µs/call
# 50 times (487µs+7.10ms) by Petal::Tiny::makeitso_node at line 201, avg 152µs/call
# 10 times (108µs+363µs) by Petal::Tiny::__ANON__[lib/Petal/Tiny.pm:127] at line 123, avg 47µs/call
# 10 times (123µs+185µs) by Petal::Tiny::_do_repeat at line 243, avg 31µs/call | ||||
| 271 | 1980 | 495µs | my ($self, $expr, $context) = @_; | ||
| 272 | |||||
| 273 | 1980 | 312µs | $expr = "" unless defined $expr; | ||
| 274 | 1980 | 3.38ms | 1980 | 1.24ms | $expr =~ s/[\n\r]/ /g; # spent 1.24ms making 1980 calls to Petal::Tiny::CORE:subst, avg 626ns/call |
| 275 | 1980 | 2.78ms | 1980 | 905µs | $expr =~ s/^\s+//; # spent 905µs making 1980 calls to Petal::Tiny::CORE:subst, avg 457ns/call |
| 276 | 1980 | 3.25ms | 1980 | 1.43ms | $expr =~ s/\s+$//; # spent 1.43ms making 1980 calls to Petal::Tiny::CORE:subst, avg 724ns/call |
| 277 | |||||
| 278 | 1980 | 2.93ms | 1980 | 1.04ms | $expr =~ s/([;\$])\1/$1/g; # spent 1.04ms making 1980 calls to Petal::Tiny::CORE:subst, avg 525ns/call |
| 279 | 1980 | 390µs | $expr eq 'nothing' and return undef; | ||
| 280 | 1980 | 7.02ms | 1980 | 444µs | $expr =~ s/^fresh\s+//; # spent 444µs making 1980 calls to Petal::Tiny::CORE:subst, avg 224ns/call |
| 281 | 1980 | 2.46ms | 1980 | 424µs | my $structure = ($expr =~ s/^structure\s+//); # spent 424µs making 1980 calls to Petal::Tiny::CORE:subst, avg 214ns/call |
| 282 | 1980 | 1.52ms | 1980 | 70.2ms | my $resolved = $self->resolve($expr, $context); # spent 70.2ms making 1980 calls to Petal::Tiny::resolve, avg 35µs/call |
| 283 | 1980 | 3.84ms | 1960 | 3.22ms | return $structure ? $resolved : xmlencode($resolved); # spent 3.22ms making 1960 calls to Petal::Tiny::xmlencode, avg 2µs/call |
| 284 | } | ||||
| 285 | |||||
| 286 | sub reftype { | ||||
| 287 | 7440 | 1.24ms | my ($self, $obj) = @_; | ||
| 288 | 7440 | 8.01ms | return ref $obj; | ||
| 289 | } | ||||
| 290 | |||||
| 291 | # spent 70.2ms (60.1+10.1) within Petal::Tiny::resolve which was called 4430 times, avg 16µs/call:
# 2300 times (11.1ms+-11.1ms) by Petal::Tiny::resolve at line 307, avg 0s/call
# 1980 times (47.4ms+22.8ms) by Petal::Tiny::resolve_expression at line 282, avg 35µs/call
# 150 times (1.62ms+-1.62ms) by Petal::Tiny::modifier_true at line 366, avg 0s/call | ||||
| 292 | 4430 | 1.03ms | my ($self, $expr, $context) = @_; | ||
| 293 | 4430 | 10.5ms | 4430 | 785µs | $expr =~ /:(?!pattern)/ and do { # XXX what is :pattern? # spent 785µs making 4430 calls to Petal::Tiny::CORE:match, avg 177ns/call |
| 294 | 150 | 191µs | my ($mod, $expr) = split /:(?!pattern)\s*/, $expr, 2; | ||
| 295 | 150 | 490µs | 150 | 198µs | my $meth = $self->can("modifier_$mod"); # spent 198µs making 150 calls to UNIVERSAL::can, avg 1µs/call |
| 296 | 150 | 343µs | 150 | 2.55ms | return $self->$meth($expr, $context) if $meth; # spent 1.37ms making 90 calls to Petal::Tiny::modifier_true, avg 15µs/call
# spent 1.18ms making 60 calls to Petal::Tiny::modifier_false, avg 20µs/call |
| 297 | confess "unknown modifier $mod"; | ||||
| 298 | }; | ||||
| 299 | 4280 | 19.2ms | 4280 | 2.33ms | return $expr if $expr =~ s/^--//; # spent 2.33ms making 4280 calls to Petal::Tiny::CORE:subst, avg 546ns/call |
| 300 | |||||
| 301 | 1980 | 2.10ms | my ($what, @args) = split ' ', $expr; | ||
| 302 | 1980 | 268µs | defined $what or return; | ||
| 303 | |||||
| 304 | 1980 | 1.49ms | my (@path) = split /\//, $what; | ||
| 305 | 1980 | 269µs | my @resolved; | ||
| 306 | 1980 | 332µs | my $obj = $context; | ||
| 307 | 4280 | 3.57ms | 2300 | 0s | @args = map { $self->resolve($_, $context) } @args; # spent 13.3ms making 2300 calls to Petal::Tiny::resolve, avg 6µs/call, recursion: max depth 1, sum of overlapping time 13.3ms |
| 308 | 1980 | 639µs | while (@path) { | ||
| 309 | 3720 | 743µs | my $attribute_or_method = shift @path; | ||
| 310 | 3720 | 882µs | push @resolved, $attribute_or_method; | ||
| 311 | 3720 | 1.20ms | my $resolved = join '/', @resolved; | ||
| 312 | 3720 | 483µs | $obj or confess "cannot fetch $what, because $resolved is undefined"; | ||
| 313 | 3720 | 2.32ms | 3720 | 2.49ms | my $reftype = $self->reftype($obj); # spent 2.49ms making 3720 calls to Petal::Tiny::reftype, avg 668ns/call |
| 314 | 3720 | 434µs | $reftype or confess "cannot fetch $what, because $resolved is not a reference"; | ||
| 315 | |||||
| 316 | 3720 | 1.91ms | if ($reftype eq 'ARRAY') { | ||
| 317 | $obj = $obj->[$attribute_or_method]; | ||||
| 318 | } | ||||
| 319 | elsif ($reftype eq 'HASH') { | ||||
| 320 | $obj = $obj->{$attribute_or_method}; | ||||
| 321 | } | ||||
| 322 | elsif ($obj->can($attribute_or_method)) { | ||||
| 323 | if (@path) { | ||||
| 324 | $obj = $obj->$attribute_or_method(); | ||||
| 325 | } | ||||
| 326 | else { | ||||
| 327 | $obj = $obj->$attribute_or_method(@args); | ||||
| 328 | @args = (); | ||||
| 329 | } | ||||
| 330 | } | ||||
| 331 | |||||
| 332 | # now, check if what we found was a code-ref | ||||
| 333 | 3720 | 2.07ms | 3720 | 2.24ms | $reftype = $self->reftype($obj); # spent 2.24ms making 3720 calls to Petal::Tiny::reftype, avg 603ns/call |
| 334 | 3720 | 847µs | if ($reftype eq 'CODE') { | ||
| 335 | 1730 | 485µs | if (@path) { | ||
| 336 | $obj = $obj->(); | ||||
| 337 | } | ||||
| 338 | else { | ||||
| 339 | 1730 | 1.50ms | 1730 | 1.39ms | $obj = $obj->(@args); # spent 559µs making 560 calls to main::__ANON__[opt.pl:19], avg 998ns/call
# spent 252µs making 450 calls to main::__ANON__[opt.pl:17], avg 560ns/call
# spent 203µs making 290 calls to main::__ANON__[opt.pl:18], avg 700ns/call
# spent 117µs making 180 calls to main::__ANON__[opt.pl:16], avg 651ns/call
# spent 58µs making 50 calls to main::__ANON__[opt.pl:12], avg 1µs/call
# spent 57µs making 60 calls to main::__ANON__[opt.pl:13], avg 955ns/call
# spent 55µs making 80 calls to main::__ANON__[opt.pl:14], avg 682ns/call
# spent 40µs making 30 calls to main::__ANON__[opt.pl:11], avg 1µs/call
# spent 18µs making 10 calls to main::__ANON__[opt.pl:9], avg 2µs/call
# spent 17µs making 10 calls to main::__ANON__[opt.pl:8], avg 2µs/call
# spent 15µs making 10 calls to main::__ANON__[opt.pl:25], avg 2µs/call |
| 340 | 1730 | 542µs | @args = (); | ||
| 341 | } | ||||
| 342 | } | ||||
| 343 | |||||
| 344 | # if we're done with @path and there's a single arg, use it to look up in array/hash | ||||
| 345 | 3720 | 884µs | if (not @path and @args == 1) { | ||
| 346 | $reftype = $self->reftype($obj); | ||||
| 347 | |||||
| 348 | if ($reftype eq 'ARRAY') { | ||||
| 349 | $obj = $obj->[ $args[0] ]; | ||||
| 350 | last; | ||||
| 351 | } | ||||
| 352 | elsif ($reftype eq 'HASH') { | ||||
| 353 | $obj = $obj->{ $args[0] }; | ||||
| 354 | last; | ||||
| 355 | } | ||||
| 356 | } | ||||
| 357 | |||||
| 358 | 3720 | 1.74ms | not @path and @args and confess "cannot resolve expression $expr"; | ||
| 359 | } | ||||
| 360 | 1980 | 2.86ms | return $obj; | ||
| 361 | } | ||||
| 362 | |||||
| 363 | |||||
| 364 | sub modifier_true { | ||||
| 365 | 150 | 52µs | my ($self, $expr, $context) = @_; | ||
| 366 | 150 | 129µs | 150 | 0s | my $arg = $self->resolve($expr, $context); # spent 1.89ms making 150 calls to Petal::Tiny::resolve, avg 13µs/call, recursion: max depth 1, sum of overlapping time 1.89ms |
| 367 | 150 | 44µs | ref $arg and $self->reftype($arg) eq 'ARRAY' and return scalar @$arg; | ||
| 368 | 150 | 230µs | return $arg ? 1 : 0; | ||
| 369 | } | ||||
| 370 | |||||
| 371 | |||||
| 372 | # spent 1.18ms (190µs+986µs) within Petal::Tiny::modifier_false which was called 60 times, avg 20µs/call:
# 60 times (190µs+986µs) by Petal::Tiny::resolve at line 296, avg 20µs/call | ||||
| 373 | 60 | 15µs | my $self = shift; | ||
| 374 | 60 | 147µs | 60 | 986µs | return not $self->modifier_true(@_); # spent 986µs making 60 calls to Petal::Tiny::modifier_true, avg 16µs/call |
| 375 | } | ||||
| 376 | |||||
| 377 | |||||
| 378 | sub modifier_string { | ||||
| 379 | my ($self, $string, $context) = @_; | ||||
| 380 | $string = $self->_interpolate_dollar($context, $string, 'resolve'); | ||||
| 381 | return $string; | ||||
| 382 | } | ||||
| 383 | |||||
| 384 | |||||
| 385 | # spent 26.2ms within Petal::Tiny::node2txt which was called 2630 times, avg 10µs/call:
# 2630 times (26.2ms+0s) by Petal::Tiny::makeitso_node at line 235, avg 10µs/call | ||||
| 386 | 2630 | 425µs | my $node = shift; | ||
| 387 | |||||
| 388 | 2630 | 596µs | return $node unless ref $node eq 'HASH'; # handle textnodes introduced in makeitso_node | ||
| 389 | 2630 | 561µs | return $node->{_elem} if $node->{_simple}; | ||
| 390 | |||||
| 391 | 2630 | 726µs | delete $node->{_ns}; | ||
| 392 | 2630 | 689µs | delete $node->{_has_tal}; | ||
| 393 | 2630 | 4.67ms | delete $node->{_kids}; | ||
| 394 | |||||
| 395 | 2630 | 680µs | my $change = delete $node->{_change}; | ||
| 396 | 2630 | 1.05ms | my $elem = delete $node->{_elem}; | ||
| 397 | 2630 | 884µs | my $tag = delete $node->{_tag}; | ||
| 398 | 2630 | 751µs | my $close = delete $node->{_selfclose}; | ||
| 399 | 2630 | 792µs | my $quotes = delete $node->{_quotes}; | ||
| 400 | 2630 | 865µs | my $contents = delete $node->{_contents}; | ||
| 401 | 8870 | 7.21ms | my $att = join ' ', map { my $q = $quotes->{$_} || '"'; qq|$_=$q$node->{$_}$q| } keys %$node; | ||
| 402 | |||||
| 403 | 2630 | 7.59ms | if ($close) { | ||
| 404 | return $change ? ($att ? "<$tag $att />" : "<$tag />") : $elem; | ||||
| 405 | } | ||||
| 406 | |||||
| 407 | 1910 | 1.02ms | my $start = $change ? ($att ? "<$tag $att>" : "<$tag>") : $elem; | ||
| 408 | 1910 | 803µs | my $end = "</$tag>"; | ||
| 409 | |||||
| 410 | 1910 | 285µs | $contents = "" unless defined $contents; | ||
| 411 | |||||
| 412 | 1910 | 4.16ms | return $start . $contents . $end; | ||
| 413 | } | ||||
| 414 | |||||
| 415 | # spent 169ms (70.2+99.1) within Petal::Tiny::tag2node which was called 14960 times, avg 11µs/call:
# 14960 times (70.2ms+99.1ms) by Petal::Tiny::xml2nodes at line 80, avg 11µs/call | ||||
| 416 | 14960 | 3.38ms | my ($elem, $ns) = @_; | ||
| 417 | |||||
| 418 | 14960 | 36.3ms | 14960 | 17.0ms | if ($elem =~ m,^<(/?)([A-Za-z0-9][A-Za-z0-9_:-]+).*?(/?)>$,) { # spent 17.0ms making 14960 calls to Petal::Tiny::CORE:match, avg 1µs/call |
| 419 | 7270 | 4.14ms | my ($has_close, $tag, $has_self_close) = ($1,$2,$3); | ||
| 420 | |||||
| 421 | 7270 | 5.65ms | return { _tag => $tag, _close => 1 } if $has_close; # don't waste any time on </...> nodes, they're just for book-keeping | ||
| 422 | |||||
| 423 | 4050 | 6.27ms | 4050 | 82.2ms | my %node = extract_attributes($elem); # spent 82.2ms making 4050 calls to Petal::Tiny::extract_attributes, avg 20µs/call |
| 424 | 4050 | 1.41ms | $node{_ns} ||= $ns; | ||
| 425 | |||||
| 426 | 4050 | 2.09ms | $node{_has_tal} = exists $node{_ns_prefix}{ $node{_ns} }; | ||
| 427 | 4050 | 1.43ms | $node{_tag} = $tag; | ||
| 428 | 4050 | 1.35ms | $node{_selfclose} = $has_self_close; | ||
| 429 | 4050 | 1.44ms | $node{_elem} = $elem; | ||
| 430 | 4050 | 1.57ms | $node{_kids} = []; | ||
| 431 | |||||
| 432 | 4050 | 1.53ms | delete $node{_ns_prefix}; | ||
| 433 | |||||
| 434 | 4050 | 15.7ms | return \%node; | ||
| 435 | } | ||||
| 436 | |||||
| 437 | return { | ||||
| 438 | 7690 | 10.5ms | _elem => $elem, | ||
| 439 | _simple => 1, | ||||
| 440 | }; | ||||
| 441 | } | ||||
| 442 | |||||
| 443 | # spent 82.2ms (59.5+22.6) within Petal::Tiny::extract_attributes which was called 4050 times, avg 20µs/call:
# 4050 times (59.5ms+22.6ms) by Petal::Tiny::tag2node at line 423, avg 20µs/call | ||||
| 444 | 4050 | 600µs | my $tag = shift; | ||
| 445 | |||||
| 446 | 4050 | 17.4ms | 4051 | 10.4ms | my %attr = $tag =~ /$ATTR_RE/og; # spent 10.4ms making 4050 calls to Petal::Tiny::CORE:match, avg 3µs/call
# spent 1µs making 1 call to Petal::Tiny::CORE:regcomp |
| 447 | |||||
| 448 | 4050 | 423µs | my (%quotes, %prefix); | ||
| 449 | |||||
| 450 | 4050 | 3.21ms | foreach my $key (keys %attr) { | ||
| 451 | 5990 | 23.1ms | 5990 | 10.2ms | $attr{$key} =~ s/^(['"])(.*?)\1$/$2/; # spent 10.2ms making 5990 calls to Petal::Tiny::CORE:subst, avg 2µs/call |
| 452 | 5990 | 1.81ms | my $q = $1 || '"'; | ||
| 453 | |||||
| 454 | 5990 | 19.6ms | 5990 | 1.97ms | if ($key =~ /^(.*?):/) { # spent 1.97ms making 5990 calls to Petal::Tiny::CORE:match, avg 329ns/call |
| 455 | 2940 | 921µs | if ($1 eq 'xmlns' && $attr{$key} eq 'http://purl.org/petal/1.0/') { | ||
| 456 | 50 | 51µs | delete $attr{$key}; | ||
| 457 | 50 | 153µs | 50 | 78µs | $key =~ s/^xmlns\://; # spent 78µs making 50 calls to Petal::Tiny::CORE:subst, avg 2µs/call |
| 458 | 50 | 31µs | $attr{_ns} = $key; | ||
| 459 | 50 | 19µs | $attr{_change} = 1; | ||
| 460 | 50 | 46µs | next; | ||
| 461 | } | ||||
| 462 | 2890 | 1.71ms | $prefix{$1} = 1; | ||
| 463 | } | ||||
| 464 | 5940 | 4.51ms | $quotes{$key} = $q; | ||
| 465 | } | ||||
| 466 | |||||
| 467 | 4050 | 1.23ms | $attr{_quotes} = \%quotes; | ||
| 468 | 4050 | 950µs | $attr{_ns_prefix} = \%prefix; | ||
| 469 | |||||
| 470 | 4050 | 20.3ms | %attr; | ||
| 471 | } | ||||
| 472 | |||||
| 473 | 1 | 2µs | my %_encode_dict = ( | ||
| 474 | '&' => '&', | ||||
| 475 | '<' => '<', | ||||
| 476 | '>' => '>', | ||||
| 477 | '"' => '"', | ||||
| 478 | "'" => ''', | ||||
| 479 | ); | ||||
| 480 | |||||
| 481 | # spent 3.22ms (2.81+412µs) within Petal::Tiny::xmlencode which was called 1960 times, avg 2µs/call:
# 1960 times (2.81ms+412µs) by Petal::Tiny::resolve_expression at line 283, avg 2µs/call | ||||
| 482 | 1960 | 380µs | my $string = shift; | ||
| 483 | 1960 | 6.91ms | return $string if !$string or ref $string; | ||
| 484 | 990 | 1.43ms | 990 | 412µs | $string =~ s/([&<>"'])/$_encode_dict{$1}/g; # spent 412µs making 990 calls to Petal::Tiny::CORE:subst, avg 416ns/call |
| 485 | 990 | 1.07ms | return $string; | ||
| 486 | } | ||||
| 487 | |||||
| 488 | |||||
| 489 | 1 | 13µs | 1; | ||
| 490 | |||||
| 491 | |||||
| 492 | __END__ | ||||
# spent 46.1ms within Petal::Tiny::CORE:match which was called 34050 times, avg 1µs/call:
# 14960 times (17.0ms+0s) by Petal::Tiny::tag2node at line 418, avg 1µs/call
# 5990 times (1.97ms+0s) by Petal::Tiny::extract_attributes at line 454, avg 329ns/call
# 4520 times (710µs+0s) by Petal::Tiny::_interpolate_dollar at line 120, avg 157ns/call
# 4430 times (785µs+0s) by Petal::Tiny::resolve at line 293, avg 177ns/call
# 4050 times (10.4ms+0s) by Petal::Tiny::extract_attributes at line 446, avg 3µs/call
# 50 times (15.0ms+0s) by Petal::Tiny::xml2nodes at line 75, avg 300µs/call
# 50 times (167µs+0s) by Petal::Tiny::new at line 52, avg 3µs/call | |||||
# spent 2µs within Petal::Tiny::CORE:qr which was called:
# once (2µs+0s) by main::BEGIN@2 at line 43 | |||||
sub Petal::Tiny::CORE:regcomp; # opcode | |||||
# spent 19.1ms within Petal::Tiny::CORE:subst which was called 24140 times, avg 789ns/call:
# 5990 times (10.2ms+0s) by Petal::Tiny::extract_attributes at line 451, avg 2µs/call
# 4280 times (2.33ms+0s) by Petal::Tiny::resolve at line 299, avg 546ns/call
# 1980 times (1.43ms+0s) by Petal::Tiny::resolve_expression at line 276, avg 724ns/call
# 1980 times (1.24ms+0s) by Petal::Tiny::resolve_expression at line 274, avg 626ns/call
# 1980 times (1.04ms+0s) by Petal::Tiny::resolve_expression at line 278, avg 525ns/call
# 1980 times (905µs+0s) by Petal::Tiny::resolve_expression at line 275, avg 457ns/call
# 1980 times (444µs+0s) by Petal::Tiny::resolve_expression at line 280, avg 224ns/call
# 1980 times (424µs+0s) by Petal::Tiny::resolve_expression at line 281, avg 214ns/call
# 990 times (412µs+0s) by Petal::Tiny::xmlencode at line 484, avg 416ns/call
# 920 times (536µs+0s) by Petal::Tiny::makeitso_node at line 208, avg 583ns/call
# 50 times (78µs+0s) by Petal::Tiny::extract_attributes at line 457, avg 2µs/call
# 10 times (30µs+0s) by Petal::Tiny::_interpolate_dollar at line 129, avg 3µs/call
# 10 times (3µs+0s) by Petal::Tiny::_interpolate_dollar at line 130, avg 300ns/call
# 10 times (2µs+0s) by Petal::Tiny::_interpolate_dollar at line 131, avg 230ns/call | |||||
# spent 18µs within Petal::Tiny::CORE:substcont which was called 20 times, avg 900ns/call:
# 20 times (18µs+0s) by Petal::Tiny::_interpolate_dollar at line 129, avg 900ns/call |