性能测试的准确时间测量[重复]

本文翻译自:Exact time measurement for performance testing [duplicate]

This question already has an answer here: 这个问题在这里已有答案:

What is the most exact way of seeing how long something, for example a method call, took in code? 查看某些内容(例如方法调用)接受代码的最精确方式是什么?

The easiest and quickest I would guess is this: 我猜的最容易和最快的是:

DateTime start = DateTime.Now;
{
    // Do some work
}
TimeSpan timeItTook = DateTime.Now - start;

But how exact is this? 但这有多精确? Are there better ways? 还有更好的方法吗?


#1楼

参考:https://stackoom.com/question/449i/性能测试的准确时间测量-重复


#2楼

I'm using this: 我正在使用这个:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(myUrl);
System.Diagnostics.Stopwatch timer = new Stopwatch();

timer.Start();

HttpWebResponse response = (HttpWebResponse)request.GetResponse();

statusCode = response.StatusCode.ToString();

response.Close();

timer.Stop();

From my blog: C# Time Measurement For Performance Testing (Not in English) 来自我的博客: C#性能测试时间测量 (不是英文)


#3楼

As others said, Stopwatch should be the right tool for this. 正如其他人所说, Stopwatch应该是正确的工具。 There can be few improvements made to it though, see this thread specifically: Benchmarking small code samples in C#, can this implementation be improved? 但是,对它的改进很少,具体看到这个主题: 在C#中对小代码示例进行基准测试,是否可以改进这种实现? .

I have seen some useful tips by Thomas Maierhofer here 我在这里看到了Thomas Maierhofer的一些有用的提示

Basically his code looks like: 基本上他的代码看起来像:

//prevent the JIT Compiler from optimizing Fkt calls away
long seed = Environment.TickCount;

//use the second Core/Processor for the test
Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(2);

//prevent "Normal" Processes from interrupting Threads
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;

//prevent "Normal" Threads from interrupting this thread
Thread.CurrentThread.Priority = ThreadPriority.Highest;

//warm up
method();

var stopwatch = new Stopwatch()
for (int i = 0; i < repetitions; i++)
{
    stopwatch.Reset();
    stopwatch.Start();
    for (int j = 0; j < iterations; j++)
        method();
    stopwatch.Stop();
    print stopwatch.Elapsed.TotalMilliseconds;
}

Another approach is to rely on Process.TotalProcessTime to measure how long the CPU has been kept busy running the very code/process , as shown here This can reflect more real scenario since no other process affects the measurement. 另一种方法是依靠Process.TotalProcessTime来测量CPU保持忙于运行代码/进程的时间如此处所示这可以反映更真实的情况,因为没有其他进程影响测量。 It does something like: 它做的事情如下:

 var start = Process.GetCurrentProcess().TotalProcessorTime;
 method();
 var stop = Process.GetCurrentProcess().TotalProcessorTime;
 print (end - begin).TotalMilliseconds;

A naked, detailed implementation of the samething can be found here. 在这里可以找到相同的裸体,详细的实现

I wrote a helper class to perform both in an easy to use manner: 我编写了一个帮助程序类,以易于使用的方式执行:

public class Clock
{
    interface IStopwatch
    {
        bool IsRunning { get; }
        TimeSpan Elapsed { get; }

        void Start();
        void Stop();
        void Reset();
    }



    class TimeWatch : IStopwatch
    {
        Stopwatch stopwatch = new Stopwatch();

        public TimeSpan Elapsed
        {
            get { return stopwatch.Elapsed; }
        }

        public bool IsRunning
        {
            get { return stopwatch.IsRunning; }
        }



        public TimeWatch()
        {
            if (!Stopwatch.IsHighResolution)
                throw new NotSupportedException("Your hardware doesn't support high resolution counter");

            //prevent the JIT Compiler from optimizing Fkt calls away
            long seed = Environment.TickCount;

            //use the second Core/Processor for the test
            Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(2);

            //prevent "Normal" Processes from interrupting Threads
            Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;

            //prevent "Normal" Threads from interrupting this thread
            Thread.CurrentThread.Priority = ThreadPriority.Highest;
        }



        public void Start()
        {
            stopwatch.Start();
        }

        public void Stop()
        {
            stopwatch.Stop();
        }

        public void Reset()
        {
            stopwatch.Reset();
        }
    }



    class CpuWatch : IStopwatch
    {
        TimeSpan startTime;
        TimeSpan endTime;
        bool isRunning;



        public TimeSpan Elapsed
        {
            get
            {
                if (IsRunning)
                    throw new NotImplementedException("Getting elapsed span while watch is running is not implemented");

                return endTime - startTime;
            }
        }

        public bool IsRunning
        {
            get { return isRunning; }
        }



        public void Start()
        {
            startTime = Process.GetCurrentProcess().TotalProcessorTime;
            isRunning = true;
        }

        public void Stop()
        {
            endTime = Process.GetCurrentProcess().TotalProcessorTime;
            isRunning = false;
        }

        public void Reset()
        {
            startTime = TimeSpan.Zero;
            endTime = TimeSpan.Zero;
        }
    }



    public static void BenchmarkTime(Action action, int iterations = 10000)
    {
        Benchmark<TimeWatch>(action, iterations);
    }

    static void Benchmark<T>(Action action, int iterations) where T : IStopwatch, new()
    {
        //clean Garbage
        GC.Collect();

        //wait for the finalizer queue to empty
        GC.WaitForPendingFinalizers();

        //clean Garbage
        GC.Collect();

        //warm up
        action();

        var stopwatch = new T();
        var timings = new double[5];
        for (int i = 0; i < timings.Length; i++)
        {
            stopwatch.Reset();
            stopwatch.Start();
            for (int j = 0; j < iterations; j++)
                action();
            stopwatch.Stop();
            timings[i] = stopwatch.Elapsed.TotalMilliseconds;
            print timings[i];
        }
        print "normalized mean: " + timings.NormalizedMean().ToString();
    }

    public static void BenchmarkCpu(Action action, int iterations = 10000)
    {
        Benchmark<CpuWatch>(action, iterations);
    }
}

Just call 打电话吧

Clock.BenchmarkTime(() =>
{
    //code

}, 10000000);

or 要么

Clock.BenchmarkCpu(() =>
{
    //code

}, 10000000);

The last part of the Clock is the tricky part. Clock的最后一部分是棘手的部分。 If you want to display the final timing, its up to you to choose what sort of timing you want. 如果您想显示最终时间,可由您自行选择所需的时间。 I wrote an extension method NormalizedMean which gives you the mean of the read timings discarding the noise. 我写了一个扩展方法NormalizedMean ,它给出了丢弃噪声的读取时间的平均值 I mean I calculate the the deviation of each timing from the actual mean, and then I discard the values which was farer (only the slower ones) from the mean of deviation (called absolute deviation; note that its not the often heard standard deviation), and finally return the mean of remaining values. 我的意思是我计算每个时间与实际平均值的偏差,然后我从偏差的平均值 (称为绝对偏差;请注意它不是经常听到的标准偏差)中丢弃更快的值(只有较慢的值) ,最后返回剩余值的平均值。 This means, for instance, if timed values are { 1, 2, 3, 2, 100 } (in ms or whatever), it discards 100 , and returns the mean of { 1, 2, 3, 2 } which is 2 . 这意味着,例如,如果定时值为{ 1, 2, 3, 2, 100 } 1,2,3,2,100 { 1, 2, 3, 2, 100 } (以ms或其他为单位),则丢弃100 ,并返回{ 1, 2, 3, 2 } 1,2,3,2 { 1, 2, 3, 2, 100 }的平均值,即2 Or if timings are { 240, 220, 200, 220, 220, 270 } , it discards 270 , and returns the mean of { 240, 220, 200, 220, 220 } which is 220 . 或者如果时间是{ 240, 220, 200, 220, 220, 270 } ,则丢弃270 ,并返回{ 240, 220, 200, 220, 220 } { 240, 220, 200, 220, 220, 270 }的平均值220

public static double NormalizedMean(this ICollection<double> values)
{
    if (values.Count == 0)
        return double.NaN;

    var deviations = values.Deviations().ToArray();
    var meanDeviation = deviations.Sum(t => Math.Abs(t.Item2)) / values.Count;
    return deviations.Where(t => t.Item2 > 0 || Math.Abs(t.Item2) <= meanDeviation).Average(t => t.Item1);
}

public static IEnumerable<Tuple<double, double>> Deviations(this ICollection<double> values)
{
    if (values.Count == 0)
        yield break;

    var avg = values.Average();
    foreach (var d in values)
        yield return Tuple.Create(d, avg - d);
}

#4楼

使用秒表课程


#5楼

A better way is to use the Stopwatch class: 更好的方法是使用秒表类:

using System.Diagnostics;
// ...

Stopwatch sw = new Stopwatch();

sw.Start();

// ...

sw.Stop();

Console.WriteLine("Elapsed={0}",sw.Elapsed);

#6楼

System.Diagnostics.Stopwatch专为此任务而设计。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值