Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

inline calls in TrinaryLogic to reduce method call overhead #1563

Merged
merged 1 commit into from Aug 20, 2022

Conversation

staabm
Copy link
Contributor

@staabm staabm commented Jul 28, 2022

looking at perf profiles of the slow test d33454d we can see TrinaryLogic creation is a major cost.

with this PR I propose to "duplicate" a few lines of code to reduce the callstack in this very perf critical path

with blackfire I can see a 30% perf improvement before/after this PR when running

blackfire run php vendor/bin/phpunit tests/PHPStan/Analyser/AnalyserIntegrationTest.php --filter testBug5081

grafik

refs phpstan/phpstan#7666 (comment)

the perf improvement is also visible when running plain

time vendor/bin/phpunit tests/PHPStan/Analyser/AnalyserIntegrationTest.php

before this PR 15-17secs; after 13-15 secs

env

php -v
PHP 8.1.2 (cli) (built: Jul 21 2022 12:10:37) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.2, Copyright (c) Zend Technologies
    with Zend OPcache v8.1.2, Copyright (c), by Zend Technologies
    with blackfire v1.80.0~linux-x64-non_zts81, https://blackfire.io, by Blackfire

@herndlm
Copy link
Contributor

herndlm commented Jul 28, 2022

This has such an impact although it was already implemented in create?

@staabm
Copy link
Contributor Author

staabm commented Jul 28, 2022

I think the impact is the actual call-overhead to create() not the logic implemented in the method. we call it milions of times and that adds up.

@oprypkhantc
Copy link

Just curious, can't PHPStan use native enums? That would likely reduce the overhead even more, although would require bumping up PHP requirement to 8.1.

@canvural
Copy link
Contributor

Just curious, can't PHPStan use native enums? That would likely reduce the overhead even more, although would require bumping up PHP requirement to 8.1.

PHPStan's source code is downgraded with Rector in the PHAR build. And I guess Rector can't downgrade native enums. That's why.

@staabm
Copy link
Contributor Author

staabm commented Jul 29, 2022

after this change, the TrinaryLogic is no longer on the slow path. IMO its fine as is.

if we find a case where its still measurably slow, we can think about enums IMO.

this PR is about reducing function/method call overhead.
using enums would only help us in this regard if we would directly access the enum cases instead of invoking a method like we do atm with TrinaryLogic::createYes() etc

its only relevant for super huge union types which are rare.

}

public static function createMaybe(): self
{
return self::create(self::MAYBE);
return self::$registry[self::MAYBE] ??= new self(self::MAYBE);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just theory crafting here so feel free to tell me if i'm wrong

but if phpstan is caching and reusing the same instance for yes no and maybe, would it be worth it to somehow pre-create the 3 instances needed and then return those directly?

this would avoid potentially millions of null checks, of which there are 3 cases where the null check is actually relevant (the first one of each case)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a question of when it should be pre-precreated. PHPStan internals are not only executed through bin/phpstan, there are also other usages, like executing test cases, and also usage of internals in 3rd party tools like Rector.

Maybe it could work if we initialize it as a side effect right before class TrinaryLogic declaration.

@ondrejmirtes
Copy link
Member

I was tempted to merge this, but this looks for the problem in the wrong place.

Sure, if you call TrinaryLogic a billion times, optimization like that can help.

The problem is that the previous version didn't call TrinaryLogic a billion times, so this problem didn't exist.

We need to fix the root cause, and not treat the symptoms.

More about my findings here: phpstan/phpstan#7666 (comment)

@staabm
Copy link
Contributor Author

staabm commented Jul 31, 2022

I agree this one is not the fix for the root cause.

Still its a easy perf improvement for one of the most used primitives in phpstan, without a relevant cost/complexity increase.

IMO it should be considered for merge as it will improve performance for cases with big/huge union types

@ondrejmirtes
Copy link
Member

Yeah, I don't see why not. Thanks!

@ondrejmirtes ondrejmirtes merged commit 2b14bf4 into phpstan:1.8.x Aug 20, 2022
@staabm staabm deleted the trinary-perf branch September 23, 2022 05:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
7 participants