분기 예측 최적화에 더 적합한 코드는 무엇입니까?


10

분기 예측과 컴파일러 최적화의 영향으로 어떤 코드가 우수한 성능을 제공합니까?

bRareExceptionPresent는 일반적이지 않은 조건을 나타냅니다. 정상적인 논리 경로가 아닙니다.

/* MOST COMMON path must branch around IF clause */

bool SomeFunction(bool bRareExceptionPresent)
{
  // abort before function
  if(bRareExceptionPresent)
  {
     return false;
  }    
  .. function primary body ..    
  return true;
}

/* MOST COMMON path does NOT branch */

bool SomeFunction(bool bRareExceptionPresent)
{
  if(!bRareExceptionPresent)
  {
    .. function primary body ..
  }
  else
  {
    return false;
  }
  return true;
}

9
나는 여기서 사지로 나가서 아무런 차이가 없다고 말할 것입니다.
Robert Harvey

7
파이프 라인 아키텍처가 다르기 때문에 (지연 슬롯과 지연 슬롯이 없음) 컴파일중인 특정 CPU에 따라 달라질 수 있습니다. 이것에 대해 생각한 시간은 프로파일을 실행 한 다음 최적화 할 때 절약되는 시간보다 훨씬 많은 시간 일 것입니다.

2
거의 확실하게 미시 최적화입니다.
Robert Harvey

2
@MichaelT 그렇습니다. 프로파일 링은 실제로 컨텍스트 내에서 대상 플랫폼의 코드 성능에 대해 실제로 어떤 일이 일어나고 있는지 알 수있는 신뢰할 수있는 유일한 방법입니다. 그러나 나는 일반적으로 선호되는지 궁금했습니다.
dyasta

1
@RobertHarvey : 조건이 모두 충족 되는 경우를 제외하고 는 조기 미세 최적화입니다 . (1) 루프를 수십억 (백만이 아닌) 번이라고합니다. 그리고 (2) 아이러니하게도, 루프 코드가 기계 코드 측면에서 작을 때. 조건 # 2는 오버 헤드에 소요되는 시간의 비율이 유용한 작업에 소요되는 시간과 비교하여 중요하지 않음을 의미 합니다. 좋은 소식은 일반적으로 두 조건이 모두 충족되는 상황에서는 사실상 분기가없는 SIMD (벡터화)가 모든 성능 문제를 해결한다는 것입니다.
rwong

답변:


10

오늘날의 세계에서는 전혀 중요하지 않습니다.

동적 브랜치 예측 (수십 년 동안 생각한 것 ( 1996 년에 게시 된 동적 브랜치 예측 스키마 시스템 워크로드 분석 참조 )은 상당히 일반적입니다.

이에 대한 예는 ARM 프로세서에서 찾을 수 있습니다. 지점 예측 의 팔 정보 센터에서

분기 예측 정확도를 향상시키기 위해 정적 기술과 동적 기술의 조합이 사용됩니다.

그렇다면 문제는 "팔 프로세서에서 동적 브랜치 예측이란 무엇입니까?"입니다. 다이내믹 브랜치 예측 의 지속적인 판독은 그것이 브랜치가 강하게 또는 약하게 취해 지는지에 대한 정보를 구축한다는 것을 (종이에 설명 된) 2 비트 예측 방식을 사용한다는 것을 보여준다.

시간이 지남에 따라 (그리고 그 블록을 몇 번 통과한다는 것을 의미) 이것은 코드가 어떤 방식으로 진행되는지에 대한 정보를 작성합니다.

들어 정적 예측 , 그것은 분기가 시험에 만들어지는 코드 자체와 어떤 방법을 보이는 방법에 보이는 - 이전 명령 또는 코드에 더 하나

ARM1136JF-S 프로세서에 사용 된 체계는 모든 정방향 조건부 분기가 수행되지 않고 모든 역방향 분기가 수행 될 것으로 예측합니다. 모든 가지의 약 65 %가 완전히 예측하기에 충분한 비 분기주기가 선행됩니다.

Sparky가 언급했듯이 이것은 루프가 아닌 루프가 더 자주 반복된다는 이해에 기초합니다. 루프는 뒤로 분기합니다 (루프 끝에는 분기를 시작하여 맨 위에서 다시 시작 함). 일반적으로이 작업을 수행합니다.

컴파일러를 다시 추측하려고 할 때의 위험은 그 코드가 실제로 어떻게 컴파일되고 최적화 될지 모른다는 것입니다. 그리고 대부분의 경우 중요하지 않습니다. 동적 예측을 사용하면 함수를 두 번 통해 조기 반환을위한 guard 문 건너 뛰기를 예측합니다. 플러시 된 두 파이프 라인의 성능이 중요한 성능이면 걱정할 다른 사항이 있습니다.

한 스타일을 다른 스타일로 읽는 데 걸리는 시간이 더 중요합니다. 코드를 깨끗하게 작성하여 사람이 읽을 수 있도록 코드를 작성하는 것은 컴파일러가 코드를 작성하는 방식이 아무리 지저분하거나 이상화 되었더라도 괜찮습니다.


7
유명한 stackoverflow 질문은 오늘날에도 분기 예측 중요 하다는 것을 보여주었습니다 .
Florian Margaine

3
@FlorianMargaine 중요하지만 실제로 문제가되는 상황에서 컴파일하는 내용과 작동 방식 (팔 대 x86 대 밉 ...)을 이해해야합니다. 처음에이 마이크로 최적화를 시도하는 코드 작성은 잘못된 구내에서 작동하고 원하는 효과를 얻지 못할 수 있습니다.

물론 DK를 인용하지 마십시오. 그러나 나는 이미 프로파일 링 단계를 지났을 때이 질문이 최적화의 의미에 있다고 생각합니다. :-)
Florian Margaine

2
@MichaelT 좋은 답변, 그리고 나는 당신의 결론에 매우 동의합니다. 이러한 종류의 사전 프로파일 링 / 추상 최적화는 확실히 비생산적 일 수 있습니다. 결국 추측 게임이되어 비합리적인 이유로 디자인 결정을 내립니다. 아직도, 나는 나 자신이 호기심을 발견했다; o
dyasta

5
@
90h

9

내 이해는 CPU가 처음으로 분기를 만나면 앞으로 분기가 수행되지 않고 하위 분기가 수행된다는 것을 예측합니다 (지원되는 경우). 이것에 대한 이론적 근거는 루프 (일반적으로 뒤로 분기)가 수행되는 것으로 가정합니다.

일부 프로세서에서는 어셈블리 경로에 어느 경로가 더 가능성이 있는지 힌트를 줄 수 있습니다. 이것에 대한 세부 사항은 현재 나를 탈출합니다.

또한 일부 C 컴파일러는 정적 분기 예측도 지원하므로 어느 분기가 더 가능성이 높은지를 컴파일러에 알릴 수 있습니다. 결과적으로 생성 된 코드를 재구성하거나 수정 된 지시 사항을 사용하여이 정보를 활용할 수 있습니다 (또는 무시해도됩니다).

__builtin_expect((long)!!(x), 1L)  /* GNU C to indicate that <x> will likely be TRUE */
__builtin_expect((long)!!(x), 0L)  /* GNU C to indicate that <x> will likely be FALSE */

도움이 되었기를 바랍니다.


3
"내 이해는 CPU가 처음으로 분기를 만나면 앞으로 분기가 수행되지 않고 하위 분기가 발생한다고 예측합니다 (지원되는 경우)." 이것은 매우 흥미로운 생각입니다. 이것이 공통 아키텍처에서 실제로 구현되었다는 증거가 있습니까?
blubb

5
말의 입에서 곧장 : 앞으로 분기는 기본적으로 사용되지 않습니다. 뒤로 분기는 기본적으로 사용 됩니다. 그리고 같은 페이지에서 : "접두사 0x3E – 분기를 정적으로 예측합니다".
MSalters

플랫폼에 독립적 인 프라그 마가 __builtin_expect있습니까?
MarcusJ
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.