方法性能比较的好帮手:CodeTimer的扩展应用

09年的.NET技术大会上Jeffery Richard展示的性能测试代码中,功能强大的CodeTimer引起了大家的注意,由于Jeffery Richard还没有公布源码,于是园子里的老赵就自己写了一个,适用于在Console应用程序中输出性能测试的各个指标。

最近参与的项目中有很多想要进行方法性能比较的地方,于是就想起了这个CodeTimer,便狗尾续貂在老赵原有的代码上加上了一个Time方法的重载,以适用于非Console应用程序中快速的性能测试,比如Winform、Web、UnitTest、WindowsService等等。

修改后的代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Threading;

namespace PerformanceTest
{
    public static class CodeTimer
    {
        public static void Initialize()
        {
            Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
            Thread.CurrentThread.Priority = ThreadPriority.Highest;
            Time("", 1, () => { });
        }

        public static void Time(string name, int iteration, Action action)
        {
            Time(name, iteration, action, Console.WriteLine);
        }

        public static void Time(string name, int iteration, Action action, Action<string> output)
        {
            if (String.IsNullOrEmpty(name)) return;

            // 1.
            ConsoleColor currentForeColor = Console.ForegroundColor;
            Console.ForegroundColor = ConsoleColor.Yellow;
            output(name);

            // 2.
            GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
            int[] gcCounts = new int[GC.MaxGeneration + 1];
            for (int i = 0; i <= GC.MaxGeneration; i++)
            {
                gcCounts[i] = GC.CollectionCount(i);
            }

            // 3.
            Stopwatch watch = new Stopwatch();
            watch.Start();
            ulong cycleCount = GetCycleCount();
            for (int i = 0; i < iteration; i++) action();
            ulong cpuCycles = GetCycleCount() - cycleCount;
            watch.Stop();

            // 4.
            Console.ForegroundColor = currentForeColor;
            output("\tTime Elapsed:\t" + watch.ElapsedMilliseconds.ToString("N0") + "ms");
            output("\tCPU Cycles:\t" + cpuCycles.ToString("N0"));

            // 5.
            for (int i = 0; i <= GC.MaxGeneration; i++)
            {
                int count = GC.CollectionCount(i) - gcCounts[i];
                output("\tGen " + i + ": \t\t" + count);
            }

            output(string.Empty);
        }

        private static ulong GetCycleCount()
        {
            ulong cycleCount = 0;
            QueryThreadCycleTime(GetCurrentThread(), ref cycleCount);
            return cycleCount;
        }

        [DllImport("kernel32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool QueryThreadCycleTime(IntPtr threadHandle, ref ulong cycleTime);

        [DllImport("kernel32.dll")]
        static extern IntPtr GetCurrentThread();
    }
}

这样一来,就能够在Winform、Web、UnitTest、Service等各种应用程序中方便快捷的使用CodeTimer了,比如在Winform中的一个应用:

2010年1月13日1

StringBuilder result;

private void button1_Click(object sender, EventArgs e)
{
    string s = string.Empty;
    PerformanceTest.CodeTimer.Time("String Concat", 10000, () => { s += "a"; }, Print);

    StringBuilder sb = new StringBuilder();
    PerformanceTest.CodeTimer.Time("StringBuilder", 10000, () => { sb.Append("a"); }, Print);

    this.textBox1.Text = result.ToString();
}

void Print(string msg)
{
    if (result == null)
        result = new StringBuilder();
    result.AppendLine(msg);
    Console.WriteLine(msg);
}
posted @ 2010-01-13 12:03 LanceZhang 阅读(...) 评论(...) 编辑 收藏