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