A few requests for Farseer 3.0

Sep 7, 2010 at 6:43 PM
Edited Sep 7, 2010 at 8:17 PM

Hello,

It's been a while since I was on last, I was just using an iteration of the Farseer Beta, and I'm finally deciding

to move to the release version.

I'm probably going to keep adding to this thread as I think of suggestions, but for now I'm just going to list

a few:

- Make an overload for ApplyLinearImpulse that doesn't take a point, and simply assumes the impulse will be applied to the body's center

- Make an overload for FixtureFactory.CreatePolygon that takes a Body, to remain consistent with FixtureFactory.CreateRectangle

- Spell "CreateCompunPolygon" in FixtureFactory as "CreateCompoundPolygon"

- EditAdd: I noticed in Body.Active (was Body.Enabled), that the for loop has turned into a foreach (Fixture...) loop, aren't we possibly allocating

memory needlessly here?

- EditAdd: As it stands, there doesn't appear to be a way to get Vertices from the Fixture's shape anymore, am I missing something?

- EditAdd: Make a "ResetDynamics" method as part of Body that zeros out Angular and Linear velocities and possibly Torque and Force

Thanks =)

Coordinator
Sep 7, 2010 at 8:16 PM

Nice to have you (and your input ;)) back.

1. Done - I did it on ApplyForce and others back when converting the code to FPE 3.0. I forgot ApplyLinearImpulse since it was not used in the library.

2. Done - I've uploaded an overloaded method, but I've not tested it.

3. Done

4. Done - It is a very little amount of memory (The enumerator), but it does not hurt readability or anything else to use for loops in that (and some other) cases. I've swiched a few foreach to for loops.

Thanks a lot for the suggestions.

Sep 7, 2010 at 8:21 PM

No problem, I just hope I'm not being a nuisance ;P

If I had known you were typing up that reply, I probably would've waited to

tack on the other few suggestions I've added to the original post, and put them

here in this reply

Thanks for the quick, good work! 

Sep 7, 2010 at 8:28 PM
Edited Sep 7, 2010 at 8:56 PM

For the record:
Last time I checked, for List<T>, foreach uses a struct enumerator, and therefor does not allocate memory. 

Furthermore, the difference in performance between any of the for-constructs (for loop calling Count, for loop using a precalculated count, foreach, or calling List<T>.ForEach) is practically immeasurable unless you have literally millions of items in the list. Also, the performance of the engine will be be unusably slow long before you'd notice any per-loop overhead (say, calling Body.Active on every body in the scene, even calling it 2 or 3 times per body). 

But, as genbox said, this is one micro-optimization that doesn't hurt readability, so there's no reason not to do it.

 

FYI: do not do the Count caching optimization that is recommended elsewhere. Use Length/Count in the for test always. The JIT looks for this when deciding whether to elide bounds checking.

Coordinator
Sep 7, 2010 at 8:38 PM

5. It was removed since it was used in the buoyancy controller only. It approximated circles (A hack) to support circles in the controller. You can still get the vertices by casting Fixture.Shape to a PolygonShape and access PolygonShape.Vertices. Any thoughts on this?

6. Done

Sep 7, 2010 at 8:43 PM
Edited Sep 7, 2010 at 8:51 PM

@JeroMiya

You make a good point about that particular case.

I don't mean to sound like a for loop purist (I like me some foreach action too!), it's just that when I see

a foreach loop, especially iterating through a long list, often, I make an involuntary eyebrow raise.

I was under the impression that List<T> sometimes will not allocate memory. In this case, I think it does, but

I would of course prefer to stand corrected.

On the topic of enumerators, would it be a hassle to make ContactEdge enumerable, so that we can

use foreach instead of contactedge.Next. I mean, it's not a big deal, just wondering.

 

Thanks for reply JeroMiya (where did you come up with this alias?)! 

 

EDIT: @genbox

Wow, you're on top of it! Thanks!

Ahh... good eye, Vertices is public in PolygonShape... but not in the other child classes it seems (not as important).

You're right though, it's a bit of a hack...

I think that a more proper property could be useful for a number of games, but eh, whatever works. =)

Coordinator
Sep 7, 2010 at 8:50 PM

@JeroMiya: Correct, it is indeed a struct and yes, the difference between for loops and foreach loops are very little. Structs still need to be allocated on the stack, it is just removed right after the struct gets out of bound (no GC anywhere). The index used on List<T> is a method call only (no extra struct) and the getter inside the Count property is inlined (special case in the compiler) when optimizations are enabled.

In this case I choose to change the foreach loops to for loops because it could not hurt :) very minor details.

Coordinator
Sep 7, 2010 at 9:02 PM

@oranjoose: You are touching yet another common case of performance problems: when to use linked lists and when to use lists? We might as well take it up now.

Lists are arrays with logic to handle capacity and some common functionality (like List.Count). The reason Erin (from Box2D) choose linked lists over arrays is because he is working with C++ and pointers. It is a difficult task to handle arrays of pointers plus he would have to implement all the functionality of List<T> himself. The result would be worse cache performance and a lot of code for a simple change in API.

In .NET we DO have List<T> and all the memory issues are handled for us by the GC and compactor (The GC subsystem that compacts the heap after collection of dead objects). That made me choose List<T> over linked lists simply because we gain flexibility and usability from it. (random access is possible with lists + it is easier to work with lists because of the extra functionality List<T> provide).

I changed the outer API first and kept the inner API intact. This way we preserve some backwards compatibility with Box2D (easier to port over changes) while still providing easy to use API. I've been wondering if I should change Body.JointList and Body.ContactList to List<T> instead of linked lists. I guess some users would like the ability to easily traverse the contacts and joints that a body contains. Any thoughts on this?

Sep 7, 2010 at 9:02 PM
Edited Sep 7, 2010 at 9:14 PM

@genbox See my edits to my original post. I was editing while you were replying heh. Agreed on the "this optimization doesn't hurt anything" front.

Also, this is a good article with regards to this discussion:

http://blogs.msdn.com/b/clrcodegeneration/archive/2009/08/13/array-bounds-check-elimination-in-the-clr.aspx

But, note that both the silverlight and XBox JIT compilers, I believe, are completely separate code-bases than either of the two mentioned in the article (x86 and x64), so I can only suppose that they use the same conditions for bounds check removal. I couldn't find a similar article addressing those particular VMs (or the ARM/JIT used in WP7 for that matter). 

This one too, but it's out of date (specifically, I question the cached Count performance benefits, based on the article above):

http://diditwith.net/2006/10/05/PerformanceOfForeachVsListForEach.aspx

 

Coordinator
Sep 7, 2010 at 9:13 PM

@JeroMiya:

Yep, the count caching trick is redundant when using the CLR compiler. As I wrote, it is a special case in the compiler. I also wrote about it somewhere on my blog (Such a long time ago, not really sure).

The array bounds stuff is a good read for those who would like to know more about CLR internals. It is a very clever piece of technology. I've never really been interested in Silverlight internals and thus, I don't know much more than it runs with its own framework. The compact framework has some limitations (also wrote about this on my blog I think) such as non-generational GC, less optimizations to compiled code and so on. Back in the FPE 2.x days I did a lot of micro-optimizations that were very helpful on the Xbox360 - Jeff also did a huge amount (actually most of them) all the way back in 1.x. If I remember correctly, he tested how much he gained from it and it was more than 10%.

Sep 7, 2010 at 10:33 PM

Thank you both for the clarification and information. It was helpful!

Thanks JeroMiya for posting those articles, they were interesting.