Skip to content

Progress Report 2018.06.03

TimHe edited this page Feb 10, 2019 · 1 revision

一、阅读ICSE'18三篇关于性能相关的文章

How not to structure your database-backed web applications: a study of performance bugs in the wild

ICSE'18

作者 Shan Lu组 本文主要研究的是ORM框架下的web应用的性能问题,先开展study,然后总结root-cause规律。Shan Lu组在CIKM’17(B会)发了一篇Understanding Database Performance Inefficiencies in Real-world Web Applications,也是研究ORM框架的性能问题的,相关内容在4月1日周报。在本文中,他们继续了这个工作。本文的历史地位作者是这样说的:"there has been no comprehensive study to understand the performance and scalability of real-world ORM applications",而CIKM'17那篇作者说是“has looked at specific performance problems in ORM applications

本文主要做了三件事:

  1. 用profile工具测试了一下12个ORM开源应用,当数据量上去了之后,这些应用的性能怎么样
  2. 调研了12个开源应用的140个用户提交的性能issue+64个通过方法1新发现的性能issue,总结出了9个影响性能的anti-pattern
  3. 人工修复了这64个新的性能问题,并取得了平均2倍的加速

对于问题1,作者如何做:

如何测是一个很重要的问题,这个和我目前在做的比较相关。 作者所研究的这几个软件都是开源的,但是如果要测高负载下的性能,需要自己造数据,那么作者就为待测的12个应用造了低(数据库主表有200条数据)、中(数据库主表有2000条数据)、高(数据库主表有20000条数据)三组数据,当然还有其他一些表也做了相应量级的填充,这个规模是从官方的数据统计中得到的,模拟性很好。举个例子来说,gitlab这个应用的数据库中,有如下图所示的数据,这都是模拟真实的数据。

1.png

然后,作者就用一个爬虫随机地访问这些应用中的链接,然后用浏览器自带的profile工具测试页面的加载时间。 这样就可以得到哪些操作会导致缓慢(这里对缓慢(test-oracle)的定义有二:1,响应超过2s 2,随着数据库从200->2000->20000性能呈超线性增长,因为是特定的领域,所以oracle的确定也比较容易),最终找到了40个操作。这40个操作会产生64个性能issue,这作为下一步的研究数据。

总结起来,作者分三步做:1.Populating databases(填充数据库) 2.Scaling input data(设置不同量级的负载200,2000,20000) 3.Identifying problematic actions(找到反应慢的操作)。感觉这个实验方法和我的的确是有点像

对于问题2,作者如何做:###

调研204个性能issue,对他们的root-cause进行分类,并总结9个anti-pattern:

1.png

CIKM17那篇文章所研究的性能问题全都属于‘Inefficient queries’这一个anti-pattern

总结:ORM的广泛应用及其自身所带来的性能问题使得本文的研究具有很大意义,本文的study很扎实,又解决了实际的64个问题。目前最值得我借鉴的是他的试验方法,十分科学,而且好像他们还把填充数据库的脚本公开了,如果好用的话,我想我可以用他们的试验方法

Empirical Study on the Discrepancy between Performance Testing Results from Virtual and Physical Environments

[Journal First]on ICSE'18 & [Full Paper]on ESE'17(B类期刊) 这篇文章在虚拟机上和物理设备上运行同一个软件的性能测试,发现单个的性能指标在两个环境中并不相同(比如CPU时间在两个环境中不同),而且是分布不同,不是简单的成倍数。不同性能指标之间的关联也不同(比如cpu和io的关联)。因此作者建议研究者不要直接把虚拟环境中的数据拿到物理环境中。

Speedoo: Prioritizing Performance Optimization Opportunities

ICSE'18 本文的工作是-用静态分析+动态分析的方法,找到一个已知开源软件的性能问题,更具体来说,是找到源码中哪些函数可能有性能问题,然后报给开发者。其实用的主要还是静态的方法,因此找到的可能有问题的函数是一个粗略的结果。

历史工作中的地位:

找有性能问题的函数这一研究,有两类方法,第一类是用profile工具,缺陷也很明显,就是只能找到那个函数花了最长的时间,但是花了最长时间的函数未必是需要被优化的函数(有bug的函数)。第二类使用基于pattern的方法,比如LuShan的检测inefficient-loops的工作,但是只能cover某一类的性能问题。而本文的方法可以解决上述两个问题。

实现思路:

第一步是找到哪个比较high-level的函数有性能问题

一般的Profile方法在挑选需要优化的函数时一般是选择执行时间长的,而本文选择了多个参考指标,其中也包括了执行时间。多个参考指标的思想是这样的:如果一个函数被很多个其他的函数调用、或者其复杂度(包含循环、路径的数量)较大、或者是其执行时间较长。这三个指标设计思想可以细化成具体的12个指标。根据12个指标的值,可以计算出一个函数的“优先级”,优先级越高代表这个函数越有可能、越需要被优化。如何根据指标计算优先级呢?很简单,就是把指标的值先规约到0~1范围内,然后同类指标加起来求平均,得到的类指标相乘得到优先级。

工作的目的是告诉开发者那些函数可能有性能问题,那么是否是优先级越高就越代表有问题呢?我的理解,作者的回答是:是的,只不过,可能粒度不合适,也就是说优先级高的函数的确有问题,但是真正有问题的可能是这个函数调用的某个优先级并不高的函数。那么如何找到这个更细粒度的真正有问题的优先级不高的函数呢?

第二步是将找到的high-level函数里面,更细粒度的有性能问题的函数,而更细粒度的函数,往往就是bug所在

如何做呢?作者是通过总结现实中的3个软件的75个性能问题,归纳出5中pattern,(LuShan的inefficient-loop是其中一种pattern)。作者认为high-level的有性能问题的函数一定是满足其中一个pattern。而每一种pattern都可以细化出细粒度的需要修复的函数。比如下面例子中,foo满足其中一个pattern,那么有问题的函数就从foo变成了slow_function。

#!c++

foo()
  for()
    slow_function()

评估 从两方面评估

评估有效性

也就是作者方法检测出来的需要被优化的(有性能问题的)函数,在历史演化中,有多少真的被优化了,这个比例是20%-40%(不同软件)。而被修复的函数占总函数的1%-7%,作者这个准确率只能说还可以,其实并不太能真正起到debug的作用,还是会提交给开发者很多不需要被优化的函数。

评估各个指标的合理性

作者分别去掉每一类指标,然后其他步骤不变,进行试验,得到的需要被优化的函数,其中在历史演化中,真正被修复的都比20%-40%少,得出结论,每个指标都是有用的。我认为他这个指标只是简单取平均是这里一个比较粗糙的部分。加上本来静态分析性能就是一种粗略估计的手法,所以能有这个效果已经不错了。

文章从第一步到第二步的过程,实际上就是从“表现出性能问题的位置(failure)”到“代码的bug(root cause)”的过程。主要是静态分析+一点动态分析,其中动态分析很依赖与测数据所用的workload,如果workload设计的不好,得到的执行时间也不具有代表性。

性能分布实验

对mysql的3个、mariadb的1个bug做了性能测试实验,具体结果如下:

图例:

表的左上角是配置名称(绿色是修复后的,红色是修复前的),纵向是其取值,横向代表了典型的工作负载(分为0负载、轻负载、中负载、重负载)。其中最后一个是两个配置的名称,这个bug不涉及负载。 1.png


2.png


3.png


4.png

遇到的问题:

  1. 对于典型负载的构造比较有技巧性。我把相关脚本上传到了这个项目的仓库,的确是典型场景中的操作(而不是特别奇怪的操作)。这四个是bugreport中有testcase,对于大量没有testcase的配置,需要自己理解其功能然后自己设计,比较难保证测的结果有代表性。
  2. 对于一些配置的值,可能只有取到比如128G的时候才会触发bug,但是个人计算机最多取到4G(内存限制)。

好的方面: 感觉是可以从分布中总结出一些pattern的,比如‘在0负载下无论配置如何取,都不应该有性能的明显下降’等等。在本次周报的第一篇论文里,lushan也做了与我目前工作相似的事,只不过她没有总结pattern,而是使用了两个比较普遍的pattern(延迟超过阈值、性能非线性增长)检测性能bug。

Clone this wiki locally