Java에서 올바른 마이크로 벤치 마크를 작성하려면 어떻게해야합니까?
Java에서 올바른 마이크로 벤치 마크를 어떻게 작성하고 실행합니까?
생각할 여러 가지를 설명하는 몇 가지 코드 샘플과 주석을 찾고 있습니다.
예 : 벤치 마크는 시간 / 반복 또는 반복 / 시간을 측정해야하며 그 이유는 무엇입니까?
관련 : 스톱워치 벤치마킹이 허용됩니까?
답변
Java HotSpot 제작자의 마이크로 벤치 마크 작성에 대한 팁 :
규칙 0 : JVM 및 마이크로 벤치마킹에 대한 평판 좋은 논문을 읽으십시오. 좋은 사람은 Brian Goetz, 2005 입니다. 마이크로 벤치 마크에서 너무 많은 것을 기대하지 마십시오. 제한된 범위의 JVM 성능 특성 만 측정합니다.
규칙 1 : 타이밍 단계 전에 모든 초기화 및 컴파일을 트리거하기에 충분한 테스트 커널을 실행하는 준비 단계를 항상 포함합니다. (워밍업 단계에서는 반복 횟수를 줄여도 좋습니다. 경험상 수만 번의 내부 루프 반복을 사용하는 것이 좋습니다.)
규칙 2 : 항상 실행 -XX:+PrintCompilation
, -verbose:gc
당신은 컴파일러와 JVM의 다른 부분은 타이밍 단계에서 예상치 못한 일을하지 않는 것을 확인할 수 있도록, 등.
규칙 2.1 : 타이밍 및 워밍업 단계의 시작과 끝에서 메시지를 인쇄하여 타이밍 단계 중에 규칙 2의 출력이 없는지 확인할 수 있습니다.
규칙 3 :-client
및 -server
, OSR 및 일반 편집 의 차이점을 인식하십시오 . -XX:+PrintCompilation
플래그는 예를 들어, 비 초기 진입 점을 표시하기에 - 기호 OSR 컴파일을보고합니다 Trouble$1::run @ 2 (41 bytes)
. 최상의 성능을 원한다면 서버보다 클라이언트를 선호하고 OSR을 정기적으로 선호하십시오.
규칙 4 : 초기화 효과에 유의하십시오. 인쇄는 클래스를로드하고 초기화하므로 타이밍 단계에서 처음으로 인쇄하지 마십시오. 특별히 클래스로드를 테스트하지 않는 한 (그리고이 경우 테스트 클래스 만로드) 준비 단계 (또는 최종보고 단계) 외부에서 새 클래스를로드하지 마십시오. 규칙 2는 이러한 효과에 대한 첫 번째 방어선입니다.
규칙 5 : 최적화 해제 및 재 컴파일 효과에 유의하십시오. 타이밍 단계에서 처음으로 코드 경로를 사용하지 마십시오. 컴파일러가 경로가 전혀 사용되지 않을 것이라는 이전의 낙관적 가정을 기반으로 코드를 정크 및 재 컴파일 할 수 있기 때문입니다. 규칙 2는 이러한 효과에 대한 첫 번째 방어선입니다.
규칙 6 : 적절한 도구를 사용하여 컴파일러의 마음을 읽고 그것이 생성하는 코드에 놀라게 될 것입니다. 무언가를 더 빠르게 또는 더 느리게 만드는 것에 대한 이론을 형성하기 전에 코드를 직접 검사하십시오.
규칙 7 : 측정에서 노이즈를 줄이십시오. 조용한 시스템에서 벤치 마크를 실행하고 여러 번 실행하여 이상 값을 제거합니다. -Xbatch
응용 프로그램과 함께 컴파일러를 직렬화하는 데 사용 하고 컴파일러 -XX:CICompilerCount=1
가 자체적으로 병렬로 실행되지 않도록 설정 하는 것을 고려 하십시오. 최선을 다해 GC 오버 헤드를 줄이고 Xmx
(충분히 크게) 동일하게 설정 Xms
하고 가능한 UseEpsilonGC경우 사용하십시오.
규칙 8 : 벤치 마크에 라이브러리를 사용하십시오. 아마도 더 효율적이고이 유일한 목적을 위해 이미 디버깅 되었기 때문입니다. 같은 JMH , 캘리퍼스 또는 빌과 자바에 대한 바울의 우수한 UCSD 벤치 마크 .
이 질문이 답변 된 것으로 표시되었지만 마이크로 벤치 마크를 작성하는 데 도움이되는 두 개의 라이브러리를 언급하고 싶습니다.
Google의 Caliper
시작하기 튜토리얼
- http://codingjunkie.net/micro-benchmarking-with-caliper/
- http://vertexlabs.co.uk/blog/caliper
OpenJDK의 JMH
시작하기 튜토리얼
- JVM에서 벤치마킹 함정 방지
- Java Microbenchmarking에 JMH 사용
- JMH 소개
Java 벤치 마크의 중요한 사항은 다음과 같습니다.
- 코드를 여러 번 실행하여 먼저 JIT를 예열 시간이 초과되기까지의 시간 을
- 결과를 몇 초 또는 (더 나은) 수십 초 내에 측정 할 수있을만큼 충분히 오래 실행해야합니다.
System.gc()
반복 사이에 호출 할 수는 없지만 테스트 사이에 실행하여 각 테스트가 작업 할 "깨끗한"메모리 공간을 확보 할 수 있도록하는 것이 좋습니다. (예,gc()
보증 이라기보다는 힌트에 가깝지만 제 경험으로는 실제로 가비지 수집이 될 가능성 이 큽니다 .)- 나는 반복과 시간을 표시하는 것을 좋아하며, "최고"알고리즘이 1.0의 점수를 얻고 다른 알고리즘은 상대적인 방식으로 점수를 매길 수 있도록 시간 / 반복 점수를 조정할 수 있습니다. 즉 , 반복 횟수와 시간을 변경하면서 오랜 시간 동안 모든 알고리즘을 실행할 수 있지만 여전히 비슷한 결과를 얻을 수 있습니다.
.NET의 벤치마킹 프레임 워크 설계에 대해 블로그를 작성하는 중입니다. 내가있어 부부 의 이전 게시물 몇 가지 아이디어를 제공 할 수 있습니다 - 모든 것이 물론 적절한 것, 그러나 그것의 일부가 될 수있다.
jmh 는 최근 OpenJDK에 추가되었으며 Oracle의 일부 성능 엔지니어가 작성했습니다. 확실히 볼 가치가 있습니다.
jmh는 Java 및 JVM을 대상으로하는 기타 언어로 작성된 나노 / 마이크로 / 매크로 벤치 마크를 빌드, 실행 및 분석하기위한 Java 하네스입니다.
샘플 테스트 주석에 묻혀있는 매우 흥미로운 정보 입니다.
또한보십시오:
- JVM에서 벤치마킹 함정 방지
- jmh의 주요 강점에 대한 토론 .
벤치 마크는 시간 / 반복 또는 반복 / 시간을 측정해야하며 그 이유는 무엇입니까?
이에 따라 무엇을 당신이 시험에 노력하고 있습니다.
지연 시간 에 관심이있는 경우 시간 / 반복을 사용 하고 처리량에 관심이있는 경우 반복 / 시간을 사용합니다.
두 알고리즘을 비교하려는 경우 순서를 번갈아 가며 각각에 대해 최소 두 개의 벤치 마크를 수행하십시오. 즉 :
for(i=1..n)
alg1();
for(i=1..n)
alg2();
for(i=1..n)
alg2();
for(i=1..n)
alg1();
다른 패스에서 동일한 알고리즘의 런타임에서 몇 가지 눈에 띄는 차이 (때로는 5-10 %)를 발견했습니다.
또한 n 이 매우 큰지 확인 하여 각 루프의 런타임이 10 초 정도가되도록하십시오. 반복 횟수가 많을수록 벤치 마크 시간에 더 중요한 수치가 표시되고 데이터의 신뢰성이 높아집니다.
벤치 마크 코드에서 계산 된 결과를 어떻게 든 사용하는지 확인하십시오. 그렇지 않으면 코드를 최적화 할 수 있습니다.
자바로 마이크로 벤치 마크를 작성하는 데는 많은 잠재적 인 함정이 있습니다.
첫째, 시간이 다소 무작위로 걸리는 모든 종류의 이벤트로 계산해야합니다 : 가비지 수집, 캐싱 효과 (파일 용 OS 및 메모리 용 CPU), IO 등.
둘째 : 매우 짧은 간격 동안 측정 된 시간의 정확성을 신뢰할 수 없습니다.
셋째 : JVM은 실행하는 동안 코드를 최적화합니다. 따라서 동일한 JVM 인스턴스에서 다른 실행이 더 빠르고 빨라질 것입니다.
내 권장 사항 : 벤치 마크를 몇 초 동안 실행하십시오. 이는 밀리 초 이상의 런타임보다 더 안정적입니다. JVM 워밍업 (측정하지 않고 벤치 마크를 한 번 이상 실행하면 JVM이 최적화를 실행할 수 있음). 벤치 마크를 여러 번 (아마도 5 번) 실행하고 중앙값을 취하십시오. 새 JVM 인스턴스에서 모든 마이크로 벤치 마크를 실행합니다 (모든 벤치 마크 새 Java에 대해 호출). 그렇지 않으면 JVM의 최적화 효과가 나중에 실행되는 테스트에 영향을 미칠 수 있습니다. 워밍업 단계에서 실행되지 않는 것은 실행하지 마십시오 (클래스로드 및 재 컴파일을 트리거 할 수 있으므로).
다른 구현을 비교할 때 마이크로 벤치 마크의 결과를 분석하는 것도 중요 할 수 있습니다. 따라서 유의성 테스트 가 이루어져야합니다.
이는 A
대부분의 벤치 마크 실행 중에 구현 이 구현 보다 더 빠를 수 있기 때문 B
입니다. 그러나 A
의 측정 성능 이점이 있으므로 또한, 높은 확산을 가질 수 A
와 비교했을 때 어떤 의미가되지 않습니다 B
.
따라서 마이크로 벤치 마크를 올바르게 작성하고 실행하는 것뿐만 아니라 올바르게 분석하는 것도 중요합니다.
다른 훌륭한 조언에 추가하기 위해 다음 사항도 염두에 두어야합니다.
일부 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");
http://opt.sourceforge.net/Java Micro Benchmark-서로 다른 플랫폼에서 컴퓨터 시스템의 비교 성능 특성을 결정하는 데 필요한 제어 작업입니다. 최적화 결정을 안내하고 다양한 Java 구현을 비교하는 데 사용할 수 있습니다.