JMH
JMH(Java Microbenchmark Harness)๋ Java ๊ธฐ๋ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ง์ดํฌ๋ก ๋ฒค์น๋งํฌ๋ฅผ ์์ฑํ๊ธฐ ์ํ ํ๋ ์์ํฌ์ ๋๋ค. ๋จ์ํ ์ฑ๋ฅ ํ ์คํธ ์ฝ๋๋ก ์ธํด ๋ฐ์ํ ์ ์๋ JVM ์ต์ ํ(JIT, Dead Code Elimination ๋ฑ) ๋ฌธ์ ๋ฅผ ๋ฐฉ์งํ๊ณ , ์ ํํ๊ณ ์ ๋ขฐํ ์ ์๋ ๊ฒฐ๊ณผ๋ฅผ ์ ๊ณตํฉ๋๋ค.
JMH๋ JVM ์๋ฐ์ , ์ค๋ ๋ฉ ์ต์ , ์ฑ๋ฅ ์ธก์ ๋ฐ๋ณต ๋ฑ ๋ค์ํ ๊ธฐ๋ฅ์ ์ ๊ณตํ์ฌ ๋ฒค์น๋งํน ๊ณผ์ ์์ ๋ฐ์ํ ์ ์๋ ํํ ์ค์๋ฅผ ์๋ฐฉํฉ๋๋ค.
ํน์ง
JIT ์ต์ ํ ๋ฐฉ์ง: JVM์ ํซ์คํ ์ปดํ์ผ๋ฌ๊ฐ ๋ฒค์น๋งํฌ ๊ฒฐ๊ณผ๋ฅผ ์๊ณกํ์ง ์๋๋ก ๊ด๋ฆฌ.
๋ฉํฐ์ค๋ ๋ ํ๊ฒฝ ์ง์: ๋์์ฑ ํ ์คํธ๋ฅผ ์ฝ๊ฒ ์ค์ ๊ฐ๋ฅ.
์ ํํ ์ฑ๋ฅ ์ธก์ : Warm-up, Iteration, Fork ์ค์ ์ ํตํ ์์ ์ ์ธ ๊ฒฐ๊ณผ ์ ๊ณต.
์ฌ์ฉ ํธ๋ฆฌ์ฑ: ์ด๋ ธํ ์ด์ ๊ธฐ๋ฐ ์ค์ ์ผ๋ก ์ฝ๊ฒ ์์ฑ ๊ฐ๋ฅ.
์ค์ ๋ฐฉ๋ฒ
Maven ํ๋ก์ ํธ์ JMH ์ถ๊ฐ
<dependencies>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>1.38</version> <!-- ์ต์ ๋ฒ์ ํ์ธ ํ์ -->
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>1.38</version>
</dependency>
</dependencies>
Gradle ํ๋ก์ ํธ์ JMH ์ถ๊ฐ
plugins {
id 'java'
id 'me.champeau.jmh' version '0.7.1' // JMH ํ๋ฌ๊ทธ์ธ ์ฌ์ฉ
}
dependencies {
implementation 'org.openjdk.jmh:jmh-core:1.38'
annotationProcessor 'org.openjdk.jmh:jmh-generator-annprocess:1.38'
}
JMH ์ฌ์ฉ๋ฒ
import org.openjdk.jmh.annotations.*;
import java.util.concurrent.TimeUnit;
@BenchmarkMode(Mode.Throughput) // 1์ด๋น ์คํ ํ์ ์ธก์
@OutputTimeUnit(TimeUnit.MILLISECONDS) // ๊ฒฐ๊ณผ๋ฅผ ๋ฐ๋ฆฌ์ด ๋จ์๋ก ์ถ๋ ฅ
@State(Scope.Thread) // ์ํ๋ฅผ ๊ฐ ์ค๋ ๋์์ ๋
๋ฆฝ์ ์ผ๋ก ์ ์ง
public class MyBenchmark {
private int[] numbers;
@Setup(Level.Iteration) // ๊ฐ ๋ฐ๋ณต ์ ์ด๊ธฐํ
public void setUp() {
numbers = new int[1_000];
for (int i = 0; i < numbers.length; i++) {
numbers[i] = i;
}
}
@Benchmark
public int sumArray() {
int sum = 0;
for (int num : numbers) {
sum += num;
}
return sum;
}
@Benchmark
public int sumArrayUsingStreams() {
return java.util.Arrays.stream(numbers).sum();
}
}
mvn clean install
๋๋./gradlew jmhJar
๋ก ๋น๋.์คํ:
java -jar target/benchmarks.jar
๋๋
java -jar build/libs/benchmarks.jar
์ฃผ์ ์ด๋
ธํ
์ด์
๋ฐ ์ค์
@Benchmark: ๋ฒค์น๋งํฌ ํ ์คํธ ๋ฉ์๋ ํ์.
@BenchmarkMode: ๋ฒค์น๋งํฌ ์ธก์ ๋ชจ๋ ์ค์ (์: Throughput, AverageTime, SampleTime, AllModes ๋ฑ).
@OutputTimeUnit: ๊ฒฐ๊ณผ์ ์๊ฐ ๋จ์ ์ค์ .
@State: ๋ฒค์น๋งํฌ ์คํ ์ํ๋ฅผ ๋ํ๋ด๋ ๊ฐ์ฒด ์ค์ฝํ ์ค์ (Thread, Group, Singleton).
@Setup / @TearDown: ๋ฒค์น๋งํฌ ์ค๋น ๋ฐ ์ ๋ฆฌ ์์ ์ง์ .
@Param: ํ๋ผ๋ฏธํฐ๋ฅผ ์ค์ ํ์ฌ ๋ค์ํ ์ ๋ ฅ๊ฐ ํ ์คํธ ๊ฐ๋ฅ.
6. JMH ์คํ ์ ์ฃผ์ ์ค์
Fork: JVM ํ๋ก์ธ์ค๋ฅผ ๋ช ๋ฒ ์ฌ์์ํ์ฌ ๋ฒค์น๋งํฌ ์คํํ ์ง ๊ฒฐ์ .
@Fork(2) // ๋ ๋ฒ์ ํ๋ก์ธ์ค๋ฅผ ์คํ
Warmup: JVM ์๋ฐ์ ์ ๋ช ๋ฒ ๋ฐ๋ณตํ ์ง ์ค์ .
@Warmup(iterations = 5) // 5ํ ์๋ฐ์
Measurement: ์ค์ ๋ฒค์น๋งํฌ ๋ฐ๋ณต ํ์.
@Measurement(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS)
Last updated