Skip to content

Conversation

@SavageTiger
Copy link
Contributor

@SavageTiger SavageTiger commented Jan 29, 2026

Description

While investigating the performance of our API that runs on top of Webonyx, I made some cachegrind profiles and found that we perform an insane amount of is_array checks for each query.

The source of this is the method extractVisitFn. While investigating this, I found that if I do a null check on $kindVisitor and $specificVisitor before checking if they are arrays, it cuts down our callgraph by about 50%. It might seem a bit counterintuitive since is_array also performs the null check implicitly; however, the overhead cost of calling the method on such a hot path is pretty high.

After this finding, I did some more digging into the visitor and found that we also do a bunch of instanceof checks on the result while it is null in many cases. By doing an early null check, all those if and else-if conditions can be skipped.

Lastly, I noticed the instanceof checks in leave() in TypeInfo. instanceof is more expensive computationally than you might think since, under the hood, it’s a string comparison for which memory gets allocated. In this case, we can use ->kind due to the strict typehint.

I tested all these changes by comparing a previous benchmark run to the latest benchmark run and have seen a clear performance improvement with each consecutive change. Here is a table of the overall win:

The baseline is the current version

Benchmark Original This PR Reduction
benchHeroQuery 0.991ms 0.929ms 6.26%
benchNestedQuery 2.421ms 2.271ms 6.20%
benchQueryWithFragment 2.605ms 2.386ms 8.41%
benchQueryWithInterfaceFragment 2.447ms 2.230ms 8.87%
benchStarWarsIntrospectionQuery 24.996ms 23.661ms 5.34%

instanceof is a slow-ish operation, since it's a string compare, but using ->kind directly we can do a direct pointer check, which is way faster.
By doing a null check before calling is_array we prevent tons of method calls, since its very common for calling visitors to be null.
@SavageTiger SavageTiger marked this pull request as draft January 29, 2026 14:10
Since it common for the result to be null, by doing that check before we do the more expensive instanceof checks we can prevent allot of if checks
@SavageTiger SavageTiger changed the title [Performance] 15% performance improvement by lessening is_array and instanceof checks. [Performance] 6% performance improvement by lessening is_array and instanceof checks. Jan 29, 2026
@SavageTiger SavageTiger marked this pull request as ready for review January 29, 2026 14:46
@spawnia spawnia merged commit f753e57 into webonyx:master Jan 29, 2026
20 checks passed
@spawnia
Copy link
Collaborator

spawnia commented Jan 29, 2026

Thanks, released with https://github.com/webonyx/graphql-php/releases/tag/v15.30.1. Please consider sponsoring.

@SavageTiger SavageTiger deleted the sven/performance branch January 29, 2026 15:31
@ruudk
Copy link
Collaborator

ruudk commented Jan 29, 2026

Thanks Sven 💪

@shmax
Copy link
Contributor

shmax commented Jan 29, 2026

Yeah, man, awesome. Keep 'em coming!

@stayallive
Copy link
Contributor

Respect, thanks!

@jerowork
Copy link
Contributor

jerowork commented Feb 2, 2026

Yeey thank you @SavageTiger :)

wmfgerrit pushed a commit to wikimedia/mediawiki-vendor that referenced this pull request Feb 2, 2026
https://github.com/webonyx/graphql-php/releases/tag/v15.30.1

> Improve performance 6% by lessening is_array and instanceof checks

webonyx/graphql-php#1845

Change-Id: Ica32b9e771ad4abaaa0b5c8522e5e055364df3fd
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants