programing

인접 인터페이스의 Java 스위치가 케이스가 추가되면 더 빨리 동작하는 것처럼 보이는 이유는 무엇입니까?

bestcode 2022. 8. 15. 21:13
반응형

인접 인터페이스의 Java 스위치가 케이스가 추가되면 더 빨리 동작하는 것처럼 보이는 이유는 무엇입니까?

나는 그것으로서 많은 곳에서 나의 주된 프로그램 논리에서 호출되면 뜨거운 기능에 출마한다 고도로 최적화될 몇가지가 Java코드 중입니다.메인 프로그램 로직의 여러 지점에서 실행되는 핫 함수에서 실행되므로 고도로 최적화되어야 하는 자바 코드를작업하고 있습니다.이 코드의 일부는 코드의 이, 또한 multiplying한 것 일부는 다음 수를 곱하는 것과 관련이 있습니다를 포함한다.double변수로 하다에 의해 변수다.10임의의non-negative 임의의로 상승하게 비부정치로 상승하다int exponentS. 어느 빠른 방법(편집:지만 가능한 가장 빠른, 아래 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 intConstants 1일까지 incrementing,이 정말 19상수는 계속 1씩 증가하기 때문에 실제로는 19개가 있다 있습니다.caseS는 위의 코드 일부에서.위의코드 스니펫에 있습니다.이후 나는 나는 실제로 10의 파워가에 10의 모든 힘이 필요할지 확신이 없었는데확신이서지 않았기 때문에 필요할지 난.case진술 진술들10관통 스루18, 좀 microbenchmarks 시간이 이 1000만 번의 연산을 완료하는 데 걸리는 시간을 비교한 몇 가지 마이크로 벤치마크를 실행했습니다로 10만 작전을 완료할 비교하는 달렸다.switch대 진술 성명 댄switch오직만으로와cases 0관통 스루9((A함께와)exponent9이하로 그 pared-down 깎은 것을이 파손되지 않게에 한하위해 9이하로 제한된다 피하기.switch)나는 다소 놀랄 만한(나에게, 적어도!)결과는(적어도!)꽤놀라운 결과를 얻었는데 더 오래,그결과는 길수록 좋았닸다.switch과 더 많은 더 많이case진술들도 더 달렸다.진술이 실제로 더빨리 실행되었습니다.

종달새에 저는 그 의미를 더 종달새처럼, 나는 더 많은 것을 더하려고 노력했다를 넣으려고 했다.caseS이 것과 스위치 더 빠르게 주변 22-27을 선언했다방금 더미 값을 반환한 결과 약 22-27이 선언된 상태에서 스위치를 더 빠르게 실행할 수 있었습니다와 함께 할 수 있다는 것을 알아내더미 값으로 돌아왔다.caseS(반면 코드가 실행되는 심지어 이 더미 경우 사실을 친 적이 없다).(이러한 더미 케이스는 코드 실행 중에는 실제로 히트하지 않습니다만).(다시,(다시 말씀드리지만)caseS는 연속된 패션에 있어서는 선행 가 연속적인방법으로 추가되었다 incrementing가 추가되었다.case에의해 정해지는에 의해 상수입니다.1.) 이러한 실행 시간 차이가:무작위.)이러한 실행 시간 차이는 그다지 크지 않습니다 의미가 없다.랜덤의 경우exponent0 ★★★★★★★★★★★★★★★★★」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

github 테스트 repo "스위치 실험"

업데이트: 벤치마킹 라이브러리를 충분히 청소하고 /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.java2110 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , .

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스위치 블록 뒤의 순서를 나타내는 엔트리가 포함됩니다.기본적인 테스트를 몇 가지 실시했는데, 마지막 지수와 이전 지수의 차이가 있는 경우(935 , 을합니다.lookupswitchtableswitch

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

반응형