Click here to Skip to main content
15,885,953 members
Articles / Programming Languages / C#
Tip/Trick

Sequential Structure Layout For Speed

Rate me:
Please Sign up or sign in to vote.
5.00/5 (1 vote)
21 Jul 2010CPOL1 min read 14.8K   2   5
This code will Highlight Wise Choice for sequential layout Structure
We are going to declare a Matrix which is used to house a Set.. Explicitly.  Just by putting the iteration value in the middle of the sequence you can speed up that example code by a factor of 36% !.. and that is just by adjusting the location of data in the memory....

The code below highlights the differences (there was a nice table here to show the differences... but it has been improved to be actual code (not it's intent, so I edited it out :( ) Nearly Full code is given below.


The thing to notice is that position of the class member i is in different places.. the reason this is so useful is that it highlights quite nicely the effect of cache misses... a quick look at the Compiler choice classes will show you where the differences are...

And Here are the results from adding i to the matrix elements... (this was individually timed inside of a for loop  200 times, then a simple average was taken)... Total savings 0.0175 seconds! This was pitted against the CLR and CLR results are somewhere in between (as would be expected).

--Upgraded From My Blog.... :laugh:


Here is the Running code, The CompilerChoice classes are CLR layout comparisons (results not shown)



[StructLayout(LayoutKind.Explicit)]
public class PoorChoice
{
    [FieldOffset(0)]
    public int i;
    [FieldOffset(4)]
    public int m00;
    [FieldOffset(8)]
    public int m01;
    [FieldOffset(16)]
    public int m02;
    [FieldOffset(20)]
    public int m03;
    [FieldOffset(24)]
    public int m10;
    [FieldOffset(28)]
    public int m11;
    [FieldOffset(32)]
    public int m12;
    [FieldOffset(36)]
    public int m13;
    [FieldOffset(40)]
    public int m20;
    [FieldOffset(44)]
    public int m21;
    [FieldOffset(48)]
    public int m22;
    [FieldOffset(52)]
    public int m23;
    [FieldOffset(56)]
    public int m30;
    [FieldOffset(60)]
    public int m31;
    [FieldOffset(64)]
    public int m32;
    [FieldOffset(68)]
    public int m33;
}

[StructLayout(LayoutKind.Explicit)]
public class GreatChoice
{
    [FieldOffset(0)]
    public int m00;
    [FieldOffset(4)]
    public int m01;
    [FieldOffset(8)]
    public int m02;
    [FieldOffset(12)]
    public int m03;
    [FieldOffset(16)]
    public int m10;
    [FieldOffset(20)]
    public int m11;
    [FieldOffset(24)]
    public int m12;
    [FieldOffset(28)]
    public int m13;
    [FieldOffset(32)]
    public byte i;
    [FieldOffset(33)]
    public int m20;
    [FieldOffset(37)]
    public int m21;
    [FieldOffset(41)]
    public int m22;
    [FieldOffset(45)]
    public int m23;
    [FieldOffset(49)]
    public int m30;
    [FieldOffset(53)]
    public int m31;
    [FieldOffset(57)]
    public int m32;
    [FieldOffset(61)]
    public int m33;
}

public class CompilerChoice1
{
    public int i;
    public int m00;
    public int m01;
    public int m02;
    public int m03;
    public int m10;
    public int m11;
    public int m12;
    public int m13;
    public int m20;
    public int m21;
    public int m22;
    public int m23;
    public int m30;
    public int m31;
    public int m32;
    public int m33;
}

public class CompilerChoice2
{
    public int m00;
    public int m01;
    public int m02;
    public int m03;
    public int m10;
    public int m11;
    public int m12;
    public int m13;
    public byte i;
    public int m20;
    public int m21;
    public int m22;
    public int m23;
    public int m30;
    public int m31;
    public int m32;
    public int m33;
}
    public GreatLayoutTest(System.Windows.Forms.Label label)
    {
        Console.WriteLine("the Size of Poor Choice is:" + System.Runtime.InteropServices.Marshal.SizeOf(typeof(PoorChoice)).ToString());
        Console.WriteLine("the Size of Great Choice is:" + System.Runtime.InteropServices.Marshal.SizeOf(typeof(GreatChoice)).ToString());
        //Type 'ThreadingBestPractices.CompilerChoice1' cannot be marshaled as an unmanaged structure; no meaningful size or offset can be computed."
        //Console.WriteLine("the Size of Compiler Choice 1 is:" + System.Runtime.InteropServices.Marshal.SizeOf(typeof(CompilerChoice1)).ToString());
        //Type 'ThreadingBestPractices.CompilerChoice1' cannot be marshaled as an unmanaged structure; no meaningful size or offset can be computed."
        //Console.WriteLine("the Size of Compiler Choice 2 is:" + System.Runtime.InteropServices.Marshal.SizeOf(typeof(CompilerChoice2)).ToString());
        List<double[]> ControlResults = new List<double[]>();
        PoorLayout pl = new PoorLayout();
        label.Text = pl.Test();
        TimeSpan[] ts = new TimeSpan[2];
        DateTime[] ts_start = new DateTime[2];
        double[] duration = new double[4];

        PoorChoice poor = new PoorChoice();
        GreatChoice great = new GreatChoice();
        CompilerChoice1 clr1 = new CompilerChoice1();
        CompilerChoice2 clr2 = new CompilerChoice2();

        for (int i = 0; i < 200; i++)
        {
            label.Text = (200 - i).ToString(); label.Refresh();
            #region Poor
            Stopwatch sw = Stopwatch.StartNew();
            poor.m00 += poor.i;
            poor.i++;
            poor.m01 += poor.i;
            poor.i++;
            poor.m02 += poor.i;
            poor.i++;
            poor.m03 += poor.i;
            poor.i++;
            poor.m10 += poor.i;
            poor.i++;
            poor.m11 += poor.i;
            poor.i++;
            poor.m12 += poor.i;
            poor.i++;
            poor.m13 += poor.i;
            poor.i++;
            poor.m20 += poor.i;
            poor.i++;
            poor.m21 += poor.i;
            poor.i++;
            poor.m22 += poor.i;
            poor.i++;
            poor.m23 += poor.i;
            poor.i++;
            poor.m30 += poor.i;
            poor.i++;
            poor.m31 += poor.i;
            poor.i++;
            poor.m32 += poor.i;
            poor.i++;
            poor.m33 += poor.i;
            poor.i++;
            duration[0] = sw.Elapsed.TotalMilliseconds;
            #endregion

            #region great
            sw = Stopwatch.StartNew();
            great.m00 += great.i;
            great.i++;
            great.m01 += great.i;
            great.i++;
            great.m02 += great.i;
            great.i++;
            great.m03 += great.i;
            great.i++;
            great.m10 += great.i;
            great.i++;
            great.m11 += great.i;
            great.i++;
            great.m12 += great.i;
            great.i++;
            great.m13 += great.i;
            great.i++;
            great.m20 += great.i;
            great.i++;
            great.m21 += great.i;
            great.i++;
            great.m22 += great.i;
            great.i++;
            great.m23 += great.i;
            great.i++;
            great.m30 += great.i;
            great.i++;
            great.m31 += great.i;
            great.i++;
            great.m32 += great.i;
            great.i++;
            great.m33 += great.i;
            great.i++;
            duration[1] = sw.Elapsed.TotalMilliseconds;
            #endregion

            #region Compiler1
            sw = Stopwatch.StartNew();
            clr1.m00 += clr1.i;
            clr1.i++;
            clr1.m01 += clr1.i;
            clr1.i++;
            clr1.m02 += clr1.i;
            clr1.i++;
            clr1.m03 += clr1.i;
            clr1.i++;
            clr1.m10 += clr1.i;
            clr1.i++;
            clr1.m11 += clr1.i;
            clr1.i++;
            clr1.m12 += clr1.i;
            clr1.i++;
            clr1.m13 += clr1.i;
            clr1.i++;
            clr1.m20 += clr1.i;
            clr1.i++;
            clr1.m21 += clr1.i;
            clr1.i++;
            clr1.m22 += clr1.i;
            clr1.i++;
            clr1.m23 += clr1.i;
            clr1.i++;
            clr1.m30 += clr1.i;
            clr1.i++;
            clr1.m31 += clr1.i;
            clr1.i++;
            clr1.m32 += clr1.i;
            clr1.i++;
            clr1.m33 += clr1.i;
            clr1.i++;
            duration[2] = sw.Elapsed.TotalMilliseconds;
            #endregion

            #region Compiler2
            sw = Stopwatch.StartNew();
            clr2.m00 += clr2.i;
            clr2.i++;
            clr2.m01 += clr2.i;
            clr2.i++;
            clr2.m02 += clr2.i;
            clr2.i++;
            clr2.m03 += clr2.i;
            clr2.i++;
            clr2.m10 += clr2.i;
            clr2.i++;
            clr2.m11 += clr2.i;
            clr2.i++;
            clr2.m12 += clr2.i;
            clr2.i++;
            clr2.m13 += clr2.i;
            clr2.i++;
            clr2.m20 += clr2.i;
            clr2.i++;
            clr2.m21 += clr2.i;
            clr2.i++;
            clr2.m22 += clr2.i;
            clr2.i++;
            clr2.m23 += clr2.i;
            clr2.i++;
            clr2.m30 += clr2.i;
            clr2.i++;
            clr2.m31 += clr2.i;
            clr2.i++;
            clr2.m32 += clr2.i;
            clr2.i++;
            clr2.m33 += clr2.i;
            clr2.i++;
            duration[3] = sw.Elapsed.TotalMilliseconds;
            #endregion
            results.Add(new double[] {
                duration[0],
                duration[1],
                duration[2],
                duration[3]});
        }
        IO.WriteOut("GreatLayoutTest.txt", results);
        label.Text = "Done";
    }

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Product Manager Magenic Technologies
United States United States
I'm sometimes also active at the XNA Creaters Club Fourms.

I'm currently the leader of the Twin Cities XNA User Group.

Comments and Discussions

 
GeneralReason for my vote of 5 Learned a new thing today. Thanks fo... Pin
GPUToaster™21-Jul-10 19:27
GPUToaster™21-Jul-10 19:27 
GeneralCode sample added... Pin
ely_bob21-Jul-10 3:47
professionalely_bob21-Jul-10 3:47 
GeneralBenchmarks mean nothing without code. Please provide some. Pin
leppie20-Jul-10 20:18
leppie20-Jul-10 20:18 
Generalother processes affect results of test Pin
arcticbrew22-Jul-10 8:17
arcticbrew22-Jul-10 8:17 
GeneralRe: other processes affect results of test Pin
ely_bob22-Jul-10 14:56
professionalely_bob22-Jul-10 14:56 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.