eaglet

本博专注于基于微软技术的搜索相关技术
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

对老赵写的简单性能计数器的修改

Posted on 2009-03-10 14:10  eaglet  阅读(12606)  评论(44编辑  收藏  举报

对老赵写的简单性能计数器的修改

    早上看到老赵写的这个性能计数器,感觉很实用,不过老赵用了很多.C# 3.0 的新语法,还用了 VISTA 和 Server 2008 下特有的Win32 API,对于还在用C#2.0 或者还工作在 XP 或者 Server 2003 下的兄弟们,只能望代码心叹了。应老赵的要求,我修改了他的代码,增加了对低版本C# 和 低版本windows 操作系统的支持。

    老赵的原文: 一个简单的性能计数器:CodeTimer

    修改说明

    1. 采用 接口 取代了原代码中的 Lambda 表达式

    2. 采用 GetThreadTimes 这个API 函数替代了原代码中的 QueryThreadCycleTime

    这里需要说明的是 GetThreadTimes 给出了线程在内核态和用户态占用的时间,单位是 100 ns。两个时间的总和就是线程占用的CPU时间。这个API的时间精度我看了一些资料似乎没有达到 100ns. 所以GetThreadTimes 这个API函数的进度没有 QueryThreadCycleTime 高。

    下面是我修改后的代码

    注释1: 2009-03-11 增加委托的调用,修改 GC.Collect 参数,兼容.Net 2.0.  增加每次调用时间统计 

    增加了委托调用后,我发现同样是测试空函数,采用接口比采用委托效率要略高一些,这和我的预计基本吻合,因为委托不是单纯的函数调用,具体原理超出本文范围,我就不多说了。

 

 

using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Threading;
using System.Runtime.InteropServices;
  
 
    
public interface IAction
    
{
        
void Action();
    }


    
public static class CodeTimer
    
{
        [DllImport(
"kernel32.dll", SetLastError = true)]
        
static extern bool GetThreadTimes(IntPtr hThread, out long lpCreationTime,
           
out long lpExitTime, out long lpKernelTime, out long lpUserTime);

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

        
public delegate void ActionDelegate();

        
private static long GetCurrentThreadTimes()
        
{
            
long l;
            
long kernelTime, userTimer;
            GetThreadTimes(GetCurrentThread(), 
out l, out l, out kernelTime, 
               
out userTimer);
            
return kernelTime + userTimer;
        }


        
static CodeTimer()
        
{
            Process.GetCurrentProcess().PriorityClass 
= ProcessPriorityClass.High;
            Thread.CurrentThread.Priority 
= ThreadPriority.Highest;

        }


        
public static void Time(string name, int iteration, ActionDelegate action)
        
{
            
if (String.IsNullOrEmpty(name))
            
{
                
return;
            }


            
if (action == null)
            
{
                
return;
            }


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


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


            
// 3. Run action
            Stopwatch watch = new Stopwatch();
            watch.Start();
            
long ticksFst = GetCurrentThreadTimes(); //100 nanosecond one tick

            
for (int i = 0; i < iteration; i++) action();
            
long ticks = GetCurrentThreadTimes() - ticksFst;
            watch.Stop();

            
// 4. Print CPU
            Console.ForegroundColor = currentForeColor;
            Console.WriteLine(
"\tTime Elapsed:\t\t" + 
               watch.ElapsedMilliseconds.ToString(
"N0"+ "ms");
            Console.WriteLine(
"\tTime Elapsed (one time):" + 
               (watch.ElapsedMilliseconds 
/ iteration).ToString("N0"+ "ms");

            Console.WriteLine(
"\tCPU time:\t\t" + (ticks * 100).ToString("N0"
               
+ "ns");
            Console.WriteLine(
"\tCPU time (one time):\t" + (ticks * 100 / 
               iteration).ToString(
"N0"+ "ns");

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


            Console.WriteLine();

        }


        
public static void Time(string name, int iteration, IAction action)
        
{
            
if (String.IsNullOrEmpty(name))
            
{
                
return;
            }


            
if (action == null)
            
{
                
return;
            }


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


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


            
// 3. Run action
            Stopwatch watch = new Stopwatch();
            watch.Start();
            
long ticksFst = GetCurrentThreadTimes(); //100 nanosecond one tick
            
            
for (int i = 0; i < iteration; i++) action.Action();
            
long ticks = GetCurrentThreadTimes() - ticksFst;
            watch.Stop();

            
// 4. Print CPU
            Console.ForegroundColor = currentForeColor;
            Console.WriteLine(
"\tTime Elapsed:\t\t" + 
               watch.ElapsedMilliseconds.ToString(
"N0"+ "ms");
            Console.WriteLine(
"\tTime Elapsed (one time):" + 
               (watch.ElapsedMilliseconds 
/ iteration).ToString("N0"+ "ms");

            Console.WriteLine(
"\tCPU time:\t\t" + (ticks * 100).ToString("N0"
                
+ "ns");
            Console.WriteLine(
"\tCPU time (one time):\t" + (ticks * 100 / 
                iteration).ToString(
"N0"+ "ns");

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


            Console.WriteLine();

        }

    }

   

测试类

 

 

    public class TestSleep3000 : IAction
    {
        
#region IAction Members

        
public void Action()
        {
            Thread.Sleep(
3000);
        }

        
#endregion
    }


    
public class TestEmptyMethod : IAction
    {
        
#region IAction Members

        
public void Action()
        {
        }

        
#endregion
    }

    
public class TestStringConcat : IAction
    {
        
string s = "";

        
#region IAction Members

        
public void Action()
        {
            s 
+= "a";
        }

        
#endregion
    }

    
public class TestStringBuilderConcat : IAction
    {
        StringBuilder s 
= new StringBuilder();

        
#region IAction Members

        
public void Action()
        {
            s.Append (
"a");
        }

        
#endregion
    }

 

测试代码

采用接口 

            CodeTimer.Time("Thread Sleep"1new TestSleep3000());
            CodeTimer.Time(
"Thread Sleep"10000000new TestEmptyMethod());
            CodeTimer.Time(
"String Concat"100000new TestStringConcat());
            CodeTimer.Time(
"StringBuilder Conca"100000
                 
new TestStringBuilderConcat()); 

 

测试结果

 

 

Thread Sleep
        Time Elapsed:           2,997ms
        Time Elapsed (one time):2,997ms
        CPU time:               0ns
        CPU time (one time):    0ns
        Gen 0:                  0
        Gen 1:                  0
        Gen 2:                  0

Empty Method
        Time Elapsed:           138ms
        Time Elapsed (one time):0ms
        CPU time:               125,000,000ns
        CPU time (one time):    12ns
        Gen 0:                  0
        Gen 1:                  0
        Gen 2:                  0

String Concat
        Time Elapsed:           10,547ms
        Time Elapsed (one time):0ms
        CPU time:               10,546,875,000ns
        CPU time (one time):    105,468ns
        Gen 0:                  4102
        Gen 1:                  2661
        Gen 2:                  2545

StringBuilder Conca
        Time Elapsed:           4ms
        Time Elapsed (one time):0ms
        CPU time:               0ns
        CPU time (one time):    0ns
        Gen 0:                  0
        Gen 1:                  0
        Gen 2:                  0

 

采用委托

 

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

string a = "";

CodeTimer.Time(
"String Concat"100000delegate() { a += "a"; });

StringBuilder s 
= new StringBuilder();
CodeTimer.Time(
"StringBuilder Conca"100000delegate() { s.Append("a"); }); 

 

 测试结果

 

Thread Sleep
        Time Elapsed:           2,989ms
        Time Elapsed (one time):2,989ms
        CPU time:               0ns
        CPU time (one time):    0ns
        Gen 0:                  0
        Gen 1:                  0
        Gen 2:                  0

Empty Method
        Time Elapsed:           156ms
        Time Elapsed (one time):0ms
        CPU time:               156,250,000ns
        CPU time (one time):    15ns
        Gen 0:                  0
        Gen 1:                  0
        Gen 2:                  0

String Concat
        Time Elapsed:           10,425ms
        Time Elapsed (one time):0ms
        CPU time:               10,406,250,000ns
        CPU time (one time):    104,062ns
        Gen 0:                  4102
        Gen 1:                  2661
        Gen 2:                  2545

StringBuilder Conca
        Time Elapsed:           4ms
        Time Elapsed (one time):0ms
        CPU time:               0ns
        CPU time (one time):    0ns
        Gen 0:                  0
        Gen 1:                  0
        Gen 2:                  0