Speeding Up SceneNode::setPosition()?
- excaliburHisSheath
- Gnoblar
- Posts: 18
- Joined: Sat Feb 15, 2014 8:06 pm
Speeding Up SceneNode::setPosition()?
I'm running into an issue where SceneNode::setPosition() is eating up a lot of my frame time. The test I'm running involves setting 1000+ scene nodes to random positions, and my bottleneck is in setPosition(). The documentation warns not to call this method too frequently because it needs to convert the position to SoA, but that makes me wonder how one is supposed to move things around in the scene? Is there an alternate method for moving nodes around that has better performance?
For the record I'm on Ogre 2.0 in case that has something to do with the problem.
Thanks for the help!
For the record I'm on Ogre 2.0 in case that has something to do with the problem.
Thanks for the help!
-
- OGRE Expert User
- Posts: 1227
- Joined: Thu Dec 11, 2008 7:56 pm
- Location: Bristol, UK
- x 157
Re: Speeding Up SceneNode::setPosition()?
You bring up an interesting point, I would love to hear dark_sylinc's response!
However, whilst we wait for that, there a couple of things you can try
1) access the SoA transform directly using Node::_getTransform which returns a reference to it. I have not looked into this in detail yet, so tread carefully!
2) Multi thread your updates, more specifically have a look at SceneManager::executeUserScalableTask, an example of its use can be found here;
https://bitbucket.org/dark_sylinc/ogret ... ault#cl-49
hope that helps
However, whilst we wait for that, there a couple of things you can try
1) access the SoA transform directly using Node::_getTransform which returns a reference to it. I have not looked into this in detail yet, so tread carefully!
2) Multi thread your updates, more specifically have a look at SceneManager::executeUserScalableTask, an example of its use can be found here;
https://bitbucket.org/dark_sylinc/ogret ... ault#cl-49
hope that helps
- dark_sylinc
- OGRE Team Member
- Posts: 5296
- Joined: Sat Jul 21, 2007 4:55 pm
- Location: Buenos Aires, Argentina
- x 1278
- Contact:
Re: Speeding Up SceneNode::setPosition()?
Random positions != random order of access of the scene nodes.
Tutorial06 from the 2.1 samples shows how to multithread the logic & render loop, but also how to update all scene nodes from multiple threads (which is what the code al2950 pointed out is doing) while keeping an order of creation so SceneNodes are iterated relatively in order. This applies to 2.0 as well.
If you've created SceneNode A, B, C ... Z; try to make your updates A, B, C ... Z. If you update Z, M, B, H ... A; you're going to blow the cache (due to the SoA nature).
What you shouldn't be doing is calling setPosition more than once per SceneNode per frame (with minor exceptions, but most of your objects don't need to be updating more than once per frame), hence the warning in the comments. In other words, don't use the SceneNode as a physics representation of your object. Keeping the position somewhere else for temporary calculations until you reach the final position and then finally set the SceneNode's position will get you more performance.
Furthermore: How bad are your measures? There's no way even 1000s of SceneNodes updated in the worst possible order would show up as a huge bottleneck, specially compared against other giants (AABB updates, GPU rendering, API overhead from 2.0, etc, etc).
Tutorial06 from the 2.1 samples shows how to multithread the logic & render loop, but also how to update all scene nodes from multiple threads (which is what the code al2950 pointed out is doing) while keeping an order of creation so SceneNodes are iterated relatively in order. This applies to 2.0 as well.
If you've created SceneNode A, B, C ... Z; try to make your updates A, B, C ... Z. If you update Z, M, B, H ... A; you're going to blow the cache (due to the SoA nature).
What you shouldn't be doing is calling setPosition more than once per SceneNode per frame (with minor exceptions, but most of your objects don't need to be updating more than once per frame), hence the warning in the comments. In other words, don't use the SceneNode as a physics representation of your object. Keeping the position somewhere else for temporary calculations until you reach the final position and then finally set the SceneNode's position will get you more performance.
Furthermore: How bad are your measures? There's no way even 1000s of SceneNodes updated in the worst possible order would show up as a huge bottleneck, specially compared against other giants (AABB updates, GPU rendering, API overhead from 2.0, etc, etc).
- excaliburHisSheath
- Gnoblar
- Posts: 18
- Joined: Sat Feb 15, 2014 8:06 pm
Re: Speeding Up SceneNode::setPosition()?
That's an image of the profile I'm taking of my code. The test I'm running is I'm creating and destroying 1000 unit cubes per frame, with "destruction" meaning "hide the mesh". I'm focusing only on code that I'm writing, so the image above is focused on Scene::Update(), which is everything except rendering the scene. From the profiling it looks like Node::setPosition() is taking up more than half of the non-rendering time of the frame. Obviously this is because there's nothing else going on in the scene, but it's the last bottleneck that's making this test run slower than I'd like. I'm only setting the position of a node once per frame, and I'm iterating in blocks of 1000 in order of creation.
So yeah, setPosition() isn't that bad, especially since I'm excluding all of the render stuff. I'm just looking to speed things up as much as possible for the purposes of benchmarking the code I've been writing. Is multithreading the only solution? I'm willing to try it, it just seems a bit much for my simple example.
- dark_sylinc
- OGRE Team Member
- Posts: 5296
- Joined: Sat Jul 21, 2007 4:55 pm
- Location: Buenos Aires, Argentina
- x 1278
- Contact:
Re: Speeding Up SceneNode::setPosition()?
That hardly tells me anything. First, because I have no information of how many milliseconds the whole frame takes, and how many are spent in setPosition.excaliburHisSheath wrote:From the profiling it looks like Node::setPosition() is taking up more than half of the non-rendering time of the frame. Obviously this is because there's nothing else going on in the scene, but it's the last bottleneck that's making this test run slower than I'd like. I'm only setting the position of a node once per frame, and I'm iterating in blocks of 1000 in order of creation.
No. I also said that order in which you update the SceneNodes is very important. Sort them using (uint8*)Node::mTransform::mParents + Node::mTransform::mIndex as key(any of the pointers will do actually). Though keeping them in the order they were created usually is enough.excaliburHisSheath wrote:Is multithreading the only solution?
Second, I'm seeing _RTC_CheckEsp, which means you're profiling a debug build. This can strongly skew the results.
Third, I'm usually in favour of early profiling and optimization, but you're very early microprofiling. Things like scalability and relationships are important. If setPosition takes 50% of your CPU time at 1000 cubes, it could take 5% of your time at 50.000 cubes because the ratios with other bottlenecks wasn't linear. First make sure that setPosition is really the culprit and that it is going to pose an actual problem.
Fourth, it seems from that profile pic like you're not doing anything else important. It's no wonder the only relevant function is going to show up.
How are you "hiding" the mesh?I'm creating and destroying 1000 unit cubes per frame, with "destruction" meaning "hide the mesh"
Define "slower than I'd like". You're being very vague, again.excaliburHisSheath wrote:but it's the last bottleneck that's making this test run slower than I'd like.
- excaliburHisSheath
- Gnoblar
- Posts: 18
- Joined: Sat Feb 15, 2014 8:06 pm
Re: Speeding Up SceneNode::setPosition()?
Thank you for your help, I think a big part of the problem was that I was profiling in debug and that was slowing things down hugely. This is part of an independent study for university and I'm doing comparisons against a professor-provided engine which was not building in release mode, so I was profiling my code in debug as well to keep things fair. At your suggestion I got both engines building in release and now for my code the non-draw code is taking 0.05% of the frame time, so setPosition() is definitely not a major bottleneck That said, let me still answer your questions so I can at least get more familiar with Ogre.
The scene update time (excluding render time) was about 1.5 ms, so setPosition() would have been taking ~0.7 ms each frame. The draw time was upwards of 100 ms each frame, though I'm making no attempts to optimize draw times because it's not relevant to the work I'm doing.dark_sylinc wrote:That hardly tells me anything. First, because I have no information of how many milliseconds the whole frame takes, and how many are spent in setPosition.
You're right, I've already cleared up much more major bottlenecks, so this is down to minor fiddling. I asked more out of curiosity than necessity since I'm not terribly experienced with Ogre.dark_sylinc wrote:Third, I'm usually in favour of early profiling and optimization, but you're very early microprofiling.
Entity::setVisible( false ); I tried using setVisible() on the SceneNodes, but doing it directly on the Entity seemed to be faster.dark_sylinc wrote:How are you "hiding" the mesh?
It's slightly slower than the reference engine that I mentioned above. When I removed the calls to setPosition() my code ran faster than the reference engine, so I was curious if there was something I could do to make things a bit faster. After changing to a release build the two are about the same, so I'm not worried about it any more.dark_sylinc wrote:Define "slower than I'd like". You're being very vague, again.