CodeTimer 修改版

/************************************************************************************************************************
 * 作者		:	赵劼
 * Blog		:	http://blog.zhaojie.me/2009/03/codetimer.html
 * 创建日期	:	2009年03月10日
 * 日志 :
 *		*****************************************************************************************************************
 *		修改者	:	Loney
 *		邮箱		:	X-0.0-X@Live.cn
 *		修改日期	:	2011年11月1日 12:05
 *		目的 : 
 *			 参照
 *				eaglet	: http://www.cnblogs.com/eaglet/archive/2009/03/10/1407791.html
 *			 	LanceZhang : http://www.cnblogs.com/blodfox777/archive/2010/01/13/codetimer.html
 *			 	新生命开发团队 : http://www.cnblogs.com/nnhy/archive/2011/03/11/codetimer.html
 *			 	......
 *			 进行进一步优化该类.
 *		*****************************************************************************************************************
 *		修改者	:	Loney
 *		邮箱		:	X-0.0-X@Live.cn
 *		修改日期	:	2011年11月4日 9:04
 *		目的 : 
 *			 针对不同的 Windows 操作系统调用不同的 Api :
 *			 	针对 Winodws Vista 系统(包含)以上调用	QueryThreadCycleTime.
 *			 	针对 Winodws Vista 系统以下调用		GetThreadTimes.
 *		*****************************************************************************************************************
 *		修改者	:	Loney
 *		邮箱		:	X-0.0-X@Live.cn
 *		修改日期	:	2011年11月5日 0:42
 *		目的 : 
 *			 增加了多线程并发执行的方法.	-- Pass : 不知道方法是否正确.
 *		*****************************************************************************************************************
 *		修改者	:	Loney
 *		邮箱		:	X-0.0-X@Live.cn
 *		修改日期	:	2012年4月3日 8:21
 *		目的 : 
 *			 将代码中的文本输出提取为资源文件.
 ***********************************************************************************************************************/

  

CodeTimerResult
 1 /// <summary>
2 /// 表示 <see cref="CodeTimer"/> 执行结果的类.
3 /// </summary>
4 public class CodeTimerResult {
5 /// <summary>
6 /// 初始化 <see cref="CodeTimer"/> 类的新实例.
7 /// </summary>
8 public CodeTimerResult() {
9 GenerationList = new Int32[GC.MaxGeneration + 1];
10 }
11
12 /// <summary>
13 /// 名称.
14 /// </summary>
15 public String Name { get; set; }
16
17 /// <summary>
18 /// 运行时间.
19 /// </summary>
20 public Int64 TimeElapsed { get; set; }
21
22 /// <summary>
23 /// Cpu 时钟周期.
24 /// </summary>
25 public UInt64 CPUCycles { get; set; }
26
27 /// <summary>
28 /// GC 代数集合.
29 /// </summary>
30 public Int32[] GenerationList { get; set; }
31
32 /// <summary>
33 /// 线程的计数.
34 /// </summary>
35 public Int32 ThreadCount { get; set; }
36
37 /// <summary>
38 /// 重复的次数.
39 /// </summary>
40 public Int32 Iteration { get; set; }
41
42 /// <summary>
43 /// 模拟思考的时间.
44 /// </summary>
45 public Int32 MockThinkTime { get; set; }
46
47 /// <summary>
48 /// 执行成功计数.
49 /// </summary>
50 public Int32 SuccessCount { get; set; }
51
52 /// <summary>
53 /// 执行失败计数.
54 /// </summary>
55 public Int32 FailureCount { get; set; }
56
57 /// <summary>
58 /// 重置 <see cref="CodeTimer"/>.
59 /// </summary>
60 /// <returns>重置后的 <see cref="CodeTimer"/> 对象实例.</returns>
61 public CodeTimerResult Reset() {
62 Name = String.Empty;
63 TimeElapsed = 0;
64 CPUCycles = 0;
65 GenerationList = new Int32[GC.MaxGeneration + 1];
66
67 return this;
68 }
69 }
CodeTimer
  1 /// <summary>
2 /// 代码性能计时器.
3 /// </summary>
4 static public class CodeTimer {
5 /// <summary>
6 /// 是否输出详细的数据.
7 /// </summary>
8 static public Boolean _IsDetail = false;
9
10 /*
11 * Initialize 方法应该在测试开始前调用.
12 * 首先它会把当前进程及当前线程的优先级设为最高,这样便可以相对减少操作系统在调度上造成的干扰.
13 * 然后调用一次 Time 方法进行“预热”,让 JIT 将 IL 编译成本地代码,让 Time 方法尽快“进入状态”.
14 * Execute 方法则是真正用于性能计数的方法.
15 * CPU 时钟周期是性能计数中的辅助参考
16 * 说明 CPU 分配了多少时间片给这段方法来执行,它和消耗时间并没有必然联系.
17 * 例如 Thread.Sleep 方法会让CPU暂时停止对当前线程的“供给”,这样虽然消耗了时间,但是节省了CPU时钟周期 :
18 * CodeTimer.Time("Thread Sleep", 1, () =&gt; { Thread.Sleep(3000); });
19 * CodeTimer.Time("Empty Method", 10000000, () =&gt; { });
20 * 垃圾收集次数的统计,即直观地反应了方法资源分配(消耗)的规模 :
21 * Int32 iteration = 100 * 1000;
22 * String s = "";
23 * CodeTimer.Execute("String Concat", iteration, () =&gt; { s += "a"; });
24 * StringBuilder sb = new StringBuilder();
25 * CodeTimer.Execute("StringBuilder", iteration, () =&gt; { sb.Append("a"); });
26 */
27
28 #region 单线程
29
30 /// <summary>
31 /// 单线程 Execute 方法的初始化.
32 /// </summary>
33 static public void InitializeBySingle() {
34 Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
35 Thread.CurrentThread.Priority = ThreadPriority.Highest;
36 Execute("", 1, () => { }, null);
37 }
38
39 /// <summary>
40 /// 使用单线程的方式执行 <paramref name="action"/>,并打印出 : 方法的运行时间, Cpu 时钟周期, 各代垃圾收集的回收次数的统计.
41 /// </summary>
42 /// <param name="name">名称.</param>
43 /// <param name="iteration">循环次数.</param>
44 /// <param name="action">需要执行的方法体.</param>
45 /// <remarks>一个 <see cref="CodeTimerResult"/> 表示执行的结果.</remarks>
46 static public CodeTimerResult Execute(String name, Int32 iteration, Action action) {
47 return Execute(name, iteration, () => { action(); return true; }, Console.WriteLine);
48 }
49
50 /// <summary>
51 /// 使用单线程的方式执行 <paramref name="func"/>,并打印出 : 方法的运行时间, Cpu 时钟周期, 各代垃圾收集的回收次数的统计.
52 /// </summary>
53 /// <param name="name">名称.</param>
54 /// <param name="iteration">循环次数.</param>
55 /// <param name="func">需要执行的方法体.</param>
56 /// <remarks>一个 <see cref="CodeTimerResult"/> 表示执行的结果.</remarks>
57 static public CodeTimerResult Execute(String name, Int32 iteration, Func<Boolean> func) {
58 return Execute(name, iteration, func, Console.WriteLine);
59 }
60
61 /// <summary>
62 /// 使用单线程的方式执行 <paramref name="action"/>,并使用 <paramref name="Output"/> 方法输出 : 方法的运行时间, Cpu 时钟周期, 各代垃圾收集的回收次数的统计.
63 /// </summary>
64 /// <param name="name">名称.</param>
65 /// <param name="iteration">循环次数.</param>
66 /// <param name="action">需要执行的方法体.</param>
67 /// <param name="Output">要写入的输出流.</param>
68 /// <remarks>一个 <see cref="CodeTimerResult"/> 表示执行的结果.</remarks>
69 static public CodeTimerResult Execute(String name, Int32 iteration, Action action, Action<String> Output) {
70 return Execute(name, iteration, () => { action(); return true; }, Output);
71 }
72
73 /// <summary>
74 /// 使用单线程的方式执行 <paramref name="func"/>,并使用 <paramref name="Output"/> 方法输出 : 方法的运行时间, Cpu 时钟周期, 各代垃圾收集的回收次数的统计.
75 /// </summary>
76 /// <param name="name">名称.</param>
77 /// <param name="iteration">循环次数.</param>
78 /// <param name="func">需要执行的方法体.</param>
79 /// <param name="Output">要写入的输出流.</param>
80 /// <remarks>一个 <see cref="CodeTimerResult"/> 表示执行的结果.</remarks>
81 static public CodeTimerResult Execute(String name, Int32 iteration, Func<Boolean> func, Action<String> Output) {
82 if (name == null) name = String.Empty;
83 if (func == null) { return null; }
84 CodeTimerResult result = new CodeTimerResult();
85 Int32 successCount = 0;
86 Int32 failureCount = 0;
87
88 #region 强制 GC 进行收集,并记录目前各代已经收集的次数.
89
90 GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
91 Int32[] gcCounts = new Int32[GC.MaxGeneration + 1];
92 for (Int32 i = 0; i <= GC.MaxGeneration; i++) {
93 gcCounts[i] = GC.CollectionCount(i);
94 }
95
96 #endregion
97
98 #region 执行代码,记录下消耗的时间及 CPU 时钟周期.
99
100 Stopwatch watch = new Stopwatch();
101 watch.Start();
102 UInt64 cycleCount = GetCycleCount();
103 for (Int32 i = 0; i < iteration; i++) {
104 if (func()) ++successCount;
105 else ++failureCount;
106 }
107 UInt64 cpuCycles = GetCycleCount() - cycleCount;
108 watch.Stop();
109
110 #endregion
111
112 #region 收集数据
113
114 result.Name = String.Format(Resources.SingleThreadName, name, Resources.NameSuffix);
115 result.TimeElapsed = watch.ElapsedMilliseconds;
116 result.CPUCycles = cpuCycles;
117 for (Int32 i = 0; i <= GC.MaxGeneration; i++) {
118 Int32 count = GC.CollectionCount(i) - gcCounts[i];
119 result.GenerationList[i] = count;
120 }
121 result.SuccessCount = successCount;
122 result.FailureCount = failureCount;
123 result.ThreadCount = 1;
124 result.Iteration = iteration;
125 PrintExecuteResult(result, Output);
126
127 #endregion
128
129 return result;
130 }
131
132 #endregion
133
134 #region 多线程
135
136 /// <summary>
137 /// 多线程并发 Execute 方法的初始化.
138 /// </summary>
139 static public void InitializeByConcurrent() {
140 Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
141 Thread.CurrentThread.Priority = ThreadPriority.Highest;
142 Execute("", 1, 1, 0, () => { return true; }, null);
143 }
144
145 /// <summary>
146 /// 使用多线程并发的方式执行 <paramref name="action"/>,并打印出 : 方法的运行时间, Cpu 时钟周期, 各代垃圾收集的回收次数的统计.
147 /// </summary>
148 /// <param name="name">名称.</param>
149 /// <param name="iteration">循环次数.</param>
150 /// <param name="threadCount">线程的计数.</param>
151 /// <param name="action">需要执行的方法体.</param>
152 /// <remarks>一个 <see cref="CodeTimerResult"/> 表示执行的结果.</remarks>
153 static public List<CodeTimerResult> Execute(String name, Int32 iteration, Int32 threadCount, Action action) {
154 return Execute(name, iteration, threadCount, 0, () => { action(); return true; }, Console.WriteLine);
155 }
156
157 /// <summary>
158 /// 使用多线程并发的方式执行 <paramref name="func"/>,并打印出 : 方法的运行时间, Cpu 时钟周期, 各代垃圾收集的回收次数的统计.
159 /// </summary>
160 /// <param name="name">名称.</param>
161 /// <param name="iteration">循环次数.</param>
162 /// <param name="threadCount">线程的计数.</param>
163 /// <param name="func">需要执行的方法体.</param>
164 /// <remarks>一个 <see cref="CodeTimerResult"/> 表示执行的结果.</remarks>
165 static public List<CodeTimerResult> Execute(String name, Int32 iteration, Int32 threadCount, Func<Boolean> func) {
166 return Execute(name, iteration, threadCount, 0, func, Console.WriteLine);
167 }
168
169 /// <summary>
170 /// 使用多线程并发的方式执行 <paramref name="action"/>,并使用 <paramref name="Output"/> 方法输出 : 方法的运行时间, Cpu 时钟周期, 各代垃圾收集的回收次数的统计.
171 /// </summary>
172 /// <param name="name">名称.</param>
173 /// <param name="iteration">循环次数.</param>
174 /// <param name="threadCount">线程的计数.</param>
175 /// <param name="action">需要执行的方法体.</param>
176 /// <param name="Output">要写入的输出流.</param>
177 /// <remarks>一个 <see cref="CodeTimerResult"/> 表示执行的结果.</remarks>
178 static public List<CodeTimerResult> Execute(String name, Int32 iteration, Int32 threadCount, Action action, Action<String> Output) {
179 return Execute(name, iteration, threadCount, 0, () => { action(); return true; }, Output);
180 }
181
182 /// <summary>
183 /// 使用多线程并发的方式执行 <paramref name="func"/>,并使用 <paramref name="Output"/> 方法输出 : 方法的运行时间, Cpu 时钟周期, 各代垃圾收集的回收次数的统计.
184 /// </summary>
185 /// <param name="name">名称.</param>
186 /// <param name="iteration">循环次数.</param>
187 /// <param name="threadCount">线程的计数.</param>
188 /// <param name="func">需要执行的方法体.</param>
189 /// <param name="Output">要写入的输出流.</param>
190 static public List<CodeTimerResult> Execute(String name, Int32 iteration, Int32 threadCount, Func<Boolean> func, Action<String> Output) {
191 return Execute(name, iteration, threadCount, 0, func, Output);
192 }
193
194 /// <summary>
195 /// 使用多线程并发的方式执行 <paramref name="action"/>,并使用 <paramref name="Output"/> 方法输出 : 方法的运行时间, Cpu 时钟周期, 各代垃圾收集的回收次数的统计.
196 /// </summary>
197 /// <param name="name">名称.</param>
198 /// <param name="iteration">循环次数.</param>
199 /// <param name="threadCount">线程的计数.</param>
200 /// <param name="mockThinkTime">模拟思考的时间.</param>
201 /// <param name="action">需要执行的方法体.</param>
202 /// <param name="Output">要写入的输出流.</param>
203 /// <remarks>一个 <see cref="CodeTimerResult"/> 表示执行的结果.</remarks>
204 static public List<CodeTimerResult> Execute(String name, Int32 iteration, Int32 threadCount, Int32 mockThinkTime, Action action, Action<String> Output) {
205 return Execute(name, iteration, threadCount, mockThinkTime, () => { action(); return true; }, Output);
206 }
207
208 /// <summary>
209 /// 使用多线程并发的方式执行 <paramref name="func"/>,并使用 <paramref name="Output"/> 方法输出 : 方法的运行时间, Cpu 时钟周期, 各代垃圾收集的回收次数的统计.
210 /// </summary>
211 /// <param name="name">名称.</param>
212 /// <param name="iteration">循环次数.</param>
213 /// <param name="threadCount">线程的计数.</param>
214 /// <param name="mockThinkTime">模拟思考的时间.</param>
215 /// <param name="func">需要执行的方法体.</param>
216 /// <param name="Output">要写入的输出流.</param>
217 /// <remarks>一个 <see cref="CodeTimerResult"/> 表示执行的结果.</remarks>
218 static public List<CodeTimerResult> Execute(String name, Int32 iteration, Int32 threadCount, Int32 mockThinkTime, Func<Boolean> func, Action<String> Output) {
219 if (name == null) name = String.Empty;
220 if (threadCount < 0) throw new ArgumentOutOfRangeException("threadCount", Resources.MessageThan0);
221 if (iteration < 0) throw new ArgumentOutOfRangeException("threadCount", Resources.MessageThan0);
222 if (mockThinkTime < 0) throw new ArgumentOutOfRangeException("thinkTime", Resources.MessageThan0);
223 if (func == null) return null;
224
225 _IsDetail = true;
226
227 List<CodeTimerResult> results = new List<CodeTimerResult>(threadCount);
228 CodeTimerResult totalResult = new CodeTimerResult();
229
230 ManualResetEvent manualResetEvent = new ManualResetEvent(true); // 主线程控制信号
231 ManualResetEvent threadResetEvent = new ManualResetEvent(true); // 子线程线程控制信号
232
233 Int32 currentThreadIndex; // 当前线程索引值
234
235 for (Int32 repeat = 0; repeat < iteration; repeat++) {
236 manualResetEvent.Reset(); // 主线程进入阻止状态
237 threadResetEvent.Reset(); // 子线程进入阻止状态
238 currentThreadIndex = 0;
239
240 for (Int32 i = 0; i < threadCount; i++) {
241 Thread thread = new Thread(
242 (threadIndex) => {
243 CodeTimerResult executeResult = new CodeTimerResult();
244 Interlocked.Increment(ref currentThreadIndex);
245 if (currentThreadIndex < threadCount) {
246 threadResetEvent.WaitOne(); // 等待所有线程创建完毕后同时执行测试
247 } else {
248 threadResetEvent.Set(); // 最后一个线程创建完成,通知所有线程,开始执行测试
249 }
250
251 // 执行测试,委托给 SingleThreadExecute 方法来做.
252 executeResult = Execute(
253 String.Format(Resources.ChildThreadName, name, threadIndex, Resources.NameSuffix),
254 1,
255 func,
256 null
257 );
258
259 Interlocked.Decrement(ref currentThreadIndex);
260
261 if (currentThreadIndex == 0) {
262 results.Add(executeResult); // 保存执行结果
263 manualResetEvent.Set(); //通知主线程继续
264 } else {
265 results.Add(executeResult); // 保存执行结果
266 }
267 }
268 );
269
270 thread.Start(i);
271 }
272
273 // 阻止主线程,等待子线程完成所有任务.
274 manualResetEvent.WaitOne();
275
276 Thread.Sleep(mockThinkTime);
277 }
278
279 totalResult.Name = String.Format(Resources.MultiThreadName, name, Resources.NameSuffix);
280 results.ForEach(
281 (item) => {
282 totalResult.TimeElapsed += item.TimeElapsed;
283 totalResult.CPUCycles += item.CPUCycles;
284 for (Int32 i = 0; i < totalResult.GenerationList.Length; i++) {
285 totalResult.GenerationList[i] += item.GenerationList[i];
286 }
287 totalResult.SuccessCount += item.SuccessCount;
288 totalResult.FailureCount += item.FailureCount;
289 }
290 );
291
292 totalResult.ThreadCount = threadCount;
293
294 totalResult.Iteration = iteration;
295
296 PrintExecuteResult(totalResult, Output);
297
298 // 释放资源
299 manualResetEvent.Close();
300 threadResetEvent.Close();
301
302 return results;
303 }
304
305 #endregion
306
307 /// <summary>
308 /// 打印 <paramref name="result"/><paramref name="Output"/>.
309 /// </summary>
310 /// <param name="result"><see cref="CodeTimer"/> 的执行结果.</param>
311 /// <param name="Output">要写入的输出流</param>
312 static public void PrintExecuteResult(CodeTimerResult result, Action<String> Output) {
313 if (Output != null) {
314 ConsoleColor currentForeColor = Console.ForegroundColor; // 保留当前控制台前景色,并使用黄色输出名称参数.
315 Console.ForegroundColor = ConsoleColor.Yellow;
316 if (String.IsNullOrWhiteSpace(result.Name)) result.Name = Resources.NameSuffix;
317 Output(result.Name);
318 Console.ForegroundColor = currentForeColor; // 恢复控制台默认前景色,并打印出消耗时间及CPU时钟周期.
319 Output(String.Format(Resources.TimeElapsed, result.TimeElapsed.ToString("N0")));
320 Output(String.Format(Resources.CPUCycles, result.CPUCycles.ToString("N0")));
321
322 // 打印执行过程中各代垃圾收集回收次数.
323 for (Int32 i = 0; i < result.GenerationList.Length; i++) {
324 Output(String.Format(Resources.CPUGen, i, result.GenerationList[i]));
325 }
326
327 if (_IsDetail) {
328 Output(String.Format(Resources.ExecuteSuccessCount, result.SuccessCount.ToString()));
329 Output(String.Format(Resources.ExecuteSuccessCount, result.FailureCount.ToString()));
330 }
331
332 // 循环次数 线程的计数 模拟思考的时间
333 String stats = String.Format(Resources.IterationCount, result.Iteration);
334 if (result.ThreadCount > 1) { stats = stats + String.Format(Resources.ThreadCount, result.ThreadCount); }
335 if (result.MockThinkTime > 0) { stats = stats + String.Format(Resources.MockThinkTime, result.MockThinkTime); }
336 Output(stats);
337 }
338 }
339
340 #region 辅助方法
341
342 #region P/Invoke
343
344 // 统计 CPU 时钟周期时.
345 [DllImport("kernel32.dll", SetLastError = true)]
346 static extern Boolean GetThreadTimes(
347 IntPtr hThread,
348 out UInt64 lpCreationTime,
349 out UInt64 lpExitTime,
350 out UInt64 lpKernelTime,
351 out UInt64 lpUserTime
352 );
353
354 // 统计 CPU 时钟周期时.(Vista 版本以上新的函数)
355 [DllImport("kernel32.dll")]
356 [return: MarshalAs(UnmanagedType.Bool)]
357 static extern Boolean QueryThreadCycleTime(IntPtr threadHandle, ref UInt64 cycleTime);
358
359 [DllImport("kernel32.dll")]
360 static extern IntPtr GetCurrentThread();
361
362 #endregion
363
364 static private UInt64 GetCycleCount() {
365 UInt64 cycleCount = 0;
366 if (EnvironmentHelper.IsGreaterThanOrEqualToVista) { // 针对 Winodws Vista 系统(包含)以上进行新的 Api 调用.
367 QueryThreadCycleTime(GetCurrentThread(), ref cycleCount);
368 } else {
369 UInt64 l;
370 UInt64 kernelTime, userTimer;
371 GetThreadTimes(GetCurrentThread(), out l, out l, out kernelTime, out userTimer);
372 cycleCount = kernelTime + userTimer;
373 }
374
375 return cycleCount;
376 }
377
378 #endregion
379 }

http://codetimer.codeplex.com/

posted @ 2012-04-03 08:44  loneys  阅读(291)  评论(0编辑  收藏  举报