3
\$\begingroup\$

I am new to data oriented design and I am currently developing a physics engine as a hobby project. I am really interested in data orinted design but I am not sure how to apply data oriented design to my physics engine. I am using Box2D as a reference and when I look at the source code, erin catto use linked list as a container for rigid bodies. The reason why he use linked list over array is stated here. This is what he stated at the forum

I could use an array of body pointers. That would have worse cache performance. First you have to get the array element, then the element data. I would also need some extra logic to ensure the array is big enough.

I'm not sure how I would use an array of bodies. If I resize the array, the pointers become invalid. I could return an index when you create a body, but then the array would have holes as bodies are freed. Traversing the body array would then involve extra logic to see if the body is allocated or destroyed. Also, it may be cumbersome for users to have to use an index rather than the object itself. If I return the current body pointer from the index, there will likely be many bugs where users hold onto that pointer and it becomes invalid.

Finally, when islands are created the set of bodies is likely no to be contiguous in memory.

I will add that when the physics engine do a broadphase collision detection, It will return a list of collider pairs that will most likely located randomly at memory. From what I understand, you need something like handle so the data can be moved around in memory. With handle, you only need to move the last object to the slot that holds the deleted object. Using handle over pointer will add an extra level of indirection which results in more cache misses. So is it really beneficial to store a set of rigid bodies or their components as array?

Edit: I believe there are parts of physics engine that benefit from storing rigid body using array. For example the integration phase. But I am not sure if the benefits outweight the disadvantages.

\$\endgroup\$
  • \$\begingroup\$ the link you provided to the forum post is broken. \$\endgroup\$ – The Light Spark Nov 26 '15 at 3:41
  • \$\begingroup\$ @AnurupDey thanks for informing me. I have fix the link. \$\endgroup\$ – kevinyu Nov 26 '15 at 3:44
  • 2
    \$\begingroup\$ Links to stuff in questions means that later, this question may become less useful. Put the relevant stuff here. \$\endgroup\$ – Almo Nov 26 '15 at 3:52
  • \$\begingroup\$ Other than this being related to game physics engine, this is more of a Stack Overflow question as it relates to programming theory, not game physics. \$\endgroup\$ – Steven Nov 26 '15 at 4:32
  • \$\begingroup\$ @Steven: I think the tradeoffs here depend sensitively on the kinds of workloads we tend to encounter in games as opposed to, eg. scientific computing. The fact that these bodies aren't solely controlled by the physics system, but rather we'll likely have unrelated gameplay scripts accessing them and applying unpredictable forces/velocities/constraints or teleporting them around randomly, makes certain interfaces more practical than others in ways that might not be obvious to non-game specialists. I think this question is in the right place. \$\endgroup\$ – DMGregory Nov 26 '15 at 14:20
3
\$\begingroup\$

What you should optimize for is probably best shown in and around slide 40 of this presentation: http://www.slideshare.net/cellperformance/gdc15-code-clinic

The idea is to prevent the code from doing wasteful things with the CPU. Loading memory and then throwing it away is rather wasteful. So, naturally, you can reorder data to make better use of it. If you see a commonly used function that uses a certain set of variables, you'll want to make sure that they can be loaded on as little cache lines as possible by putting them close together and aligning them properly in memory.

With sufficiently complicated physics engines (ignoring fixed size particle system solvers), given that bodies contain lots of data and are rarely accessed sequentially, there aren't too many other optimizations to perform.

So is it really beneficial to store a set of rigid bodies or their components as array?

One extra allocation (when compared to intrusive linked lists), addition time is almost always O(1) (certain additions will trigger a resize of the array memory, but only in the beginning and can be largely avoided), removal is O(1) (when using the swap-with-last trick, since order doesn't matter), iteration requires indirection, but it doesn't happen frequently. Intrusive linked lists - O(1) addition, O(1) removal, no extra allocations, no indirection on iteration.

Intrusive linked lists look better than arrays but arrays are not far behind for this use case. Expect the performance for both to be fairly similar. The Bullet physics engine uses arrays, by the way.

P.S. Plain linked lists (like std::list) would require one more allocation for each node (since it only accepts copies of values to store, and that's not an option with physics bodies, so pointers would have to be used) and require extra indirection, so I'd recommend avoiding those.

\$\endgroup\$
  • \$\begingroup\$ Can you make it clear in your answer when you say arrays do you mean Object objects[10] or Object* object[10] - the implications on performance are different. When an array of pointers you do get benefit of pulling neighbouring pointers into cache, but with intrusive pointers you get benefit of pulling data of the pointed-to-object into the cache. Depending on cache line size this means a lot. \$\endgroup\$ – Steven Nov 26 '15 at 19:07
  • \$\begingroup\$ @Steven, as already noted by the creator of Box2D, array of objects is not a useful option. I was talking about an array of pointers. And physics bodies do not fit into cache lines anyway (i7 cache line size - 64 bytes). \$\endgroup\$ – snake5 Nov 26 '15 at 20:12
  • \$\begingroup\$ Not to nit-pick, but not all development is on i7, also there are multiple levels of cache to consider. Depending on your body layout it could fit in a cache line - for example it may be a wrapper around motion states that are stored by index into another table. Some engines do this to give the player a handle to a 'body' but internally the data is stored by value in arrays. \$\endgroup\$ – Steven Nov 26 '15 at 23:51
  • \$\begingroup\$ @snake5 If we transform RigidBody into component based object like in Entity Component System, I think every component can fit into one cache line. For example if we split RigidBody into PositionComponent, VelocityComponent, ColliderComponent and etc. Every component is stored on another table like what Steven state. The problem with this approach is, physics engine rarely access this component in isolation, like in collision system, It will access two collider at a time. \$\endgroup\$ – kevinyu Nov 27 '15 at 2:41
  • \$\begingroup\$ @Steven, it's a very common size, do your research. And using a separate motion state doesn't make things magically fit. See btCollisionObject, it's still huge: github.com/bulletphysics/bullet3/blob/master/src/… Every btTransform has its own cache line. As for "some engines" - if they're commercial-grade, please point me to them. If they're hobby projects, I don't think they qualify for this discussion. \$\endgroup\$ – snake5 Nov 27 '15 at 5:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.