Skip to content

Commit f32ebcb

Browse files
Russell Smithmr-russ
authored andcommitted
Improve Performance, reduce memory footprint
array_merge has performance issues as the input array's grow in size. mStructs is a complex array and can be a large memory user in php. mStructs was replaced with mLines which is the processed tag information to reduce the memory footprint and allow caching of the results. mLines is an array of files which can be joined together or appended to an existing file. Performance seen from changes; - Moodle 2.4 codebase can be completely scanned in 3 minutes (approximate 1 hour before)
1 parent 1c65972 commit f32ebcb

File tree

2 files changed

+60
-20
lines changed

2 files changed

+60
-20
lines changed

PHPCtags.class.php

Lines changed: 55 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,17 @@ class PHPCtags
2020
);
2121

2222
private $mParser;
23-
24-
private $mStructs;
25-
23+
private $mLines;
2624
private $mOptions;
25+
private $tagdata;
26+
private $filecount;
2727

2828
public function __construct($options)
2929
{
3030
$this->mParser = new PHPParser_Parser(new PHPParser_Lexer);
31-
$this->mStructs = array();
31+
$this->mLines = array();
3232
$this->mOptions = $options;
33+
$this->filecount = 0;
3334
}
3435

3536
public function setMFile($file)
@@ -250,10 +251,10 @@ private function struct($node, $reset=FALSE, $parent=array())
250251
return $structs;
251252
}
252253

253-
private function render()
254+
private function render($structure)
254255
{
255256
$str = '';
256-
foreach ($this->mStructs as $struct) {
257+
foreach ($structure as $struct) {
257258
$file = $struct['file'];
258259

259260
if (!isset($files[$file]))
@@ -360,6 +361,17 @@ private function render()
360361
// remove the last line ending
361362
$str = trim($str);
362363

364+
return $str;
365+
}
366+
367+
private function full_render() {
368+
// Files will have been rendered already, just join and export.
369+
370+
$str = '';
371+
foreach($this->mLines as $file => $data) {
372+
$str .= $data;
373+
}
374+
363375
// sort the result as instructed
364376
if (isset($this->mOptions['sort']) && ($this->mOptions['sort'] == 'yes' || $this->mOptions['sort'] == 'foldcase')) {
365377
$str = self::stringSortByLine($str, $this->mOptions['sort'] == 'foldcase');
@@ -378,7 +390,7 @@ public function export()
378390
$this->process($file);
379391
}
380392

381-
return $this->render();
393+
return $this->full_render();
382394
}
383395

384396
private function process($file)
@@ -404,27 +416,53 @@ private function process($file)
404416
}
405417

406418
try {
407-
$this->setMFile((string) $filename);
408-
$this->mStructs = array_merge(
409-
$this->mStructs,
410-
$this->struct($this->mParser->parse(file_get_contents($this->mFile)), TRUE)
411-
);
419+
$this->process_single_file($filename);
412420
} catch(Exception $e) {
413421
echo "PHPParser: {$e->getMessage()} - {$filename}".PHP_EOL;
414422
}
415423
}
416424
} else {
417425
try {
418-
$this->setMFile($file);
419-
$this->mStructs = array_merge(
420-
$this->mStructs,
421-
$this->struct($this->mParser->parse(file_get_contents($this->mFile)), TRUE)
422-
);
426+
$this->process_single_file($filename);
423427
} catch(Exception $e) {
424428
echo "PHPParser: {$e->getMessage()} - {$file}".PHP_EOL;
425429
}
426430
}
427431
}
432+
433+
private function process_single_file($filename)
434+
{
435+
if ($this->mOptions['v'] && $this->filecount > 1 && $this->filecount % 64 == 0) {
436+
echo " ".$this->filecount." files".PHP_EOL;
437+
}
438+
$this->filecount++;
439+
440+
$startfile = microtime(true);
441+
442+
$this->setMFile((string) $filename);
443+
$file = file_get_contents($this->mFile);
444+
$md5 = md5($file);
445+
if (isset($this->tagdata[$this->mFile][$md5])) {
446+
// The file is the same as the previous time we analyzed and saved.
447+
$this->mLines[$this->mFile] = $this->tagdata[$this->mFile][$md5];
448+
if ($this->mOptions['v']) {
449+
echo ".";
450+
}
451+
return;
452+
}
453+
454+
$struct = $this->struct($this->mParser->parse($file), TRUE);
455+
$finishfile = microtime(true);
456+
$this->mLines[$this->mFile] = $this->render($struct);
457+
$finishmerge = microtime(true);
458+
$this->tagdata[$this->mFile][$md5] = $this->mLines[$this->mFile];
459+
if ($this->mOptions['debug']) {
460+
echo "Parse: ".($finishfile - $startfile).", Merge: ".($finishmerge-$finishfile)."; (".$this->filecount.")".$this->mFile.PHP_EOL;
461+
} else if ($this->mOptions['v']) {
462+
echo "U";
463+
}
464+
}
465+
428466
}
429467

430468
class PHPCtagsException extends Exception {

bootstrap.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
Addresses: <techlivezheng@gmail.com>, https://github.com/techlivezheng/phpctags
1919
EOF;
2020

21-
$options = getopt('af:Nno:RuV', array(
21+
$options = getopt('aC:f:Nno:RuvV', array(
2222
'append::',
2323
'debug',
2424
'exclude:',
@@ -46,7 +46,8 @@
4646
-o Alternative for -f.
4747
-R Equivalent to --recurse.
4848
-u Equivalent to --sort=no.
49-
-V Equivalent to --verbose.
49+
-v Equivalent to --verbose.
50+
-V Equivalent to --version.
5051
--append=[yes|no]
5152
Should tags should be appended to existing tag file [no]?
5253
--debug
@@ -69,12 +70,13 @@
6970
Recurse into directories supplied on command line [no].
7071
--sort=[yes|no|foldcase]
7172
Should tags be sorted (optionally ignoring case) [yes]?.
72-
--version
73+
--Version
7374
Print version identifier to standard output.
7475
EOF;
7576

7677
// prune options and its value from the $argv array
7778
$argv_ = array();
79+
7880
foreach ($options as $option => $value) {
7981
foreach ($argv as $key => $chunk) {
8082
$regex = '/^'. (isset($option[1]) ? '--' : '-') . $option . '/';

0 commit comments

Comments
 (0)