views:

359

answers:

5

I read Cwalina book (recommendations on development and design of .NET apps).

He says that good designed struct has to be less than 16 bytes in size (for performance purpose).

My questions is - why exactly is this?

And (more important) can I have larger struct with same efficiency if I run my .NET 3.5 (soon to be .NET 4.0) 64-bit application on i7 under Win7 x64 (is this limitation CPU / OS based)?

Just to stress again - I need as efficient struct as it is possible. I try to keep it in stack all the time, the application is heavily multi-threaded and runs on sub-millisecond intervals, the current size of the struct is 64 byte.

+4  A: 
  • Larger struct is not as efficient, but then.... if you HAVE more data, you have it. No sense talking about efficiency there.

  • 64 bytes shuold be ok.

  • The main reason possibly is copy operations.... which get IIRC slower if the struct is larger. And it must be copied around quite a lot.

I would normally advice into using a class here ;) But without knowing the content of the struct, it is a little tricky.

TomTom
Tom thanks mate. Could you please provide some information which outlines why 64 bytes is OK for my CPU ?BTW - the struct was natural choice for avoiding locks. The cost of development will go much higher if I used immutable class or locks instead... So lets pass on class vs struct..
Well, there is no reference. I jus tthink 64 bytes may not be too much. It REALLY depends on the data that is in there. I NORMALLY dont use structs like that. I have a financial trading app (tons of data going through - little, around 64 bytes, somtiems 50.000+ items per second coming in) and I use classes.
TomTom
I might be wrong about struct vs class... It could be worth to look into it.
+9  A: 

You're misquoting the book (at least the 2nd edition). Jeffrey Richter states value types can be more than 16 bytes if:

You don't intend to pass them to other methods or copy them to and from a collection class.

Additionally Eric Gunnerson adds (regarding the 16 byte limit)

Use this guideline as a trigger to do more investigation.

It is simply not true that a struct "has to be less than 16 bytes in size". It all depends on usage.

If you are creating the struct and also consuming it and are worried about performance then use a profiler comparing a struct vs class to see which works best for you.

RichardOD
I said - it has to be to be considered a good design. Please quote the whole sentence. Cos from how you distored my words is - struct has to be 16 bytes or less... No it has not!I read this book just yesterday. I know what Richter said and this is not applicable to my application hence I simply ignored this... Because the topic is NOT to discuss the book but help me make MY application more efficientThank you very much!And as for Gunnerson - that is EXACTLY what I am trying to do here - investigate further!
@Maxima120. I didn't distort your words. You misquoted the book, I corrected you. The book does state to avoid structs that don't have an instance size under 16 bytes (then adds caveats). That is clearly not the same as a "good designed struct has to be less than 16 bytes in size".
RichardOD
+3  A: 

Only you know how your structs are being used in your program. But if nothing else, you can always test it for yourself. For instance, if it's frequently passed to other functions, the following may illuminate you:

class MainClass
{
    static void Main()
    {
        Struct64 s1 = new Struct64();
        Class64 c1 = new Class64();
        DoStuff(s1);
        DoStuff(c1);
        Stopwatch sw = new Stopwatch();
        sw.Start();
        for (int i = 0; i < 10000; i++)
        {
            s1 = DoStuff(s1);
        }
        sw.Stop();
        Console.WriteLine("Struct {0}", sw.ElapsedTicks);
        sw.Reset();

        sw.Start();
        for (int i = 0; i < 10000; i++)
        {
            c1 = DoStuff(c1);
        }
        sw.Stop();
        Console.WriteLine("Class {0}", sw.ElapsedTicks);
        sw.Reset();

        Console.ReadLine();
    }
}

with:

public class Class64
{
    public long l1;
    public long l2;
    public long l3;
    public long l4;
    public long l5;
    public long l6;
    public long l7;
    public long l8;
}
public struct Struct64
{
    public long l1;
    public long l2;
    public long l3;
    public long l4;
    public long l5;
    public long l6;
    public long l7;
    public long l8;
}

Try this sort of thing with representative structs/classes, and see what results you get. (On my machine, above test, the class seems ~3 times faster)

Damien_The_Unbeliever
Same here.. For 16 bytes I had 24/18 (struct vs class), for 32 bytes 30/17 vor 64 bytes 42/18. It seems 16 bytes indeed is a reasonable threshold regardless CPU / bus width.
A: 

I think another key point is that if you have a list with a million structs, that is still only one memory allocation on the heap, while a list with a million classes in it is going to have about a million separate heap objects. The garbage collection load is something quite different in both cases. From this point of view, the struct may come out ahead.

Tarydon
if you store you're structs in a heap allocated object you better have them heap allocated as well! otherwise things get really funny when your current stackframe dies (together with the stack allocated objects) and you try to access them through the heap allocated object. That's one reason why all members (including value typed) are stored on the heap
Rune FS
@Rune FS - true, but the whole vector of structs is going to be in one large, contiguous block of memory. As opposed to a million small pieces with individual lifetimes.
Tarydon
+1  A: 

One of the things i learnt while assembly language programming is that you align your structs (and other data) on 8 or 16 byte boundaries (there is actually a preprocessor command for it in MASM). The reason for this is considerably faster memory access when storing or moving things around in memory. Keeping your structs under 16 bytes in size would ensure that this memory alignment could be done successfully because nothing would cross the alignment boundaries.

However i would expect this sort of thing to be largely hidden from you when using the .Net framework. If your structs were bigger than 16 bytes them i would expect the framework (or JIT compiler) to align your data on 32 byte boundaries, and so on. It would be interesting to see some validation of the comments in those books, and see what the difference in speed is.

slugster
the layout of structs is not a secret. Look up for LayoutStruct C# attribute.. E.g. http://www.vsj.co.uk/articles/display.asp?id=501
That is a good link. I was more talking about the behaviour of the framework/JITter, and wondering why 16 was such a magic number (and whether it is still so magic or whether it has either been increased or made irrelevant).
slugster