759

Java로 정확한 마이크로 벤치 마크를 작성하고 실행하는 방법은 무엇입니까?

나는 여기에 대해 생각할 다양한 것들을 보여주는 코드 샘플과 설명을 찾고있다.

예 : 벤치 마크에서 시간 / 반복 또는 반복 / 시간을 측정해야 하는가? 그 이유는 무엇입니까?

관련 항목 :스톱워치 벤치마킹은 받아 들일 수 있습니까?


  • 몇 분 전에 [관련 질문] [1]을 참조하십시오. 편집 : 죄송합니다, 이것은 답변이되지 않습니다. 나는 코멘트로 게시해야합니다. [1]:stackoverflow.com/questions/503877/… - Tiago
  • 그 질문의 포스터를 이와 같은 질문에 회부 할 계획을 세운 후에 나는이 질문이 존재하지 않는다는 것에 주목했다. 그래서 여기에 그것이 잘하면 시간이 지남에 좋은 조언을 조립합니다. - John Nilsson
  • Java 9는 마이크로 벤치마킹을위한 몇 가지 기능을 제공 할 수 있습니다.openjdk.java.net/jeps/230 - Raedwald
  • @Raedwald JEP가 JDK 코드에 마이크로 벤치 마크를 추가하는 것을 목표로한다고 생각하지만 jmh가 JDK에 포함될 것이라고 생각하지 않습니다 ... - assylias
  • 가능성이있는 복제본 :Java로 메소드의 실행을 어떻게하면됩니까? - Basil Bourque

11 답변


701

마이크로 벤치 마크 작성 팁Java HotSpot의 제작자:

규칙 0 :JVM 및 마이크로 벤치마킹에 대한 평판 좋은 논문을 읽으십시오. 좋은 사람은Brian Goetz, 2005. 마이크로 벤치 마크에서 너무 많이 기대하지 마십시오. JVM 성능 특성의 제한된 범위 만 측정합니다.

규칙 1 :타이밍 단계 이전에 모든 초기화 및 컴파일을 트리거하기에 충분할 정도로 항상 테스트 커널을 실행하는 워밍업 단계를 포함하십시오. 워밍업 단계에서는 몇 번 반복해도 괜찮습니다. 어림짐작은 수만 번의 내부 루프 반복입니다.

규칙 2 :항상 함께 뛰라.-XX:+PrintCompilation,-verbose:gc컴파일러 및 JVM의 다른 부분이 타이밍 단계에서 예기치 않은 작업을하지 않는지 확인할 수 있습니다.

규칙 2.1 :타이밍과 워밍업 단계의 시작과 끝에서 메시지를 인쇄하므로 타이밍 단계에서 규칙 2의 출력이 없는지 확인할 수 있습니다.

규칙 3 :-client와 -server, OSR 및 일반 컴파일의 차이점에 유의하십시오. 그만큼-XX:+PrintCompilation플래그는 비표시 항목을 나타 내기 위해 at 기호가있는 OSR 컴파일을보고합니다. 예를 들면 다음과 같습니다.Trouble$1::run @ 2 (41 bytes). 최적의 성능을 얻은 후에는 클라이언트 대 서버를 선호하고 OSR은 정기적으로 실행하십시오.

규칙 4 :초기화 효과에 유의하십시오. 인쇄가 클래스를로드하고 초기화하므로 타이밍 단계에서 처음으로 인쇄하지 마십시오. 클래스 로딩을 구체적으로 테스트하지 않는 한 (또한 테스트 클래스 만로드하는 경우가 아니라면) 워밍업 단계 (또는 최종보고 단계)를 벗어나는 새 클래스를로드하지 마십시오. 규칙 2는 그러한 효과에 대한 첫 번째 방어선입니다.

규칙 5 :최적화 해제 및 재 컴파일 효과에 유의하십시오. 타이밍 단계에서 처음으로 코드 경로를 사용하지 마십시오. 컴파일러가 경로가 전혀 사용되지 않을 것이라는 이전의 낙관적 인 가정에 따라 코드를 정크 및 다시 컴파일 할 수 있기 때문입니다. 규칙 2는 그러한 효과에 대한 첫 번째 방어선입니다.

규칙 6 :적절한 도구를 사용하여 컴파일러의 마음을 읽고, 작성한 코드에 놀랄 것이 예상됩니다. 무언가를 더 빨리 또는 더 느리게 만드는 이론을 만들기 전에 코드를 직접 살펴보십시오.

규칙 7 :측정시 노이즈를 줄이십시오. 조용한 시스템에서 벤치 마크를 실행하고 여러 번 실행하여 이상 치를 버립니다. 용도-Xbatch응용 프로그램으로 컴파일러를 직렬화하고-XX:CICompilerCount=1컴파일러가 자신과 병렬로 실행되는 것을 방지합니다. GC 오버 헤드를 줄이기 위해 최선을 다하십시오.Xmx(충분히 크다) equalsXms사용UseEpsilonGC사용할 수있는 경우.

규칙 8 :아마 훨씬 더 효율적이고 이미이 유일한 목적을 위해 디버깅되었으므로 벤치 마크에 라이브러리를 사용하십시오. 예 :JMH,캘리퍼스또는Bill과 Paul의 Java 용 UCSD 벤치 마크.


  • 이 또한 흥미로운 기사였습니다.ibm.com/developerworks/java/library/j-jtp12214 - John Nilsson
  • 또한 대부분의 OS + JVM 조합에서 일반적으로 + 또는 - 15ms 정확도로 OK 인 경우를 제외하고는 System.currentTimeMillis ()를 사용하지 마십시오. 대신 System.nanoTime ()을 사용하십시오. - Scott Carey
  • javaOne의 일부 문서 :azulsystems.com/events/javaone_2009/session/… - bestsss
  • 그것은주의해야한다.System.nanoTime()아니다보증 된보다 정확한System.currentTimeMillis(). 적어도 정확함을 보장합니다. 그러나 대개는 훨씬 더 정확합니다. - Gravity
  • 사람이 사용해야하는 주된 이유System.nanoTime()대신에System.currentTimeMillis()전자가 단조롭게 증가한다는 것이 보장됩니다. 반환 된 값을 뺀 값은 두 개입니다.currentTimeMillis호출은 실제로 시스템 시간이 일부 NTP 데몬에 의해 조정 되었기 때문에 실제로 부정적인 결과를 가져올 수 있습니다. - Waldheinz

221

나는이 질문이 대답으로 표시되었음을 알고 있지만 마이크로 벤치 마크를 작성할 수있게 해주는 두 개의 라이브러리에 대해 언급하고 싶다.

Google의 Caliper

시작하기 자습서

  1. http://codingjunkie.net/micro-benchmarking-with-caliper/
  2. http://vertexlabs.co.uk/blog/caliper

OpenJDK의 JMH

시작하기 자습서

  1. JVM에서 함정 벤치마킹 피하기
  2. http://nitschinger.at/Using-JMH-for-Java-Microbenchmarking
  3. http://java-performance.info/jmh/



78

Java 벤치 마크에서 중요한 점은 다음과 같습니다.

  • 타이밍을 잡기 전에 코드를 여러 번 실행하여 JIT를 먼저 워밍업하십시오.
  • 결과를 초 또는 (더 나은) 수십 초 단위로 측정 할 수있을만큼 오래 실행해야합니다.
  • 전화를 걸 수없는 동안System.gc()반복 사이에 테스트간에 실행하면 각 테스트에서 작업 할 수있는 "깨끗한"메모리 공간을 얻을 수 있도록하는 것이 좋습니다. (예,gc()보증보다 힌트에 가깝지만,아마도그것은 내 경험에 쓰레기 수집 정말 것입니다.)
  • 나는 반복과 시간, 그리고 "최상의"알고리즘이 1.0의 점수를 얻고 다른 것들이 상대적으로 점수가 매겨 질 수있는 시간 / 반복의 점수를 보여주고 싶다. 이것은 당신이모든알고리즘은 오랜 시간 동안 반복 및 반복 횟수를 변화 시키지만 여전히 유사한 결과를 얻습니다.

저는 .NET에서 벤치마킹 프레임 워크의 디자인에 대해 블로그를 진행하는 중입니다. 나는이전 게시물그것은 당신에게 몇 가지 아이디어를 줄 수 있습니다 - 물론 모든 것이 적절할 수는 없지만 그 중 일부는있을 수 있습니다.


  • Minor nitpick : IMO "각 테스트가" "각 테스트가 얻을 수 있도록"되어야합니다. 전자는 인상적이다.gc 항상사용되지 않는 메모리를 비 웁니다. - Sanjay T. Sharma
  • @ SanjayT.Sharma : 음,의향그것이 실제로하는 것입니다. 엄격한 보증은 아니지만 실제로는 매우 강력한 힌트입니다. 더 명확하게 편집 할 것입니다. - Jon Skeet
  • System.gc ()를 호출하는 것에 동의하지 않습니다. 그것은 힌트입니다, 그게 전부입니다. "희망적으로 무언가를 할 것입니다"라는 것조차도 아닙니다. 절대 절대로 전화해서는 안됩니다. 이것은 예술이 아니라 프로그래밍입니다. - gyorgyabraham
  • @gyabraham : 예, 힌트입니다.하지만 일반적으로 받아 들여지는 것이 있습니다. 따라서 사용하고 싶지 않으면System.gc(), 이전 테스트에서 생성 된 객체로 인해 하나의 테스트에서 가비지 수집을 최소화하기 위해 어떻게 제안합니까? 실용적인 것이지 독단적 인 것이 아닙니다. - Jon Skeet
  • @gyabraham : '멋진 대체'라는 의미가 무엇인지 알 수 없습니다. 당신은 더 정교하고, 다시 - 당신은 더 나은 결과를주는 제안을 할 수 있습니까? 분명히 보장 할 수는 없다고 분명히 말했어. - Jon Skeet

43

jmh최근 OpenJDK에 추가 된 것으로 오라클의 일부 성능 엔지니어가 작성한 것입니다. 확실하게 볼만한 가치가 있습니다.

jmh는 JVM을 대상으로하는 Java 및 기타 언어로 작성된 나노 / 마이크로 / 매크로 벤치 마크를 작성, 실행 및 분석하기위한 Java 하네스입니다.

매우 흥미로운 정보가 묻혀있다.샘플 테스트 주석.

참조 :



17

벤치마킹은 시간 / 반복 또는 반복 / 시간을 측정해야하며 그 이유는 무엇입니까?

그것은 당신이 테스트하려고하는 것에 달려 있습니다. 대기 시간에 관심이 있다면 시간 / 반복을 사용하고 처리량에 관심이 있다면 반복 / 시간을 사용하십시오.


14

벤치 마크 된 코드로 계산 된 결과를 어떻게 든 사용하십시오. 그렇지 않으면 코드를 최적화 할 수 있습니다.


12

두 알고리즘을 비교하려는 경우 순서를 번갈아 각각 두 개 이상의 벤치 마크를 수행하십시오. 즉 :

for(i=1..n)
  alg1();
for(i=1..n)
  alg2();
for(i=1..n)
  alg2();
for(i=1..n)
  alg1();

다른 패스에서 동일한 알고리즘의 런타임에서 눈에 띄는 차이 (5-10 % 가끔)가 있음을 발견했습니다.

또한,매우 커서 각 루프의 런타임은 적어도 10 초 정도입니다. 반복 횟수가 많을수록 벤치 마크 시간이 길어지고 데이터의 신뢰성이 높아집니다.


  • 자연스럽게 순서를 변경하면 런타임에 영향을줍니다. JVM 최적화 및 캐싱 효과가 여기에서 작동 할 것입니다. 예열 & # 39; JVM 최적화, 다중 실행 및 다른 JVM에서 모든 테스트를 벤치마킹 할 수 있습니다. - Mnementh

12

Java에서 마이크로 벤치 마크를 작성하는 데는 여러 가지 단점이 있습니다.

첫 번째 : 가비지 수집, 캐싱 효과 (파일 용 OS 및 메모리 용 CPU), 입출력 등 모든 종류의 이벤트를 무작위로 계산해야합니다.

둘째 : 매우 짧은 간격 동안 측정 된 시간의 정확성을 신뢰할 수 없습니다.

셋째 : JVM은 실행 중에 코드를 최적화합니다. 따라서 동일한 JVM 인스턴스에서 서로 다른 실행이 더 빠르고 더 빨라집니다.

내 권장 사항 : 벤치 마크를 몇 초 동안 실행하십시오. 이는 밀리 초 이상의 런타임보다 안정적입니다. JVM을 워밍업 (측정하지 않고 벤치 마크를 최소 한 번 실행하면 JVM이 최적화를 실행할 수 있음을 의미). 그리고 벤치 마크를 여러 번 (아마 5 번) 실행하고 중간 값을 취하십시오. 새 JVM 인스턴스 (모든 벤치 마크 새 Java 호출)에서 모든 마이크로 벤치 마크를 실행하십시오. 그렇지 않으면 JVM의 최적화 효과가 나중에 실행되는 테스트에 영향을 줄 수 있습니다. 워밍업 단계에서 실행되지 않는 작업은 실행하지 마십시오 (클래스로드 및 재 컴파일을 유발할 수 있음).


7

또한 다른 구현을 비교할 때 마이크로 벤치 마크의 결과를 분석하는 것이 중요 할 수 있음에 유의해야합니다. 따라서유의성 검정해야한다.

이것은 구현 때문입니다.A구현보다 벤치 마크 실행 중에 더 빠를 수도 있습니다.B. 그러나A더 높은 스프레드를 가질 수도 있으므로 측정 된 성능 이점은 다음과 같습니다.A은 (는)와 비교할 때 아무런 의미가 없습니다.B.

따라서 마이크로 벤치 마크를 정확하게 작성하고 실행하는 것이 중요합니다. 또한 정확하게 분석해야합니다.


6

http://opt.sourceforge.net/Java Micro Benchmark - 다른 플랫폼에서 컴퓨터 시스템의 비교 성능 특성을 결정하는 데 필요한 작업을 제어합니다. 최적화 의사 결정을 안내하고 다양한 Java 구현을 비교하는 데 사용할 수 있습니다.


  • 임의의 Java 코드가 아니라 JVM + 하드웨어를 벤치마킹하는 것 같습니다. - Stefan L

5

다른 훌륭한 조언을 덧붙이려면 다음에 유의해야합니다.

일부 CPU (예 : TurboBoost가 적용된 Intel Core i5)의 경우 온도 (및 현재 사용중인 코어 수 및 사용률)가 클럭 속도에 영향을줍니다. CPU는 동적으로 클럭킹되므로 결과에 영향을 줄 수 있습니다. 예를 들어, 단일 스레드 응용 프로그램이있는 경우 모든 코어를 사용하는 응용 프로그램보다 TurboBoost가있는 최대 클럭 속도가 높습니다. 따라서 일부 시스템에서 단일 및 다중 스레드 성능의 비교를 방해 할 수 있습니다. 온도와 휘발성 물질도 터보 주파수가 유지되는 시간에 영향을 미친다는 점에 유의하십시오.

아마도 당신이 직접 제어 할 수있는보다 근본적으로 중요한 측면 : 당신이 옳은 것을 측정하고 있는지 확인하십시오! 예를 들어,System.nanoTime()특정 코드 비트를 벤치마킹하려면 관심이없는 것을 측정하는 것을 피하는 것이 바람직합니다. 예를 들어 다음과 같이하지 마십시오.

long startTime = System.nanoTime();
//code here...
System.out.println("Code took "+(System.nanoTime()-startTime)+"nano seconds");

문제는 코드가 끝나면 즉시 종료 시간을 알 수 없다는 것입니다. 대신 다음을 시도하십시오.

final long endTime, startTime = System.nanoTime();
//code here...
endTime = System.nanoTime();
System.out.println("Code took "+(endTime-startTime)+"nano seconds");

연결된 질문


관련된 질문

최근 질문