0

我做了一门课,可以帮助我测量 Ticks 中任何方法的时间。

基本上,它运行测试方法 100x,并强制 GC,然后记录另一个 100x 方法运行所花费的时间。x64 发布 ctrl+f5 VS2012/VS2010

结果如下:

2,914    2,909    2,913    2,909    2,908
2,907    2,909    2,998    2,976    2,855
2,446    2,415    2,435    2,401    2,402
2,402    2,399    2,401    2,401    2,400
2,399    2,400    2,404    2,402    2,401
2,399    2,400    2,402    2,404    2,403
2,401    2,403    2,401    2,400    2,399
2,414    2,405    2,401    2,407    2,399
2,401    2,402    2,401    2,404    2,401
2,404    2,405    2,368    1,577    1,579
1,626    1,578    1,576    1,578    1,577
1,577    1,576    1,578    1,576    1,578
1,577    1,578    1,576    1,578    1,577
1,579    1,585    1,576    1,579    1,577
1,579    1,578    1,579    1,577    1,578
1,577    1,578    1,576    1,578    1,577
1,578    1,599    1,579    1,578    1,582
1,576    1,578    1,576    1,579    1,577
1,578    1,577    1,591    1,577    1,578
1,578    1,576    1,578    1,576    1,578

如您所见,有 3 个阶段,第一个是 ~2,900,第二个是 ~2,400,然后是 ~1,550

可能是什么原因造成的?

更新

我现在强烈怀疑,当我使用英特尔 I5 时,是 cpu turbo boost 干扰了结果。但是,即使我禁用了涡轮增压,它仍然不稳定。同时 Core 2 Quad 产生稳定的基准

测试性能类代码如下:

    public static void RunTests(Func<long> myTest)
    {
        const int numTrials = 100;
        Stopwatch sw = new Stopwatch();
        double[] sample = new double[numTrials];

        Console.WriteLine("Checksum is {0:N0}", myTest());

        sw.Start();
        myTest();
        sw.Stop();

        Console.WriteLine("Estimated time per test is {0:N0} ticks\n", sw.ElapsedTicks);


        for (int i = 0; i < numTrials; i++)
        {
            myTest();
        }
        GC.Collect();
        string testName = myTest.Method.Name;
        Console.WriteLine("----> Starting benchmark {0}\n", myTest.Method.Name);
        for (int i = 0; i < numTrials; i++)
        {
            sw.Restart();
            myTest();
            sw.Stop();
            sample[i] = sw.ElapsedTicks;
        }
        double testResult = DataSetAnalysis.Report(sample);

        for (int j = 0; j < numTrials; j = j + 5)
            Console.WriteLine("{0,8:N0} {1,8:N0} {2,8:N0} {3,8:N0} {4,8:N0}", sample[j], sample[j + 1], sample[j + 2], sample[j + 3], sample[j + 4]);
        Console.WriteLine("\n----> End of benchmark");
    }
4

3 回答 3

1

如果我没看错你的帖子,它只会执行一个方法 100 次,那是一个非常小的样本池。在做即兴秒表时,我倾向于运行数百万次操作,具体取决于操作的复杂程度。

对于您的一般案例包装器,您可能希望让另一个线程启动秒表,向性能部件发送 eventwaithandle 信号以运行,并让您的秒表线程每 200 毫秒检查一次,直到达到 2 分钟,发送信号并检查您的性能部件表示每次迭代都停止。

查看这 2 分钟内完成了多少次迭代。

试试这个,运行 10 次,看看百分比方差是多少,总数可能相差数千,但总百分比差异应该小得多。

就在我的头顶..

public class PerfTester
{
    private EventWaitHandle _running = new EventWaitHandle(false, EventResetMode.ManualReset, "awesome_Woo");
    private int _count;

    public Run(Action actionToRun)
    {
        ParameterizedThreadStart runner = new ParameterizedThreadStart((state) =>
        {
            Action action = state as Action;
            EventWaitHandle run = = new EventWaitHandle(false, EventResetMode.ManualReset, "awesome_Woo", false);
            while(true)
            {
                run.WaitOne();
                action();
                _count++;
            }
        });

        Thread runnerThread = new Thread(runner);
        runnerThread.Start(actionToRun);

        StopWatch timer = new StopWatch();
        timer.Start();
        _running.Set();
        while(timer.ElapsedSeconds < 120) Thread.Sleep(500);
        _running.Reset();

        Console.WriteLine(_count);
    }
}

或者也许只是使用布尔值而不是等待句柄,我刚刚养成了使用它们进行跨界通信的习惯..

于 2012-08-30T22:22:19.930 回答
1

好像是快手?速度从 1/2x 开始,当它完全预热时,它会全速运行。

当我同时运行TMonitor时,基准变得稳定,甚至不需要预热

于 2012-09-02T16:07:04.927 回答
0

我认为每个滴答声大约是 1000 个时钟周期,所以 1000-2000 个滴答声并不是那么小。虽然这样做仍然更好:

myTest();
myTest();
myTest();
myTest();
myTest();

myTest();
myTest();
myTest();
myTest();
myTest();

那就是在不使用循环的情况下调用相同的方法 10 次以避免循环成本;然后将结果除以 10。

至于区别,如果您的 myTest 代码执行任何内存分配、使用任何类型的缓存或使用弱引用,则可能是这样。我最近发现在低端机器上调用 .Net 反射 API 会产生奇怪的性能结果。

于 2012-08-31T00:49:30.777 回答