phpdotenv
phpdotenv copied to clipboard
High performance impact on Parser
I have a Laravel project with about 51 environment variables on our .env.testing file. The project consist of about 1300 automation tests written on PHPUnit.
I was investigating a performance issue on our test suite and I managed to pinpoint one major degradation to https://github.com/vlucas/phpdotenv/blob/master/src/Parser/Parser.php#L27
The way I "benchmarked" this analyses was by adding a throw new SkippedTestError('Skip'); and running the entire test suite on different places. Here is the result before that line is executed:
$var = Regex::split("/(\r\n|\n|\r)/", $content)->mapError(static function () {
return 'Could not split into separate lines.';
});
throw new SkippedTestError('Skip');
$var = $var->flatMap(static function (array $lines) {
return self::process(Lines::process($lines));
});
$var = $var->mapError(static function (string $error) {
throw new InvalidFileException(\sprintf('Failed to parse dotenv file. %s', $error));
})->success();
return $var->get();
bash-4.2# ./laravel/vendor/bin/phpunit
PHPUnit 9.5.16 by Sebastian Bergmann and contributors.
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 61 / 1358 ( 4%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 122 / 1358 ( 8%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 183 / 1358 ( 13%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 244 / 1358 ( 17%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 305 / 1358 ( 22%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 366 / 1358 ( 26%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 427 / 1358 ( 31%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 488 / 1358 ( 35%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 549 / 1358 ( 40%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 610 / 1358 ( 44%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 671 / 1358 ( 49%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 732 / 1358 ( 53%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 793 / 1358 ( 58%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 854 / 1358 ( 62%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 915 / 1358 ( 67%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 976 / 1358 ( 71%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 1037 / 1358 ( 76%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 1098 / 1358 ( 80%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 1159 / 1358 ( 85%)
SSSSSSSSSSSSSSSSSSSS.SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 1220 / 1358 ( 89%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 1281 / 1358 ( 94%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 1342 / 1358 ( 98%)
SSSSSSSSSSSSSSSS 1358 / 1358 (100%)
Time: 00:03.158, Memory: 174.00 MB
It doesn't matter how many times I run the suite, it always finishes below 3.5 seconds.
Now moving the exception one step below:
$var = Regex::split("/(\r\n|\n|\r)/", $content)->mapError(static function () {
return 'Could not split into separate lines.';
});
$var = $var->flatMap(static function (array $lines) {
return self::process(Lines::process($lines));
});
throw new SkippedTestError('Skip');
bash-4.2# ./laravel/vendor/bin/phpunit
PHPUnit 9.5.16 by Sebastian Bergmann and contributors.
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 61 / 1358 ( 4%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 122 / 1358 ( 8%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 183 / 1358 ( 13%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 244 / 1358 ( 17%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 305 / 1358 ( 22%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 366 / 1358 ( 26%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 427 / 1358 ( 31%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 488 / 1358 ( 35%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 549 / 1358 ( 40%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 610 / 1358 ( 44%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 671 / 1358 ( 49%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 732 / 1358 ( 53%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 793 / 1358 ( 58%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 854 / 1358 ( 62%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 915 / 1358 ( 67%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 976 / 1358 ( 71%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 1037 / 1358 ( 76%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 1098 / 1358 ( 80%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 1159 / 1358 ( 85%)
SSSSSSSSSSSSSSSSSSSS.SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 1220 / 1358 ( 89%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 1281 / 1358 ( 94%)
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS 1342 / 1358 ( 98%)
SSSSSSSSSSSSSSSS 1358 / 1358 (100%)
Time: 00:06.796, Memory: 172.00 MB
It doesn't matter how many times I run the tests, it always end up above 6 seconds.
I'm still investigating if there is anything I can do on my side to mitigate this or if there is anything I can try to propose to the lib to improve this, but for now I thought I'd open an issue in case anybody have any bright ideas.
I'd not recommended to parse the file over and over. Use config caching. :)
The line you link to is the line that basically does all of the parsing, btw. ;)
Should I be using caching for PHPUnit? Is that really the recommendation?
Yes, definitely. Run both config and route cache, with the env set to testing.