I have a simple method that converts an array from one type to another. I wanted to know which method is the fastest. But so far I get different results, from which I can not conclude which method is really faster, with which margin.
Since the conversion is only related to memory allocation, reading the array and converting the values, I am surprised that the values are no more stable. I wanted to know how I can make accurate measurements that make sense and do not change from one day to another. The differences are approximately 20% from one day to another.
Of course, there are differences between JITer.NET 3.5 and 4.0, debugging and release mode, and not running the executable in the debugger (disables JIT optimization before disabling it), C # compiler code generation between DEBUG and RELEASE (mainly nop operations and more temporary variables in the IL code).
using System; using System.Collections.Generic; using System.Diagnostics; namespace PerfTest { class Program { const int RUNS = 10 * 1000 * 1000; static void Main(string[] args) { int[] array = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43 }; var s2 = Stopwatch.StartNew(); for (int i = 0; i < RUNS; i++) { float[] arr = Cast(array); } s2.Stop(); GC.Collect(); var s3 = Stopwatch.StartNew(); for (int i = 0; i < RUNS; i++) { float[] arr = Cast2(array); } s3.Stop(); GC.Collect(); var s4 = Stopwatch.StartNew(); for (int i = 0; i < RUNS; i++) { var arr = CastSafe(array); } s4.Stop(); Console.WriteLine("Times: {0} {1} {2}", s2.ElapsedMilliseconds, s3.ElapsedMilliseconds, s4.ElapsedMilliseconds); }
I get then
- Time: 1257 1388 1180
- Time: 1331 1428 1267
- Time: 1337 1435 1267
- Time: 1,208 1,414 1,145
From this it is clear that the option with the mute safe is faster than any unsafe option, although the limitations of checking the elimination of unsafe methods should make it at least quick, if not faster. Just for fun, I also compiled the same IL code via LCG (DynamicMethod), which seems to be even slower than any of these methods, although the additional cost of calling a delegate does not seem to play such a big role here.
The for loop executes this code 10 million times, which should lead to stable results. Why do I even see any differences? Using real-time as a process priority also did not help (psexec-realtime executable). How can I get reliable numbers?
My tests included
- Dual-core quad-core machines
- Windows 7 32/64-bit
- .NET Framework 3.5 / 4.0
- 32/64 bit version of the executable file.
If I use the profiler, I'm not sure if it will distort the measurements even more. Since he interrupts my application from time to time to get call stacks, he will certainly destroy any place in the cache that may help in performance. If there is any approach with the best (given) cache locales, I cannot find it using the profiler.
Edit1: To take into account that I do not have a real-time operating system, I am now sampling my measurements. Since for one stream I have a 15-minute time window provided by the Windows Scheduler, I can leave the Scheduler if I measure shorter than 15 ms. If I take a measurement that is too short, I will get a very small number of tags that won’t tell me much.
To get stable values, I need a time interval long enough for the OS to do what it does on a regular basis. Empirical tests have shown that 30+ seconds is a good amount of time that a single measurement may require.
This time interval is then divided into sampling time intervals that are significantly lower than 15 ms. Then I will get time information for each sample. From the samples I can extract min / max and average. That way, I can also see the initialization effects for the first time. Now the code is as follows
class Program { const int RUNS = 100 * 1000 * 1000; // 100 million runs will take about 30s const int RunsPerSample = 100; // 100 runs for on sample is about 0,01ms << 15ms static void Main(string[] args) { int[] array = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43 }; long[] sampleTimes = new long [RUNS/RunsPerSample]; int sample = 0; for (int i = 0; i < RUNS; i+=RunsPerSample) { var sw = Stopwatch.StartNew(); for (int j = i; j < i+RunsPerSample; j++) { float[] arr = Cast(array); } sw.Stop(); sampleTimes[sample] = sw.ElapsedTicks; sample++; } Console.WriteLine("SampleSize: {0}, Min {1}, Max {2}, Average {3}", RunsPerSample, sampleTimes.Min(), sampleTimes.Max(), sampleTimes.Average());
The values of these tests are still changing (<10%), but I think that if I create a histogram chart of my values and reset the 10% values that are most likely caused by the OS, GC, ... I can really get stable numbers that I can trust.
SampleSize: 100, Min 25, Max 86400, Average 28.614631
- SampleSize: 100, Min 24, Max 86027, Average 28,762608
- SampleSize: 100, Min 25, Max 49523, Average 32.102037
- SampleSize: 100, Min 24, Max 48687, Average 32.030088
Edit2: Histograms show that the measured values are not random. They look like a Landau distribution , which should give me the correct algorithms for approximating stable values. I want something like ROOT in .NET where I can interact with a suitable distribution function with my data and get the results.

Below is the code for generating a histogram using MSChart :
using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Windows.Forms; using System.Windows.Forms.DataVisualization.Charting; namespace ConsoleApplication4 { public partial class Histogram : Form { public Histogram(long [] sampleTimes) { InitializeComponent(); Series histogramSeries = cHistogram.Series.Add("Histogram");