Why is this nested struct creation slower than un-nested?

Viewed 81

I've been benchmarking some C# struct creation, and I've been surprised to find that creation of a nested struct is significantly slower than the un-nested version. I would have expected the JITter to basically produce the same assembly for a flat and nested structure, but this appears to not be the case.

Does anyone have an explanation for why the struct construction in my test code below doesn't get optimized down to just writing the 3 doubles? It seems to (if I'm reading the assembly correctly) zero and create a temporary memory location before writing the values to the final location - presumably actually creating a temporary copy of the nested struct.

And in the follow-up, is there a way to avoid this extra work such that the nested struct has similar creation speed to the un-nested one?

  
    public class StructBenchmarks
    {
        public struct Vector3_dp
        {
            public Vector3_dp(double x, double y, double z)
            {
                X = x;
                Y = y;
                Z = z;
            }

            public double X;
            public double Y;
            public double Z;
        }

        public readonly struct ContainsVector
        {
            public ContainsVector(double x, double y, double z)
            {
                m_vector = new Vector3_dp(x, y, z);
            }

            public ContainsVector(Vector3_dp input)
            {
                m_vector = input;
            }

            private readonly Vector3_dp m_vector;
        }

        private ContainsVector m_vector1;
        private ContainsVector m_vector2;

        private Vector3_dp m_vector3_dp1;
        private Vector3_dp m_vector3_dp2;

        // 0.2ns
        public void Vector3_dp_Construction()
        {
            m_vector3_dp1 = new Vector3_dp(20, 30, 40);
        }

        // 3.8ns
        public void Vector_Construction()
        {
            m_vector1 = new ContainsVector(20, 30, 40);
        }

        // 3.8ns
        public void Vector_ConstructionFromVector3_dp()
        {
            m_vector1 = new ContainsVector(m_vector3_dp1);
        }

        // ~0ns
        public void Vector3_dp_Copy()
        {
            m_vector3_dp1 = m_vector3_dp2;
        }

        // ~0ns
        public void Vector_Copy()
        {
            m_vector1 = m_vector2;
        }
    }


And SharpLab link: https://sharplab.io/#v2:EYLgxg9gTgpgtADwGwBYA0AXEBDAzgWwB8BYAKAAJLyABAZhoCZyBlDKAVzAwCEYA7MAAt82KAGtcZKuQDeU6VTrlcbThnIA1GF2i0A+gBMADvIWzTZxfS06o+4wAoDEdsAA2McgjTlnrj+QAnj5+7p4AXgCUFpbmFLGWABrkALxeANwxCZQAmqlBmfHZ0gBa+eGFxeQAvmRZZkqhAYmVxY0uYeQ5rdnt/p4lPQq1pPU09LDYznxugcqqXOQAwhB8GNgAlny4NhjQY3JFCUora5vbu9BOHQHevjeewff95FFj0odV0vh6AG7aeyg+T4MAA7poAbpDEYHHcnlEhrERu8rMtVustjtIVAHJc7NDyFsjOwMNEjrFPl9KD9/rZ8kSSYjLMjyZYjFANr9sBhPJNprMIbZ7EZyDTsUzKCzYuzOdzPKcMRdsaK/tiAIwS8gyrk8tFnTF4lW0wEMQpjbVywWA4VG7HCjXmjk6zx4m1ioXQ011VmUAD0vvIAAYAHQMbZjJTUFBWqHGPSnFQcLgbVYOMkUlHU1Ue4xq4FgmP4xwMQM+Wil8goQORTVSyz+8i0YMADnDPvGNGjePjq0TahTfDTB0zttsebSIPBCvOWNsDhLZYrVZrYzrZgbTdbknbka72J72wWGAHADEoBB8K7oUP25Tsu7AePyJO9YrZ4CHA/Y0Y1Sv22uFF3QthR7IxAhvDN22+bNrWhJ8vyLIwvX/MYI3oKNC1A8D00sO8EgQ+CYOgZCkQsEYgA=

0 Answers
Related