一个简单的性能计数器:CodeTimer

声明:本文章源自园子老赵之手,个人做学习笔记之用,地址:http://www.cnblogs.com/JeffreyZhao/archive/2009/03/10/codetimer.html

因为每次我们在在做性能比较的时候,都需要自己实例一个Stopwatch,感觉很麻烦,就在网上找到了这篇文章,作为一个实用工具,感觉值得收藏下,故整理下,留之后用,不废话,新建项目:

 static class CodeTimer
{
static CodeTimer()
{
//设置当前进程为最高优先级
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
//设置当前线程为最高优先级
Thread.CurrentThread.Priority = ThreadPriority.Highest;

//然后调用一次Time方法进行"预热",让JIT将IL编译成本地代码
//让Time方法尽快"进入状态"。
Time("", 1, () => { });
}

首先我们将静态化构造函数,保证我们每次实用该类的时候,都先调用此方法。首先它会把当前线程及当前线程的优先级设为最高,确保相对减少操作系统在调度上造成的干扰。然后调用一次Timer方法进行“预热”,让JIT将IL编译成本地代码。让Time方法尽快“进入状态”。Time方法则是真正用于性能计数的方法。

  //程序监控方法Time方法、接受三个参数,名称,循环次数以及需要执行的方法体。
public static void Time(string name, int iteration, Action action)
{
if (String.IsNullOrEmpty(name))
return;
//设置颜色

ConsoleColor currentForeColor = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine(name);

//立即进行垃圾回收,并记录下目前各代已经收集的参数
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);
}

//监视运行时间,记录下消耗的时间及CPU时钟周期
Stopwatch watch = new Stopwatch();
watch.Start();
ulong cyclecCount = GetCycleCount();
for (int i = 0; i < iteration; i++)
action();
//两者减得出CPU分配时间
ulong cpuCycles = GetCycleCount() - cyclecCount;
watch.Stop();

//恢复控制台默认前景色,并打印出消耗时间及CPU时钟周期
Console.ForegroundColor = currentForeColor;
Console.WriteLine("运行时间为:" + watch.ElapsedMilliseconds.ToString("N0") + "ms");
Console.WriteLine("Cup分配的时间片为:" + cpuCycles.ToString("N0"));
//循环输出打印执行过程中垃圾回收次数(这里对整个托管堆里面进行)
for (int i = 0; i <= GC.MaxGeneration; i++)
{
int count = GC.CollectionCount(i) - gcCounts[i];
Console.WriteLine("垃圾回收" + i + "的执行次数为" + 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();
}

与传统计数方法相比,这段代码还输出了更多的信息,CPU时钟周期(时间轮渡方法所赋予该程序的时间),以及垃圾回收次数,CPU时钟周期是性能计数器中的辅助参考。说明CPU分配了多多少时间片给这段函数执行,它和消耗时间没有必然联系。

测试一:

例如Thread.Sleep方法会让CPU暂停对当前线程的“供给”,这样虽然消耗了时间,但是节省了CPU时钟周期:

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

运行结果:

而垃圾收集次数的统计,即直观地反应了方法资源分配(消耗)的规模:

测试二:

           Console.WriteLine("---------String和StringBuilder的比较--------------");
string s=string.Empty;
CodeTimer.Time("string +", 1, () =>
{
for(int i=0;i<10000;i++)
s += "d";
});
StringBuilder sb = new StringBuilder();
CodeTimer.Time("string building", 1, () =>
{
for (int i = 0; i < 10000; i++)
sb.Append("d");
});

Console.ReadLine();

运行结果如下:

可以看出显然StringBuilder性能优越性要高的很多...

posted @ 2011-12-17 20:24  指尖流淌  阅读(1776)  评论(2编辑  收藏  举报