While attempting to achieve a maximum performance in .NET code I have stumbled on a very peculiar effect. If you compile and run the following C# code, you get a better performance in Debug configuration than in Release configuration. Moreover, if you comment out any one of the **unused** (!) case blocks in the Distance method, you get 5-fold !! increase in the performance in the Release configuration. I would appreciate any explanation that anyone can offer. And it would be great to hear comments from the .NET development them if they are following this forum.

Thanks,

Victor

P.S. I am using VS 2005 and Framework v 2.0.50727.42

using System;

using System.Text;

using System.IO;

using System.Diagnostics;

namespace Test

{

class Program

{

static void Main(string[] args)

{

try

{

MetricMatrix m = new MetricMatrix(5000, 20);

double dmin = double.MaxValue;

for (int i = 0, k = 0; i < m.Rows; ++i)

{

for (int j = 0; j < m.Cols; ++j)

{

m[i, j] = k++;

}

}

Stopwatch timer = Stopwatch.StartNew();

for (int i = 0; i < m.Rows; ++i)

{

for (int j = i + 1; j < m.Rows; ++j)

{

double d = m.Distance(i, j);

if (d < dmin) dmin = d;

}

}

timer.Stop();

Console.WriteLine("Matrix, {0} sec, d = {1}", timer.ElapsedMilliseconds / 1000.0, dmin);

}

catch (Exception e)

{

Console.WriteLine(e.ToString());

}

}

}

public class MetricMatrix

{

public enum Metrics

{

Manhattan,

Euclidean,

EuclideanSquared,

Ultrametric

}

public int Rows = 0;

public int Cols = 0;

private float[] data;

private Metrics metric = Metrics.Euclidean;

public MetricMatrix(int rows, int cols)

{

data = new float[rows * cols];

this.Rows = rows;

this.Cols = cols;

}

public float this[int row, int col]

{

get { return data[row * this.Cols + col]; }

set { data[row * this.Cols + col] = value; }

}

public double Distance(int i, int j)

{

switch (metric)

{

case Metrics.Euclidean:

{

return Euclidean(i, j);

}

case Metrics.Manhattan:

{

return Manhattan(i, j);

}

case Metrics.EuclideanSquared:

{

return EuclideanSquared(i, j);

}

case Metrics.Ultrametric:

{

return Ultrametric(i, j);

}

default:

{

throw new Exception();

}

}

}

public unsafe double Manhattan(int i, int j)

{

double d = 0;

fixed (float* p = &data[0])

{

float* row1 = p + i * Cols;

float* row2 = p + j * Cols;

for (int k = 0; k < Cols; ++k)

{

double x = row1[k] - row2[k];

d += Math.Abs(x);

}

}

return d;

}

public unsafe double Euclidean(int i, int j)

{

return Math.Sqrt(EuclideanSquared(i, j));

}

public unsafe double EuclideanSquared(int i, int j)

{

double d = 0;

fixed (float* p = &data[0])

{

float* row1 = p + i * Cols;

float* row2 = p + j * Cols;

for (int k = 0; k < Cols; ++k)

{

double x = row1[k] - row2[k];

d += x * x;

}

}

return d;

}

public unsafe double Ultrametric(int i, int j)

{

double d = 0;

fixed (float* p = &data[0])

{

float* row1 = p + i * Cols;

float* row2 = p + j * Cols;

for (int k = 0; k < Cols; ++k)

{

double x = Math.Abs(row1[k] - row2[k]);

if (x > d) d = x;

}

}

return d;

}

}

}