您的位置:首页 > 其它

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

2012-01-12 13:11 225 查看
  早上看到老赵写的这个性能计数器,感觉很实用,不过老赵用了很多.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", 1, new TestSleep3000());
CodeTimer.Time("Thread Sleep", 10000000, new TestEmptyMethod());
CodeTimer.Time("String Concat", 100000, new 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", 1, delegate() { Thread.Sleep(3000); });
CodeTimer.Time("Empty Method", 10000000, delegate() { });

string a = "";

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

StringBuilder s = new StringBuilder();
CodeTimer.Time("StringBuilder Conca", 100000, delegate() { 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

 

 

 

 

 

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息