Speeding Up SceneNode::setPosition()?

A place for users of OGRE to discuss ideas and experiences of utilitising OGRE in their games / demos / applications.
Post Reply
User avatar
excaliburHisSheath
Gnoblar
Posts: 18
Joined: Sat Feb 15, 2014 8:06 pm

Speeding Up SceneNode::setPosition()?

Post by excaliburHisSheath »

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!
al2950
OGRE Expert User
OGRE Expert User
Posts: 1227
Joined: Thu Dec 11, 2008 7:56 pm
Location: Bristol, UK
x 157

Re: Speeding Up SceneNode::setPosition()?

Post by al2950 »

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
User avatar
dark_sylinc
OGRE Team Member
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()?

Post by dark_sylinc »

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).
User avatar
excaliburHisSheath
Gnoblar
Posts: 18
Joined: Sat Feb 15, 2014 8:06 pm

Re: Speeding Up SceneNode::setPosition()?

Post by excaliburHisSheath »

Image

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.
User avatar
dark_sylinc
OGRE Team Member
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()?

Post by dark_sylinc »

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.
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:Is multithreading the only solution?
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.

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.
I'm creating and destroying 1000 unit cubes per frame, with "destruction" meaning "hide the mesh"
How are you "hiding" the mesh?
excaliburHisSheath wrote:but it's the last bottleneck that's making this test run slower than I'd like.
Define "slower than I'd like". You're being very vague, again.
User avatar
excaliburHisSheath
Gnoblar
Posts: 18
Joined: Sat Feb 15, 2014 8:06 pm

Re: Speeding Up SceneNode::setPosition()?

Post by excaliburHisSheath »

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 :D That said, let me still answer your questions so I can at least get more familiar with Ogre.
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.
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:Third, I'm usually in favour of early profiling and optimization, but you're very early microprofiling.
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:How are you "hiding" the mesh?
Entity::setVisible( false ); I tried using setVisible() on the SceneNodes, but doing it directly on the Entity seemed to be faster.
dark_sylinc wrote:Define "slower than I'd like". You're being very vague, again.
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.
Post Reply