Precisely measure execution time of code in thread (C#)

断了今生、忘了曾经 提交于 2020-01-01 04:22:07

问题


I'm trying to measure the execution time of some bits of code as accurately as possible on a number of threads, taking context switching and thread downtime into account. The application is implemented in C# (VS 2008). Example:

public void ThreadFunc ()
{
    // Some code here

    // Critical block #1 begins here
    long lTimestamp1 = Stopwatch.GetTimestamp ();

    CallComplex3rdPartyFunc (); // A

    long lTimestamp2 = Stopwatch.GetTimestamp ();
    // Critical block #1 ends here

    // Some code here

    // Critical block #2 begins here
    long lTimestamp3 = Stopwatch.GetTimestamp ();

    CallOtherComplex3rdPartyFunc (); // B

    long lTimestamp4 = Stopwatch.GetTimestamp ();
    // Critical block #2 ends here

    // Save timestamps for future analysis.
}

public int Main ( string[] sArgs )
{
    // Some code here

    int nCount = SomeFunc ();

    for ( int i = 0; i < nCount; i++ )
    {
        Thread oThread = new Thread ( ThreadFunc );
        oThread.Start ();
    }

    // Some code here

    return ( 0 );
}

I'd like to measure the execution time of the above two critical code blocks as accurately as possible. The two calls marked as A and B are potentially long function calls that may sometimes take several seconds to execute but in some cases they may complete in a few milliseconds.

I'm running the above code on a number of threads - somewhere between 1 to 200 threads, depending on user input. The computers running this code have 2-16 cores - users use lower thread counts on the weaker machines.

The problem is that A and B are both potenitally long functions so it's very likely that at least one context switch will happen during their execution - possibly more than one. So the code gets lTimestamp1, then another thread starts executing (and the current thread waits). Eventually the current thread gets back control and retrieves lTimestamp2.

This means that the duration between lTimestamp1 and lTimestamp2 includes time when the thread was not actually running - it was waiting to be scheduled again while other threads executed. The tick count, however, increases anyway, so the duration is now really

Code block time = A + B + some time spent in other threads

while I want it to be only

Code block time = A + B

This is especially an issue with a larger number of threads, since they'll all get a chance to run, so the above timings will be higher while all other threads run before the thread in question gets another chance to run.

So my question is: is it possible to somehow calculate the time when the thread is not running and then adjust the above timings accordingly? I'd like to eliminate (subtract) that 3rd term entirely or at least as much of it as possible. The code runs millions of times, so final timings are calculated from a lot of samples and then averaged out.

I'm not looking for profiler products, etc. - the application needs to time these the marked parts as accurately as possible. The functions A and B are 3rd party functions, I cannot change them in any way. I'm also aware of the possible fluctuations when measuring time with nanosecond precision and possible overhead inside those 3rd-party functions, but I still need to do this measurement.

Any advice would be greatly appreciated - C++ or x86 assembly code would work as well.

Edit: seems to be impossible to implement this. Scott's idea below (using GetThreadTimes) is good but unfortunately GetThreadTimes() is a flawed API and it almost never returns correct data. Thanks for all the replies!


回答1:


This can be done with the Native API call GetThreadTimes. Here is a article on CodeProject that uses it.

A second option is use QueryThreadCycleTime. This will not give you the time, but it will give you the number of cycles the current thread has been executing.

Be aware you can't just directly convert cycles->seconds due to the fact that many processors (especially mobile processors) do not run at a fixed speed so there is no constant number you could multiply by to get the elapsed time in seconds. But if you are using a processor that does not vary its speed it then would be a simple math problem to get wall clock time from the cycles.




回答2:


You can use Stopwatch.Start() and Stopwatch.Stop() methods to pause/continue time measurement, it does not reset Elapsed/ElapsedMilliseconds value so perhaps you can leverage this.

Regarding thread context switches - I believe there are no ways to handle it in managed code so this is not possible to exclude time when thread was suspended

EDIT:

An interesting article with benchmarks: How long does it take to make a context switch?



来源:https://stackoverflow.com/questions/7598810/precisely-measure-execution-time-of-code-in-thread-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!