Long story short - I can't explain why my console app with Kestrel server runs fast only in profiler, Debug
or Release
- doesn't matter.
The long story
I created small message-based framework that can create instance of specific class and execute one of its methods based on the argument type used in this method. Pretty much like MediatR framework. At the startup, the app gathers available assemblies and creates a dictionary where assembly name or a message type is the key and appropriate MethodInfo
is the value. When specific message is sent, the relevant MethodInfo
makes a method call via reflection.
Message handler sample that will be called via reflection
public class DemoActor
{
public virtual Task<DemoResponse> Create(CreateMessage message)
{
return Task.FromResult(new DemoResponse { Data = "Hello" });
}
}
Reflection call sample
if (Processors.TryGetValue(descriptor, out MethodInfo processor))
{
instance = Activator.CreateInstance(processor.DeclaringType); // cache
response = processor.Invoke(instance, message);
}
Performance check
var stopWatch = new Stopwatch();
stopWatch.Start();
for (var i = 0; i < 100000; i++) scene.Send<DemoResponse>("Demo", message).Result;
stopWatch.Stop();
var ts = stopWatch.Elapsed;
string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
ts.Hours, ts.Minutes, ts.Seconds,
ts.Milliseconds / 10);
Console.WriteLine("RunTime " + elapsedTime);
Preliminary testing showed that the simplest local call executed in the loop 100K times takes around 6 seconds. I immediately assumed that this is due to the reflection slowness and replaced reflection call with Delegate.CreateDelegate
, then with Expression.Compile
. This didn't make any difference, at all. Switching between Debug
and Release
mode also didn't make any difference.
Then, I tried to use built-in VS 2022 profiler, specifically, the one for async
calls, and execution time magically dropped from 6 seconds to less than 1 second.
System
Windows 10 Pro x64, Quad Core i7 2.4 GHz, SSD, RAM 32 GB, .NET 6.0, VS 2022 Preview 3
Questions
- Why there is no difference between reflection, delegates, and expressions?
Why there is no difference betweenDebug
andRelease
configuration?What is the right way to test performance in this case?
Update
Appeared to be I was always running build with attached debugger that was causing slowness. Published version runs as fast as profiler and testing performance with StopWatch
should be enough in this case. Meanwhile, I still can't explain why there is no boost after switching from reflection calls to compiled delegates.