java基准测试 笔记

2024-05-08 176点热度 0人点赞 0条评论

通过设计合理的测试方法,选用合适的测试工具和被测系统,实现对某个特定目的场景中某项性能指标进行定量的测试。

代码demo


import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.CompilerControl;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Threads;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.results.format.ResultFormatType;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

import java.util.concurrent.TimeUnit;

//用来修饰类和方法都可以。这里的value,是一个数组,可以配置多个统计维度。
// - Throughput:整体吞吐量,比如QPS,单位时间内的调用量等。
// - AverageTime:平均耗时,指的是每次执行的平均时间。如果这个值很小不好辨认,可以把统计的单位时间调小一点。
// - SampleTime: 随机 取样 。
// - SingleShotTime:如果你想要测试仅仅一次的性能,比如第一次初始化花了多长时间,就可以使用这个参数,其实和传统的main方法没有什么区别。
// - All:所有的指标,都算一遍,你可以设置成这个参数看下效果。
@BenchmarkMode(Mode.Throughput)
//代表的就是每毫秒的指标
@OutputTimeUnit(TimeUnit.MILLISECONDS)
//用于声明某个类是一个“状态”,可以用Scope 参数用来表示该状态的共享范围。这个注解必须加在类上,否则提示无法运行。
// - Benchmark:表示变量的作用范围是某个基准测试类。
// - Thread:每个线程一份副本,如果配置了Threads注解,则每个Thread都拥有一份变量,它们互不影响。
// - Group:联系上面的@Group注解,在同一个Group里,将会共享同一个变量实例。
@State(Scope.Thread)
// 对代码预热总计5秒(迭代5次,每次一秒)
@Warmup(iterations = 5, time = 5, timeUnit = TimeUnit.SECONDS)
//表示循环运行5次,总计5秒时间
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
//fork 的值一般设置成1,表示只使用一个进程进行测试;如果这个数字大于1,表示会启用新的进程进行测试;
@Fork(1)
//fork 是面向进程的,而 Threads 是面向线程的。如果配置了 Threads.MAX ,则使用和处理机器核数相同的线程数。
@Threads(2)
//这个注解可以用在类或者方法上,能够控制方法的编译行为,常用的有3种模式。
//强制使用内联(INLINE),禁止使用内联(DONT_INLINE),甚至是禁止方法编译(EXCLUDE)等
@CompilerControl(CompilerControl.Mode.DONT_INLINE)
public class BenchmarkTest {

    @Benchmark
    public List<Integer> your_bench_method() {
        int size = 512;
        List<Integer> dataList = new ArrayList<>(size);
        for (int i = 0; i < size; i++) {
            dataList.add(i);
        }

        // 随机
        Random random = new Random();
        for (int i = 0; i < size; i++) {
            int rand = random.nextInt(size);
            Collections.swap(dataList, i, rand);
        }

        return dataList;
    }

    public static void main(String[] args) throws Exception {
        Options opts = new OptionsBuilder()
                .include(BenchmarkTest.class.getSimpleName())
                //JMH支持以下5种格式的结果:
                //- TEXT导出文本文件。
                //- CSV导出csv格式文件。
                //- SCSV导出scsv等格式的文件。
                //- JSON导出成json文件。
                //- LATEX导出到latex,一种基于ΤΕΧ的排版系统。
                .resultFormat(ResultFormatType.JSON)
                .build();
        new Runner(opts).run();
    }
}

JMH和jMeter的不同

JMH和jMeter的使用场景还是有很大的不同的,
jMeter更多的是对rest api进行压测,而JMH关注的粒度更细,
它更多的是发现某块性能槽点代码,然后对优化方案进行基准测试对比。
比如json序列化方案对比,bean copy方案对比,文中提高的洗牌算法对比等。

mylomen

本人从事 JAVA 开发10多年,将之前整理的笔记分享出来,希望能够帮助到努力的你。

文章评论