性能测试在软件开发中的重要性

在编写第一行代码之前,性能测试的工作就应该开始了,并且在产品发布给公众之后,这项工作还应该继续进行。随着越来越多的应用程序迁移到复杂的多租户云服务器上,开发者从开发周期的最开始就关注他们的代码的“成本”变得至关重要。

本文展示了Visual Studio的一些特性,如PerfTips、Diagnostics Hub和Performance Analyzer,它们如何帮助开发者以有意义的方式测量他们的代码成本,特别是在开发以云为中心的应用程序的背景下。将首先关注使用传统方法来调查性能相关问题。

性能定义

性能工程可以有多种定义方式。以下是维基百科的定义:“性能工程包括在系统开发生命周期中应用的技术,以确保性能的非功能性需求(如吞吐量、延迟或内存使用)将得到满足。”这个定义是一个很好的开始,但性能工程是一个复杂的领域,根据人们的背景,它可以意味着许多不同的事情。然而,有一个更广泛的共识是应用程序的性能直接影响产品的收益和运营成本。

性能工程的关键方面围绕着测量的概念。为应用程序定义了某些性能目标,并定期进行适当的测量,以查看这些目标是否得到满足。如果需要,采取纠正措施,然后重复进行相同的测量和纠正措施的过程,直到达到目标。

云中的应用程序性能

云计算彻底改变了组织进行日常操作的方式,无论它们的规模、业务类型或地理位置如何。多年来,基于云的解决方案见证了基础设施即服务(IaaS)、平台即服务(PaaS)或软件即服务(SaaS)等平台的演变。业界已经广泛采用了这些平台,不仅为了降低企业的所有权成本,而且为了向客户提供更好的可用性、可扩展性和可靠性的解决方案。

然而,天下没有免费的午餐。基于云的解决方案也有其自身的缺陷。“嘈杂的邻居”和“级联效应”是与云解决方案相关的一些常见问题。这对软件开发人员意味着他们现在有更重的责任,确保他们编写的代码能够很好地扩展到更高的负载。他们需要高度意识到他们的代码成本,因为,在云服务中,规模可能会发生巨大的变化,这使得代码成本更加突出。

范围

当涉及到编写以性能为中心的代码时,一个基本原则可以用Vance Morrisons的一篇旧文章中的一句话来描述:“早期测量,经常测量”。然而,许多开发者要么忽视,要么在他们的日常工作流程中使用他们选择的工具时,努力将这些原则付诸实践。为了应用Vance的想法,遵循以性能为中心的设计,总是回到Joe Duffy的“过早优化是邪恶的神话”博客文章中的以下摘录。强烈推荐阅读全文,以了解这句话背后的上下文。

“要成功做到这一点,需要知道事情的成本。如果不知道事情的成本,只是在黑暗中挣扎,希望走运。”这是一个需要理解并严格遵循的重要观点。然而,执行这一点有实际的挑战。在测量应用程序的性能时,许多开发者添加日志条目以获得代码性能的“感觉”。更复杂的用户可能会使用StopWatch类型的机制,试图获得应用程序性能的更精确的测量。这两种方法都有它们的局限性和约束。

有许多有效和强大的工具可以用来在开发、QA或生产环境中测量应用程序的成本。然而,作为一个软件开发人员,需要在使用同样的工具编写和调试代码的日常开发工作中意识到这个成本。

示例应用程序设置

本文的方法将展示一个有性能问题的示例应用程序,然后演示可能的方法来深入了解这些问题。示例应用程序是一个简单的WPF应用程序,提供从一个起始地址到目的地的驾驶方向。

不会在插图中看到这个问题,但为了这个例子,问题是一旦用户点击“获取方向”按钮,应用程序就会花费一段时间才显示驾驶方向。此外,在点击这个按钮之后,看起来应用程序消耗了大量的资源。内存消耗似乎在同一时间框架内也在上升。

重要的是要重复观察应用程序行为的过程几次,以确保问题在合理的样本集中是一致的。同样重要的是要注意,仅仅查看任务管理器中的CPU和内存使用图表,并不是得出任何性能、内存或CPU问题的最好方式。一个(或多个)应用程序消耗这些资源可能有合理的原因。作为一个开发者,必须对代码成本有一个很好的理解。

传统故障排除方法

有许多商业和免费的工具可以帮助故障排除应用程序并找到内存和CPU消耗的根本原因。Windbg、DebugDiag、ProcDump、PerfView是微软提供的一些免费工具,通常被认为是好的,因为这些工具在开发、测试、暂存或甚至现场问题期间的灵活性。并非所有这些工具都将在这一部分中使用,但希望足够提供这些工具可以提供的一些感觉。

让首先回顾一下PerfView工具收集的跟踪。这个工具可以从微软的GitHub仓库下载。它提供了不同的机制来分析CPU和内存相关问题。

这个图表显示了由PerfView收集和分析的应用程序跟踪。CallTree视图提供了各种线程的CPU消耗分布。如所见,第一个线程(Id 3204)负责应用程序40%的CPU消耗。这个视图还显示了其他线程(Ids 10484, 932, 10140)及其CPU消耗。

在这个图表中,深入研究了第一个线程(Id 3204)。它显示了这个线程40%的CPU使用量大部分被应用程序的RouteViewer.DisplayDirection和RouteCalculator.CalculateRoute方法消耗了。

同样,这个图表突出了另外两个线程(Ids 10484, 932)。这也显示了应用程序的RouteCalculator.XmlDataProcessor方法的显著CPU使用。

很明显,PerfView可以帮助确定负责高CPU使用的代码部分。

让将注意力转向确定哪些对象负责高内存消耗。以下图表显示了针对同一进程的内存快照生成的DebugDiag报告。

这份报告显示,整体GC堆大小大约为2GB。这份报告还提供了最昂贵的对象列表,这些对象负责内存消耗。XmlElement在列表的顶部,负责大约80%的内存消耗。这可以为开发者提供清晰的指针,说明应用程序的哪个区域可能负责高内存消耗。

鉴于PerfView和DebugDiag的强大功能,只是触及了使用这些工具的灵活性来找到示例应用程序问题的根源。这些工具不仅可以检索更详细的信息,还可以解决更复杂的问题。

然而,大多数开发者并不在日常工作中使用PerfView或DebugDiag这样的工具。他们反而使用Visual Studio来编写、编译、故障排除和测试他们的代码。这为开发者提出了一个巨大的困境,即如何在舒适的使用Visual Studio进行日常工作的同时,解决复杂的问题,进行所需的测量并执行纠正措施。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485