Skip to content

Commit 24388bc

Browse files
MichaelBelgiumfelixfbecker
authored andcommitted
perf: change index to a tree to speed up completion (felixfbecker#680)
Refactors Index into a tree structure, rather than an array of Fqns to definitions. Closes felixfbecker#274
1 parent 18c6ccd commit 24388bc

16 files changed

+945
-242
lines changed

benchmarks/completion.php

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<?php
2+
3+
namespace LanguageServer\Tests;
4+
require __DIR__ . '/../vendor/autoload.php';
5+
6+
use Composer\XdebugHandler\XdebugHandler;
7+
use Exception;
8+
use LanguageServer\CompletionProvider;
9+
use LanguageServer\DefinitionResolver;
10+
use LanguageServer\Index\Index;
11+
use LanguageServer\PhpDocument;
12+
use LanguageServer\StderrLogger;
13+
use LanguageServerProtocol\Position;
14+
use Microsoft\PhpParser;
15+
use phpDocumentor\Reflection\DocBlockFactory;
16+
use RecursiveDirectoryIterator;
17+
use RecursiveIteratorIterator;
18+
19+
$logger = new StderrLogger();
20+
$xdebugHandler = new XdebugHandler('PHPLS');
21+
$xdebugHandler->setLogger($logger);
22+
$xdebugHandler->check();
23+
unset($xdebugHandler);
24+
25+
$totalSize = 0;
26+
27+
$framework = "symfony";
28+
29+
$iterator = new RecursiveDirectoryIterator(__DIR__ . "/../validation/frameworks/$framework");
30+
$testProviderArray = array();
31+
32+
foreach (new RecursiveIteratorIterator($iterator) as $file) {
33+
if (strpos((string)$file, ".php") !== false) {
34+
$totalSize += $file->getSize();
35+
$testProviderArray[] = $file->getRealPath();
36+
}
37+
}
38+
39+
if (count($testProviderArray) === 0) {
40+
throw new Exception("ERROR: Validation testsuite frameworks not found - run `git submodule update --init --recursive` to download.");
41+
}
42+
43+
$index = new Index;
44+
$definitionResolver = new DefinitionResolver($index);
45+
$completionProvider = new CompletionProvider($definitionResolver, $index);
46+
$docBlockFactory = DocBlockFactory::createInstance();
47+
$completionFile = realpath(__DIR__ . '/../validation/frameworks/symfony/src/Symfony/Component/HttpFoundation/Request.php');
48+
$parser = new PhpParser\Parser();
49+
$completionDocument = null;
50+
51+
echo "Indexing $framework" . PHP_EOL;
52+
53+
foreach ($testProviderArray as $idx => $testCaseFile) {
54+
if (filesize($testCaseFile) > 100000) {
55+
continue;
56+
}
57+
if ($idx % 100 === 0) {
58+
echo $idx . '/' . count($testProviderArray) . PHP_EOL;
59+
}
60+
61+
$fileContents = file_get_contents($testCaseFile);
62+
63+
try {
64+
$d = new PhpDocument($testCaseFile, $fileContents, $index, $parser, $docBlockFactory, $definitionResolver);
65+
if ($testCaseFile === $completionFile) {
66+
$completionDocument = $d;
67+
}
68+
} catch (\Throwable $e) {
69+
echo $e->getMessage() . PHP_EOL;
70+
continue;
71+
}
72+
}
73+
74+
echo "Getting completion". PHP_EOL;
75+
76+
// Completion in $this->|request = new ParameterBag($request);
77+
$start = microtime(true);
78+
$list = $completionProvider->provideCompletion($completionDocument, new Position(274, 15));
79+
$end = microtime(true);
80+
echo 'Time ($this->|): ' . ($end - $start) . 's' . PHP_EOL;
81+
echo count($list->items) . ' completion items' . PHP_EOL;
82+
83+
// Completion in $this->request = new| ParameterBag($request);
84+
// (this only finds ParameterBag though.)
85+
$start = microtime(true);
86+
$list = $completionProvider->provideCompletion($completionDocument, new Position(274, 28));
87+
$end = microtime(true);
88+
echo 'Time (new|): ' . ($end - $start) . 's' . PHP_EOL;
89+
echo count($list->items) . ' completion items' . PHP_EOL;

Performance.php renamed to benchmarks/parsing.php

+13-5
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,31 @@
11
<?php
22

33
namespace LanguageServer\Tests;
4-
require __DIR__ . '/vendor/autoload.php';
4+
require __DIR__ . '/../vendor/autoload.php';
55

6+
use Composer\XdebugHandler\XdebugHandler;
67
use Exception;
8+
use LanguageServer\DefinitionResolver;
79
use LanguageServer\Index\Index;
810
use LanguageServer\PhpDocument;
9-
use LanguageServer\DefinitionResolver;
11+
use LanguageServer\StderrLogger;
1012
use Microsoft\PhpParser;
1113
use phpDocumentor\Reflection\DocBlockFactory;
1214
use RecursiveDirectoryIterator;
1315
use RecursiveIteratorIterator;
1416

17+
$logger = new StderrLogger();
18+
$xdebugHandler = new XdebugHandler('PHPLS');
19+
$xdebugHandler->setLogger($logger);
20+
$xdebugHandler->check();
21+
unset($xdebugHandler);
22+
1523
$totalSize = 0;
1624

1725
$frameworks = ["drupal", "wordpress", "php-language-server", "tolerant-php-parser", "math-php", "symfony", "codeigniter", "cakephp"];
1826

1927
foreach($frameworks as $framework) {
20-
$iterator = new RecursiveDirectoryIterator(__DIR__ . "/validation/frameworks/$framework");
28+
$iterator = new RecursiveDirectoryIterator(__DIR__ . "/../validation/frameworks/$framework");
2129
$testProviderArray = array();
2230

2331
foreach (new RecursiveIteratorIterator($iterator) as $file) {
@@ -37,8 +45,8 @@
3745
if (filesize($testCaseFile) > 10000) {
3846
continue;
3947
}
40-
if ($idx % 1000 === 0) {
41-
echo "$idx\n";
48+
if ($idx % 500 === 0) {
49+
echo $idx . '/' . count($testProviderArray) . PHP_EOL;
4250
}
4351

4452
$fileContents = file_get_contents($testCaseFile);
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace Whatever;
4+
5+
use TestNamespace\InnerNamespace as AliasNamespace;
6+
7+
class IDontShowUpInCompletion {}
8+
9+
AliasNamespace\I;
10+
AliasNamespace\;

fixtures/symbols.php

+5
Original file line numberDiff line numberDiff line change
@@ -103,3 +103,8 @@ class Example {
103103
public function __construct() {}
104104
public function __destruct() {}
105105
}
106+
107+
namespace TestNamespace\InnerNamespace;
108+
109+
class InnerClass {
110+
}

0 commit comments

Comments
 (0)