Archived

This topic is now archived and is closed to further replies.

Jx

Stategy design pattern with different processor implementations

Recommended Posts

Hi, I''m just writing my maths code for my engine and i am using both Intel SSE and AMD 3DNow!. Is using the strategy pattern a good way of implementing this part of the engine so that I can select between the two. I can see that there would be a problem, for example, in my matrix library where i would have to have an "if" statement everytime I wanted to create an instance of a matrix to check the processor type. If this isn''t a good way of doing this then could someone please explain another way. thanks jx

Share this post


Link to post
Share on other sites
Create function pointers for all your math functions that use SSE or 3DNow.

At the beginning of your code work out what the user has 3DNow/SSE. Then set the funtion pointers to point to either the 3DNow functions or the SSE functions. Then use those function pointers for your math stuff.

[edited by - Monder on July 27, 2002 11:45:18 AM]

Share this post


Link to post
Share on other sites
Well sometimes, you just have to make a tradeoff between having lots of specialised implementation-specific functions, or having just a few functions where a lot of the code is duplicated. The benefit of the code-duplication method is that you''ve not got ifs/switches/virtual functions everywhere which will make it run faster, but obviously you now have almost double the amount of code to maintain.

Simple rule of thumb: if it''s a performance-critical piece of code, code 1 routine for each instruction set and duplicate any identical code. You could do this with a Strategy pattern where the base/interface class has only 1 member. On the other hand, if it''s not performance critical, only separate out the bits that differ between the two instruction sets. This lends itself better to the Template pattern.

[ MSVC Fixes | STL | SDL | Game AI | Sockets | C++ Faq Lite | Boost | Asking Questions | Organising code files ]

Share this post


Link to post
Share on other sites
quote:

I can see that there would be a problem, for example, in my matrix library where i would have to have an "if" statement everytime I wanted to create an instance of a matrix to check the processor type.


That would clearly be bad - you want to detect what to use once, then vector to the correct funtion.

You can use an OO method (use a factory to create the correct concrete strategy object) but it would have some additional overhead in the method invocation, as you don''t really need to pass in a ''this'' pointer to those methods (but you do need the vtbl, so you couldn''t make then static).

What''s most important to the performance, is that you process chunks of data at a time. If you set this level of granulaity high enough, the vtbl overhead become neglible, but you would need to use a template-policy based implementation to code your algorithms efficently. Then generate mutliple algorithms by passing in MMX, SSE, or SSE2 policies. This would let you write the code once, but have multiple optimized versions compiled.

Share this post


Link to post
Share on other sites
quote:

Magmai Kai Holmlor:
You can use an OO method (use a factory to create the correct concrete strategy object) but it would have some additional overhead in the method invocation, as you don''t really need to pass in a ''this'' pointer to those methods (but you do need the vtbl, so you couldn''t make then static).



I thought about this as well. However I can to the conclusion that you would still need to check (with an "if" or "case") inside the factory to see which concrete strategy to create so you don''t save anything and probably actually include extra unnecessary overhead.

I''ve been thinking though: Surely the time when I would want to create most of my vectors and matrices would be at the start of each level when I load game objects in. The overhead of the "if" at this point may not be to bad.

What i''d really like to do is at the start of my code, check the processor type then from then on just be able to do something like:

Matrix my_matrix = new Matrix;

and it automatically creates the right type of matrix without any further "ifs". I know this example is simplified but you get my point.

Any further help is appreciated.

Share this post


Link to post
Share on other sites
The best method I can come up with would involve a handful of factories. A base, with virtual CreateWhatever functions, and derived classes, one for each set of functions you need. At the begining of the game, create an instance of whichever factory you need inside a global base pointer. Then you can say Matix = ptr->CreateMatrix().

However, I''m sure there''s a better way to do it, i''m just tired.

CM

Share this post


Link to post
Share on other sites
Connor:

That''s basically what i''d been thinking yesterday too. I thought that I could have somesort of global singleton math class tailored to each processor, which was also a factory for the specific implementations of other classes.

So my maths class could do (for example only):

Math math = new IntelMath;

float I = math.Sin( 50 );

Matrix mat = math.CreateMatrix( );


This is dirty, and I don''t like it but i can''t think of a better way. It also means that every time I want to add another mathematics class, i''d have to write a create function for it too.

This must be a common problem so I can''t see why someone hasn''t thought up a more elegant solution....

thanks for your help guys

jx


Share this post


Link to post
Share on other sites
I really think that once you''ve created the matrix class, the one or two ifs needed would pale into insignificance once you actually use the matrix a few times. The complexity of the matrix code would be much, much greater than one or two ifs when you first create the class.

If I had my way, I''d have all of you shot!


codeka.com - Just click it.

Share this post


Link to post
Share on other sites
One possible solution is this assuming that the data part of
your matrix class doesnt change between implementations you
could do:


  

class Matrix
{
static stuct *MatrixFuncImp;
float data[16];
};


then on startup you only have to initialze the static pointer
with a MMMXMatrixFuncImp or SSEMatrixFuncImp or whatever.
All of the matrix functions are then written as inline forwards
to the MatrixFuncImp like

  
class Matrix
{
public:
Matrix &operator+=(const Matrix &_rhs)
{
return MatrixFuncImp->opAdd(this, _rhs);//or possibly just passing the data...

}
};


that way you eleminate any ifs the check is done once and you
don''t need a factory, the drawback is that you can''t get inlinening of trivial functions, but that would be quite impossible for any other solution propsosed here.

alas, most problems can be solved using an extra level of indirection, people have known that since like the 1950s

Share this post


Link to post
Share on other sites
i''ll suggest another way:

create a vectorprocessor. like a vertexshader, but in software.

why should you?
you take the whole at a much too expensive too detailed level. you have all your virtual function calls for every function, that kills all the speedgain you would have.

you know it bether, don''t you.

so say you have a function that calculates the tangentspace of a mesh. thats a function that has loops in and all that

code this function several times, one time normal, one time for intel, one time for amd. then you just send in the mesh and it gets done at optimal speed.

for general purposes you want to have some way to create vertex shaders, that processes a stream of data for you.

but as long as you want to use sse for simple single matrix multiplications, it doesn''t worth the overhead.. you have to use it for dataSTREAMS..

"take a look around" - limp bizkit
www.google.com

Share this post


Link to post
Share on other sites
sure, tackeling it on a higher level is a fundamentaly good idea, but it do require some extra work.
Oh, and about the cost of virtual functions for a matrix multiplicaion it''s neglible the cost of dereferencing the pointer is what 1-2 clock cycles having SSE code doing the muls does help.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Thought about using dll''s ?

you could create a dll for each processor and at the start up of the app load the correct dll for the processor.

Share this post


Link to post
Share on other sites
quote:
Original post by Anonymous Poster
Thought about using dll''s ?

you could create a dll for each processor and at the start up of the app load the correct dll for the processor.


That would have the same effect as my suggestion with the only differance that the could would also get dynamicly linked instead of staticly linked.

But sure a DLL does offer some advantages...

Share this post


Link to post
Share on other sites