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

Object.defineProperty in THREE.Vector3 constructor causing a significant performance penalty #21284

Closed
pjanik opened this issue Feb 15, 2021 · 11 comments · Fixed by #21285
Closed

Comments

@pjanik
Copy link

pjanik commented Feb 15, 2021

Describe the bug

I've noticed a significant performance drop in my application when I upgraded the THREE.JS version. Initially from 0.102.0 to 0.125.2, but I've narrowed it down to a change from 0.119.1 to 0.120.0. A single model step in my app (simulation) increased from ~10ms to ~50ms.

I've used JS profiler and noticed that Vector3.clone() is at the top now:
Screenshot 2021-02-15 at 18 34 12

I'm using THREE.Vector3 in the simulation part of the app, and since many vector operations are implemented in place, .clone() calls are very common. When I downgrade version to 0.119.1, the clone operation isn't there anymore and the model step calculates 4 times faster.

I did a little investigation and replacing Object.defineProperty( this, 'isVector3', { value: true } ); in THREE.Vector3 constructor with this.isVector3 = true; fixes the issue.

To Reproduce, Live example

On my machine, the difference is 5ms (r119) vs 45ms (r120, r125).

I don't think it'd be useful here, but the app I'm working on:
https://tectonic-explorer.concord.org/?preset=subduction

Expected behavior

No .clone performance drop.

Screenshots

THREE.JS version 0.119.1 vs 0.120.0:

Screenshot 2021-02-15 at 18 33 25

Platform:

  • Device: Desktop
  • OS: MacOS
  • Browser: Chrome v88
  • Three.js version: r120.0 and newer, r119 is the last one that works fine
@mrdoob
Copy link
Owner

mrdoob commented Feb 15, 2021

@marcofugaro @DefinitelyMaybe I think we should just do this.isVector3 = true;.

@mrdoob mrdoob added this to the r126 milestone Feb 15, 2021
@marcofugaro
Copy link
Contributor

@mrdoob hmm yep, I agree.

@pjanik thanks for pinpointing the issue.

@pjanik
Copy link
Author

pjanik commented Feb 15, 2021

I guess that's obvious, but I can see more Object.defineProperty usage in the three.js codebase. Vector3 is specific to my app. I guess results would be the same if I did a similar benchmark with Vector2 or Matrix3, etc. Also, I've tried Chrome Canary (v90) and no difference there.

pjanik added a commit to concord-consortium/tectonic-explorer that referenced this issue Feb 15, 2021
[#176905512]

Update to r126 when it's released. See: mrdoob/three.js#21284
@mrdoob
Copy link
Owner

mrdoob commented Feb 15, 2021

I think I'll just make a script and fix all.

@mrdoob
Copy link
Owner

mrdoob commented Feb 15, 2021

PR: #21285

@WestLangley
Copy link
Collaborator

I'm using THREE.Vector3 in the simulation part of the app, and since many vector operations are implemented in place, .clone() calls are very common.

IMHO, you should not be using .clone() in that manner as it causes unnecessary instantiation of objects and garbage-collection. Create working instances and reuse them -- or use a closure.

@mrdoob
Copy link
Owner

mrdoob commented Feb 15, 2021

@WestLangley that's a good point, but this is definitely a regression.

@WestLangley
Copy link
Collaborator

User's have been advised -- certainly by me -- not to call clone() in a tight loop. If that is what the OP is doing, perhaps he can fix his problem at the app level.

@pjanik
Copy link
Author

pjanik commented Feb 15, 2021

FYI, my jstfiddle example is just the simplest test case I could imagine. It doesn't have much in common with the real app. I'm not calling .clone() 100k times in one loop in the real world. 😉

My .clone() calls are spread all over the codebase, including the simulation engine where the problem is. It's thousands of lines, different classes, methods, and getters. It's not a single 10-100-200 lines block I could easily tweak that way. As usual, it's performance vs readability and maintainability. I don't think "caching" vectors would be even possible in my case. I'd rather convert my sim code to use a different math library if I really had to.

Thanks for a quick reply and fix!

@WestLangley
Copy link
Collaborator

My .clone() calls are spread all over the codebase... It's thousands of lines, different classes, methods, and getters.

@pjanik Right. That is what I assumed.

If you are calling clone() often enough per animation frame to incur a measurable performance hit, then you are misusing the method.

The three.js math classes do not use the method at all.

Just a friendly tip. :-)

@DefinitelyMaybe
Copy link
Contributor

@marcofugaro @DefinitelyMaybe I think we should just do this.isVector3 = true;.

This is the simpler way. There were reasons for not doing this but I'm happy to try this out and see where we get to.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants