인접 인터페이스의 Java 스위치가 케이스가 추가되면 더 빨리 동작하는 것처럼 보이는 이유는 무엇입니까?
나는 그것으로서 많은 곳에서 나의 주된 프로그램 논리에서 호출되면 뜨거운 기능에 출마한다 고도로 최적화될 몇가지가 Java코드 중입니다.메인 프로그램 로직의 여러 지점에서 실행되는 핫 함수에서 실행되므로 고도로 최적화되어야 하는 자바 코드를작업하고 있습니다.이 코드의 일부는 코드의 이, 또한 multiplying한 것 일부는 다음 수를 곱하는 것과 관련이 있습니다를 포함한다.double
변수로 하다에 의해 변수다.10
임의의non-negative 임의의로 상승하게 비부정치로 상승하다int
exponent
S. 어느 빠른 방법(편집:지만 가능한 가장 빠른, 아래 2업데이트를 참조하십시오)이 번식하게 값을 가져오는 방법에 적절히 끓여라 값을 곱하는 한 가지 빠른 방법(편집:그러나 가장빠른 방법은 아님,아래 업데이트 2참조)은 다음과 같습니다 있다.switch
그 에서에exponent
:
double multiplyByPowerOfTen(final double d, final int exponent) {
switch (exponent) {
case 0:
return d;
case 1:
return d*10;
case 2:
return d*100;
// ... same pattern
case 9:
return d*1000000000;
case 10:
return d*10000000000L;
// ... same pattern with long literals
case 18:
return d*1000000000000000000L;
default:
throw new ParseException("Unhandled power of ten " + power, 0);
}
}
위의commented 타원형은상기의 코멘트 첨부 줄임표는,다음과 같은 것을나타내고 있습니다를 나타낸다.case
int
Constants 1일까지 incrementing,이 정말 19상수는 계속 1씩 증가하기 때문에 실제로는 19개가 있다 있습니다.case
S는 위의 코드 일부에서.위의코드 스니펫에 있습니다.이후 나는 나는 실제로 10의 파워가에 10의 모든 힘이 필요할지 확신이 없었는데확신이서지 않았기 때문에 필요할지 난.case
진술 진술들10
관통 스루18
, 좀 microbenchmarks 시간이 이 1000만 번의 연산을 완료하는 데 걸리는 시간을 비교한 몇 가지 마이크로 벤치마크를 실행했습니다로 10만 작전을 완료할 비교하는 달렸다.switch
대 진술 성명 댄switch
오직만으로와case
s 0
관통 스루9
((A함께와)exponent
9이하로 그 pared-down 깎은 것을이 파손되지 않게에 한하위해 9이하로 제한된다 피하기.switch
)나는 다소 놀랄 만한(나에게, 적어도!)결과는(적어도!)꽤놀라운 결과를 얻었는데 더 오래,그결과는 길수록 좋았닸다.switch
과 더 많은 더 많이case
진술들도 더 달렸다.진술이 실제로 더빨리 실행되었습니다.
종달새에 저는 그 의미를 더 종달새처럼, 나는 더 많은 것을 더하려고 노력했다를 넣으려고 했다.case
S이 것과 스위치 더 빠르게 주변 22-27을 선언했다방금 더미 값을 반환한 결과 약 22-27이 선언된 상태에서 스위치를 더 빠르게 실행할 수 있었습니다와 함께 할 수 있다는 것을 알아내더미 값으로 돌아왔다.case
S(반면 코드가 실행되는 심지어 이 더미 경우 사실을 친 적이 없다).(이러한 더미 케이스는 코드 실행 중에는 실제로 히트하지 않습니다만).(다시,(다시 말씀드리지만)case
S는 연속된 패션에 있어서는 선행 가 연속적인방법으로 추가되었다 incrementing가 추가되었다.case
에의해 정해지는에 의해 상수입니다.1
.) 이러한 실행 시간 차이가:무작위.)이러한 실행 시간 차이는 그다지 크지 않습니다 의미가 없다.랜덤의 경우exponent
0
★★★★★★★★★★★★★★★★★」10
패딩 '더미'switch
스테이트먼트는 추가되지 않은 버전의 1.54초와 비교하여 1,000만 번의 실행을 1.49초 만에 완료하여 실행당 총 5ns를 대폭 절감합니다. out, a, a, a, out, out, out, out, out, out, out, out, out, out, out, out, out, so, so, out, out, out, so so, , so, so, so, so, so, so, out, out, out,switch
최적화의 관점에서 노력할 가치가 있는 문장. 난 에 어긋난다는 걸 switch
실행 속도가 느려지는 일은 없습니다(또는 기껏해야 O(1) 시간을 일정하게 유지합니다).case
가 추가됩니다.
랜덤으로 생성되는 다양한 제한으로 실행한 결과입니다.exponent
가치.저는 그 결과를 처음부터 끝까지 포함시키지 않았습니다.1
★★★★★★★★★★★★★★★★의 경우exponent
그러나 곡선의 일반적인 모양은 동일하며 12-17 케이스 마크 주위에 능선이 있고 18-28 사이의 계곡이 있습니다.모든 테스트는 JUnitBenchmarks에서 실행되어 랜덤 값 공유 컨테이너를 사용하여 동일한 테스트 입력을 보장했습니다. 두 가장 긴 순서대로 했습니다.switch
명령과 관련된 테스트 문제의 가능성을 배제하기 위해 명령문을 짧게, 반대로 설정합니다.이 결과를 재현하고 싶은 사람이 있다면 내 테스트 코드를 github repo에 올려놨어.
래서서무?무 슨??건축이나 마이크로벤치마크 건축의 일부 변형이 있습니까? 자바가 요?switch
더 할 수 있을 것 같아요.18
로로 합니다.28
case
보다 넓다11
지까지17
업데이트: 벤치마킹 라이브러리를 충분히 청소하고 /results에 텍스트 파일을 추가했습니다.또한 가능한 한 광범위한 출력이 포함되어 있습니다.exponent
그리고 에 던지지 했습니다.Exception
부터에서default
하지만 이 결과에 영향을 미치는 것처럼 보이지 않는다그러나, 이것은 결과에 영향을 주지 않는 것 같습니다.
업데이트 2: 2009년의 이 문제에 관한 꽤 좋은 토론은, 다음의 xkcd 포럼에서 볼 수 있습니다.http://forums.xkcd.com/viewtopic.php?f=11&t=33524OP의 사용에 대한 논의Array.binarySearch()
내가 멱법 패턴의 단순한array-based 구현할 수 있는 생각을 터뜨렸다.위에서 설명한 지수 패턴의 단순한 어레이 기반 구현에 대한 아이디어를 얻었습니다.그 2진 검색을 할 필요가 없기 때문에 나는 바이너리에 항목은 무엇필요 없습니다 검색은을 잘 알고 있습니다.왜냐하면 이 엔트리가 어떤 엔트리가 있는지 알고 있기 때문입니다.array
. 그것은 약 3배 빠르다를 사용하는 것보다 달리는 것으로 보인다.이 시스템은 다른 컴퓨터보다 약 3배 빠른속도로 작동합니다.switch
일부 확실히는 제어 흐름의 비용으로 분명히,그 제어 흐름의일부를 희생하고,.switch
소이.제공. 그 코드는 github 상품 회수도 첨가되어 왔다.그코드는github repo에도 추가되었습니다.
다른 답변에서 알 수 있듯이 케이스 값은 연속적이기 때문에(스퍼스와는 반대), 다양한 테스트용으로 생성된 바이트 코드는 스위치테이블(바이트 코드명령)을 사용합니다.tableswitch
).
하면, JIT가 작업을 합니다.tableswitch
수 이 「스위치」의 「」테이블이 「스위치」의 「스위치」의 「스위치」의 「스위치」의 「스위치」의 「스위치」의 「스위치」의 「스위치」의 「스위치」의 「스위치」과 같이 변환되는 가 있습니다.스위치 테이블은, 다음과 같이 변환되는 경우가 있습니다.lookupswitch
.if
/else if
★★★★★★★★★★★★★★★★★★」
JIT(핫스팟 JDK 1.7)에 의해 생성된 어셈블리를 디컴파일하면 케이스가 17개 이하일 경우 if/else, 18개 이상일 경우 포인터 배열이 연속적으로 사용됩니다(더 효율적입니다).
이 매직 넘버 18이 사용되는 이유는 JVM 플래그의 기본값(코드의 352줄 주위)으로 귀결됩니다.
핫스팟 컴파일러 목록에서 문제를 제기했는데, 이는 과거의 테스트에서 비롯된 것으로 보입니다.벤치마킹을 더 수행한 후 이 기본값은 JDK 8에서 삭제되었습니다.
마지막으로, 이 방법이 너무 길어지면(테스트에서는 25건 이상), 디폴트 JVM 설정으로 표시되지 않게 됩니다.이것은, 그 시점에서 퍼포먼스가 저하하는 가장 큰 원인입니다.
5개의 경우 디컴파일된 코드는 다음과 같습니다(cmp/je/jg/jmp 명령, if/goto 어셈블리 주의).
[Verified Entry Point]
# {method} 'multiplyByPowerOfTen' '(DI)D' in 'javaapplication4/Test1'
# parm0: xmm0:xmm0 = double
# parm1: rdx = int
# [sp+0x20] (sp of caller)
0x00000000024f0160: mov DWORD PTR [rsp-0x6000],eax
; {no_reloc}
0x00000000024f0167: push rbp
0x00000000024f0168: sub rsp,0x10 ;*synchronization entry
; - javaapplication4.Test1::multiplyByPowerOfTen@-1 (line 56)
0x00000000024f016c: cmp edx,0x3
0x00000000024f016f: je 0x00000000024f01c3
0x00000000024f0171: cmp edx,0x3
0x00000000024f0174: jg 0x00000000024f01a5
0x00000000024f0176: cmp edx,0x1
0x00000000024f0179: je 0x00000000024f019b
0x00000000024f017b: cmp edx,0x1
0x00000000024f017e: jg 0x00000000024f0191
0x00000000024f0180: test edx,edx
0x00000000024f0182: je 0x00000000024f01cb
0x00000000024f0184: mov ebp,edx
0x00000000024f0186: mov edx,0x17
0x00000000024f018b: call 0x00000000024c90a0 ; OopMap{off=48}
;*new ; - javaapplication4.Test1::multiplyByPowerOfTen@72 (line 83)
; {runtime_call}
0x00000000024f0190: int3 ;*new ; - javaapplication4.Test1::multiplyByPowerOfTen@72 (line 83)
0x00000000024f0191: mulsd xmm0,QWORD PTR [rip+0xffffffffffffffa7] # 0x00000000024f0140
;*dmul
; - javaapplication4.Test1::multiplyByPowerOfTen@52 (line 62)
; {section_word}
0x00000000024f0199: jmp 0x00000000024f01cb
0x00000000024f019b: mulsd xmm0,QWORD PTR [rip+0xffffffffffffff8d] # 0x00000000024f0130
;*dmul
; - javaapplication4.Test1::multiplyByPowerOfTen@46 (line 60)
; {section_word}
0x00000000024f01a3: jmp 0x00000000024f01cb
0x00000000024f01a5: cmp edx,0x5
0x00000000024f01a8: je 0x00000000024f01b9
0x00000000024f01aa: cmp edx,0x5
0x00000000024f01ad: jg 0x00000000024f0184 ;*tableswitch
; - javaapplication4.Test1::multiplyByPowerOfTen@1 (line 56)
0x00000000024f01af: mulsd xmm0,QWORD PTR [rip+0xffffffffffffff81] # 0x00000000024f0138
;*dmul
; - javaapplication4.Test1::multiplyByPowerOfTen@64 (line 66)
; {section_word}
0x00000000024f01b7: jmp 0x00000000024f01cb
0x00000000024f01b9: mulsd xmm0,QWORD PTR [rip+0xffffffffffffff67] # 0x00000000024f0128
;*dmul
; - javaapplication4.Test1::multiplyByPowerOfTen@70 (line 68)
; {section_word}
0x00000000024f01c1: jmp 0x00000000024f01cb
0x00000000024f01c3: mulsd xmm0,QWORD PTR [rip+0xffffffffffffff55] # 0x00000000024f0120
;*tableswitch
; - javaapplication4.Test1::multiplyByPowerOfTen@1 (line 56)
; {section_word}
0x00000000024f01cb: add rsp,0x10
0x00000000024f01cf: pop rbp
0x00000000024f01d0: test DWORD PTR [rip+0xfffffffffdf3fe2a],eax # 0x0000000000430000
; {poll_return}
0x00000000024f01d6: ret
경우 하여 모든합니다: 18개의 포인터 배열을 참조해 주십시오).jmp QWORD PTR [r8+r10*1]
올바른 곱셈으로 바로 이동) - 이것이 퍼포먼스가 향상되는 이유일 수 있습니다.
[Verified Entry Point]
# {method} 'multiplyByPowerOfTen' '(DI)D' in 'javaapplication4/Test1'
# parm0: xmm0:xmm0 = double
# parm1: rdx = int
# [sp+0x20] (sp of caller)
0x000000000287fe20: mov DWORD PTR [rsp-0x6000],eax
; {no_reloc}
0x000000000287fe27: push rbp
0x000000000287fe28: sub rsp,0x10 ;*synchronization entry
; - javaapplication4.Test1::multiplyByPowerOfTen@-1 (line 56)
0x000000000287fe2c: cmp edx,0x13
0x000000000287fe2f: jae 0x000000000287fe46
0x000000000287fe31: movsxd r10,edx
0x000000000287fe34: shl r10,0x3
0x000000000287fe38: movabs r8,0x287fd70 ; {section_word}
0x000000000287fe42: jmp QWORD PTR [r8+r10*1] ;*tableswitch
; - javaapplication4.Test1::multiplyByPowerOfTen@1 (line 56)
0x000000000287fe46: mov ebp,edx
0x000000000287fe48: mov edx,0x31
0x000000000287fe4d: xchg ax,ax
0x000000000287fe4f: call 0x00000000028590a0 ; OopMap{off=52}
;*new ; - javaapplication4.Test1::multiplyByPowerOfTen@202 (line 96)
; {runtime_call}
0x000000000287fe54: int3 ;*new ; - javaapplication4.Test1::multiplyByPowerOfTen@202 (line 96)
0x000000000287fe55: mulsd xmm0,QWORD PTR [rip+0xfffffffffffffe8b] # 0x000000000287fce8
;*dmul
; - javaapplication4.Test1::multiplyByPowerOfTen@194 (line 92)
; {section_word}
0x000000000287fe5d: jmp 0x000000000287ff16
0x000000000287fe62: mulsd xmm0,QWORD PTR [rip+0xfffffffffffffe86] # 0x000000000287fcf0
;*dmul
; - javaapplication4.Test1::multiplyByPowerOfTen@188 (line 90)
; {section_word}
0x000000000287fe6a: jmp 0x000000000287ff16
0x000000000287fe6f: mulsd xmm0,QWORD PTR [rip+0xfffffffffffffe81] # 0x000000000287fcf8
;*dmul
; - javaapplication4.Test1::multiplyByPowerOfTen@182 (line 88)
; {section_word}
0x000000000287fe77: jmp 0x000000000287ff16
0x000000000287fe7c: mulsd xmm0,QWORD PTR [rip+0xfffffffffffffe7c] # 0x000000000287fd00
;*dmul
; - javaapplication4.Test1::multiplyByPowerOfTen@176 (line 86)
; {section_word}
0x000000000287fe84: jmp 0x000000000287ff16
0x000000000287fe89: mulsd xmm0,QWORD PTR [rip+0xfffffffffffffe77] # 0x000000000287fd08
;*dmul
; - javaapplication4.Test1::multiplyByPowerOfTen@170 (line 84)
; {section_word}
0x000000000287fe91: jmp 0x000000000287ff16
0x000000000287fe96: mulsd xmm0,QWORD PTR [rip+0xfffffffffffffe72] # 0x000000000287fd10
;*dmul
; - javaapplication4.Test1::multiplyByPowerOfTen@164 (line 82)
; {section_word}
0x000000000287fe9e: jmp 0x000000000287ff16
0x000000000287fea0: mulsd xmm0,QWORD PTR [rip+0xfffffffffffffe70] # 0x000000000287fd18
;*dmul
; - javaapplication4.Test1::multiplyByPowerOfTen@158 (line 80)
; {section_word}
0x000000000287fea8: jmp 0x000000000287ff16
0x000000000287feaa: mulsd xmm0,QWORD PTR [rip+0xfffffffffffffe6e] # 0x000000000287fd20
;*dmul
; - javaapplication4.Test1::multiplyByPowerOfTen@152 (line 78)
; {section_word}
0x000000000287feb2: jmp 0x000000000287ff16
0x000000000287feb4: mulsd xmm0,QWORD PTR [rip+0xfffffffffffffe24] # 0x000000000287fce0
;*dmul
; - javaapplication4.Test1::multiplyByPowerOfTen@146 (line 76)
; {section_word}
0x000000000287febc: jmp 0x000000000287ff16
0x000000000287febe: mulsd xmm0,QWORD PTR [rip+0xfffffffffffffe6a] # 0x000000000287fd30
;*dmul
; - javaapplication4.Test1::multiplyByPowerOfTen@140 (line 74)
; {section_word}
0x000000000287fec6: jmp 0x000000000287ff16
0x000000000287fec8: mulsd xmm0,QWORD PTR [rip+0xfffffffffffffe68] # 0x000000000287fd38
;*dmul
; - javaapplication4.Test1::multiplyByPowerOfTen@134 (line 72)
; {section_word}
0x000000000287fed0: jmp 0x000000000287ff16
0x000000000287fed2: mulsd xmm0,QWORD PTR [rip+0xfffffffffffffe66] # 0x000000000287fd40
;*dmul
; - javaapplication4.Test1::multiplyByPowerOfTen@128 (line 70)
; {section_word}
0x000000000287feda: jmp 0x000000000287ff16
0x000000000287fedc: mulsd xmm0,QWORD PTR [rip+0xfffffffffffffe64] # 0x000000000287fd48
;*dmul
; - javaapplication4.Test1::multiplyByPowerOfTen@122 (line 68)
; {section_word}
0x000000000287fee4: jmp 0x000000000287ff16
0x000000000287fee6: mulsd xmm0,QWORD PTR [rip+0xfffffffffffffe62] # 0x000000000287fd50
;*dmul
; - javaapplication4.Test1::multiplyByPowerOfTen@116 (line 66)
; {section_word}
0x000000000287feee: jmp 0x000000000287ff16
0x000000000287fef0: mulsd xmm0,QWORD PTR [rip+0xfffffffffffffe60] # 0x000000000287fd58
;*dmul
; - javaapplication4.Test1::multiplyByPowerOfTen@110 (line 64)
; {section_word}
0x000000000287fef8: jmp 0x000000000287ff16
0x000000000287fefa: mulsd xmm0,QWORD PTR [rip+0xfffffffffffffe5e] # 0x000000000287fd60
;*dmul
; - javaapplication4.Test1::multiplyByPowerOfTen@104 (line 62)
; {section_word}
0x000000000287ff02: jmp 0x000000000287ff16
0x000000000287ff04: mulsd xmm0,QWORD PTR [rip+0xfffffffffffffe5c] # 0x000000000287fd68
;*dmul
; - javaapplication4.Test1::multiplyByPowerOfTen@98 (line 60)
; {section_word}
0x000000000287ff0c: jmp 0x000000000287ff16
0x000000000287ff0e: mulsd xmm0,QWORD PTR [rip+0xfffffffffffffe12] # 0x000000000287fd28
;*tableswitch
; - javaapplication4.Test1::multiplyByPowerOfTen@1 (line 56)
; {section_word}
0x000000000287ff16: add rsp,0x10
0x000000000287ff1a: pop rbp
0x000000000287ff1b: test DWORD PTR [rip+0xfffffffffd9b00df],eax # 0x0000000000230000
; {poll_return}
0x000000000287ff21: ret
의 케이스가 있는 케이스와 보입니다.movapd xmm0,xmm1
@cHao에서 알 수 있듯이 코드 중간으로 표시됩니다.단, 퍼포먼스가 저하되는 가장 큰 이유는 메서드가 너무 길어서 기본 JVM 설정으로 인라인화할 수 없기 때문입니다.
[Verified Entry Point]
# {method} 'multiplyByPowerOfTen' '(DI)D' in 'javaapplication4/Test1'
# parm0: xmm0:xmm0 = double
# parm1: rdx = int
# [sp+0x20] (sp of caller)
0x0000000002524560: mov DWORD PTR [rsp-0x6000],eax
; {no_reloc}
0x0000000002524567: push rbp
0x0000000002524568: sub rsp,0x10 ;*synchronization entry
; - javaapplication4.Test1::multiplyByPowerOfTen@-1 (line 56)
0x000000000252456c: movapd xmm1,xmm0
0x0000000002524570: cmp edx,0x1f
0x0000000002524573: jae 0x0000000002524592 ;*tableswitch
; - javaapplication4.Test1::multiplyByPowerOfTen@1 (line 56)
0x0000000002524575: movsxd r10,edx
0x0000000002524578: shl r10,0x3
0x000000000252457c: mulsd xmm0,QWORD PTR [rip+0xfffffffffffffe3c] # 0x00000000025243c0
;*dmul
; - javaapplication4.Test1::multiplyByPowerOfTen@364 (line 118)
; {section_word}
0x0000000002524584: movabs r8,0x2524450 ; {section_word}
0x000000000252458e: jmp QWORD PTR [r8+r10*1] ;*tableswitch
; - javaapplication4.Test1::multiplyByPowerOfTen@1 (line 56)
0x0000000002524592: mov ebp,edx
0x0000000002524594: mov edx,0x31
0x0000000002524599: xchg ax,ax
0x000000000252459b: call 0x00000000024f90a0 ; OopMap{off=64}
;*new ; - javaapplication4.Test1::multiplyByPowerOfTen@370 (line 120)
; {runtime_call}
0x00000000025245a0: int3 ;*new ; - javaapplication4.Test1::multiplyByPowerOfTen@370 (line 120)
0x00000000025245a1: mulsd xmm0,QWORD PTR [rip+0xfffffffffffffe27] # 0x00000000025243d0
;*dmul
; - javaapplication4.Test1::multiplyByPowerOfTen@358 (line 116)
; {section_word}
0x00000000025245a9: jmp 0x0000000002524744
0x00000000025245ae: mulsd xmm0,QWORD PTR [rip+0xfffffffffffffe22] # 0x00000000025243d8
;*dmul
; - javaapplication4.Test1::multiplyByPowerOfTen@348 (line 114)
; {section_word}
0x00000000025245b6: jmp 0x0000000002524744
0x00000000025245bb: mulsd xmm0,QWORD PTR [rip+0xfffffffffffffe1d] # 0x00000000025243e0
;*dmul
; - javaapplication4.Test1::multiplyByPowerOfTen@338 (line 112)
; {section_word}
0x00000000025245c3: jmp 0x0000000002524744
0x00000000025245c8: mulsd xmm0,QWORD PTR [rip+0xfffffffffffffe18] # 0x00000000025243e8
;*dmul
; - javaapplication4.Test1::multiplyByPowerOfTen@328 (line 110)
; {section_word}
0x00000000025245d0: jmp 0x0000000002524744
0x00000000025245d5: mulsd xmm0,QWORD PTR [rip+0xfffffffffffffe13] # 0x00000000025243f0
;*dmul
; - javaapplication4.Test1::multiplyByPowerOfTen@318 (line 108)
; {section_word}
0x00000000025245dd: jmp 0x0000000002524744
0x00000000025245e2: mulsd xmm0,QWORD PTR [rip+0xfffffffffffffe0e] # 0x00000000025243f8
;*dmul
; - javaapplication4.Test1::multiplyByPowerOfTen@308 (line 106)
; {section_word}
0x00000000025245ea: jmp 0x0000000002524744
0x00000000025245ef: mulsd xmm0,QWORD PTR [rip+0xfffffffffffffe09] # 0x0000000002524400
;*dmul
; - javaapplication4.Test1::multiplyByPowerOfTen@298 (line 104)
; {section_word}
0x00000000025245f7: jmp 0x0000000002524744
0x00000000025245fc: mulsd xmm0,QWORD PTR [rip+0xfffffffffffffe04] # 0x0000000002524408
;*dmul
; - javaapplication4.Test1::multiplyByPowerOfTen@288 (line 102)
; {section_word}
0x0000000002524604: jmp 0x0000000002524744
0x0000000002524609: mulsd xmm0,QWORD PTR [rip+0xfffffffffffffdff] # 0x0000000002524410
;*dmul
; - javaapplication4.Test1::multiplyByPowerOfTen@278 (line 100)
; {section_word}
0x0000000002524611: jmp 0x0000000002524744
0x0000000002524616: mulsd xmm0,QWORD PTR [rip+0xfffffffffffffdfa] # 0x0000000002524418
;*dmul
; - javaapplication4.Test1::multiplyByPowerOfTen@268 (line 98)
; {section_word}
0x000000000252461e: jmp 0x0000000002524744
0x0000000002524623: mulsd xmm0,QWORD PTR [rip+0xfffffffffffffd9d] # 0x00000000025243c8
;*dmul
; - javaapplication4.Test1::multiplyByPowerOfTen@258 (line 96)
; {section_word}
0x000000000252462b: jmp 0x0000000002524744
0x0000000002524630: movapd xmm0,xmm1
0x0000000002524634: mulsd xmm0,QWORD PTR [rip+0xfffffffffffffe0c] # 0x0000000002524448
;*dmul
; - javaapplication4.Test1::multiplyByPowerOfTen@242 (line 92)
; {section_word}
0x000000000252463c: jmp 0x0000000002524744
0x0000000002524641: movapd xmm0,xmm1
0x0000000002524645: mulsd xmm0,QWORD PTR [rip+0xfffffffffffffddb] # 0x0000000002524428
;*dmul
; - javaapplication4.Test1::multiplyByPowerOfTen@236 (line 90)
; {section_word}
0x000000000252464d: jmp 0x0000000002524744
0x0000000002524652: movapd xmm0,xmm1
0x0000000002524656: mulsd xmm0,QWORD PTR [rip+0xfffffffffffffdd2] # 0x0000000002524430
;*dmul
; - javaapplication4.Test1::multiplyByPowerOfTen@230 (line 88)
; {section_word}
0x000000000252465e: jmp 0x0000000002524744
0x0000000002524663: movapd xmm0,xmm1
0x0000000002524667: mulsd xmm0,QWORD PTR [rip+0xfffffffffffffdc9] # 0x0000000002524438
;*dmul
; - javaapplication4.Test1::multiplyByPowerOfTen@224 (line 86)
; {section_word}
[etc.]
0x0000000002524744: add rsp,0x10
0x0000000002524748: pop rbp
0x0000000002524749: test DWORD PTR [rip+0xfffffffffde1b8b1],eax # 0x0000000000340000
; {poll_return}
0x000000000252474f: ret
스위치 - 케이스 값이 좁은 범위 Eg에 배치될 경우 케이스가 더 빠릅니다.
case 1:
case 2:
case 3:
..
..
case n:
왜냐하면 이 경우 컴파일러는 스위치스테이트먼트의 모든 케이스 레그에 대해 비교를 회피할 수 있기 때문입니다.컴파일러는 다른 레그에서 수행할 액션의 주소를 포함하는 점프 테이블을 만듭니다.스위치가 실행되고 있는 값은 에 대한 인덱스로 변환되도록 조작됩니다.이 실장에서는 switch 스테이트먼트에 걸리는 시간은 동등한 if-else-if 스테이트먼트에 걸리는 시간보다 훨씬 짧습니다.또, switch 스테이트먼트에 걸리는 시간은, switch 스테이트먼트의 케이스 레그의 수와 무관합니다.
위키피디아에서 컴파일 섹션의 스위치 문에 대해 기술한 바와 같습니다.
입력값의 범위가 식별 가능한 '작고' 몇 개의 갭만 있는 경우, 옵티마이저를 내장한 일부 컴파일러는 실제로 일련의 긴 조건부 명령 대신 분기 테이블 또는 색인화된 함수 포인터의 배열로서 스위치 문을 구현할 수 있다.이것에 의해, 스위치문은 비교 리스트를 참조하지 않고, 실행할 브랜치를 곧바로 결정할 수 있습니다.
답은 바이트 코드에 있습니다.
SwitchTest10.java
public class SwitchTest10 {
public static void main(String[] args) {
int n = 0;
switcher(n);
}
public static void switcher(int n) {
switch(n) {
case 0: System.out.println(0);
break;
case 1: System.out.println(1);
break;
case 2: System.out.println(2);
break;
case 3: System.out.println(3);
break;
case 4: System.out.println(4);
break;
case 5: System.out.println(5);
break;
case 6: System.out.println(6);
break;
case 7: System.out.println(7);
break;
case 8: System.out.println(8);
break;
case 9: System.out.println(9);
break;
case 10: System.out.println(10);
break;
default: System.out.println("test");
}
}
}
해당하는 바이트 코드. 관련 부품만 표시됨:
public static void switcher(int);
Code:
0: iload_0
1: tableswitch{ //0 to 10
0: 60;
1: 70;
2: 80;
3: 90;
4: 100;
5: 110;
6: 120;
7: 131;
8: 142;
9: 153;
10: 164;
default: 175 }
SwitchTest22.java:
public class SwitchTest22 {
public static void main(String[] args) {
int n = 0;
switcher(n);
}
public static void switcher(int n) {
switch(n) {
case 0: System.out.println(0);
break;
case 1: System.out.println(1);
break;
case 2: System.out.println(2);
break;
case 3: System.out.println(3);
break;
case 4: System.out.println(4);
break;
case 5: System.out.println(5);
break;
case 6: System.out.println(6);
break;
case 7: System.out.println(7);
break;
case 8: System.out.println(8);
break;
case 9: System.out.println(9);
break;
case 100: System.out.println(10);
break;
case 110: System.out.println(10);
break;
case 120: System.out.println(10);
break;
case 130: System.out.println(10);
break;
case 140: System.out.println(10);
break;
case 150: System.out.println(10);
break;
case 160: System.out.println(10);
break;
case 170: System.out.println(10);
break;
case 180: System.out.println(10);
break;
case 190: System.out.println(10);
break;
case 200: System.out.println(10);
break;
case 210: System.out.println(10);
break;
case 220: System.out.println(10);
break;
default: System.out.println("test");
}
}
}
대응하는 바이트 코드입니다.다시 말씀드리지만, 관련된 부분만 표시되어 있습니다.
public static void switcher(int);
Code:
0: iload_0
1: lookupswitch{ //23
0: 196;
1: 206;
2: 216;
3: 226;
4: 236;
5: 246;
6: 256;
7: 267;
8: 278;
9: 289;
100: 300;
110: 311;
120: 322;
130: 333;
140: 344;
150: 355;
160: 366;
170: 377;
180: 388;
190: 399;
200: 410;
210: 421;
220: 432;
default: 443 }
경우 는 '''를 합니다.tableswitch
컴파일된 는 " " "를 lookupswitch
»tableswitch
스택 상단의 정수값을 사용하여 테이블에 인덱스를 붙이고 브랜치 또는 타깃을 찾습니다.점프/브런치는 즉시 실행된다.은 「」입니다.O(1)
★★★★★★ 。
A lookupswitch
더 복잡합니다.이 경우 올바른 키를 찾을 때까지 정수 값을 테이블 내의 모든 키와 비교해야 합니다.키가 발견되면 (이 키가 매핑된) 분기/점프 타깃이 점프로 사용됩니다.에서 lookupswitch
는 정렬되어 바이너리 검색 알고리즘을 사용하여 올바른 키를 찾을 수 있습니다.는 「」입니다.O(log n)
그 전 도 역시 전 is is , , , , , , , also 。O(log n)
는 아직 '점프'이기O(1)
sparse 직접 수 에 먼저 올바른 sparse range는 다음과 같습니다.
sparse만 tableswitch
사용하는 경우 으로 ""가 포함되어 있습니다.이 엔트리는 " Entry"를 있습니다.default
의 마지막 엔트리가 " "의 마지막 엔트리가 " "라고 합니다.SwitchTest10.java
21
10
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , .
public static void switcher(int);
Code:
0: iload_0
1: tableswitch{ //0 to 21
0: 104;
1: 114;
2: 124;
3: 134;
4: 144;
5: 154;
6: 164;
7: 175;
8: 186;
9: 197;
10: 219;
11: 219;
12: 219;
13: 219;
14: 219;
15: 219;
16: 219;
17: 219;
18: 219;
19: 219;
20: 219;
21: 208;
default: 219 }
한 이 큰은 갭의 .이 테이블은 브런치 타겟을 가리키고 있습니다.default
설명.설령 없다 해도default
스위치 블록 뒤의 순서를 나타내는 엔트리가 포함됩니다.기본적인 테스트를 몇 가지 실시했는데, 마지막 지수와 이전 지수의 차이가 있는 경우(9
큼35
, 을합니다.lookupswitch
tableswitch
의 switch
스테이트먼트는 Java Virtual Machine Specification(© 3.10)에 정의되어 있습니다.
스위치의 케이스가 희박한 경우 테이블 스위치명령어의 테이블 표현은 공간 면에서 비효율적입니다.대신 조회 스위치 명령을 사용할 수 있습니다.조회 스위치 명령은 테이블의 대상 오프셋과 키(케이스 레이블 값)를 쌍을 이룹니다.룩업 스위치명령어를 실행하면 스위치의 식 값이 테이블 내의 키와 비교됩니다.키 중 하나가 식 값과 일치하면 연관된 타깃오프셋에서 실행이 계속됩니다.일치하는 키가 없으면 기본 대상에서 실행을 계속합니다. [...]
질문에 대한 답은 이미 나왔기 때문에 몇 가지 힌트를 드리겠습니다.사용하다
private static final double[] mul={1d, 10d...};
static double multiplyByPowerOfTen(final double d, final int exponent) {
if (exponent<0 || exponent>=mul.length) throw new ParseException();//or just leave the IOOBE be
return mul[exponent]*d;
}
이 코드는 훨씬 적은 IC(명령 캐시)를 사용하며 항상 인라인화됩니다.코드가 핫할 경우 어레이는 L1 데이터 캐시에 있습니다.룩업 테이블은 거의 항상 성공입니다.(특히 micro benchmark의 경우:D )
을 핫인 는, 「」등의 .throw new ParseException()
최소값으로 짧게 하거나 별도의 정적 방법으로 이동합니다(최소값으로 짧게 합니다).은 ★★★★★★★★★★★★★★★★입니다.throw new ParseException("Unhandled power of ten " + power, 0);
약한 아이디어 b/c는 해석만 가능한 코드의 인라인 버젯을 많이 소비합니다.문자열 연결은 바이트 코드로 매우 상세합니다.Array List를 통한 상세 정보 및 실제 사례
javac 소스를 기반으로 스위치가 사용하는 방법으로 스위치를 쓸 수 있습니다.tableswitch
.
javac source의 계산을 사용하여 두 번째 예시의 비용을 계산할 수 있습니다.
lo = 0
hi = 220
nlabels = 24
table_space_cost = 4 + hi - lo + 1
table_time_cost = 3
lookup_space_cost = 3 + 2 * nlabels
lookup_time_cost = nlabels
table_cost = table_space_cost + 3 * table_time_cost // 234
lookup_cost = lookup_space_cost + 3 * lookup_time_cos // 123
여기서는 테이블스위치 비용이 룩업스위치(123)보다 높기 때문에 룩업스위치가 이 스위치문의 opcode로 선택됩니다.
언급URL : https://stackoverflow.com/questions/15621083/why-does-java-switch-on-contiguous-ints-appear-to-run-faster-with-added-cases
'programing' 카테고리의 다른 글
Linux에서 시간 측정 - 시간 vs 클럭 vs getrusage vs clock_gettime vs gettime vs timespec_get? (0) | 2022.08.15 |
---|---|
nuxt Auth Module과 vuex-persist의 비교 가능성 문제가 있습니까? (0) | 2022.08.15 |
파이어폭스에서 Vuejs 이벤트가 작동하지 않음 - Chrome에서는 정상 (0) | 2022.08.15 |
printf를 사용하여 문자를 반복하는 방법 (0) | 2022.08.15 |
RegisterServiceWorker.js에서 Vue 앱 $refs.components 또는 Vuex $store 메서드를 호출하는 방법 (0) | 2022.08.14 |