Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Sequential Structure Layout For Speed

5.00/5 (1 vote)
21 Jul 2010CPOL1 min read 15.3K  
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)