最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java JMH進(jìn)行基準(zhǔn)測試的使用小結(jié)

 更新時間:2025年05月07日 09:32:49   作者:終點(diǎn)就在前方  
在 Java 的依賴庫中,有個大名鼎鼎的 JMH(Java Microbenchmark Harness),是由 Java虛擬機(jī)團(tuán)隊(duì)開發(fā)的 Java 基準(zhǔn)測試工具,下面小編來和大家講講它的具體使用吧

在 Java 的依賴庫中,有個大名鼎鼎的 JMH(Java Microbenchmark Harness),是由 Java虛擬機(jī)團(tuán)隊(duì)開發(fā)的 Java 基準(zhǔn)測試工具。

在 JMH 中,正如 單元測試框架 JUnit 一樣,我們也可以通過大量的注解來進(jìn)行一定的配置,一個典型的 JMH 程序執(zhí)行如下圖所示[2]:

也即,通過開啟多個進(jìn)程,多個線程,先執(zhí)行預(yù)熱,然后執(zhí)行迭代,最后匯總所有的測試數(shù)據(jù)進(jìn)行分析,這就是 JMH 的執(zhí)行流程,聽起來是不是不難理解。

1.示例

學(xué)習(xí)新技能通常先通過一個 case 來幫準(zhǔn)我們怎么用,有什么結(jié)果,這里我們通過改寫官方的一個 sample 來看看。

package org.example;
 
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.results.format.ResultFormatType;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
 
import java.util.concurrent.TimeUnit;
 
@Warmup(iterations = 1, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 2, time = 1, timeUnit = TimeUnit.SECONDS)
public class HelloWorldBenchmark {
    private static int num = 0;
    @Benchmark
    public void helloWorld() {
        ++num;
    }
 
 
    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .include(HelloWorldBenchmark.class.getSimpleName())
                .forks(1)
                .result("helloWorld.json")
                .resultFormat(ResultFormatType.JSON)
                .build();
 
        new Runner(opt).run();
    }
}

示例很簡單,就是簡單對 static 變量做自增,最后將結(jié)果輸出到 json 文件中,下面是運(yùn)行結(jié)果:

# JMH version: 1.23
# VM version: JDK 21, Java HotSpot(TM) 64-Bit Server VM, 21+35-LTS-2513
# VM invoker: C:\Program Files\Java\jdk-21\bin\java.exe
# VM options: -javaagent:D:\chromedownload\ideaIC-2023.2.3.win\lib\idea_rt.jar=55507:D:\chromedownload\ideaIC-2023.2.3.win\bin -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8
# Warmup: 1 iterations, 1 s each
# Measurement: 2 iterations, 1 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Throughput, ops/time
# Benchmark: org.example.HelloWorldBenchmark.helloWorld
 
# Run progress: 0.00% complete, ETA 00:00:03
# Fork: 1 of 1
# Warmup Iteration   1: 1659899825.872 ops/s
Iteration   1: 1646745186.884 ops/s
Iteration   2: 1681125023.980 ops/s
 
 
Result "org.example.HelloWorldBenchmark.helloWorld":
  1663935105.432 ops/s
 
 
# Run complete. Total time: 00:00:03
 
REMEMBER: The numbers below are just data. To gain reusable insights, you need to follow up on
why the numbers are the way they are. Use profilers (see -prof, -lprof), design factorial
experiments, perform baseline and negative tests that provide experimental control, make sure
the benchmarking environment is safe on JVM/OS/HW level, ask for reviews from the domain experts.
Do not assume the numbers tell you what you want them to tell.
 
Benchmark                        Mode  Cnt           Score   Error  Units
HelloWorldBenchmark.helloWorld  thrpt    2  1663935105.432          ops/s
 
Benchmark result is saved to helloWorld.json

通過簡單的設(shè)置,我們在基準(zhǔn)測試中可以看到多次測試的每秒吞吐量,最后結(jié)果輸出到 helloWorldjson 文件:

[
    {
        "jmhVersion" : "1.23",
        "benchmark" : "org.example.HelloWorldBenchmark.helloWorld",
        "mode" : "thrpt",
        "threads" : 1,
        "forks" : 1,
        "jvm" : "C:\Program Files\Java\jdk-21\bin\java.exe",
        "jvmArgs" : [
            "-javaagent:D:\chromedownload\ideaIC-2023.2.3.win\lib\idea_rt.jar=55507:D:\chromedownload\ideaIC-2023.2.3.win\bin",
            "-Dfile.encoding=UTF-8",
            "-Dsun.stdout.encoding=UTF-8",
            "-Dsun.stderr.encoding=UTF-8"
        ],
        "jdkVersion" : "21",
        "vmName" : "Java HotSpot(TM) 64-Bit Server VM",
        "vmVersion" : "21+35-LTS-2513",
        "warmupIterations" : 1,
        "warmupTime" : "1 s",
        "warmupBatchSize" : 1,
        "measurementIterations" : 2,
        "measurementTime" : "1 s",
        "measurementBatchSize" : 1,
        "primaryMetric" : {
            "score" : 1.6639351054317546E9,
            "scoreError" : "NaN",
            "scoreConfidence" : [
                "NaN",
                "NaN"
            ],
            "scorePercentiles" : {
                "0.0" : 1.6467451868835843E9,
                "50.0" : 1.6639351054317546E9,
                "90.0" : 1.6811250239799252E9,
                "95.0" : 1.6811250239799252E9,
                "99.0" : 1.6811250239799252E9,
                "99.9" : 1.6811250239799252E9,
                "99.99" : 1.6811250239799252E9,
                "99.999" : 1.6811250239799252E9,
                "99.9999" : 1.6811250239799252E9,
                "100.0" : 1.6811250239799252E9
            },
            "scoreUnit" : "ops/s",
            "rawData" : [
                [
                    1.6467451868835843E9,
                    1.6811250239799252E9
                ]
            ]
        },
        "secondaryMetrics" : {
        }
    }
]

看完怎么用,接下來看看在項(xiàng)目中注意的點(diǎn)和值得注意的參數(shù)注解。

2.JMH的使用

引入依賴

由于這不是標(biāo)準(zhǔn)庫有的依賴,所以這里我們依然用 Maven 管理依賴,在我們構(gòu)建的 Maven 項(xiàng)目中的 pom.xml 添加下列依賴:

<dependencies>
    <dependency>
        <groupId>org.openjdk.jmh</groupId>
        <artifactId>jmh-core</artifactId>
        <version>1.23</version>
    </dependency>
    <dependency>
        <groupId>org.openjdk.jmh</groupId>
        <artifactId>jmh-generator-annprocess</artifactId>
        <version>1.23</version>
    </dependency>

接下來看看代碼應(yīng)用。

代碼示例基于參考編寫:

package org.example;
 
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.results.format.ResultFormatType;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
 
import java.util.concurrent.TimeUnit;
 
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
 
@State(Scope.Thread)
@Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
 
@Fork(1)
@Threads(2)
public class MyBenchmarkTest {
    @Benchmark
    public long shift() {
        long t = 455565655225562L;
        long a = 0;
        for (int i = 0; i < 1000; i++) {
            a = t >> 30;
        }
        return a;
    }
 
    @Benchmark
    public long div() {
        long t = Long.MAX_VALUE;
        long a = 0;
        for (int i = 0; i < 1000; i++) {
            a = t / 1024 / 1024 / 1024;
        }
 
        return a;
    }
 
    public static void main(String[] args) throws RunnerException {
        Options opts = new OptionsBuilder()
                .include(MyBenchmarkTest.class.getSimpleName())
                .result("MyBenchmarkTest.json")
                .resultFormat(ResultFormatType.JSON)
                .build();
 
        new Runner(opts).run();
    }
}

在示例中,其實(shí)我們的目的就是測試 移位和整除 兩個方法的性能,看看每秒的吞吐量如何,最后將結(jié)果匯總在 MyBenchmarkTest.json 文件中,當(dāng)然運(yùn)行測試,我們也可以在控制臺得到相應(yīng)輸出。

注解

在上面的 demo 中,我們在類上加了很多注解,注解的作用又是啥呢?

@BenchmarkMode

該注解用來指定基準(zhǔn)測試類型,對應(yīng) Mode 選項(xiàng),修飾類和方法,這里我們修飾類,注解的 value 是 Mode[] 類型,我們這里填入的是 Throughput ,表示整體吞吐量,即單位時間內(nèi)的調(diào)用量,查看 Mode 源碼就可以發(fā)現(xiàn),其實(shí)總的類型有以下:

  • Throughput: 略

  • AverageTime: 平均耗時,指的是每次執(zhí)行的平均時間。如果這個值很小不好辨認(rèn),可以把統(tǒng)計(jì)的單位時間調(diào)小一點(diǎn)。

  • SampleTime: 隨機(jī)取樣。

  • SingleShotTime: 如果你想要測試僅僅一次的性能,比如第一次初始化花了多長時間,就可以使用這個參數(shù),其實(shí)和傳統(tǒng)的main方法沒有什么區(qū)別。

  • All: 所有的指標(biāo),都算一遍。

從 控制臺的結(jié)果可以看看相關(guān)輸出:

Benchmark               Mode  Cnt       Score      Error   Units
MyBenchmarkTest.div    thrpt    5  500758.115 ± 3350.796  ops/ms
MyBenchmarkTest.shift  thrpt    5  500045.811 ± 1609.779  ops/ms

如果填入 Mode.All 看看結(jié)果輸出:

Benchmark                              Mode     Cnt       Score      Error   Units
MyBenchmarkTest.div                   thrpt       5  500554.176 ± 8015.731  ops/ms
MyBenchmarkTest.shift                 thrpt       5  499731.423 ± 4635.160  ops/ms
MyBenchmarkTest.div                    avgt       5      ≈ 10??              ms/op
MyBenchmarkTest.shift                  avgt       5      ≈ 10??              ms/op
MyBenchmarkTest.div                  sample  316909      ≈ 10??              ms/op
MyBenchmarkTest.div:div·p0.00        sample                 ≈ 0              ms/op
MyBenchmarkTest.div:div·p0.50        sample                 ≈ 0              ms/op
MyBenchmarkTest.div:div·p0.90        sample              ≈ 10??              ms/op
MyBenchmarkTest.div:div·p0.95        sample              ≈ 10??              ms/op
MyBenchmarkTest.div:div·p0.99        sample              ≈ 10??              ms/op
MyBenchmarkTest.div:div·p0.999       sample              ≈ 10??              ms/op
MyBenchmarkTest.div:div·p0.9999      sample               0.002              ms/op
MyBenchmarkTest.div:div·p1.00        sample               0.025              ms/op
MyBenchmarkTest.shift                sample  315964      ≈ 10??              ms/op
MyBenchmarkTest.shift:shift·p0.00    sample                 ≈ 0              ms/op
MyBenchmarkTest.shift:shift·p0.50    sample                 ≈ 0              ms/op
MyBenchmarkTest.shift:shift·p0.90    sample              ≈ 10??              ms/op
MyBenchmarkTest.shift:shift·p0.95    sample              ≈ 10??              ms/op
MyBenchmarkTest.shift:shift·p0.99    sample              ≈ 10??              ms/op
MyBenchmarkTest.shift:shift·p0.999   sample              ≈ 10??              ms/op
MyBenchmarkTest.shift:shift·p0.9999  sample               0.001              ms/op
MyBenchmarkTest.shift:shift·p1.00    sample               0.024              ms/op
MyBenchmarkTest.div                      ss       5       0.052 ±    0.091   ms/op
MyBenchmarkTest.shift                    ss       5       0.015 ±    0.023   ms/op

此時可以看到十分詳盡的輸出,每秒的吞吐量,每個操作的耗費(fèi)時間等,因?yàn)楸纠唵?,時間耗費(fèi)建議填入 ns 等單位。

@BenchmarkMode 表示單位時間的操作數(shù)或者吞吐量,或者每個操作耗費(fèi)的時間等,注意我們都沒有限定時間單位,所以通常這個注解也會和 @OutputTimeUnit 結(jié)合使用。

@OutputTimeUnit

基準(zhǔn)測試結(jié)果的時間類型。一般選擇秒、毫秒、微秒,這里填入的是 TimeUnit 這個枚舉類型,涉及單位很多從納秒到天都有,按需選擇,最終輸出易讀的結(jié)果。

@State

@State 指定了在類中變量的作用范圍。它有三個取值。

@State 用于聲明某個類是一個“狀態(tài)”,可以用Scope 參數(shù)用來表示該狀態(tài)的共享范圍。這個注解必須加在類上,否則提示無法運(yùn)行。

Scope有如下3種值:

  • Benchmark:表示變量的作用范圍是某個基準(zhǔn)測試類。
  • Thread:每個線程一份副本,如果配置了Threads注解,則每個Thread都擁有一份變量,它們互不影響。
  • Group:聯(lián)系上面的@Group注解,在同一個Group里,將會共享同一個變量實(shí)例。

本例中,相關(guān)變量的作用范圍是 Thread。

@Warmup

預(yù)熱,可以加在類上或者方法上,預(yù)熱只是測試數(shù)據(jù),是不作為測量結(jié)果的。

該注解一共有4個參數(shù):

  • iterations 預(yù)熱階段的迭代數(shù)
  • time 每次預(yù)熱時間
  • timeUnit 時間單位,通常秒
  • batchSize 批處理大小,指定每次操作調(diào)用幾次方法

本例中,我們加在類上,讓它迭代3次,每次1秒,時間單位秒。

@Measurement

和預(yù)熱類似,這里的注解是會影響測試結(jié)果的,它的參數(shù)和 Warmup 一樣,這里不多介紹。

本例中我們在迭代中設(shè)置的是5次,每次1秒。

通常 @Warmup 和 @Measurement 兩個參數(shù)會一起使用。

@Fork

表示開啟幾個進(jìn)程測試,通常我們設(shè)為1,如果數(shù)值大于1,則啟用新的進(jìn)程測試,如果設(shè)置為0,程序依然進(jìn)行,但是在用戶的 JVM 進(jìn)程上運(yùn)行。

追蹤一下JMH的源碼,發(fā)現(xiàn)每個fork進(jìn)程是單獨(dú)運(yùn)行在Proccess進(jìn)程里的,這樣就可以做完全的環(huán)境隔離,避免交叉影響。它的輸入輸出流,通過Socket連接的模式,發(fā)送到我們的執(zhí)行終端。

如果需要更多的設(shè)置,可以看看 Fork.class 源碼,上面還有 jvm 參數(shù)設(shè)置。

@Threads

上面的注解注重開啟幾個進(jìn)程,這里就是開啟幾個線程,只有一個參數(shù) value,指定注解的value,將會開啟并行測試,如果設(shè)置的 value 過大,如 Threads.Max,則使用處理機(jī)的相同線程數(shù)。

@Benchmark

加在測試方法上,表示該方法是需要進(jìn)行基準(zhǔn)測試的,類似 JUnit5 中的 @Test 注解需要單元測試的方法一樣。

@Setup

注解的作用就是我們需要在測試之前進(jìn)行一些準(zhǔn)備工作,比如對一些數(shù)據(jù)的初始化之類的,這個也和Junit的@Before

@Teardown

在測試之后進(jìn)行一些結(jié)束工作,主要用于資源回收

開啟測試

上述的學(xué)習(xí)中主要是相關(guān)注解,這里看看具體我們怎么用。

public static void main(String[] args) throws RunnerException {
    Options opts = new OptionsBuilder()
            // 表示包含的測試類
            .include(MyBenchmarkTest.class.getSimpleName()) 
            // 最后結(jié)果輸出文件的命名
            .result("MyBenchmarkTest.json")
            // 結(jié)果輸出什么格式,可以是json, csv, text等
            .resultFormat(ResultFormatType.JSON)
            .build();
 
    new Runner(opts).run(); // 運(yùn)行
}

3.JMH可視化

作為程序開發(fā)人員,看懂測試結(jié)果沒難度,測試結(jié)果文本能可視化更好。

好在我們拿到了JMH 結(jié)果后,根據(jù)文件格式,我們可以二次加工,就可以圖表化展示[2]。

JMH 支持的幾種輸出格式:

  • TEXT 導(dǎo)出文本文件。
  • CSV 導(dǎo)出csv格式文件。
  • SCSV 導(dǎo)出scsv等格式的文件。
  • JSON 導(dǎo)出成json文件。
  • LATEX 導(dǎo)出到latex,一種基于ΤΕΧ的排版系統(tǒng)。

到此這篇關(guān)于Java JMH進(jìn)行基準(zhǔn)測試的使用小結(jié)的文章就介紹到這了,更多相關(guān)Java JMH基準(zhǔn)測試內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java集合ArrayDeque類實(shí)例分析

    Java集合ArrayDeque類實(shí)例分析

    這篇文章主要介紹了Java集合ArrayDeque類實(shí)例分析的相關(guān)資料,需要的朋友可以參考下
    2017-04-04
  • Java編程線程間通信與信號量代碼示例

    Java編程線程間通信與信號量代碼示例

    這篇文章主要介紹了Java編程線程間通信與信號量代碼示例,具有一定借鑒價值,需要的朋友可以參考下。
    2017-12-12
  • Java循環(huán)創(chuàng)建對象內(nèi)存溢出的解決方法

    Java循環(huán)創(chuàng)建對象內(nèi)存溢出的解決方法

    在Java中,如果在循環(huán)中不當(dāng)?shù)貏?chuàng)建大量對象而不及時釋放內(nèi)存,很容易導(dǎo)致內(nèi)存溢出(OutOfMemoryError),所以本文給大家介紹了Java循環(huán)創(chuàng)建對象內(nèi)存溢出的解決方法,需要的朋友可以參考下
    2025-01-01
  • feign調(diào)用中文參數(shù)被encode編譯的問題

    feign調(diào)用中文參數(shù)被encode編譯的問題

    這篇文章主要介紹了feign調(diào)用中文參數(shù)被encode編譯的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • SpringBoot?web靜態(tài)資源映射實(shí)現(xiàn)步驟詳解

    SpringBoot?web靜態(tài)資源映射實(shí)現(xiàn)步驟詳解

    在springBoot中的靜態(tài)資源的映射是通過SpringMVC中的resourceHttpRequestHandler來進(jìn)行實(shí)現(xiàn)的。在該請求映射器中默認(rèn)規(guī)定了,SpringBoot會將classPath或者ServletContext下的/static?(/public、/resources?或?/META-INF/resources)目錄中,存放靜態(tài)資源
    2022-09-09
  • 詳解Java的位操作符

    詳解Java的位操作符

    位操作就是對這些數(shù)據(jù)進(jìn)行基本的操作。如果基本類型是char、byte或者short類型的數(shù)值進(jìn)行移位處理,那么會轉(zhuǎn)化成int類型,再進(jìn)行移位的處理
    2017-09-09
  • Spring Transaction事務(wù)實(shí)現(xiàn)流程源碼解析

    Spring Transaction事務(wù)實(shí)現(xiàn)流程源碼解析

    此文就Spring 事務(wù)實(shí)現(xiàn)流程進(jìn)行源碼解析,我們可以借此對Spring框架更多一層理解,下面以xml形式創(chuàng)建一個事務(wù)進(jìn)行分析
    2022-09-09
  • SpringBoot整合MongoDB流程詳解

    SpringBoot整合MongoDB流程詳解

    這篇文章主要介紹了SpringBoot整合MongoDB流程詳解,MongoDB是一種面向文檔的數(shù)據(jù)庫管理系統(tǒng),它是一個介于關(guān)系型數(shù)據(jù)庫和非關(guān)系型數(shù)據(jù)庫之間的產(chǎn)品,MongoDB支持一種類似JSON的BSON數(shù)據(jù)格式,既可以存儲簡單的數(shù)據(jù)格式,也可以存儲復(fù)雜的數(shù)據(jù)類型,需要的朋友可以參考下
    2024-01-01
  • JVM線上調(diào)優(yōu)參數(shù)配置實(shí)踐完全指南

    JVM線上調(diào)優(yōu)參數(shù)配置實(shí)踐完全指南

    JVM調(diào)優(yōu)的基本思路涉及多個方面,旨在提升Java應(yīng)用的性能、穩(wěn)定性和響應(yīng)速度,下面這篇文章主要介紹了JVM線上調(diào)優(yōu)參數(shù)配置的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2025-08-08
  • Spring Boot 通過注解實(shí)現(xiàn)數(shù)據(jù)校驗(yàn)的方法

    Spring Boot 通過注解實(shí)現(xiàn)數(shù)據(jù)校驗(yàn)的方法

    這篇文章主要介紹了Spring Boot 通過注解實(shí)現(xiàn)數(shù)據(jù)校驗(yàn)的方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-09-09

最新評論

利辛县| 靖州| 壶关县| 蒲江县| 秦皇岛市| 海南省| 吴旗县| 富宁县| 阜城县| 阿瓦提县| 响水县| 白山市| 本溪| 玛沁县| 杭州市| 咸阳市| 崇州市| 苏尼特左旗| 平南县| 吴堡县| 库伦旗| 兴文县| 康平县| 洛南县| 武邑县| 望江县| 神农架林区| 龙门县| 天镇县| 龙江县| 汤阴县| 岗巴县| 浙江省| 利辛县| 沾化县| 远安县| 施秉县| 冕宁县| 理塘县| 子洲县| 津市市|