一个简单的性能计数器:CodeTimer
2011-12-17 20:24
281 查看
声明:本文章源自园子老赵之手,个人做学习笔记之用,地址:http://www.cnblogs.com/JeffreyZhao/archive/2009/03/10/codetimer.html
因为每次我们在在做性能比较的时候,都需要自己实例一个Stopwatch,感觉很麻烦,就在网上找到了这篇文章,作为一个实用工具,感觉值得收藏下,故整理下,留之后用,不废话,新建项目:
首先我们将静态化构造函数,保证我们每次实用该类的时候,都先调用此方法。首先它会把当前线程及当前线程的优先级设为最高,确保相对减少操作系统在调度上造成的干扰。然后调用一次Timer方法进行“预热”,让JIT将IL编译成本地代码。让Time方法尽快“进入状态”。Time方法则是真正用于性能计数的方法。
与传统计数方法相比,这段代码还输出了更多的信息,CPU时钟周期(时间轮渡方法所赋予该程序的时间),以及垃圾回收次数,CPU时钟周期是性能计数器中的辅助参考。说明CPU分配了多多少时间片给这段函数执行,它和消耗时间没有必然联系。
测试一:
例如Thread.Sleep方法会让CPU暂停对当前线程的“供给”,这样虽然消耗了时间,但是节省了CPU时钟周期:
运行结果:
而垃圾收集次数的统计,即直观地反应了方法资源分配(消耗)的规模:
测试二:
运行结果如下:
可以看出显然StringBuilder性能优越性要高的很多...
因为每次我们在在做性能比较的时候,都需要自己实例一个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性能优越性要高的很多...
相关文章推荐
- 一个简单的性能计数器:CodeTimer
- 一个简单的性能计数器:CodeTimer
- 一个简单的性能计数器:CodeTimer
- 一个简单的性能计数器:CodeTimer
- 一个简单的性能计数器:CodeTimer
- 一个简单的性能计数器:CodeTimer
- 一个简单的性能计数器:CodeTimer
- 一个简单的性能计数器:CodeTimer
- 一个简单的性能计数器
- 简单的创建一个性能计数器
- 一个简单的性能计数器
- 通过编码方式使用性能计数器来进行性能计数的一个简单例子 - ZT
- 创建一个基于for 的简单的循环。使其循环10 次,并且使用fmt 包打印 出计数器的值
- 对老赵写的简单性能计数器的修改
- 一个简单存储过程的性能分析
- 代码函数从零开始学习OpenCL开发(二)一个最简单的示例与简单性能分析
- 从零开始学习OpenCL开发(二)一个最简单的示例与简单性能分析
- 04、 struts1 总结 一个简单的计数器
- 【性能跟踪】btrace学习二--btrace一个简单例子
- 一个简单的C++性能测试工具(ms级别)