前言

做性能的同学一定遇到过这样的场景:应用级别的性能测试发现一个操作的响应时间很长,然后要花费很多时间去逐级排查,最后却发现罪魁祸首是代码中某个实现低效的底层算法。这种自上而下的逐级排查定位的方法,效率通常都很低,代价也很高。所以,我们就需要在项目早期,对一些关键算法进行代码级别的性能测试,以防止此类在代码层面就可以被发现的性能问题,遗留到最后的系统性能测试阶段才被发现。但是,从实际执行的层面来讲,代码级性能测试并不存在严格意义上的测试工具,通常的做法是:改造现有的单元测试框架

而最常使用的改造方法是:

  • 将原本只会执行一次的单元测试用例连续执行 n 次,这个 n 的取值范围通常是 2000~5000;

  • 统计执行 n 次的平均时间。如果这个平均时间比较长(也就是单次函数调用时间比较长)的话,比如已经达到了秒级,那么通常情况下这个被测函数的实现逻辑一定需要优化。

这里之所以采用执行 n 次的方式,是因为函数执行时间往往是毫秒级的,单次执行的误差会比较大,所以采用多次执行取平均值的做法。

那么有没有现成的这样的测试工具呢?当然也是有的,比如今天我们介绍的主角-- ContiPerf

ContiPerf 简介

ContiPerf 是一个轻量级的测试工具,基于JUnit 4 开发,可用于效率测试等。可以指定在线程数量和执行次数,通过限制最大时间和平均执行时间来进行性能测试。

官网地址:https://sourceforge.net/p/contiperf/wiki/Home

ContiPerf 使用

接下来我们一起来实践一个例子,

首先,加入 pom 依赖包:

  1. <dependency>

  2. <groupId>org.springframework.boot</groupId>

  3. <artifactId>spring-boot-starter</artifactId>

  4. </dependency>

  5. <!--引入 ContiPerf 测试工具-->

  6. <dependency>

  7. <groupId>org.databene</groupId>

  8. <artifactId>contiperf</artifactId>

  9. <version>2.3.4</version>

  10. <scope>test</scope>

  11. </dependency>

  12. <dependency>

  13. <groupId>org.springframework.boot</groupId>

  14. <artifactId>spring-boot-starter-test</artifactId>

  15. <scope>test</scope>

  16. <exclusions>

  17. <exclusion>

  18. <groupId>org.junit.vintage</groupId>

  19. <artifactId>junit-vintage-engine</artifactId>

  20. </exclusion>

  21. </exclusions>

  22. </dependency>

  23. <dependency>

  24. <groupId>org.springframework.boot</groupId>

  25. <artifactId>spring-boot-starter-web</artifactId>

  26. </dependency><dependency>

  27. <groupId>junit</groupId>

  28. <artifactId>junit</artifactId>

  29. <scope>test</scope>

  30. </dependency>

这里为了演示,编写了一个简单的测试接口: UnitTestService.java

  1. /**

  2. * 测试接口类

  3. * @author zuozewei

  4. *

  5. */

  6. public interface UnitTestService {

  7. public String process(String msg);

  8. }

实现类:UnitTestServiceImpl.java

  1. @Service

  2. public class UnitTestServiceImpl implements UnitTestService {

  3. /**

  4. * 为了测试,这里直接返回传入的值

  5. */

  6. @Override

  7. public String process(String msg) {

  8. // TODO Auto-generated method stub

  9. return msg;

  10. }

  11. }

编写 UnitTestServiceTest 测试类,进入 ContiPerfRule。

  1. /**

  2. * 编写接口性能测试类

  3. * @author zuozewei

  4. *

  5. */

  6. @RunWith(SpringRunner.class)

  7. @SpringBootTest //SpringBootTest 是springboot 用于测试的注解,可指定启动类或者测试环境等,这里直接默认。

  8. public class UnitTestServiceTest {

  9. @Autowired

  10. UnitTestService testService;

  11. // 引入 ContiPerf 进行性能测试

  12. @Rule

  13. public ContiPerfRule contiPerfRule = new ContiPerfRule();

  14. @Test

  15. @PerfTest(invocations = 10000,threads = 100) //100个线程 执行10000次

  16. public void test() {

  17. String msg = "this is a test";

  18. String result = testService.process(msg);

  19. //断言 是否和预期一致

  20. Assert.assertEquals(msg,result);

  21. }

  22. }

注意:

@Rule 是J unit 提供的一个扩展接口注解,其接口类为:org.junit.rules.MethodRule,注意在 Junit5 中,已经被 TestRule 所替代了。也可以通过对类指定 @PerfTest 和 @Required,表示类中方法的默认设置。

@PerfTest注解:

  • invocations:执行次数n,与线程数量无关,默认值为1

  • threads:线程池数量n,并发执行n个线程

  • duration:重复执行时间n,测试至少执行n毫秒

@Required注解:

  • @Required(throughput = 20):要求每秒至少执行20个测试;

  • @Required(average = 50):要求平均执行时间不超过50ms;

  • @Required(median = 45):要求所有执行的50%不超过45ms;

  • @Required(max = 2000):要求没有测试超过2s;

  • @Required(totalTime = 5000):要求总的执行时间不超过5s;

  • @Required(percentile90 = 3000):要求90%的测试不超过3s;

  • @Required(percentile95 = 5000):要求95%的测试不超过5s;

  • @Required(percentile99 = 10000):要求99%的测试不超过10s;

  • @Required(percentiles = “66:200,96:500”):要求66%的测试不超过200ms,96%的测试不超过500ms。

运行测试,控制台会生成结果:

  1. com.zuozewei.springbootcontiperfdemo.service.UnitTestServiceTest.test

  2. samples: 10000

  3. max: 331

  4. average: 33.3522

  5. median: 30

同时访问:target/contiperf-report/index.html,会生成图表: 

图表中的指标:

  • Execution time: 执行时间

  • Throughput: TPS

  • Min. latency: 最小响应时间

  • Average latency: 平均响应时间

  • Median: 响应时间中位数

  • 90%: 90%响应时间范围

  • Max latency: 最大响应时间

小结

这里主要是对 Junit 和 ContiPerf 的使用简单的示例,在单元测试阶段的时候考虑做这种代码级性能测试,肯定会提高 ROI(投入产出比)的,而且代价非常小,希望本文对各位同学都能有所启发。

性能工具之代码级性能测试工具ContiPerf的更多相关文章

  1. 【Linux常用工具】03. Linux性能测试工具ab

    在Apache服务器的套件中,有一个叫做 ab (ApacheBench) 的工具. ApacheBench 主要是用来测试Apache服务器执行效率用的 ApacheBench 可以针对某个特定的 ...

  2. Linux系统性能测试工具(三)——内存性能综合测试工具lmbench

    本文介绍关于Linux系统(适用于centos/ubuntu等)的内存性能综合测试工具-lmbench.内存性能测试工具包括: 内存带宽测试工具——mbw: 内存压力测试工具——memtester: ...

  3. Ceph性能测试工具和方法。

    0. 测试环境 同 Ceph 的基本操作和常见故障排除方法 一文中的测试环境. 1. 测试准备 1.1 磁盘读写性能 1.1.1 单个 OSD 磁盘写性能,大概 165MB/s. root@ceph1 ...

  4. 理解 OpenStack + Ceph (8): 基本的 Ceph 性能测试工具和方法

    本系列文章会深入研究 Ceph 以及 Ceph 和 OpenStack 的集成: (1)安装和部署 (2)Ceph RBD 接口和工具 (3)Ceph 物理和逻辑结构 (4)Ceph 的基础数据结构 ...

  5. ceph--磁盘和rbd、rados性能测试工具和方法

    我在物理机上创建了5台虚拟机,搭建了一个ceph集群,结构如图: 具体的安装步骤参考文档:http://docs.ceph.org.cn/start/ http://www.centoscn.com/ ...

  6. 基本的Ceph性能测试工具和方法

    测试环境 1. 测试准备 1.1 磁盘读写性能 1.1.1 单个 OSD 磁盘写性能,大概 165MB/s. root@ceph1:~# echo 3 > /proc/sys/vm/drop_c ...

  7. Linux系统性能测试工具(四)——CPU性能测试工具之super_pi、sysbench

    本文介绍关于Linux系统(适用于centos/ubuntu等)的CPU性能测试工具-sysbench.CPU性能测试工具包括: super_pi: sysbench——不仅可以测试CPU性能,而且可 ...

  8. 转 1 认识开源性能测试工具jmeter

    1 认识开源性能测试工具jmeter   典型的性能测试工具主要有2个,Load Runner和jmeter.Load Runner是商业化的,Jmeter是开源的.下面我们认识一下开源性能测试工具j ...

  9. Linux系统性能测试工具(二)——内存压力测试工具memtester

    本文介绍关于Linux系统(适用于centos/ubuntu等)的内存压力测试工具-memtester.内存性能测试工具包括: 内存带宽测试工具——mbw: 内存压力测试工具——memtester: ...

随机推荐

  1. Mybatis中使用级联查询,一对多的查询

    一.需求描述 自己在开发一个小程序的过程中,需要做的一个查询是稍微比较复杂的查询,根据用户信息去查询用户所对应的宠物信息. 一个用户可能对应多个宠物,所以在用户和宠物信息的对应关系就是一对多的关系. ...

  2. python实现rtsp取流并截图

    import cv2 def get_img_from_camera_net(folder_path): cap = cv2.VideoCapture("rtsp://admin:admin ...

  3. P4929-[模板]舞蹈链(DLX)

    正题 题目链接:https://www.luogu.com.cn/problem/P4929 题目大意 \(n*m\)的矩形有\(0/1\),要求选出若干行使得每一列有且仅有一个\(1\). 解题思路 ...

  4. NLP与深度学习(五)BERT预训练模型

    1. BERT简介 Transformer架构的出现,是NLP界的一个重要的里程碑.它激发了很多基于此架构的模型,其中一个非常重要的模型就是BERT. BERT的全称是Bidirectional En ...

  5. 树莓派使用python+继电器控制220V灯泡

    需要的材料 1.继电器:继电器是一种电控制器件,它实际上是用小电流去控制大电流运作的一种"自动开关",我们这里用它来控制电灯.控制了继电器就等于控制了电灯. 我购买的是某宝上3块钱 ...

  6. Netty常用招式——ChannelHandler与编解码

    本文是Netty系列第8篇 上一篇文章我们深入学习了Netty逻辑架构中的核心组件ChannelHandler和ChannelPipeline,并介绍了它在日常开发使用中的最佳实践.文中也提到了,Ch ...

  7. spring 创建Bean最全实现方法

    创建bean方式,spring创建bean的方式包含:自动注入方式和人工注入方式.分别为:1)xml 配置化方式  2)@bean注解注入方式3)@Component方式 4)接口注入方式 5)imp ...

  8. Apache ShardingSphere 元数据加载剖析

    唐国城 小米软件工程师,主要负责 MIUI 浏览器服务端研发工作.热爱开源,热爱技术,喜欢探索,热衷于研究学习各种开源中间件,很高兴能参与到 ShardingSphere 社区建设中,希望在社区中努力 ...

  9. 沟谷网络的提取及沟壑密度的计算(ArcPy实现)

    一.背景 沟壑密度是描述地面被水道切割破碎程度的一个指标.沟壑密度是气候.地形.岩性.植被等因素综合影响的反映.沟壑密度越大,地面越破碎,平均坡度增大,地表物质稳定性降低,且易形成地表径流,土壤侵蚀加 ...

  10. 使用固件库点亮led灯

    1. 项目 使用STM32F103VE的固件库实现流水灯设计. 2. 代码 由于这是基于野火的视频进行学习的,项目代码在上节基础上进行编写的. 点亮绿灯: main.c #include " ...