SpringBoot项目集成JMH测试用例

news2024/9/21 11:06:39

SpringBoot项目集成JMH测试用例

    • 1. JMH
    • 2. JMH使用
      • 2.1 pom引用JMH
      • 2.2 BaseBenchmark
    • 3. 部分注解介绍
    • 4. Jenkins 集成 JMH
      • 4.1 下载插件配置Job

1. JMH

JMH(Java Microbenchmark Harness)是一个 Java 工具,用于构建、运行和分析用 Java 和其他针对 JVM 的语言编写的 纳米/微米/毫/宏观 基准测试,而且是由Java虚拟机团队开发的。简单说,就是用来测量代码运行性能。

JMH官网:https://openjdk.org/projects/code-tools/jmh/
JMH源码下载:https://github.com/openjdk/jmh
JMH示例代码:https://github.com/openjdk/jmh/tree/1.36/jmh-samples/src/main/java/org/openjdk/jmh/samples

2. JMH使用

完整的示例代码

2.1 pom引用JMH

    <properties>
        <jmh.version>1.36</jmh.version>
    </properties>

   <dependencies>
        <dependency>
            <groupId>org.openjdk.jmh</groupId>
            <artifactId>jmh-core</artifactId>
            <version>${jmh.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.openjdk.jmh</groupId>
            <artifactId>jmh-generator-annprocess</artifactId>
            <version>${jmh.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

2.2 BaseBenchmark

import org.openjdk.jmh.results.format.ResultFormatType;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

/**
 * @author lytao123
 * @version 1.0.0
 * @date 2023/4/12 18:40
 */
public abstract class BaseBenchmark {

    protected String string(Integer times) {
        String s = "";
        for (int i = 0; i < times; i++) {
            s += String.valueOf(i);
        }

        return s;
    }

    protected String stringBuilder(Integer times) {
        StringBuilder s = new StringBuilder();
        for (int i = 0; i < times; i++) {
            s.append(i);
        }

        return s.toString();
    }

    protected Options getOptions() {
        String resultFilePrefix = "jmh-result";
        ResultFormatType resultsFileOutputType = ResultFormatType.JSON;

        return new OptionsBuilder()
                .include("\\." + this.getClass().getSimpleName() + "\\.")
                .shouldDoGC(true)
                .shouldFailOnError(true)
                .forks(0)
                .resultFormat(resultsFileOutputType)
                .result(buildResultsFileName(resultFilePrefix, resultsFileOutputType))
                .shouldFailOnError(true)
                .jvmArgs("-server")
                .build();
    }

    private static String buildResultsFileName(String resultFilePrefix, ResultFormatType resultType) {
        String suffix;
        switch (resultType) {
            case CSV:
                suffix = ".csv";
                break;
            case SCSV:
                suffix = ".scsv";
                break;
            case LATEX:
                suffix = ".tex";
                break;
            case JSON:
            default:
                suffix = ".json";
                break;

        }

        return String.format("target/%s%s", resultFilePrefix, suffix);
    }
}

  • 2.3 Benchmark Tests
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

import static org.junit.Assert.assertNotNull;

@SpringBootTest
@State(Scope.Benchmark)
@BenchmarkMode({Mode.Throughput, Mode.AverageTime})
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@RunWith(SpringRunner.class)
@ActiveProfiles("pref")
public class StringBenchmarkTest extends BaseBenchmark {

    private static final int EVENT_COUNT = 1000;

    private static final Logger LOGGER = LoggerFactory.getLogger(StringBenchmarkTest.class);
	
	// 如果有 bean 注入,必须是静态变量
    private static UserService USER_SERVICE;

    @Autowired
    public void setUserService(UserService userService) {
        // 注入 bean 时必须使用 public set 方式给静态变量赋值
        USER_SERVICE = userService;
    }

    @BeforeAll
    public static void setUp() {
        LOGGER.info("开始进行性能测试,请耐心等待结果");
    }

    @Test
    public void executeJmhRunner() throws RunnerException, IOException {
        assertNotNull(USER_SERVICE );
		// 启动,注意 @Test 注解包,J5 的
        new Runner(getOptions()).run();
    }
    
    @Benchmark
    @Warmup(time = 5)
    @Measurement(iterations = 3)
    public void string(final Blackhole bh) {
        LOGGER.info("开始执行 String 字符拼接 {} 次", EVENT_COUNT);

        bh.consume(string(EVENT_COUNT));
    }

    @Benchmark
    @Warmup(time = 5)
    @Measurement(iterations = 3)
    public void stringBuilder(final Blackhole bh) {
        LOGGER.info("开始执行 StringBuilder 字符拼接 {} 次", EVENT_COUNT);

        bh.consume(stringBuilder(EVENT_COUNT));
    }
}

  • 2.4 Run Benchmark
    执行如下命令:
mvn test -Dtest=StringBenchmarkTest -DfailIfNoTests=false

在这里插入图片描述
得到结果在 target/jmh-result.json
在这里插入图片描述

  • 2.5 可视化

把上述生成的 json 测试结果上传到测试结果可视化
在这里插入图片描述
在这里插入图片描述

3. 部分注解介绍

注解说明
@BenchmarkModeMode 表示 JMH 进行 Benchmark 时所使用的模式。通常是测量的维度不同,或是测量的方式不同。目前 JMH 共有四种模式:
Throughput: 整体吞吐量,例如“1秒内可以执行多少次调用”,单位是操作数/时间。
AverageTime: 调用的平均时间,例如“每次调用平均耗时xxx毫秒”,单位是时间/操作数。
SampleTime: 随机取样,最后输出取样结果的分布,例如“99%的调用在xxx毫秒以内,99.99%的调用在xxx毫秒以内”
SingleShotTime: 以上模式都是默认一次 iteration 是 1s,唯有SingleShotTime 是只运行一次。往往同时把 warmup 次数设为0,用于测试冷启动时的性能。
@OutputTimeUnit输出的时间单位。
@IterationIteration 是 JMH 进行测试的最小单位。在大部分模式下,一次 iteration 代表的是一秒,JMH 会在这一秒内不断调用需要 Benchmark 的方法,然后根据模式对其采样,计算吞吐量,计算平均执行时间等。
@WarmUpWarmup 是指在实际进行 Benchmark 前先进行预热的行为。为什么需要预热?因为 JVM 的 JIT 机制的存在,如果某个函数被调用多次之后,JVM 会尝试将其编译成为机器码从而提高执行速度。为了让 Benchmark 的结果更加接近真实情况就需要进行预热。
@State类注解,JMH测试类必须使用 @State 注解,它定义了一个类实例的生命周期,可以类比 Spring Bean 的 Scope。由于 JMH 允许多线程同时执行测试,不同的选项含义如下:
Scope.Thread:默认的 State,每个测试线程分配一个实例;
Scope.Benchmark:所有测试线程共享一个实例,用于测试有状态实例在多线程共享下的性能;
Scope.Group:每个线程组共享一个实例;
@Fork进行 fork 的次数。如果 fork 数是2的话,则 JMH 会 fork 出两个进程来进行测试。
@Meansurement提供真正的测试阶段参数。指定迭代的次数,每次迭代的运行时间和每次迭代测试调用的数量(通常使用 @BenchmarkMode(Mode.SingleShotTime) 测试一组操作的开销——而不使用循环)
@Setup方法注解,会在执行 benchmark 之前被执行,正如其名,主要用于初始化。
@TearDown方法注解,与@Setup 相对的,会在所有 benchmark 执行结束以后执行,主要用于资源的回收等。@Setup/@TearDown注解使用Level参数来指定何时调用fixture: Level.Trial 默认level。全部benchmark运行(一组迭代)之前/之后Level.Iteration 一次迭代之前/之后(一组调用) Level.Invocation 每个方法调用之前/之后(不推荐使用,除非你清楚这样做的目的)
@Benchmark方法注解,表示该方法是需要进行 benchmark 的对象。
@Param成员注解,可以用来指定某项参数的多种情况。特别适合用来测试一个函数在不同的参数输入的情况下的性能。@Param 注解接收一个String数组,在 @Setup 方法执行前转化为为对应的数据类型。多个 @Param 注解的成员之间是乘积关系,譬如有两个用 @Param 注解的字段,第一个有5个值,第二个字段有2个值,那么每个测试方法会跑5*2=10次。

4. Jenkins 集成 JMH

4.1 下载插件配置Job

需要 Jenkins 下载插件 JMH Report 插件,接着在“构建后操作” 选择该插件,配置 json 路径即可
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/432044.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【redis】缓存双写一致性之工程落地实现(下)

【redis】缓存双写一致性之工程落地实现&#xff08;下&#xff09; 本篇由于没有进行实操&#xff0c;所以没有记录详细的配置内容 文章目录 【redis】缓存双写一致性之工程落地实现&#xff08;下&#xff09;本篇由于没有进行实操&#xff0c;所以没有记录详细的配置内容 前…

树莓派 GPIO口控制双色LED灯

目录 一、首先加载库 二、设置编码规范 三、去除GPIO口警告 四、进行详细编程 五、程序源码 GPIO&#xff08;General Purpose I/O Ports&#xff09;意思为通用输入/输出端口&#xff0c;通过它们可以输出高低电平或者通过它们读入引脚的状态&#xff08;是高电平或是低电…

Faster RCNN系列——RPN的真值详解

RPN的真值分为类别真值和偏移量真值&#xff0c;即每一个Anchor是否对应着真实物体&#xff0c;以及每一个Anchor对应物体的真实偏移值&#xff0c;这两种真值的具体求解过程如下图所示&#xff1a; Anchor生成 Anchor生成的具体过程可参考Faster RCNN系列——Anchor生成过程&a…

C++|引用篇

目录 引用概念 引用的用法 做函数形参 优点一 优点二 引用做返回值 让我们更深入的了解引用与指针 语法层引用与指针完全不同的概念 站在底层的角度看指针与引用 引用概念 在语言层面上&#xff1a;引用不是定义新的变量&#xff0c;而是给已存在变量再取一个别名&am…

Spring——读取和存储(包含五大注解,对象装配,注入关键字)

目录 一、创建Spring项目 1. 创建一个普通的maven项目 2. 添加Spring框架支持&#xff08;spring-context&#xff0c;spring-beans&#xff09; 3. 添加启动类 二、Bean对象的读取和存储——不使用注释版 1. 创建Bean 2. 将Bean注册到容器 3. 获取并使用Bean对象 3.1…

Faster RCNN系列——Anchor生成过程

一、RPN模块概述 RPN模块的输入、输出如下&#xff1a; 输入&#xff1a;feature map&#xff08;输入图像经过特征提取网络后得到的特征图&#xff09;、物体标签&#xff08;训练集中所有物体的类别和边框信息&#xff09;输出&#xff1a;Proposal&#xff08;生成的建议框…

KD-2125地下管线故障测试仪

一、产品概述 KD-2125电缆综合探测仪&#xff08;管线仪&#xff09;可进行地下电缆线路&#xff08;停电/带电&#xff09;和金属管道等敷设路径探测、识别、埋深测量&#xff1b;以及路灯电缆、地埋线路的故障查找等&#xff0c;同时也可进行地下带电线缆排查。该设备以其优越…

Android---内存性能优化

内存抖动 内存抖动是由于短时间内有大量对象进出新生区导致的&#xff0c;内存忽高忽低&#xff0c;有短时间内快速上升和下落的趋势&#xff0c;分析图呈锯齿状。 它伴随着频繁的 GC&#xff0c;GC 会大量占用 UI 线程和 CPU 资源&#xff0c;会导致 APP 整体卡顿&#xff08;…

07 dubbo源码学习_集群Cluster

1. 入口2. 源码分析2.1 FailbackClusterInvoker2.2 FailoverClusterInvoker 失败自动切换2.3 FailfastClusterInvoker 快速失败2.4 FailsafeClusterInvoker 失败安全2.4 FailsafeClusterInvoker 并行调用多个服务提供者,只要有一个返回,就立即响应3. 如何使用本篇主要介绍集群…

Python VTK STL 映射三维模型表面距离

目录 前言&#xff1a; 效果&#xff1a; 实现步骤&#xff1a; Code: 前言&#xff1a; 本文介绍了Python VTK映射三维模型表面距离&#xff0c;通过如何使用VTK计算两个三维模型(stl)的表面距离&#xff0c;并将其距离值以颜色映射到模型&#xff0c;可用于对比 两相模型…

智慧养老平台建设方案word

本资料来源公开网络&#xff0c;仅供个人学习&#xff0c;请勿商用&#xff0c;如有侵权请联系删除。 1、 总体设计 1.1 建设原则 养老机构智能化管理工程是一项涉及多学科知识的复杂的系统工程&#xff0c;养老机构智能化管理围绕机构发展战略&#xff0c;立足机构需求&…

超星项目er图,进程

一.er图 二. 进程&#xff1a;发现之前的写的分类太乱而且服务端与客户端未分离&#xff0c;于是分离客户端与服务端&#xff0c;然后将客户端的界面三个程序整理放在三个包下&#xff0c;在服务端与客户端的数据交互方面采用序列化与反序列化进行功能判断采用以及数据传输&a…

WPF入门教程(六)--依赖属性(2)--属性值优先级与继承

一、 依赖属性的优先级 由于WPF 允许我们可以在多个地方设置依赖属性的值&#xff0c;所以我们就必须要用一个标准来保证值的优先级别。比如下面的例子中&#xff0c;我们在三个地方设置了按钮的背景颜色&#xff0c;那么哪一个设置才会是最终的结果呢&#xff1f;是Black、Re…

【论文阅读】On clustering using random walks

《On clustering using random walks》阅读笔记 1. 问题建模 1.1 问题描述 let G(V,E,ω)G(V,E,\omega)G(V,E,ω) be a weighted graph, VVV is the set of nodes, EEE is the edge between nodes in VVV, ω\omegaω is the function ω&#xff1a;E→Rn\omega&#xff1a…

网络基础2【HTTP、UDP、TCP】

目录 一.应用层 1.协议 2.网络版计算器 3.HTTP协议 &#xff08;1&#xff09;了解url和http &#xff08;2&#xff09;http的用处 &#xff08;3&#xff09;urlencode和urldecode &#xff08;4&#xff09;http协议格式 4.HTTPS协议 &#xff08;1&#xff09;加密…

《花雕学AI》用ChatGPT创造猫娘角色:人工智能角色扮演聊天对话的风险与对策

出于好奇心&#xff0c;我以“ChatGPT&#xff0c;调教猫娘”为题&#xff0c;开始了解ChatGPT角色扮演提示语的用法。ChatGPT给出的介绍是&#xff0c;调教猫娘是一种利用ChatGPT的角色扮演功能&#xff0c;让模型模仿一种类似猫的拟人化生物的行为和语言的活动&#xff0c;并…

【云原生网关】apisix使用详解

目录 一、apisix介绍 1.1 apisix是什么 二、apisix特点 2.1 多平台支持 2.2 全动态能力 2.3 精细化路由 2.4 对运维友好 2.5 多语言支持 三、apisix优势 3.1 apisix生态全景图 3.2 apisix定位 3.3 apisix优点 3.4 与nginx对比 四、apisix应用场景 4.1 Load Bala…

设计模式-结构型模式之桥接模式

2. 桥接模式2.1. 模式动机设想如果要绘制矩形、圆形、椭圆、正方形&#xff0c;我们至少需要4个形状类&#xff0c;但是如果绘制的图形需要具有不同的颜色&#xff0c;如红色、绿色、蓝色等&#xff0c;此时至少有如下两种设计方案&#xff1a;第一种设计方案是为每一种形状都提…

Python 基础(七):常用运算符

❤️ 博客主页&#xff1a;水滴技术 &#x1f338; 订阅专栏&#xff1a;Python 入门核心技术 &#x1f680; 支持水滴&#xff1a;点赞&#x1f44d; 收藏⭐ 留言&#x1f4ac; 文章目录一、算术运算符二、按位运算符2.1 按位与 &2.2 按位或 |2.3 按位异或 ^2.4 按位取反…

Three.js教程:顶点颜色数据插值计算

推荐&#xff1a;将 NSDT场景编辑器 加入你3D工具链 其他工具系列&#xff1a; NSDT简石数字孪生 顶点颜色数据插值计算 上节课自定义几何体给大家介绍了一个顶点位置坐标概念&#xff0c;本节课给大家介绍一个新的几何体顶点概念&#xff0c;就是几何体顶点颜色。 通常几何体…