Kris Nye

The overhead of passing a 64 byte Matrix by value is significant. Most especially when you are comparing two matrices for equivalency (==), or performing a Vector*Matrix multiplication (Vector3.Transform(Matrix)).

The following matrix comparison function performs 5-10 times better than your built in == comparison. If the matrices are equal, then it is about 5 times faster. If they are unequal then it fails fast, and is about 10 times faster.

public static bool Equals(ref Matrix a, ref Matrix b)
{
// i check the diagonal first for quick fails
return a.M11 == b.M11
&& a.M22 == b.M22
&& a.M33 == b.M33
&& a.M44 == b.M44
&& a.M12 == b.M12
&& a.M13 == b.M13
&& a.M14 == b.M14
&& a.M21 == b.M21
&& a.M23 == b.M23
&& a.M24 == b.M24
&& a.M31 == b.M31
&& a.M32 == b.M32
&& a.M34 == b.M34
&& a.M41 == b.M41
&& a.M42 == b.M42
&& a.M43 == b.M43;
}

It's faster simply because it passes the Matrices by reference, whereas the == operator passes both matrices by value:
public static bool operator ==(Matrix a, Matrix b)

That's a copy of 128 bytes of data, before we even check the first element!

Please confirm that you plan on providing "by ref" methods like this in addition to the very handy (if inefficient) current members.


btw- good job on the API overall guys.  Especially you Tom Miller.  Getting past the MS bureacracy in order to make something cool is not easy.  I know.  Kudos.


Re: XNA Framework End users shouldn't have to rewrite XNA math functions in order to improve performance.

Serapth

I understand your point, and I agree 100%. However, I don't think this is yet the time to worry about performance. The age old axiom of make it work then make it fast is a good thing. I hope by final release they add optimized options but right now I don't think it should be the focus. This is doubly true given XNAs focus on Indy and beginning developers, which actually adds a 3rd aspect to that equation. Make it work, make it easy, then make it fast.

I love the simplicity of XNA as it stands now ( minus the bits that dont work right, or lack of content pipeline! :D ) and I dont want to see that prematurely fouled by early optomizations.

However, if at release the glaring performance flaws still exist, ill join you in the revolution!!! ;)





Re: XNA Framework End users shouldn't have to rewrite XNA math functions in order to improve performance.

AndyL

Hmmm, I always assumed that using 'ref' would lead to the value types being boxed first, and thus would be slower. In fact I've just looked at the MSIL for the test case above, and it does box the values. If your timings are correct then I can only assume that the Jitter is somehow optimising that away, but I've never heard of that happening before!



Re: XNA Framework End users shouldn't have to rewrite XNA math functions in order to improve performance.

Jurak

AndyL- There is no "box" when using the "ref" keyword. Which IL instruction are you interpreting as a "box" instruction

Seraph- This is a "design philosophy" issue that should be addressed now. XNA is not just a fun little toolkit for beginners to write sprite based games. Many serious game developers want to use this for state of the art games. If the developers take advantage of what the language provides then this will be much easier.

C# IS as fast as C++ IF you take advantage of what the language provides.

I guarantee that pretty much all of the XNA authors are former C++ coders who wouldn't dream of passing a 64 byte struct to a C++ method by value.
What suddenly makes it ok to do it in C#

Here is the Direct3D Vector Transform method:

D3DXVECTOR4 *
D3DXVec4Transform( D3DXVECTOR4 * pOut, CONST D3DXVECTOR4 * pV, CONST D3DXMATRIX * pM );

Check thru all the Direct3D Math api's, and you will find that they only pass large structures by reference.

Is there really any good reason why we can't have C# methods that perform just as well   That's all I'm asking for, and that requires using the ref keyword when passing matrices (and Vectors).







Re: XNA Framework End users shouldn't have to rewrite XNA math functions in order to improve performance.

Serapth

No, as I understand it, using ref will only result in boxing if the type is a value type( not derived from type object ). This means int will result in boxing as would any struct, but any non struct object would not be boxed. In that case, passing it by ref should be almost identical to the C++ world of passing by reference, meaning the reference itself sits on the stack, but points to memory on the heap ( whatever the hell that actually means in managed world ).

Structs are an exception, as I believe they are basically light weight classes ( with limits ) that exists solely on the stack. Thus, when passed by reference they need to be boxed. It also means that passing objects via ref is actually better from a performance perspective, assuming the object is of a sufficent size to see a gain.

Granted, this is all C# 1.0 based knowledge, if things have changed in the last few versions, I apologize.





Re: XNA Framework End users shouldn't have to rewrite XNA math functions in order to improve performance.

Serapth

Jurak wrote:
AndyL- There is no "box" when using the "ref" keyword. Which IL instruction are you interpreting as a "box" instruction

As I said above, that isnt strictly true. Intrinsic types and structs are boxed when passed by reference. Unless, like I said earlier, this was changes with C#2 or C#3.

Jurak wrote:

Seraph- This is a "design philosophy" issue that should be addressed now. XNA is not just a fun little toolkit for beginners to write sprite based games. Many serious game developers want to use this for state of the art games. If the developers take advantage of what the language provides then this will be much easier.

C# IS as fast as C++ IF you take advantage of what the language provides.

I guarantee that pretty much all of the XNA authors are former C++ coders who wouldn't dream of passing a 64 byte struct to a C++ method by value.
What suddenly makes it ok to do it in C#

Here is the Direct3D Vector Transform method:

D3DXVECTOR4 *
D3DXVec4Transform( D3DXVECTOR4 * pOut, CONST D3DXVECTOR4 * pV, CONST D3DXMATRIX * pM );

Check thru all the Direct3D Math api's, and you will find that they only pass large structures by reference.

Is there really any good reason why we can't have C# methods that perform just as well That's all I'm asking for, and that requires using the ref keyword when passing matrices (and Vectors).

I think you misunderstood me. I agree with you on this point. I just think at this point in the beta is the wrong time to address performance issues, especially performance issues at the sake of complexity. There are so many things in XNA that need to be fixed or added, that I dont think performance should be the primary concern.

I understand the C# can be damned near as fast as C++, and I would love to see XNA go a long way towards smashing down the irrational bias against C#. That said, I think your estimates that "pretty much all" XNA authors are former C++ coders is most likely wrong... this coming from a C++ programmer! Many of the C++ coders are probrably ignoring XNA as they are working for major dev houses and are still using the XDK and C++ to create games. That leaves two groups, C++ programmers who are writing small or indy games who jumped on XNA as an opportunity to develop on a console ( for the first real time, ignoring the Net Yaroze from sony ) and the demographic that has always wanted to write games but were daunted by the process. I imagine you would find atleast a 50/50 split between the two camps.





Re: XNA Framework End users shouldn't have to rewrite XNA math functions in order to improve performance.

Jurak

Serapth- Your understanding of "boxing", "structs", "references" and "values" within the .Net CLR framework is incorrect.

1. Boxing only occurs when a struct is assigned to a "reference" type variable. (such as "object", or an "interface".)
2. Using the "ref" keyword has NOTHING WHATSOEVER to do with boxing. It merely passes the address to the variable, rather than the "value" of the variable. This means that any modification to the variable within the called method will change the variable in the calling method.
3. When passed by "ref", the address ALWAYS points to an object on the STACK. This is how we know that the referenced item can't move. It's on the stack underneath the current method call.

This thread really isn't about the mechanics of the CLR though. If you don't understand them, then please ask a question in another thread.

-ps. Serapth- I said all of the "XNA Authors" are probably former C++.  Ask them.  Pretty much all Microsoft C# programmers are former C++ coders.  About 95%+.




Re: XNA Framework End users shouldn't have to rewrite XNA math functions in order to improve performance.

AndyL

 Jurak wrote:

This thread really isn't about the mechanics of the CLR though. If you don't understand them, then please ask a question in another thread.

Well, it is really, as it's the mechanics that dictate the performance you mention .

I'll always be able to rewrite the XNA matrix to be more efficient - for instance think about how you can optimise the maths (and storage) if you know the transformation matrix is always affine. But I guess the optimisation you mention is a no-brainer really (apart from the fact that I know of no case where an exact equality check is useful for comparing matrices ).

Anyhow, you're right, the MSIL doesn't box the struct- I just had a typo in my test case. (It is 2.00am here!)

Andy.

 

Edit: And of course, now is the time to sort the perf out.





Re: XNA Framework End users shouldn't have to rewrite XNA math functions in order to improve performance.

Jurak

You are right that Matrix comparison is rarely needed, but I do have a part of my rendering engine that checks to make sure a state change is needed before applying it. That requires checking matrices.

Can you say it's not useful to call Vector3.Transform(Vector3 v, Matrix m)
If you have 1000 vertexes to transform (and there are very good reasons to do this from outside of a vertex shader), then is it a good idea to pass a matrix by value, a vector by value, then reassign the vector by value for every single one I don't think so.

What's wrong with adding

///<Summary>
/// Transforms the vector v by the matrix m and leaves the result in v.
// Matrix m is not modified by this call.
///</Summary>
public static void Vector3.Transform(ref Vector3 v, ref Matrix m);

This doesn't make anything harder for the novice developers since they can still use the easily understandable "by value" method, but provides the performance that some of us need for our engines.

As it is I will have to write yet another Matrix Vector transform function (for the millionth time). And that is a real disappointment.

edit- if I don't do the matrix comparisons to reduce redundant API calls, then I run about 7fps slower than normal.





Re: XNA Framework End users shouldn't have to rewrite XNA math functions in order to improve performance.

AndyL

 Jurak wrote:

What's wrong with adding

///<Summary>
/// Transforms the vector v by the matrix m and leaves the result in v.
//  Matrix m is not modified by this call.
///</Summary>
public static void Vector3.Transform(ref Vector3 v, ref Matrix m);

This doesn't make anything harder for the novice developers since they can still use the easily understandable "by value" method, but provides the performance that some of us need for our engines.

As it is I will have to write yet another Matrix Vector transform function (for the millionth time). And that is a real disappointment.

Hey, I'm not arguing .

I guess I have such low expectations of any 3rd party maths library that I expect to have to write my own, as they are always missing something I need, and invariably slower than optimal. What worries me is that any future VMX optimisations might be applied to the XNA maths classes only, so if we use our own structs/classes we will be screwed!

Edit: And I wouldn't advocate leaving in the non-ref versions for the same reason I'd shoot anyone passing matrices on the stack in C++. Why teach bad habits





Re: XNA Framework End users shouldn't have to rewrite XNA math functions in order to improve performance.

Serapth

Jurak wrote:
Serapth- Your understanding of "boxing", "structs", "references" and "values" within the .Net CLR framework is incorrect.

1. Boxing only occurs when a struct is assigned to a "reference" type variable. (such as "object", or an "interface".)
2. Using the "ref" keyword has NOTHING WHATSOEVER to do with boxing. It merely passes the address to the variable, rather than the "value" of the variable. This means that any modification to the variable within the called method will change the variable in the calling method.
3. When passed by "ref", the address ALWAYS points to an object on the STACK. This is how we know that the referenced item can't move. It's on the stack underneath the current method call.

This thread really isn't about the mechanics of the CLR though. If you don't understand them, then please ask a question in another thread.

-ps. Serapth- I said all of the "XNA Authors" are probably former C++. Ask them. Pretty much all Microsoft C# programmers are former C++ coders. About 95%+.

I by no means pretend to be an expert on managed code, like I said earlier I have come from a C++ background and have mostly used C# in areas where performance really didnt mean a damned thing. However, everything I have read ( unless, like I said, in the last few C# revisions has changed ) says you are wrong on a few points here. Please don't take this as hostility, it isnt.

1. Boxing only occurs when a struct is assigned to a "reference" type variable. (such as "object", or an "interface".)
This may be a simple miscommunication between us, Im not sure. A struct is a value type ( like an intrinsic int ), so if passed to a managed object or collection, it is boxed. I have a feeling we are saying the same thing. Keep in mind my origonal responce wasnt to you, it was in explanation of why he saw certain types being boxed. However, passing an intrinsic type or struct where a class derived from object is expected, will result in boxing.

2. Using the "ref" keyword has NOTHING WHATSOEVER to do with boxing. It merely passes the address to the variable, rather than the "value" of the variable. This means that any modification to the variable within the called method will change the variable in the calling method.

"ref" itself has nothing to do with boxing, but if the function is something like void foo(ref Object myFoo) and you pass in a struct, it will be boxed and the resulting boxed value will be passed in. Atleast, this is how I understand it. So yes, "ref" itself has no end result but what is "ref'd" will have an impact.

For example from the language reference on boxing:

Since structs are not reference types, these operations are implemented differently for struct types. When a value of a struct type is converted to type object or to an interface type that is implemented by the struct, a boxing operation takes place. Likewise, when a value of type object or a value of an interface type is converted back to a struct type, an unboxing operation takes place. A key difference from the same operations on class types is that boxing and unboxing copies the struct value either into or out of the boxed instance. Thus, following a boxing or unboxing operation, changes made to the unboxed struct are not reflected in the boxed struct.

All I was saying is, there are cases, even when ref is used, where items get boxed.

As to your 3rd point, I admit, I mangled termenongly about stack and heap to the point, I wont even bother arguing! :)

As to the XNA authors bit, im still not sure. I have talked to many people with only introductory programming experience that are excited by XNA. Also, Microsoft in their own literature talked about XNA reaching the masses. I will agree thought that the vast majority of C# programmers have a C++ background *in the professional world*. I think thats my distinction. I think there are a ton of people interested in XNA that have never written a line of C++ code.





Re: XNA Framework End users shouldn't have to rewrite XNA math functions in order to improve performance.

DamienG

The .NET Framework Design Guidelines Book has a section on choosing struct (value type) over class (reference type).

They recommend you do NOT use struct if your type is over 16 bytes or immutable (amoung other things).

This Matrix type at 64 bytes is well over 16 bytes AND is not immutable.

It would be interesting to know why the XNA team decided to ignore both recommendations from the team behind the CLR/Framework.

[)amien





Re: XNA Framework End users shouldn't have to rewrite XNA math functions in order to improve performance.

AndyL

Serapth,

Read above - I've checked the MSIL and there is no boxing (only my typos!)

As for XNA being for hobby developers - XNA set out to make professional games development faster and cheaper. It just so happens that the XNA framework (a small part of XNA) has been released to the hobby market first, before the pro version is completed.





Re: XNA Framework End users shouldn't have to rewrite XNA math functions in order to improve performance.

AndyL

DamienG wrote:

It would be interesting to know why the XNA team decided to ignore both recommendations from the team behind the CLR/Framework.

Can't speak for them in person, but I suspect it is to speed up marshalling into native code.





Re: XNA Framework End users shouldn't have to rewrite XNA math functions in order to improve performance.

Serapth

AndyL wrote:

Serapth,

Read above - I've checked the MSIL and there is no boxing (only my typos!)

As for XNA being for hobby developers - XNA set out to make professional games development faster and cheaper. It just so happens that the XNA framework (a small part of XNA) has been released to the hobby market first, before the pro version is completed.

Dont get me wrong, im not saying XNA is *Only* for hobby devs, im saying many people out there are hobby devs. Keep in mind, there are two versions of XNA, the version we have now ( hobby oriented ) and a version to be released in the near future, which is the pro version. Im not saying XNA isnt capable of creating professional games. Im just saying what we have no is mostly targeted at smaller dev houses and hobby programmers. This is probrably why we cant use Visual Studio professional yet :(

I have nothing against XNA, and I especially have nothing against C#. Don't read my words that way.

As to the fact your MSIL turned out to be mistaken, there are cases where a ref value would be passed as a boxed type, that was all I was trying to explain. Alot of this thread has just been a giant miscommunication.