-
-
Notifications
You must be signed in to change notification settings - Fork 2k
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
More specific if conditions lead to ~10% faster render. #610
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! Might even be able to kill the vchildren check now that props.children
is always an array!
@bmeurer just held a talk about these a few days ago. See the last two slides of his talk where he shares that https://docs.google.com/presentation/d/1_eLlVzcj94_G4r9j9d_Lj5HRKFnq6jgpuPJtnmIBs88/edit?usp=sharing |
@@ -187,10 +187,10 @@ function innerDiffNode(dom, vchildren, context, mountAll, absorb) { | |||
min = 0, | |||
len = originalChildren.length, | |||
childrenLen = 0, | |||
vlen = vchildren && vchildren.length, | |||
vlen = vchildren ? vchildren.length : 0, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the real culprit, as now vlen will always be a Number (and known to the compiler as such). You could probably go one step further and avoid the ToBoolean on vchildren
as well by writing something like vlen = (vchildren !== undefined) ? vchildren.length : 0
if that matches the contract.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your insights, @bmeurer!
Would an undefined
default (e.g.vlen = vchildren ? vchildren.length : undefined
) be less optimal for the compiler than the default of 0
? Same question for null
. Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
undefined
or null
are less ideal than 0
here, as the compiler needs to choose a tagged representation that can represents both undefined
/null
as well as numbers. If you use only (small integer) numbers, then the optimizing compilers in VMs can usually pick the ideal unboxed Word/Word32 representation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it. Thank you!
In general using let len = o && o.length; Here |
Interesting! @bmeurer, what if I do this instead: let len = Boolean(o && o.length); |
Then |
Doh! Haha, that's embarrassing 😅 var x = y ? true : z To this: var x = Boolean(y) || z And for some reason I saw this and thought it would be related. 😅 |
I have the gut feeling that the first example is better. |
Ha! Maybe I should change the transformation around then! |
Yes, the |
@bmeurer just think of generalizations - using a ternary seems to avoid an unintentionally different type for falsey conditions - seems like that's the kicker here? (the goal being to have the expression produce a uniform type) |
@developit That too! |
j, c, vchild, child; | ||
|
||
if (len) { | ||
if (len!==0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While you're making things more explicit, don't you really mean len > 0
in both cases?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using >
and <
does valueOf
coercion on non-numeric values, so I have a vague guess that doing an exact equals check may be faster than greater-than. But, I did not actually profile and am not an expert on this, so if someone else knows better please correct me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Strict equality should be faster than a comparison since it does no casting, but @bmeurer is far more knowledgeable on that than I am.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand now. You're focusing on perf over explicit code intent. 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With the ?:
above the optimizing compiler knows that len
is a number, so len > 0
is fine. Shouldn't be any speed difference for this. Even the interpreted code is mostly equivalent from perf perspective.
LGTM. Thank-you for the detailed insights @bmeurer . |
Wouldn't it make sense to switch |
@kurtextrem I'd base it on whichever is smaller when gzipped. If I had to guess, the inequality might be smaller because it's used elsewhere in the codebase (but I often guess wrong). |
I'm not sure if this is stuff you already found in your secret v8 work. But here goes...
if(variable)
checks are super slow because the whole truthy/falsy thing is complicated. You mentionedinnerDiffNode
was the hottest thing on your benchmarks, and I was reading through it to try to explain it, and noticed some flagrant usage of vagueif(variable)
tests. By being very explicit that we only want number comparison to 0, they get faster. On my computer, running the benchmarks test, I see everything 1-5% faster after this change. (I initially reported a larger difference, but after re-running a bunch more times under fair conditions it looks like it's smaller.)