博客园  :: 首页  :: 新随笔  :: 联系 :: 管理

老赵的性能计数器:CodeTimer

Posted on 2009-12-16 21:56  codingsilence  阅读(235)  评论(0编辑  收藏  举报

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)
{
    if (String.IsNullOrEmpty(name)) return;

    // 1.
    ConsoleColor currentForeColor = Console.ForegroundColor;
    Console.ForegroundColor = ConsoleColor.Yellow;
    Console.WriteLine(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;
    Console.WriteLine("/tTime Elapsed:/t" + watch.ElapsedMilliseconds.ToString("N0") + "ms");
    Console.WriteLine("/tCPU Cycles:/t" + cpuCycles.ToString("N0"));

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

    Console.WriteLine();
}

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();


}

 

Time方法接受三个参数,名称,循环次数以及需要执行的方法体。打印出花费时间,消耗的CPU时钟周期,以及各代垃圾收集的回收次数。具体实现分几个步骤,如下:

  1. 保留当前控制台前景色,并使用黄色输出名称参数。
  2. 强制GC进行收集,并记录目前各代已经收集的次数。
  3. 执行代码,记录下消耗的时间及CPU时钟周期1
  4. 恢复控制台默认前景色,并打印出消耗时间及CPU时钟周期。
  5. 打印执行过程中各代垃圾收集回收次数。

  与传统计数方法相比,这段代码还输出了更多信息:CPU时钟周期及各代垃圾收集回收次数。CPU时钟周期是性能计数中的辅助参考,说明CPU分配了多少时间片给这段方法来执行,它和消耗时间并没有必然联系。例如Thread.Sleep方法会让CPU暂时停止对当前线程的“供给”,这样虽然消耗了时间,但是节省了CPU时钟周期:

CodeTimer.Time("Thread Sleep", 1, () => { Thread.Sleep(3000); });
CodeTimer.Time("Empty Method", 10000000, () => { });

  结果如下: