Speed ​​up the project cache in NoVerify (linter for PHP) 10 times

One evening, while discussing the difficulties of developing a linter for PHP in Go with Iskander @quasilyte , Iskander mentioned that the tests take a long time when run locally (about a minute, and it seems to me that for Go it is quite long). We started digging, and it quickly became clear that the tests that run NoVerify (the name of the linter) in the mode with the race detector turned on are mainly "slowing down" . The phpstorm-stubs repository is indexed for each launch, which contains all the definitions of built-in functions / classes / constants that are in PHP, and indexing this repository takes about 4 seconds on a 4-core machine (note that without a race detector everything is much faster). Since there are several such runs, one for each tested open-source project, the total execution time of all tests can take minutes. NoVerify positions itself as a very fast linter for PHP, so, of course, this performance is a little sad and it was necessary to find some kind of solution.

NoVerify architecture

For a start, it's still worth talking a little about how NoVerify works. Linter work is divided into two broad phases: indexing and direct analysis.

Project indexing means that definitions and types of all functions, classes, methods, constants and global variables are extracted from all PHP files, and all this information is stored in RAM for quick access. Also, this information is saved in the cache on disk in gob format to avoid the need to parse the entire project every time. It is important that even to analyze a single file, the entire project must be indexed, because if there is an autoload for classes in PHP, then there is no such thing for functions, constants, and even more so global variables, and they can be defined anywhere. Of course, in modern PHP projects, only classes are usually used and such problems do not arise, but for projects with a long history this is still relevant. It was the need to index the entire project for its analysis that was the reason for writing NoVerify in Go, since this language supports multithreading well, which means it will be able to index the project much faster than is possible in PHP.

(, , ), . , , ( , phpstorm-stubs 90+% ). //, .

phpstorm-stubs

, , , , phpstorm-stubs, , , «» (.. ) // PHP, 25% , , . , : phpstorm-stubs «» , , , , , , .., , .

«» :

  1. , . , phpstorm-stubs .

  2. phpstorm-stubs , , .

  3. , gob.

  4. , phpstorm-stubs , Go- phpstorm-stubs . , , , 2-3 .

, (2), . , (1), , , . , , Go phpstorm-stubs ~200 (.. 20 ), , 18 , , .

?

, golden- , , , - . , , phpstorm-stubs. , -.

, ( Laravel, composer create-project --prefer-dist laravel/laravel blog, 1.6 PHP) 450 ( 4 ), NoVerify , , , , language server.

/

Go- 1.6 20-60 , , , , . .

: noverifyturbo 20 100 , ~80 1.6 PHP-.

, - NoVerify, , NoVerify. , .

-

: , Go- fmt.Printf("%#v", value).

example of generated code

, , , , GoStringer(), .

PHP- Go-, map[string]func()*PerFileCache, ( PHP- , , ), , PHP-. , , , , map ( - , ), , , , map , .

+ , , - stat() , .

Laravel 1.6 , composer create-project --prefer-dist laravel/laravel blog , :

  1. , 1 : 4

  2. -, 1 : 400

  3. , 12 : 1 (10 )

  4. -, 12 : 240 (800 )

, - , , - map , , . , - , , .

— , , , , ( Google, ).

NoVerify Go, , phpstorm-stubs «» . . , , NoVerify workflow , PHPStorm VS Code , .

  1. NoVerify — PHP .

  2. phpstorm-stubs — «» PHP .

  3. NoVerify

  4. phpstorm-stubs

  5. Comparing different data serialization formats in Go




All Articles