I wrote some simple C# code to test if a number is a prime. I was surprised to see that there was a huge difference in performance when I ran the code in a WinForms app vs a console app.
The code is pretty simple:
ulong num = 18446744073709551557;
Stopwatch stopwatch = Stopwatch.StartNew();
if (num % 2 == 0)
{
stopwatch.Stop();
MessageBox.Show("Composite " stopwatch.ElapsedMilliseconds.ToString());
return;
}
for (ulong i = 3; i <= Math.Sqrt(num); i = 2)
{
if (num % i == 0)
{
stopwatch.Stop();
MessageBox.Show("Composite " stopwatch.ElapsedMilliseconds.ToString());
return;
}
}
stopwatch.Stop();
MessageBox.Show("Prime " stopwatch.ElapsedMilliseconds.ToString());
For the console app, instead of MessageBox.Show()
, I use Console.WriteLine()
. Now I would have thought the performance difference would be negligible. However, the console app seems to consistently perform worse than the windows form app.
Compiled by Visual Studio 2022, for the debug build (run without debugging), it takes ~36000 milliseconds for the winforms app, but ~156000 ms for the console app. For the release build (run without debugging), ~35500 ms for winforms and ~137000 ms for the console. (Interestingly, both seem to run slightly faster if run with debugging.) What is the reason for this discrepancy?
CodePudding user response:
I could not reproduce the issue.
Here is a summary of my findings running in release, and without the debugger (Ctrl-F5 in VS). Significant differences between 32-bit and 64-bit processes exist for both Console and WinForms.
IDE | Platform | Console | WinForms |
---|---|---|---|
VS2017/NET 4.8 | x32 | 43.94 sec | 43.21 sec |
VS2017/NET 4.8 | x64 | 4.43 sec | 4.38 sec |
VS2022/NET 4.8 | x32 | 43.62 sec | 43.33 sec |
VS2022/NET 4.8 | x64 | 4.56 sec | 4.45 sec |
VS2022/NET 6.0 | x64 | 4.46 sec | 4.45 sec |
NOTE: The differences between console and winforms are within the noise.
Code
Identical code for both projects for the test
internal static bool IsPrimeTest(ulong num)
{
if (num == 1)
{
return true;
}
if (num % 2 == 0)
{
return false;
}
for (ulong i = 3; i <= Math.Sqrt(num); i = 2)
{
if (num % i == 0)
{
return false;
}
}
return true;
}
and the runner
private void button1_Click(object sender, EventArgs e)
{
button1.Enabled = false;
ulong x = 18446744073709551557ul;
textBox1.Text = "Burn-in";
Program.IsPrimeTest(x / 16);
textBox1.Text = "Start timming";
var sw = Stopwatch.StartNew();
bool ok = Program.IsPrimeTest(x);
sw.Stop();
string bits = Environment.Is64BitProcess ? "x64" : "x32";
textBox1.Text = $"Bits={bits}, Prime={ok}, Time={sw.Elapsed.TotalSeconds:f2} sec";
button1.Enabled = true;
}
As fun side-note, a similar test with Intel Fortran produced Time = 3.80 sec
, which is only slightly faster than C#. Granted, Fortran does not support unsigned integers, so the checking had to happen with full precission floating point numbers. Each mod(x,p)==0
call is translated into x/p == int(x/p)
.