Edit: I've resolved my problem. The cause was an error in testing procedure and will be detailed once I'm allowed to answer my own question.
I know this type of question should generally be avoided, but I've come across a really strange situation that I can't make sense of. I've been trying to implement a PRNG, and I've been testing its performance against System.Random. I found that my code was ~50 times slower, but it wasn't the algorithm that was the problem, but just calling the method. Even if I just returned a constant, it would still be many times slower.
So I write a simple test program that compares calling a method that wraps random.NextDouble(), a method that returns -1, and calling random.NextDouble() directly. I ran my test in Ideone, and it gave the expected results; all the times were similar, and returning a constant was fastest. The times were all around 0.1 seconds.
However, the same code compiled in Visual Studio 2011 Beta or 2010 C# Express would result in 4 seconds, 4 seconds, and 0.1 seconds, for each case respectively. I'm definitely running in release mode, the optimize code checkbox is ticked, and launching from outside Visual Studio gives the same results. So why are such simple method calls so much slower in Visual Studio than Ideone? Here's the code I used to benchmark:
using System;
using System.Diagnostics;
public class Test{
static Random random = new Random();
public static Double Random() {
return random.NextDouble();
}
public static Double Random2() {
return -1;
}
public static void Main() {
{
Stopwatch s = new Stopwatch();
Double a = 0;
s.Start();
for (Int32 i = 0; i < 5000000; i++)
a += Random();
s.Stop();
Console.WriteLine(s.ElapsedMilliseconds);
}
{
Stopwatch s = new Stopwatch();
Double a = 0;
s.Start();
for (Int32 i = 0; i < 5000000; i++)
a += Random2();
s.Stop();
Console.WriteLine(s.ElapsedMilliseconds);
}
{
Stopwatch s = new Stopwatch();
Double a = 0;
s.Start();
for (Int32 i = 0; i < 5000000; i++)
a += random.NextDouble();
s.Stop();
Console.WriteLine(s.ElapsedMilliseconds);
}
}
}
You shouldn't measure the first call to Random() and Random2(). The first time a function is called, it is handled by the JITTER. Instead, call Random() and Random2() once, then start measuring. random.NextDouble() was already compiled after .NET was installed, so it doesn't suffer from the same problem.
I don't believe this will explain all the difference, but it should level the playing field.
Related
So I made a mistake and instead of creating a project as C# Console Application I
created .NET Core one. It is a simple game (Conway's Game of life) and one of the things implemented is creating a random board (2D Array), transforming it and then printing it to the console.
The random board generation works fine in .NET Core however if I try to paste my cs files including Program.cs to .NET Framework or C# app everything seems to be working except said random generation. When I debug it also seems to be working fine but at the point of returning the randomly generated board from GenerateRandom in BoardGenerator.cs it returns an array of all true values or all false values.
I have not changed a single line of code, I tried to delete all build files and re-build, nothing works and it is driving me nuts.
Program.cs
class Program
{
static void Main()
{
var game = new Game();
Console.WriteLine("CONWAY'S GAME OF LIFE");
Console.WriteLine();
var folder = #"D:\_programming projects\game-of-life\GameOfLife\patterns\";
var files = Directory.GetFiles(folder, "*.txt");
for (var i = 0; i < files.Length; i++)
{
Console.WriteLine(i + 1 + ": " + Path.GetFileNameWithoutExtension(files[i]));
}
Console.WriteLine(files.Length + 1 + ": Random");
Console.Write("Enter number to load board: ");
var input = Console.ReadLine();
int.TryParse(input, out var option);
option--;
try
{
if (option == files.Length)
game.SetBoard(new BoardGenerator().GenerateRandom(Constants.BoardRows, Constants.BoardColumns));
else
game.SetBoard(new BoardGenerator().GenerateFromFile(
files[option],
Constants.BoardRows,
Constants.BoardColumns));
}
catch (Exception)
{
Console.WriteLine("Error");
}
game.PrintBoard();
while (true)
{
Thread.Sleep(200);
Console.Clear();
game.MutateBoard();
game.PrintBoard();
}
}
}
BoardGenerator.cs
public class BoardGenerator
{
private readonly bool[] _values = { true, false };
private bool[,] _board;
public bool[,] GenerateRandom(int noRows, int noColumns)
{
_board = new bool[noRows, noColumns];
BoardProcessor.ProcessValue(_board, tile => _values[new Random().Next(0, _values.Length)]);
return _board;
}
[...]
}
BoardProcessor.cs
public static class BoardProcessor
{
public static void ProcessValue(bool[,] board, Func<bool, bool> func)
{
for (var i = 0; i < board.GetLength(0); i++)
for (var j = 0; j < board.GetLength(1); j++)
board[i, j] = func(board[i, j]);
}
}
Again, this code works in .NET Core. What's the problem?
.NET Framework and .NET Core have different implementation of Random default constructor. Both try to generate some default seed to start the pseudo-random sequence with, but ways they generate the seed are different. In particular the .NET Core implementation uses internal global random objects to generate random seed which guarantees different seeds for all sequential calls of new Random(). The Framework implementation however uses Environment.TickCount as a seed, which imposes the risk that sequential calls of new Random() which are called quickly enough will get the same seed (because ticks count isn't updated during the instances initialization period) which int turn means the same pseudo-random sequence for all instances of Random initialized in that period with default constructor. That's what most likely happens in your case. The fix is simple - as suggested use single instance of Random initialized before BoardProcessor.ProcessValue call.
Following this question - Pass Method as Parameter using C# and some of my personal experience I'd like to know a little more about the performance of calling a delegate vs just calling a method in C#.
Although delegates are extremely convenient, I had an app that did lots of callbacks via delegates and when we rewrote this to use callback interfaces we got an order of magnitude speed improvement. This was with .NET 2.0 so I'm not sure how things have changed with 3 and 4.
How are calls to delegates handled internally in the compiler/CLR and how does this affect performance of method calls?
EDIT - To clarify what I mean by delegates vs callback interfaces.
For asynchronous calls my class could provide an OnComplete event and associated delegate which the caller could subscribe to.
Alternatively I could create an ICallback interface with an OnComplete method that the caller implements and then registers itself with the class that will then call that method on completion (i.e. the way Java handles these things).
I haven't seen that effect - I've certainly never encountered it being a bottleneck.
Here's a very rough-and-ready benchmark which shows (on my box anyway) delegates actually being faster than interfaces:
using System;
using System.Diagnostics;
interface IFoo
{
int Foo(int x);
}
class Program : IFoo
{
const int Iterations = 1000000000;
public int Foo(int x)
{
return x * 3;
}
static void Main(string[] args)
{
int x = 3;
IFoo ifoo = new Program();
Func<int, int> del = ifoo.Foo;
// Make sure everything's JITted:
ifoo.Foo(3);
del(3);
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < Iterations; i++)
{
x = ifoo.Foo(x);
}
sw.Stop();
Console.WriteLine("Interface: {0}", sw.ElapsedMilliseconds);
x = 3;
sw = Stopwatch.StartNew();
for (int i = 0; i < Iterations; i++)
{
x = del(x);
}
sw.Stop();
Console.WriteLine("Delegate: {0}", sw.ElapsedMilliseconds);
}
}
Results (.NET 3.5; .NET 4.0b2 is about the same):
Interface: 5068
Delegate: 4404
Now I don't have particular faith that that means delegates are really faster than interfaces... but it makes me fairly convinced that they're not an order of magnitude slower. Additionally, this is doing almost nothing within the delegate/interface method. Obviously the invocation cost is going to make less and less difference as you do more and more work per call.
One thing to be careful of is that you're not creating a new delegate several times where you'd only use a single interface instance. This could cause an issue as it would provoke garbage collection etc. If you're using an instance method as a delegate within a loop, you will find it more efficient to declare the delegate variable outside the loop, create a single delegate instance and reuse it. For example:
Func<int, int> del = myInstance.MyMethod;
for (int i = 0; i < 100000; i++)
{
MethodTakingFunc(del);
}
is more efficient than:
for (int i = 0; i < 100000; i++)
{
MethodTakingFunc(myInstance.MyMethod);
}
Could this have been the problem you were seeing?
I find it completely implausible that a delegate is substantially faster or slower than a virtual method. If anything the delegate should be negligibly faster. At a lower level, delegates are usually implemented something like (using C-style notation, but please forgive any minor syntax errors as this is just an illustration):
struct Delegate {
void* contextPointer; // What class instance does this reference?
void* functionPointer; // What method does this reference?
}
Calling a delegate works something like:
struct Delegate myDelegate = somethingThatReturnsDelegate();
// Call the delegate in de-sugared C-style notation.
ReturnType returnValue =
(*((FunctionType) *myDelegate.functionPointer))(myDelegate.contextPointer);
A class, translated to C, would be something like:
struct SomeClass {
void** vtable; // Array of pointers to functions.
SomeType someMember; // Member variables.
}
To call a vritual function, you would do the following:
struct SomeClass *myClass = someFunctionThatReturnsMyClassPointer();
// Call the virtual function residing in the second slot of the vtable.
void* funcPtr = (myClass -> vtbl)[1];
ReturnType returnValue = (*((FunctionType) funcPtr))(myClass);
They're basically the same, except that when using virtual functions you go through an extra layer of indirection to get the function pointer. However, this extra indirection layer is often free because modern CPU branch predictors will guess the address of the function pointer and speculatively execute its target in parallel with looking up the address of the function. I've found (albeit in D, not C#) that virtual function calls in a tight loop are not any slower than non-inlined direct calls, provided that for any given run of the loop they're always resolving to the same real function.
Since CLR v 2, the cost of delegate invocation is very close to that of virtual method invocation, which is used for interface methods.
See Joel Pobar's blog.
I did some tests (in .Net 3.5... later I will check at home using .Net 4).
The fact is:
Getting an object as an interface and then executing the method is faster than getting a delegate from a method then calling the delegate.
Considering the variable is already in the right type (interface or delegate) and simple invoking it makes the delegate win.
For some reason, getting a delegate over an interface method (maybe over any virtual method) is MUCH slower.
And, considering there are cases when we simple can't pre-store the delegate (like in Dispatches, for example), that may justify why interfaces are faster.
Here are the results:
To get real results, compile this in Release mode and run it outside Visual Studio.
Checking direct calls twice
00:00:00.5834988
00:00:00.5997071
Checking interface calls, getting the interface at every call
00:00:05.8998212
Checking interface calls, getting the interface once
00:00:05.3163224
Checking Action (delegate) calls, getting the action at every call
00:00:17.1807980
Checking Action (delegate) calls, getting the Action once
00:00:05.3163224
Checking Action (delegate) over an interface method, getting both at
every call
00:03:50.7326056
Checking Action (delegate) over an interface method, getting the
interface once, the delegate at every call
00:03:48.9141438
Checking Action (delegate) over an interface method, getting both once
00:00:04.0036530
As you can see, the direct calls are really fast.
Storing the interface or delegate before, and then only calling it is really fast.
But having to get a delegate is slower than having to get an interface.
Having to get a delegate over an interface method (or virtual method, not sure) is really slow (compare the 5 seconds of getting an object as an interface to the almost 4 minutes of doing the same to get the action).
The code that generated those results is here:
using System;
namespace ActionVersusInterface
{
public interface IRunnable
{
void Run();
}
public sealed class Runnable:
IRunnable
{
public void Run()
{
}
}
class Program
{
private const int COUNT = 1700000000;
static void Main(string[] args)
{
var r = new Runnable();
Console.WriteLine("To get real results, compile this in Release mode and");
Console.WriteLine("run it outside Visual Studio.");
Console.WriteLine();
Console.WriteLine("Checking direct calls twice");
{
DateTime begin = DateTime.Now;
for (int i = 0; i < COUNT; i++)
{
r.Run();
}
DateTime end = DateTime.Now;
Console.WriteLine(end - begin);
}
{
DateTime begin = DateTime.Now;
for (int i = 0; i < COUNT; i++)
{
r.Run();
}
DateTime end = DateTime.Now;
Console.WriteLine(end - begin);
}
Console.WriteLine();
Console.WriteLine("Checking interface calls, getting the interface at every call");
{
DateTime begin = DateTime.Now;
for (int i = 0; i < COUNT; i++)
{
IRunnable interf = r;
interf.Run();
}
DateTime end = DateTime.Now;
Console.WriteLine(end - begin);
}
Console.WriteLine();
Console.WriteLine("Checking interface calls, getting the interface once");
{
DateTime begin = DateTime.Now;
IRunnable interf = r;
for (int i = 0; i < COUNT; i++)
{
interf.Run();
}
DateTime end = DateTime.Now;
Console.WriteLine(end - begin);
}
Console.WriteLine();
Console.WriteLine("Checking Action (delegate) calls, getting the action at every call");
{
DateTime begin = DateTime.Now;
for (int i = 0; i < COUNT; i++)
{
Action a = r.Run;
a();
}
DateTime end = DateTime.Now;
Console.WriteLine(end - begin);
}
Console.WriteLine();
Console.WriteLine("Checking Action (delegate) calls, getting the Action once");
{
DateTime begin = DateTime.Now;
Action a = r.Run;
for (int i = 0; i < COUNT; i++)
{
a();
}
DateTime end = DateTime.Now;
Console.WriteLine(end - begin);
}
Console.WriteLine();
Console.WriteLine("Checking Action (delegate) over an interface method, getting both at every call");
{
DateTime begin = DateTime.Now;
for (int i = 0; i < COUNT; i++)
{
IRunnable interf = r;
Action a = interf.Run;
a();
}
DateTime end = DateTime.Now;
Console.WriteLine(end - begin);
}
Console.WriteLine();
Console.WriteLine("Checking Action (delegate) over an interface method, getting the interface once, the delegate at every call");
{
DateTime begin = DateTime.Now;
IRunnable interf = r;
for (int i = 0; i < COUNT; i++)
{
Action a = interf.Run;
a();
}
DateTime end = DateTime.Now;
Console.WriteLine(end - begin);
}
Console.WriteLine();
Console.WriteLine("Checking Action (delegate) over an interface method, getting both once");
{
DateTime begin = DateTime.Now;
IRunnable interf = r;
Action a = interf.Run;
for (int i = 0; i < COUNT; i++)
{
a();
}
DateTime end = DateTime.Now;
Console.WriteLine(end - begin);
}
Console.ReadLine();
}
}
}
I created code to see how fast my static compression method takes to execute, and I noticed that the first execution takes 8,500,000 nanoseconds, the second about half that, and then everything after that executes at 0 nanoseconds. Why?
private void CheckPerformance()
{
while (KeepRunning)
{
//generates a complex random 500 character string
string text = GenerateString(500, 4);
DateTime beginTime = DateTime.Now;
byte[] bytes = Compress(text); // < - timing this
long elapsedTicks = DateTime.Now.Ticks - beginTime.Ticks;
Console.WriteLine(" {0:N0} nanoseconds", elapsedTicks * 100);
//sleep for 5 seconds
Thread.Sleep(5000);
}
}
public static byte[] Compress(string text)
{
using (MemoryStream output = new MemoryStream())
{
using (DeflateStream ds = new DeflateStream(output, CompressionMode.Compress))
{
using (StreamWriter writer = new StreamWriter(ds, Encoding.UTF8))
{
writer.Write(text);
}
}
return output.ToArray();
}
}
The DateTime.Now gets updates around 10 times per second but don't quote me on this (could be depending on hardware and software setting). It's also slow because it needs to figure out what timezone the system is on. UtcNow is faster but will still be cached for a bit. Therefore, it could be using the cached version on subsequent calls.
Use StopWatch instead for more accurate measurement. StopWatch uses high precision by utilizing hardware. You can check that using Stopwatch.IsHighResolution.
using System.Diagnostics;
Stopwatch sw = new Stopwatch();
sw.Start();
// code to benchmark
sw.Stop();
Let's see if you get same metrics.
EDIT
While it is true that your method needs to be JIT compiled, the difference cannot be due to JIT compilation because it will be JIT compiled only once (not always but in your case it will be once) and then reused. Therefore, only the first call should take longer and the subsequent calls should be the same. To throw this assumption away, simply call Compress once outside the benchmarking phase so it is JIT compiled. Then benchmark it, and now the JIT compilation will not occur, and DateTime will still give you random results because it is cached.
Note: The JIT compiler does not necessarily always compile the whole method into machine code but only when execution passes through the code. So if you have if statements, the blocks may not be compiled until execution is passed through the block. But yours have no if statements so that is why it will be JIT compiled once.
Furthermore, we cannot say with confidence this was due to JIT compilation since it is possible Compress method could have been inlined but in your case it was most likely not inlined since you most likely had the debugger on and therefore, JIT optimization will be disabled.
Try this code and you will notice it gives random results for elapsed time even though the same code is executed:
for (int i = 0; i < 1000; i++)
{
DateTime beginTime = DateTime.UtcNow;
var sw = Stopwatch.StartNew();
while (sw.ElapsedTicks < 100)
{
Console.WriteLine("*");
}
long elapsedTicks = DateTime.UtcNow.Ticks - beginTime.Ticks;
Console.WriteLine(" {0:N0} nanoseconds", elapsedTicks * 100);
}
On my system if I change this line to sw.ElapsedTicks < 2050, then there is always is a difference of non zero reported consistently. Which means right around there is when DateTime.Now gets a new value instead of using the cached one.
In conclusion, I do not buy that JIT compilation is the explanation for what you are noticing.
When you hit it the first time, it gets jitted. So that takes time. Not sure though why the second and third times differ.
I'm just a beginner at c++ so I might be doing something wrong but anyways I created a c++ dll and I call it from my wpf project:
c++ code:
extern "C" __declspec (dllexport) double writeTxt()
{
ofstream mf("c:\\cpp.txt");
for(int i=0;i<999;i++)
{
mf<<"xLine: \n";
}
mf.close();
return 1;
}
calling code from c#:
[DllImport(#"C:\Users\neo\Documents\visual studio 2010\Projects\TestDll\Debug\TestDll.dll",
CallingConvention = CallingConvention.Cdecl)]
public static extern double writeTxt();
Now I'm trying to compare the execution time with this c# function:
double writeTxtCs()
{
StreamWriter sw = new StreamWriter(#"c:\cs.txt");
for (int i = 0; i < 999; i++)
{
sw.WriteLine("Line: " + i);
}
sw.Close();
return 0;
}
but the c# function is about twice as faster than the c++ function.
tested like this:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
long[] arr = new long[100];
Stopwatch sw = new Stopwatch();
for (int i = 0; i < 99; i++)
{
sw.Start();
//double xxx = writeTxt();
double xxx = writeTxtCs();
arr[i] = sw.ElapsedMilliseconds;
sw.Reset();
}
MessageBox.Show(arr.Average().ToString());
Close();
}
When running the c# function I normally get ~0.65ms and when running the c++ function I get ~1.1ms.
my question is: am I doing something wrong or does c# really is faster in this scenario than c++?
All other answers have valid points. In addition to those:
You are testing against "Debug" build of your C++ DLL and that might be degrading C++ performance more than how it affects C#'s performance. Try unleashing optimizations on both and see how it works out for you.
Nevertheless I/O doesn't have much to do with the "language". It's more about runtime and the OS.
You're not testing C++ vs. C#. You're testing [C++ plus libraries] vs. [C# plus libraries].
In order to find out why ofstream is slower than StreamWriter you'd need to profile the code or look into the internals.
Anyway, single milliseconds are a very small amount of time for a computer. I'd repeat the test with 1000 times the load to make timing jitter irrelevant.
It could be a buffering issue, i.e. the C# and C++ file writing guts might be buffering data in a different way, which would result in performance differences.
I recommend you use an operation which is purely CPU bound for benchmarking, rather than something IO bound (such as writing to a hard drive). For instance, see how fast each function can count from 0 to MAX_INT.
That's not really a reliable benchmark. You're doing file IO there, which is highly dependent on the implementation of ofstream and StreamWriter. Also, is it a problem?
I am considering using something like StackFrame stackFrame = new StackFrame(1) to log the executing method, but I don't know about its performance implications. Is the stack trace something that is build anyway with each method call so performance should not be a concern or is it something that is only build when asked for it? Do you recommend against it in an application where performance is very important? If so, does that mean I should disable it for the release?
edit: Some background
We have a similar feature which is disabled 99% of the time; we were using an approach like:
public void DoSomething()
{
TraceCall(MethodBase.GetCurrentMethod().Name);
// Do Something
}
public void TraceCall(string methodName)
{
if (!loggingEnabled) { return; }
// Log...
}
TraceCall(MethodBase.GetCurrentMethod().Name)
It was simple, but regardless of whether or not tracing was enabled we were incurring the performance hit of using Reflection to lookup the method name.
Our options were to either require more code in every method (and risk simple mistakes or refusal) or to switch to using StackFrame to determine the calling method only when logging was enabled.
Option A:
public void DoSomething()
{
if (loggingEnabled)
{
TraceCall(MethodBase.GetCurrentMethod().Name);
}
// Do Something
}
public void TraceCall(string methodName)
{
if (!loggingEnabled) { return; }
// Log...
}
Option B:
public void DoSomething()
{
TraceCall();
// Do Something
}
public void TraceCall()
{
if (!loggingEnabled) { return; }
StackFrame stackFrame = new StackFrame(1);
// Log...
}
We opted for Option B. It offers significant performance improvements over Option A when logging is disabled, 99% of the time and is very simple to implement.
Here's an alteration of Michael's code, to display the cost / benefit of this approach
using System;
using System.Diagnostics;
using System.Reflection;
namespace ConsoleApplication
{
class Program
{
static bool traceCalls;
static void Main(string[] args)
{
Stopwatch sw;
// warm up
for (int i = 0; i < 100000; i++)
{
TraceCall();
}
// call 100K times, tracing *disabled*, passing method name
sw = Stopwatch.StartNew();
traceCalls = false;
for (int i = 0; i < 100000; i++)
{
TraceCall(MethodBase.GetCurrentMethod());
}
sw.Stop();
Console.WriteLine("Tracing Disabled, passing Method Name: {0}ms"
, sw.ElapsedMilliseconds);
// call 100K times, tracing *enabled*, passing method name
sw = Stopwatch.StartNew();
traceCalls = true;
for (int i = 0; i < 100000; i++)
{
TraceCall(MethodBase.GetCurrentMethod());
}
sw.Stop();
Console.WriteLine("Tracing Enabled, passing Method Name: {0}ms"
, sw.ElapsedMilliseconds);
// call 100K times, tracing *disabled*, determining method name
sw = Stopwatch.StartNew();
traceCalls = false;
for (int i = 0; i < 100000; i++)
{
TraceCall();
}
Console.WriteLine("Tracing Disabled, looking up Method Name: {0}ms"
, sw.ElapsedMilliseconds);
// call 100K times, tracing *enabled*, determining method name
sw = Stopwatch.StartNew();
traceCalls = true;
for (int i = 0; i < 100000; i++)
{
TraceCall();
}
Console.WriteLine("Tracing Enabled, looking up Method Name: {0}ms"
, sw.ElapsedMilliseconds);
Console.ReadKey();
}
private static void TraceCall()
{
if (traceCalls)
{
StackFrame stackFrame = new StackFrame(1);
TraceCall(stackFrame.GetMethod().Name);
}
}
private static void TraceCall(MethodBase method)
{
if (traceCalls)
{
TraceCall(method.Name);
}
}
private static void TraceCall(string methodName)
{
// Write to log
}
}
}
The Results:
Tracing Disabled, passing Method Name: 294ms
Tracing Enabled, passing Method Name: 298ms
Tracing Disabled, looking up Method Name: 0ms
Tracing Enabled, looking up Method Name: 1230ms
I know this is an old post, but just in case anyone comes across it there is another alternative if you are targeting .Net 4.5
You can use the CallerMemberName attribute to identify the calling method name. It is far faster than reflection or StackFrame. Here are the results from a quick test iterating a million times. StackFrame is extremely slow compared to reflection, and the new attribute makes both look like they are standing still. This was ran in the IDE.
Reflection Result:
00:00:01.4098808
StackFrame Result
00:00:06.2002501
CallerMemberName attribute Result:
00:00:00.0042708
Done
The following is from the compiled exe:
Reflection Result:
00:00:01.2136738
StackFrame Result
00:00:03.6343924
CallerMemberName attribute Result:
00:00:00.0000947
Done
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
sw.Stop();
Console.WriteLine("Reflection Result:");
sw.Start();
for (int i = 0; i < 1000000; i++)
{
//Using reflection to get the current method name.
PassedName(MethodBase.GetCurrentMethod().Name);
}
Console.WriteLine(sw.Elapsed);
Console.WriteLine("StackFrame Result");
sw.Restart();
for (int i = 0; i < 1000000; i++)
{
UsingStackFrame();
}
Console.WriteLine(sw.Elapsed);
Console.WriteLine("CallerMemberName attribute Result:");
sw.Restart();
for (int i = 0; i < 1000000; i++)
{
UsingCallerAttribute();
}
Console.WriteLine(sw.Elapsed);
sw.Stop();
Console.WriteLine("Done");
Console.Read();
}
static void PassedName(string name)
{
}
static void UsingStackFrame()
{
string name = new StackFrame(1).GetMethod().Name;
}
static void UsingCallerAttribute([CallerMemberName] string memberName = "")
{
}
A quick and naive test indicates that for performance-sensitive code, yes, you want to pay attention to this:
Don't generate 100K frames: 3ms
Generate 100K frames: 1805ms
About 20 microseconds per generated frame, on my machine. Not a lot, but a measurable difference over a large number of iterations.
Speaking to your later questions ("Should I disable StackFrame generation in my application?"), I'd suggest you analyze your application, do performance tests like the one I've done here, and see if the performance difference amounts to anything with your workload.
using System;
using System.Diagnostics;
namespace ConsoleApplication
{
class Program
{
static bool generateFrame;
static void Main(string[] args)
{
Stopwatch sw;
// warm up
for (int i = 0; i < 100000; i++)
{
CallA();
}
// call 100K times; no stackframes
sw = Stopwatch.StartNew();
for (int i = 0; i < 100000; i++)
{
CallA();
}
sw.Stop();
Console.WriteLine("Don't generate 100K frames: {0}ms"
, sw.ElapsedMilliseconds);
// call 100K times; generate stackframes
generateFrame = true;
sw = Stopwatch.StartNew();
for (int i = 0; i < 100000; i++)
{
CallA();
}
Console.WriteLine("Generate 100K frames: {0}ms"
, sw.ElapsedMilliseconds);
Console.ReadKey();
}
private static void CallA()
{
CallB();
}
private static void CallB()
{
CallC();
}
private static void CallC()
{
if (generateFrame)
{
StackFrame stackFrame = new StackFrame(1);
}
}
}
}
From the MSDN documentation, it seems like StackFrames are being created all the time:
A StackFrame is created and pushed on
the call stack for every function call
made during the execution of a thread.
The stack frame always includes
MethodBase information, and optionally
includes file name, line number, and
column number information.
The constructor new StackFrame(1) you'd call would do this:
private void BuildStackFrame(int skipFrames, bool fNeedFileInfo)
{
StackFrameHelper sfh = new StackFrameHelper(fNeedFileInfo, null);
StackTrace.GetStackFramesInternal(sfh, 0, null);
int numberOfFrames = sfh.GetNumberOfFrames();
skipFrames += StackTrace.CalculateFramesToSkip(sfh, numberOfFrames);
if ((numberOfFrames - skipFrames) > 0)
{
this.method = sfh.GetMethodBase(skipFrames);
this.offset = sfh.GetOffset(skipFrames);
this.ILOffset = sfh.GetILOffset(skipFrames);
if (fNeedFileInfo)
{
this.strFileName = sfh.GetFilename(skipFrames);
this.iLineNumber = sfh.GetLineNumber(skipFrames);
this.iColumnNumber = sfh.GetColumnNumber(skipFrames);
}
}
}
GetStackFramesInternal is an external method. CalculateFramesToSkip has a loop that operates exactly once, since you specified only 1 frame. Everything else looks pretty quick.
Have you tried measuring how long it would take to create, say, 1 million of them?
I am considering using something like StackFrame stackFrame = new StackFrame(1) to log the executing method
Out of interest: Why? If you only want the current method, then
string methodName = System.Reflection.MethodBase.GetCurrentMethod().Name;
seems better. Maybe not more performant (I didn't compare, but Reflection shows that GetCurrentMethod() does not simply create a StackFrame but does some "magic"), but clearer in it's intent.
I know what you mean, but this example result is overshoot. Executing the GetCurrentMethod even when logging is turned off is a waste.
It should be something like:
if (loggingEnabled) TraceCall(MethodBase.GetCurrentMethod());
Or if you want the TraceCall always executed:
TraceCall(loggingEnabled ? MethodBase.GetCurrentMethod() : null);
I think Paul Williams hit the nail on the head with the work being done. If you dig deeper into StackFrameHelper you'll find that fNeedFileInfo is actually the performance killer - especially in debug mode. Try setting it false if performance is important. You won't get much useful information in release mode anyway.
If you pass false in here you'll still get method names when doing a ToString() and without outputting any information, just moving stack pointers around, it's very fast.