Vector2.Distance() is slooooooooow.....

For those that are not aware, using the Vector2.Distance() method is extremely slow compared to just doing the calculation…

By a factor of around 3.4+ times slower…

When I ran it:

diff2 was 67.9991
diff3 was 236.0034

Fairly significant difference.

Some Test Code:

        DateTime startTime;
        DateTime endTime;
        double answer;
        double diff2;
        double diff3;
        Vector2 pos1 = new Vector2(10, 10);
        Vector2 pos2 = new Vector2(50, 50);

        startTime = DateTime.Now;
        for (int i = 0; i < 10000000; i++)
        {
            pos1.X = 100;
            pos1.Y = 100;

            pos2.X = 500;
            pos2.Y = 500;

            answer = Math.Sqrt((pos2.X - pos1.X) * (pos2.X - pos1.X) + (pos2.Y - pos1.Y) * (pos2.Y - pos1.Y));
        }

        endTime = DateTime.Now;

        diff2 = (endTime - startTime).TotalMilliseconds;

        startTime = DateTime.Now;
        for (int i = 0; i < 10000000; i++)
        {
            pos1.X = 100;
            pos1.Y = 100;

            pos2.X = 500;
            pos2.Y = 500;

            answer = Vector2.Distance(pos1, pos2);
        }

        endTime = DateTime.Now;

        diff3 = (endTime - startTime).TotalMilliseconds;

Seems kind of strange! This is the code for Vector2.Distace from the MG Github repo:

public static float Distance(Vector2 value1, Vector2 value2)
{
    float v1 = value1.X - value2.X, v2 = value1.Y - value2.Y;
	return (float)Math.Sqrt((v1 * v1) + (v2 * v2));
}

If anything that should be more efficient (unless double to float is killing it).

1 Like

There are some previous considerations to this message:

First, your difference of ~3.4 is around ~2 for me. That’s because you’re either using the MonoGame debug DLL, or you’re compiling your speed test project with Debug, or you’re running your project with F5 (instead of Ctrl+F5), or a combination of those. When testing speeds it’s better to test the “really release mode” (that’s MG release, release compilation, and Ctrl+F5)

Second, DateTime is not an accurate way to measure short amounts of time. It’s better to use Stopwatch.

That said, the reason it’s slower is that the Vector2.Distance call is not inlined, so a call is made. This is always slower than an inlined code execution. When in doubt about this kind of things, launch ILSpy and have a look at the generated code.

Workarounds? You could mark the Vector2.Distance in monogame source code as Aggressive Inlining, but I’m not sure if it’ll work. I’m not an expert but I think that the JIT plays a big role in inlining, so, being the code in another assembly it’s possible that the Vector2.Distance is inlined depending on the JIT. You may get it inlined in net core 3, but not on a previous version.

1 Like

Additionally the method call has to convert the float back to double to store it in ‘answer’.
To make a fair comparison you should make double float and call ‘answer = (float)Math.Sqrt((pos2.X - pos1.X) * (pos2.X - pos1.X) + (pos2.Y - pos1.Y) * (pos2.Y - pos1.Y));’

My guess is that most of the cycles are wasted on copying the two vectors.
Try the faster Vector2.Distance(ref pos1, ref pos2, out answer);

3 Likes