执行性能测试—起步
程序越来越大,为了让程序更快地响应用户的输入,需要执行性能测试,最近在研究性能测试,就从这篇最基础的文章开始起步吧。VS 2010自带了一个功能强大的性能测试工具—Performance Wizard,在研究过程中,我决定用通过分析最普通的排序操作的程序来开始我的学习过程。
程序的功能很简单,接受任何文本文件,排序,然后将结果输出到一个新的文件中。第一个版本很简单,使用最好写的冒泡排序实现:
#region 常见的排序方法 — 适合小文件的排序 static void Main(string[] args) { if (args.Length != 2) { Console.WriteLine("Usage: sort <file name> <output file name>"); return; }
string[] sortedLines; using (StreamReader reader = new StreamReader(Path.GetFullPath(args[0]))) { var text = reader.ReadToEnd(); sortedLines = Sort(text); }
using (StreamWriter writer = new StreamWriter(Path.GetFullPath(args[1]))) { foreach (var line in sortedLines) writer.WriteLine(line); } }
#region 使用冒泡排序来测试性能 // V1: 使用冒泡排序来测试性能 private static string[] Sort(string text) { var lines = text.Split(new string[] { "\r\n" }, StringSplitOptions.None);
for (int i = 0; i < lines.Length; ++i) { for (int j = i + 1; j < lines.Length; ++j) { if (string.CompareOrdinal(lines[i], lines[j]) < 0) { var temp = lines[i]; lines[i] = lines[j]; lines[j] = temp; } } }
return lines; } #endregion |
使用一个大小为2.5 兆的文本文件作为输入数据,并且用下面的步骤执行性能测试:
1. 打开Visual Studio,并点击菜单栏里的“分析(Analyze)”。
2. 点击“启动性能测试向导(Launch Performance Wizard)”。
3. 在“性能测试向导(Performance Wizard)”页面上选择“CPU Sampling (recommended)”。
4. 在后续页面上,使用页面默认的选项做完设置。
耐心等待程序执行完以后,Visual studio会提供一个报表,在摘要(Summary)里面—下图,可以看到,程序使用了大约36秒才完成了所有的过程。
另外,在Hot Path表格里,也可以看出,String.CompareOrdinal函数所占用的时间是最多的,占整个程序执行的78.44%。而从另外一个统计表Functions,这个统计表显示了在程序执行完毕之前,函数触发样例的次数,注意,这个样例触发的次数和函数被调用的次数没有对应关系,两个样例之间,函数可能被调用了多次,而且多个函数也可能被调用到—这个跟我们使用“CPU Sampling (recommended)”的策略有关,它的优点是快不影响被测程序的运行,缺点就是不够精确。从Functions的统计表里面,可以看到String.CompareOrdinal被调用到的次数是其他函数的好几倍:
既然已经知道冒泡排序是整个程序的瓶颈了,那我们第二个版本就是将冒泡算法改成快速排序,看看有没有改进:
#region 常见的排序方法 — 适合小文件的排序 static void Main(string[] args) { if (args.Length != 2) { Console.WriteLine("Usage: sort <file name> <output file name>"); return; }
string[] sortedLines; using (StreamReader reader = new StreamReader(Path.GetFullPath(args[0]))) { var text = reader.ReadToEnd(); sortedLines = Sort(text); }
using (StreamWriter writer = new StreamWriter(Path.GetFullPath(args[1]))) { foreach (var line in sortedLines) writer.WriteLine(line); } }
#region 使用快速排序来测试性能 // V2: 使用快速排序来测试性能 private static string[] Sort(string text) { var lines = text.Split(new string[] { "\r\n" }, StringSplitOptions.None);
QuickSort(lines, 0, lines.Length - 1);
return lines; }
private static int Partition(string[] lines, int lower, int upper) { var pivot = lines[upper]; var newPivot = lower - 1;
for (int i = lower; i < upper; ++i) { if (string.CompareOrdinal(pivot, lines[i]) > 0) { var temp = lines[i]; newPivot = newPivot + 1; lines[i] = lines[newPivot]; lines[newPivot] = temp; } }
++newPivot; lines[upper] = lines[newPivot]; lines[newPivot] = pivot; return newPivot; }
private static void QuickSort(string[] lines, int lower, int upper) { if (lower < upper) { var pivot = Partition(lines, lower, upper); QuickSort(lines, lower, pivot - 1); QuickSort(lines, pivot + 1, upper); } } #endregion
#endregion
|
这次的结果要比上次好很多,这次只用了3秒多就完成了所有的工作,而且在Hot Path里面,String.CompareOrdinal函数在程序执行时间的比重也下降了很多。
虽然我们从总的执行时间上来看,看到了很大的性能提高,但是知道那些函数的执行效率提高了,会让你更直观的感觉到后续性能优化的目标。VS 2010支持对比多个性能报告,并给出两个报告之间的差别,例如哪些函数的执行速度有提高之类的:
1. 点击菜单栏里的“分析(Analyze)”。
2. 点击“Compare Performance Report”,在弹出来的对话框里选择两个性能测试的报告。
上图里,我在“Column” 里面选择了“Exclusive Samples”—因为对比百分比对我来说不够直观。从对比的结果来看,快速排序在各个方面全面胜出—除了Partition函数,因为那是一个新函数。
接下来,为了查看快排对大文件排序的性能,我使用了一个700多兆的文本文件进行测试,这次—程序崩溃了,崩溃的原因是OutOfMemoryException……
下一篇讲解OutOfMemoryException的分析过程。