Saturday, August 10, 2013

Structs in Code Contracts and Vector Optimizations

After spending hours trying to get my code to verify properly on a Vector2 struct, I have finally given up the goat. Not only was I running into some subtle issues that I couldn't get to the bottom of, but a coworker convinced me that having a mutable vector object was a good idea. So in the end, it just made sense to scrap the idea and switch it over.

That done, everything is verifying beautifully. The only things that aren't verified are things that CC would have problems with anyway, and that I could probably only truly verify with Spec#.

Now that I'm over those hurdles, I can explain the other reason why I made the switch. After a lunchtime discussion that threatened to devolve into napkin sketches, I finally grasped the concept Derek was trying to explain. It goes something like this:

In any given second of the application, the physics engine will be called something  like 100 times. Which means lots of vectors will be needed for the application. Say there's even only 100 vectors being created by each step. That's 10,000 vectors per second being created and destroyed. In C#, structs are value types, meaning they pass by value and not by reference. Every method that needed a vector would cause the object to be copied and, though it isn't big, this isn't necessary. Instead, the program should pool vectors, pulling old, unused vector objects from a collection, mutating the x and y values to suit the needs of the calculation and then putting them back in the collection when they are no longer being used. Theoretically, instead of creating 10,000 objects (or more) a second, this should allow me to instantiate no more than 100 vector objects, no matter how many times per second my physic engine is doing work. Even though structures are optimized for performance in C#, pooling them should prevent an insane amount of work from being performed under the hood.

Another (tiny) optimization I made is to lazily perform the length computation. Since it involves a square root operation, I want to only calculate it on demand. For collision detection reasons, I'm instead storing the length squared value. Another coworker (John) turned me on to this idea. For most things, I won't even need to get the actual length and storing the "c squared" value of the Pythagorean theorem will allow me to skip a costly operation when I need to.

Well, that's all for now. If anyone has any other suggestions, or and clues to how I can get structures to work for me with Code Contracts, leave a comment. I'd love to see what other people are doing with it.

No comments:

Post a Comment