← Index
NYTProf Performance Profile   « block view • line view • sub view »
For /usr/local/src/github.com/foswiki/core/bin/view
  Run on Sun Dec 4 17:17:59 2011
Reported on Sun Dec 4 17:27:03 2011

Filename/usr/local/src/github.com/foswiki/core/lib/Foswiki/Configure/Load.pm
StatementsExecuted 2046 statements in 24.4ms
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
11111.7ms24.5msFoswiki::Configure::Load::::readConfigFoswiki::Configure::Load::readConfig
5964211.2ms12.8msFoswiki::Configure::Load::::expandValueFoswiki::Configure::Load::expandValue (recurses: max depth 4, inclusive time 26.6ms)
46711788µs788µsFoswiki::Configure::Load::::CORE:substFoswiki::Configure::Load::CORE:subst (opcode)
2011766µs766µsFoswiki::Configure::Load::::_handleExpandFoswiki::Configure::Load::_handleExpand
3311107µs107µsFoswiki::Configure::Load::::CORE:substcontFoswiki::Configure::Load::CORE:substcont (opcode)
11128µs35µsFoswiki::Configure::Load::::BEGIN@14Foswiki::Configure::Load::BEGIN@14
44120µs20µsFoswiki::Configure::Load::::CORE:qrFoswiki::Configure::Load::CORE:qr (opcode)
11118µs47µsFoswiki::Configure::Load::::BEGIN@15Foswiki::Configure::Load::BEGIN@15
0000s0sFoswiki::Configure::Load::::_loadDefaultsFromFoswiki::Configure::Load::_loadDefaultsFrom
0000s0sFoswiki::Configure::Load::::mergeHashFoswiki::Configure::Load::mergeHash
0000s0sFoswiki::Configure::Load::::readDefaultsFoswiki::Configure::Load::readDefaults
Call graph for these subroutines as a Graphviz dot language file.
Line State
ments
Time
on line
Calls Time
in subs
Code
1# See bottom of file for license and copyright information
2
3=begin TML
4
5---+ package Foswiki::Configure::Load
6
7Handling for loading configuration information (Foswiki.spec, Config.spec and
8LocalSite.cfg) as efficiently and flexibly as possible.
9
10=cut
11
12package Foswiki::Configure::Load;
13
14251µs243µs
# spent 35µs (28+8) within Foswiki::Configure::Load::BEGIN@14 which was called: # once (28µs+8µs) by Foswiki::BEGIN@51 at line 14
use strict;
# spent 35µs making 1 call to Foswiki::Configure::Load::BEGIN@14 # spent 8µs making 1 call to strict::import
1521.81ms276µs
# spent 47µs (18+29) within Foswiki::Configure::Load::BEGIN@15 which was called: # once (18µs+29µs) by Foswiki::BEGIN@51 at line 15
use warnings;
# spent 47µs making 1 call to Foswiki::Configure::Load::BEGIN@15 # spent 29µs making 1 call to warnings::import
16
1712µsour $TRUE = 1;
1811µsour $FALSE = 0;
19
20# Configuration items that have been deprecated and must be mapped to
21# new configuration items. The value is mapped unchanged.
2216µsour %remap = (
23 '{StoreImpl}' => '{Store}{Implementation}',
24 '{AutoAttachPubFiles}' => '{RCS}{AutoAttachPubFiles}',
25 '{QueryAlgorithm}' => '{Store}{QueryAlgorithm}',
26 '{SearchAlgorithm}' => '{Store}{SearchAlgorithm}',
27 '{RCS}{FgrepCmd}' => '{Store}{FgrepCmd}',
28 '{RCS}{EgrepCmd}' => '{Store}{EgrepCmd}',
29);
30
31=begin TML
32
33---++ StaticMethod readConfig([$noexpand])
34
35In normal Foswiki operations as a web server this method is called by the
36=BEGIN= block of =Foswiki.pm=. However, when benchmarking/debugging it can be
37replaced by custom code which sets the configuration hash. To prevent us from
38overriding the custom code again, we use an "unconfigurable" key
39=$cfg{ConfigurationFinished}= as an indicator.
40
41Note that this method is called by Foswiki and configure, and *only* reads
42Foswiki.spec= to get defaults. Other spec files (those for extensions) are
43*not* read.
44
45The assumption is that =configure= will be run when an extension is installed,
46and that will add the config values to LocalSite.cfg, so no defaults are
47needed. Foswiki.spec is still read because so much of the core code doesn't
48provide defaults, and it would be silly to have them in two places anyway.
49
50$noexpand can be set to suppress expansion of $Foswiki vars embedded in
51values.
52
53=cut
54
55
# spent 24.5ms (11.7+12.8) within Foswiki::Configure::Load::readConfig which was called: # once (11.7ms+12.8ms) by Foswiki::BEGIN@134 at line 331 of /usr/local/src/github.com/foswiki/core/lib/Foswiki.pm
sub readConfig {
5612µs my $noexpand = shift;
57
5812µs return if $Foswiki::cfg{ConfigurationFinished};
5912µs my $validLSC =
60 1; # Assume it's valid - will be set false if errors detected.
61
62 # Read Foswiki.spec and LocalSite.cfg
6314µs for my $file (qw( Foswiki.spec LocalSite.cfg)) {
6429.46ms unless ( my $return = do $file ) {
65 my $errorMessage;
66 if ($@) {
67 $errorMessage = "Could not parse $file: $@";
68 print STDERR "$errorMessage \n";
69 }
70 elsif ( not defined $return ) {
71 print STDERR
72"Could not 'do' $file: $! \n - This might be okay if file LocalSite.cfg does not exist in a new installation.\n";
73 unless ( $! == 2 && $file eq 'LocalSite.cfg' ) {
74
75 # LocalSite.cfg doesn't exist, which is OK
76 $errorMessage = "Could not do $file: $!";
77 }
78 $validLSC = 0;
79 }
80 elsif ( not $return eq '1' ) {
81 print STDERR
82 "Running file $file returned unexpected results: $return \n";
83 $errorMessage = "Could not run $file" unless $return;
84 }
85 if ($errorMessage) {
86 die <<GOLLYGOSH;
87Content-type: text/plain
88
89$errorMessage
90Please inform the site admin.
91GOLLYGOSH
92 exit 1;
93 }
94 }
95 }
96
97 # If we got this far without definitions for key variables, then
98 # we need to default them. otherwise we get peppered with
99 # 'uninitialised variable' alerts later.
100
10117µs foreach my $var (
102 qw( DataDir DefaultUrlHost PubUrlPath ToolsDir WorkingDir
103 PubDir TemplateDir ScriptDir ScriptUrlPath LocalesDir )
104 )
105 {
106
107 # We can't do this, because it prevents Foswiki being run without
108 # a LocalSite.cfg, which we don't want
109 # die "$var must be defined in LocalSite.cfg"
110 # unless( defined $Foswiki::cfg{$var} );
1111030µs unless ( defined $Foswiki::cfg{$var} ) {
112 $Foswiki::cfg{$var} = 'NOT SET';
113 $validLSC = 0;
114 }
115 }
116
117 # Patch deprecated config settings
11812µs if ( exists $Foswiki::cfg{StoreImpl} ) {
119 $Foswiki::cfg{Store}{Implementation} =
120 'Foswiki::Store::' . $Foswiki::cfg{StoreImpl};
121 delete $Foswiki::cfg{StoreImpl};
122 }
123114µs foreach my $el ( keys %remap ) {
1246244µs if ( eval 'exists $Foswiki::cfg' . $el ) {
# spent 6µs executing statements in string eval # spent 6µs executing statements in string eval # spent 6µs executing statements in string eval # spent 5µs executing statements in string eval # spent 5µs executing statements in string eval # spent 5µs executing statements in string eval
125 eval <<CODE;
126\$Foswiki::cfg$remap{$el}=\$Foswiki::cfg$el;
127delete \$Foswiki::cfg$el;
128CODE
129 }
130 }
131
132 # Expand references to $Foswiki::cfg vars embedded in the values of
133 # other $Foswiki::cfg vars.
134110µs112.8ms expandValue( \%Foswiki::cfg ) unless $noexpand;
# spent 12.8ms making 1 call to Foswiki::Configure::Load::expandValue
135
13613µs $Foswiki::cfg{ConfigurationFinished} = 1;
137
138#on Windows, File::Spec returns a really useless empty string for tempdir under apache
139#(in its unix code, it assumes /tmp - but at least thats standard..)
140#so defaulting $ENV{TMP} can get us limping along (and can over-ride using TMPDIR or TEMP env
14113µs if ( $^O eq 'MSWin32' ) {
142
143 #force paths to use '/'
144 $Foswiki::cfg{PubDir} =~ s|\\|/|g;
145 $Foswiki::cfg{DataDir} =~ s|\\|/|g;
146 $Foswiki::cfg{ToolsDir} =~ s|\\|/|g;
147 $Foswiki::cfg{ScriptDir} =~ s|\\|/|g;
148 $Foswiki::cfg{TemplateDir} =~ s|\\|/|g;
149 $Foswiki::cfg{LocalesDir} =~ s|\\|/|g;
150 $Foswiki::cfg{WorkingDir} =~ s|\\|/|g;
151
152 #$ENV{TMPDIR}
153 #$ENV{TEMP}
154 #$ENV{TMP}
155 $ENV{TMP} = $Foswiki::cfg{WorkingDir};
156 }
157
158 # Alias TWiki cfg to Foswiki cfg for plugins and contribs
15914µs *TWiki::cfg = \%Foswiki::cfg;
160
161 # Explicit return true if we've completed the load
16218µs return $validLSC;
163}
164
165=begin TML
166
167---++ StaticMethod expandValue($datum)
168
169Expands references to Foswiki configuration items which occur in the
170values configuration items contained within the datum, which may be a
171hash reference or a scalar value. The replacement is done in-place.
172
173=cut
174
175
# spent 12.8ms (11.2+1.66) within Foswiki::Configure::Load::expandValue which was called 596 times, avg 22µs/call: # 535 times (9.63ms+-9.63ms) by Foswiki::Configure::Load::expandValue at line 177, avg 0s/call # 59 times (681µs+-681µs) by Foswiki::Configure::Load::expandValue at line 180, avg 0s/call # once (821µs+12.0ms) by Foswiki::Configure::Load::readConfig at line 134 # once (25µs+6µs) by Foswiki::Logger::PlainFile::_getLogForLevel at line 239 of /usr/local/src/github.com/foswiki/core/lib/Foswiki/Logger/PlainFile.pm
sub expandValue {
1765963.47ms if ( ref( $_[0] ) eq 'HASH' ) {
1778174.11ms5350s map { expandValue($_) } values %{ $_[0] };
# spent 25.9ms making 535 calls to Foswiki::Configure::Load::expandValue, avg 48µs/call, recursion: max depth 4, sum of overlapping time 25.9ms
178 }
179 elsif ( ref( $_[0] ) eq 'ARRAY' ) {
18061366µs590s map { expandValue($_) } @{ $_[0] };
# spent 768µs making 59 calls to Foswiki::Configure::Load::expandValue, avg 13µs/call, recursion: max depth 2, sum of overlapping time 768µs
181
182 # Can't do this, because Windows uses an object (Regexp) for regular
183 # expressions.
184 # } elsif (ref($_[0])) {
185 # Carp::confess("Can't handle a ".ref($_[0]));
186 }
187 elsif ( defined( $_[0] ) ) {
1884543.97ms500895µs while (
# spent 788µs making 467 calls to Foswiki::Configure::Load::CORE:subst, avg 2µs/call # spent 107µs making 33 calls to Foswiki::Configure::Load::CORE:substcont, avg 3µs/call
1892099µs20766µs $_[0] =~ s/(\$Foswiki::cfg{[[A-Za-z0-9{}]+})/_handleExpand($1)/ge )
# spent 766µs making 20 calls to Foswiki::Configure::Load::_handleExpand, avg 38µs/call
190 {
191 }
192 }
193}
194
195# Used to expand the $Foswiki::cfg variable in the expand* routines.
196# Resolves issue with defined but null variables expanding as "undef"
197# Tasks:Item5608
198
# spent 766µs within Foswiki::Configure::Load::_handleExpand which was called 20 times, avg 38µs/call: # 20 times (766µs+0s) by Foswiki::Configure::Load::expandValue at line 189, avg 38µs/call
sub _handleExpand {
19920558µs my $val = eval $_[0];
# spent 20µs executing statements in 4 string evals (merged) # spent 19µs executing statements in 4 string evals (merged) # spent 19µs executing statements in 4 string evals (merged) # spent 15µs executing statements in 3 string evals (merged) # spent 5µs executing statements in string eval # spent 5µs executing statements in string eval # spent 5µs executing statements in string eval # spent 5µs executing statements in string eval # spent 5µs executing statements in string eval
2002028µs $val = ( defined $val ) ? $val : 'undef';
20120123µs return $val;
202}
203
204=begin TML
205
206---++ StaticMethod readDefaults() -> \@errors
207
208This is only called by =configure= to initialise the Foswiki config hash with
209default values from the .spec files.
210
211Normally all configuration values come from LocalSite.cfg. However when
212=configure= runs it has to get default values for config vars that have not
213yet been saved to =LocalSite.cfg=.
214
215Returns a reference to a list of the errors it saw.
216
217SEE ALSO: Foswiki::Configure::FoswikiCfg::load
218
219=cut
220
221sub readDefaults {
222 my %read = ();
223 my @errors;
224
225 eval {
226 do 'Foswiki.spec';
227 $read{'Foswiki.spec'} = $INC{'Foswiki.spec'};
228 };
229 push( @errors, $@ ) if ($@);
230 foreach my $dir (@INC) {
231 my $root; # SMELL: Not used
232 _loadDefaultsFrom( "$dir/Foswiki/Plugins", $root, \%read, \@errors );
233 _loadDefaultsFrom( "$dir/Foswiki/Contrib", $root, \%read, \@errors );
234 _loadDefaultsFrom( "$dir/TWiki/Plugins", $root, \%read, \@errors );
235 _loadDefaultsFrom( "$dir/TWiki/Contrib", $root, \%read, \@errors );
236 }
237
238 # SMELL: This will create the %TWiki::cfg
239 # But as it ought to be aliased to %Foswiki::cfg, it's not a big deal
240 # XXX: Do we still need this code?
241 if ( %TWiki::cfg && \%TWiki::cfg != \%Foswiki::cfg ) {
242
243 # We had some TWiki plugins, need to map their config to Foswiki
244 sub mergeHash {
245
246 # Merges the keys in the right hashref to the ones in the
247 # left hashref
248 my ( $left, $right, $errors ) = @_;
249 while ( my ( $key, $value ) = each %$right ) {
250 if ( exists $left->{$key} ) {
251 if ( ref($value) ne ref( $left->{$key} ) ) {
252 push @$errors,
253 'Trying to overwrite $Foswiki::cfg{'
254 . $key
255 . '} with its $TWiki::cfg version ('
256 . $value . ')';
257 }
258 elsif ( ref($value) eq 'SCALAR' ) {
259 $left->{$key} = $value;
260 }
261 elsif ( ref($value) eq 'HASH' ) {
262 $left->{$key} =
263 mergeHash( $left->{$key}, $value, $errors );
264 }
265 elsif ( ref($value) eq 'ARRAY' ) {
266
267 # It's an array. try to be smart
268 # SMELL: Ideally, it should keep order too
269 foreach my $item (@$value) {
270 unless ( grep /^$item$/, @{ $left->{$key} } ) {
271
272 # The item isn't in the current list,
273 # add it at the end
274 unshift @{ $left->{$key} }, $item;
275 }
276 }
277 }
278 else {
279
280 # It's something else (GLOB, coderef, ...)
281 push @$errors,
282 '$TWiki::cfg{'
283 . $key
284 . '} is a reference to a'
285 . ref($value)
286 . '. No idea how to merge that, sorry.';
287 }
288 }
289 else {
290
291 # We don't already have such a key in the Foswiki scope
292 $left->{$key} = $value;
293 }
294 }
295 return $left;
296 }
297 mergeHash \%Foswiki::cfg, \%TWiki::cfg, \@errors;
298 }
299
300 return \@errors;
301}
302
303sub _loadDefaultsFrom {
304 my ( $dir, $root, $read, $errors ) = @_;
305
306 return unless opendir( D, $dir );
307 foreach my $extension ( grep { !/^\./ } readdir D ) {
308 $extension =~ /(.*)/;
309 $extension = $1; # untaint
310 next if $read->{$extension};
311 my $file = "$dir/$extension/Config.spec";
312 next unless -e $file;
313 eval { do $file; };
314 push( @$errors, $@ ) if ($@);
315 $read->{$extension} = $file;
316 }
317 closedir(D);
318}
319
32018µs1;
321__END__
 
# spent 20µs within Foswiki::Configure::Load::CORE:qr which was called 4 times, avg 5µs/call: # once (11µs+0s) by Foswiki::Configure::Load::readConfig at line 348 of /usr/local/src/github.com/foswiki/core/lib/Foswiki.spec # once (3µs+0s) by Foswiki::Configure::Load::readConfig at line 645 of /usr/local/src/github.com/foswiki/core/lib/Foswiki.spec # once (3µs+0s) by Foswiki::Configure::Load::readConfig at line 652 of /usr/local/src/github.com/foswiki/core/lib/Foswiki.spec # once (3µs+0s) by Foswiki::Configure::Load::readConfig at line 1102 of /usr/local/src/github.com/foswiki/core/lib/Foswiki.spec
sub Foswiki::Configure::Load::CORE:qr; # opcode
# spent 788µs within Foswiki::Configure::Load::CORE:subst which was called 467 times, avg 2µs/call: # 467 times (788µs+0s) by Foswiki::Configure::Load::expandValue at line 188, avg 2µs/call
sub Foswiki::Configure::Load::CORE:subst; # opcode
# spent 107µs within Foswiki::Configure::Load::CORE:substcont which was called 33 times, avg 3µs/call: # 33 times (107µs+0s) by Foswiki::Configure::Load::expandValue at line 188, avg 3µs/call
sub Foswiki::Configure::Load::CORE:substcont; # opcode