๐ต JMH(Java MicroBenchmark Harness) ๋?
- Open JDK์์ ๊ฐ๋ฐํ ์ฑ๋ฅ ์ธก์ ํด
- ํน์ ๋ฉ์๋์ ์ฑ๋ฅ์ ์ธก์ ํ๋ ๋ฐฉ์์ผ๋ก ์ฌ์ฉ
๐ต JMH ๋ ์ธ์ ์ฌ์ฉํ ์ ์์๊น?
์ฑ๋ฅ ํ๋์ ํ ๋, ๋ฉ์๋์ ์ฑ๋ฅ์ ์ธก์ ํ์ฌ ๊ฐ๋จํ ํ ์คํธ๋ฅผ ์งํํ ์ ์๋ค.
์ฌ๋ฌ๊ฐ์ง ์กฐ๊ฑด ๋ฐ ๋ถํ๋ฅผ ์ฃผ๊ณ ํ ์คํธ๋ฅผ ํ ์ ์์ง๋ง, JMH๋ฅผ ํตํด์๋ ๋ฉ์๋์ ์ฑ๋ฅ ํ๋์ ๋ก์ปฌ์์ ๊ฐ๋จํ๊ฒ ์คํํด๋ณด๊ณ ์งํํด๋ณผ ์ ์๋ค๋ ์ ์ด ์ข๋ค.
๐ต JMH ์ฌ์ฉํ์ฌ ๋ฉ์๋์ ์ฑ๋ฅ ์ธก์ ํ๊ธฐ
1) pom.xml ์ jmh-core ์ jmh-generator-annprocess ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ถ๊ฐ
pom.xml
<!-- jmh -->
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>1.26</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>1.26</version>
</dependency>
2) Benchmark ์ฉ ํด๋์ค ์์ฑ
BenchmarkTest class ๋ฅผ ์์ฑํด์ฃผ๊ณ , ์ค์ ๋ก ์ฑ๋ฅ ํ ์คํธํ๊ณ ์ถ์ ๋์์ ์ฝ๋๋ฅผ ์์ฑํด์ค๋ค.
public class BenchmarkTest {
@Benchmark
public void benchmark(BenchmarkState state, Blackhole bh) {
// ์ค์ ์ฑ๋ฅ ํ
์คํธํ๊ณ ์ถ์ ์ฝ๋ ์์ฑ
List<Integer> list = state.list;
for (int i = 0; i < 1000; i++)
bh.consume (list.get (i));
}
3) ํ ์คํธ๋ฅผ ๋๋ฆด jmh ์์ฑ๋ค์ ์ ํ
์์ฑ์ properties๋ก ๋นผ์ ์ฌ์ฉํ ์ ์์ผ๋, ์ฝ๋ ์์์ ์ค์ ํ ์ ์๋๋ก ํ๋ค.
์์ฑ๋ค์ ๋ํ ์ฝ๋ฉํธ๋ ์๋์์ ํ์ธํด์ฃผ์๊ธธ ๋ฐ๋๋๋ค.
public class BenchmarkTest {
@Test
public void launchBenchmark() throws Exception {
Options opt = new OptionsBuilder()
.include(this.getClass().getName() + ".*")
.mode(Mode.AverageTime)
.timeUnit(TimeUnit.MICROSECONDS) // ์ฑ๋ฅ ๊ฒฐ๊ณผ์ ์๊ฐ ๋จ์
.warmupTime(TimeValue.seconds(1))
.warmupIterations(2) // ์ฌ์ ํ
์คํธ ํ์
.measurementTime(TimeValue.seconds(1)) // ํ
์คํธ ๋น ์ธก์ ์๊ฐ
.measurementIterations(2) // ํ
์คํธ ๋ฐ๋ณตํ์
.threads(2) // ์ฐ๋ ๋
.forks(1)
.shouldFailOnError(true)
.shouldDoGC(true)
.build();
new Runner(opt).run();
}
@Benchmark
public void benchmark(BenchmarkState state, Blackhole bh) {
// ์ค์ ์ฑ๋ฅ ํ
์คํธํ๊ณ ์ถ์ ์ฝ๋ ์์ฑ
List<Integer> list = state.list;
for (int i = 0; i < 1000; i++)
bh.consume (list.get (i));
}
4) @State๋ฅผ ์ฌ์ฉํ์ฌ ํ ์คํธ ์ํ๋ฅผ ์ง์ ๋ฐ @Setup ์ ํตํด ์ฌ์ ์์ ์ ์งํ
(1) Scope.Thread
์ฐ๋ ๋๋ณ๋ก ์ธ์คํด์ค ์์ฑ
(2) Scope.Benchmark
๋์ผํ ํ ์คํธ ๋ด์ ๋ชจ๋ ์ฐ๋ ๋์์ ๋์ผํ ์ธ์คํด์ค๋ฅผ ๊ณต์ ํ๋ค. (๋ฉํฐ์ค๋ ๋ฉ ์ฑ๋ฅ ํ ์คํธ์ ์ฌ์ฉ)
(3) Scope.Group
์ฐ๋ ๋ ๊ทธ๋ฃน๋ง๋ค ์ธ์คํด์ค ์์ฑ
@State(Scope.Thread)
public static class BenchmarkState {
List<Integer> list;
@Setup(Level.Trial)
public void init() {
Random rand = new Random();
list = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
list.add (rand.nextInt());
}
}
}
์คํ ๊ฒฐ๊ณผ
# Run progress: 0.00% complete, ETA 00:00:04
# Fork: 1 of 1
# Warmup Iteration 1: 2.744 us/op
# Warmup Iteration 2: 2.688 us/op
Iteration 1: 2.466 us/op
Iteration 2: 2.453 us/op
๐ต Trouble Shooting
์๋ฌ
java.lang.RuntimeException: ERROR: Unable to find the resource: /META-INF/BenchmarkList
ํด๊ฒฐ ๋ฐฉ๋ฒ : pom.xml ์์
์๋ ๋ฌธ์ ์ฐธ๊ณ ํ์ฌ ํด๊ฒฐ
https://howtodoinjava.com/java/exception-handling/jmh-error-unable-to-find-the-resource-meta-inf-benchmarklist/
// 1. properties ์์ jmh.version ์ถ๊ฐ
<properties>
...(์ค๋ต)
<jmh.version>1.26</jmh.version>
</properties>
// 2. path ์ถ๊ฐ > jmh
<plugin>
...(์ค๋ต)
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>${jmh.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
๐ฃ jmh์ ์์ฑ
jmh {
includes = ['some regular expression'] // include pattern (regular expression) for benchmarks to be executed
excludes = ['some regular expression'] // exclude pattern (regular expression) for benchmarks to be executed
iterations = 10 // Number of measurement iterations to do.
benchmarkMode = ['thrpt','ss'] // Benchmark mode. Available modes are: [Throughput/thrpt, AverageTime/avgt, SampleTime/sample, SingleShotTime/ss, All/all]
batchSize = 1 // Batch size: number of benchmark method calls per operation. (some benchmark modes can ignore this setting)
fork = 2 // How many times to forks a single benchmark. Use 0 to disable forking altogether
failOnError = false // Should JMH fail immediately if any benchmark had experienced the unrecoverable error?
forceGC = false // Should JMH force GC between iterations?
jvm = 'myjvm' // Custom JVM to use when forking.
jvmArgs = ['Custom JVM args to use when forking.']
jvmArgsAppend = ['Custom JVM args to use when forking (append these)']
jvmArgsPrepend =[ 'Custom JVM args to use when forking (prepend these)']
humanOutputFile = project.file("${project.buildDir}/results/jmh/human.txt") // human-readable output file
resultsFile = project.file("${project.buildDir}/results/jmh/results.txt") // results file
operationsPerInvocation = 10 // Operations per invocation.
benchmarkParameters = [:] // Benchmark parameters.
profilers = [] // Use profilers to collect additional data. Supported profilers: [cl, comp, gc, stack, perf, perfnorm, perfasm, xperf, xperfasm, hs_cl, hs_comp, hs_gc, hs_rt, hs_thr, async]
timeOnIteration = '1s' // Time to spend at each measurement iteration.
resultFormat = 'CSV' // Result format type (one of CSV, JSON, NONE, SCSV, TEXT)
synchronizeIterations = false // Synchronize iterations?
threads = 4 // Number of worker threads to run with.
threadGroups = [2,3,4] //Override thread group distribution for asymmetric benchmarks.
timeout = '1s' // Timeout for benchmark iteration.
timeUnit = 'ms' // Output time unit. Available time units are: [m, s, ms, us, ns].
verbosity = 'NORMAL' // Verbosity mode. Available modes are: [SILENT, NORMAL, EXTRA]
warmup = '1s' // Time to spend at each warmup iteration.
warmupBatchSize = 10 // Warmup batch size: number of benchmark method calls per operation.
warmupForks = 0 // How many warmup forks to make for a single benchmark. 0 to disable warmup forks.
warmupIterations = 1 // Number of warmup iterations to do.
warmupMode = 'INDI' // Warmup mode for warming up selected benchmarks. Warmup modes are: [INDI, BULK, BULK_INDI].
warmupBenchmarks = ['.*Warmup'] // Warmup benchmarks to include in the run in addition to already selected. JMH will not measure these benchmarks, but only use them for the warmup.
zip64 = true // Use ZIP64 format for bigger archives
jmhVersion = '1.35' // Specifies JMH version
includeTests = true // Allows to include test sources into generate JMH jar, i.e. use it when benchmarks depend on the test classes.
duplicateClassesStrategy = DuplicatesStrategy.FAIL // Strategy to apply when encountring duplicate classes during creation of the fat jar (i.e. while executing jmhJar task)
}
๐ด JMH Benchmark Test์ ํ๊ณ์
- ํ ์คํธ์ ๋ํ CPU ์ฌ์ฉ๋ฅ , ๊ฐ์ธ PC ์ฑ๋ฅ์ ๋ฐ๋ผ ๊ฒฐ๊ณผ๊ฐ์ด ๋ฌ๋ผ์ง ์ ์์ผ๋ฏ๋ก ์ ํํ ๋ฐ์ดํฐ์ ์งํ๋ก ํ๋ฌํ ์ ์์
- ์ฝ๋๊ฐ ๋์ผํ๋ค๊ณ ๋ค๋ฅธ ์ฌ์์ PC์์ ์งํํ๋ฉด ์ธก์ ํ๊ธฐ ์ด๋ ต๊ธฐ ๋๋ฌธ์ ๊ฐ๋จํ ๋ฉ์๋ ์ฑ๋ฅ ์ธก์ ์ ์ฌ์ฉํด์ผ ํจ.
๐ต ์ฐธ๊ณ ๋ฌธ์
1) github
2) baeldung
3) openJDK ๊ณต์๋ฌธ์
4) ์ค๋ฅ ์ฐธ๊ณ
'SERVER > Spring Boot' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Spring boot] intellij error ํ๋ก์ ํธ ์ ํ ์ค ์๋ฌ (0) | 2023.03.20 |
---|---|
[Spring Boot] REDIS PUB/SUB ๊ตฌํ (0) | 2023.01.16 |
[Spring] DAO/DTO/VO/Entity ๋? (0) | 2021.08.24 |
[Spring] ๋ก๊ทธ ๋จ๊ธฐ๊ธฐ - Log4j / SLF4J / Logger (0) | 2021.08.24 |
[ErrorLog] ๊ตฌ๊ธ SMTP ๋ฉ์ผ์ ์ก์ ๋ธ๋ฃจ์คํฌ๋ฆฐ ๋จ๋ ํ์ (0) | 2021.01.06 |