likely/unlikely 사용시 차이점
compiler 정보 : gcc version 4.3.3 (Sourcery G++ Lite 2009q1-203)
http://www.codesourcery.com/sgpp/lite/arm/portal/release858
int abcdefg(int test1)
{
if ( unlikely(test1 == 5 ) )
test1++;
else
printk("--n");
printk("%dn", test1);
return 0;
}
--------------------------------------unlikely를 사용한 경우
0000001c <abcdefg>:
1c: e1a0c00d mov ip, sp
20: e92dd830 push {r4, r5, fp, ip, lr, pc}
24: e24cb004 sub fp, ip, #4 ; 0x4
28: e3500005 cmp r0, #5 ; 0x5
2c: e1a04000 mov r4, r0
30: 03a04006 moveq r4, #6 ; 0x6
34: 0a000002 beq 44 <abcdefg+0x28>
38: e3000000 movw r0, #0 ; 0x0
3c: e3400000 movt r0, #0 ; 0x0
40: ebfffffe bl 0 <printk>
44: e1a01004 mov r1, r4
48: e3000000 movw r0, #0 ; 0x0
4c: e3400000 movt r0, #0 ; 0x0
50: ebfffffe bl 0 <printk>
54: e3a00000 mov r0, #0 ; 0x0
58: e89da830 ldm sp, {r4, r5, fp, sp, pc}
--------------------------------------unlikely부분에 likely or 둘다 없는 것
0000001c <abcdefg>:
1c: e1a0c00d mov ip, sp
20: e92dd830 push {r4, r5, fp, ip, lr, pc}
24: e24cb004 sub fp, ip, #4 ; 0x4
28: e3500005 cmp r0, #5 ; 0x5
2c: e1a04000 mov r4, r0
30: 03a04006 moveq r4, #6 ; 0x6
34: 1a000005 bne 50 <abcdefg+0x34>
38: e1a01004 mov r1, r4
3c: e3000000 movw r0, #0 ; 0x0
40: e3400000 movt r0, #0 ; 0x0
44: ebfffffe bl 0 <printk>
48: e3a00000 mov r0, #0 ; 0x0
4c: e89da830 ldm sp, {r4, r5, fp, sp, pc}
50: e3000000 movw r0, #0 ; 0x0
54: e3400000 movt r0, #0 ; 0x0
58: ebfffffe bl 0 <printk>
5c: eafffff5 b 38 <abcdefg+0x1c>
결론 : 분기문에서 확률이 적은 곳에 unlikely를 사용하면 이부분을 branch하여 수행하도록 만들어 줍니다.
반대로 이야기 하면 확률이 높은 쪽은 branch하지 않고 연속하여 수행하도록 해줍니다.
이것으로 인하여 branch에 의해 다른 곳으로 가게 되면 미리 가져왔던 것을 flushing 하고 다시 fetch하는 것을 줄여 줍니다.
-------------------------------------------------------------------------------------------------
ps. branch가 필요없을 때에는 unlikely, likely 사용이 동일합니다.
예 : 아래 예제는 unlikely, likely, 둘다 없는 것으로 확인 시 모두 동일합니다.
int abcdefg(int test1)
{
if ( unlikely(test1 == 5 ) )
test1++;
else
test1--;
printk("%dn", test1);
return 0;
}
0000001c <abcdefg>:
1c: e1a0c00d mov ip, sp
20: e92dd800 push {fp, ip, lr, pc}
24: e24cb004 sub fp, ip, #4 ; 0x4
28: e3500005 cmp r0, #5 ; 0x5
2c: 12401001 subne r1, r0, #1 ; 0x1
30: e3000000 movw r0, #0 ; 0x0
34: 03a01006 moveq r1, #6 ; 0x6
38: e3400000 movt r0, #0 ; 0x0
3c: ebfffffe bl 0 <printk>
40: e3a00000 mov r0, #0 ; 0x0
44: e89da800 ldm sp, {fp, sp, pc}
댓글 9
-
myskan
2011.07.11 13:03
-
박량우
2011.07.11 15:59
1 C674x+; 1 ARM Cortex-A8
http://focus.ti.com/docs/prod/folders/print/tms320dm8168.html
-
김용욱
2011.07.11 13:41
두가지 이슈가 합쳐졌네요.
- unlikely - x86이든 arm이든 unlikely 부분이 jmp나 b의 타겟이 되도록 조정합니다. 반면에 likely가 있다면 jmp나 b의 타겟이 되지 않도록 조정하겠죠.
- 분기화된 명령(branched execution) - ARM은 o2 이상의 최적화 옵션에서 분기문(if 등)에서 B명령어를 안 쓰도록 분기화된 명령어를 사용할 수 있는 상황에선 분기화된 명령을 사용합니다. 위에서 보이는 subne가 그 흔적이죠.
둘 중의 우선순위가 높은 것은 2번입니다. 분기화된 명령어가 더 효율이 높기 때문입니다.
likely와 unlikely는 실행 효율을 떨어뜨릴 수 있기 때문에 가능한 사용하지 말라고 하는데 VM에서는 일반적으로 수행통계를 내어서 어떤 쪽을 브랜치로 둘꺼냐를 계속 바꿉니다. 오래동안 같은 프로그램이 반복 수행되는 서버 프로그래밍에서 VM환경이 이점이 있는 이유입니다.
- unlikely - x86이든 arm이든 unlikely 부분이 jmp나 b의 타겟이 되도록 조정합니다. 반면에 likely가 있다면 jmp나 b의 타겟이 되지 않도록 조정하겠죠.
-
박량우
2011.07.11 16:04
말씀대로 위의 컴파일 환경은 '-O2' 입니다.
-
홍문화
2011.07.12 21:04
와~ 프로세서의 세계도 알면 알수록 참 매력적인것 같습니다.
하고 싶은것은 점점 많아지고 큰일입니다. ㅋ
감사합니다. ^^;
-
myskan
2011.07.12 20:07
네.
그렇기 때문에 분기 예측 성공률이 무척 중요합니다.
-
홍문화
2011.07.12 13:15
어려워서 잘 이해는 안되지만 염치 불구하고 살짝 질문 드립니다. ㅋ
분기 예측 기법을 사용 할 경우 파이프라인에서 분기 명령어 다음에 존재하는 명령어들이 분기 된 이후에
실행 할 명령어라는 말씀이신가요? 이렇게 된다면 파이프라인이 깨지지 않아 성능이 좋아 진다는 것으로
이해 됩니다. 하지만 분기 예측이 실패 할 경우 오히려 성능이 저하 될 수도 있을것 같은데
분기 예측기가 성능 향상에 많은 도움이 되나보네요.
-
myskan
2011.07.11 16:19
전 약간 다른 관점입니다.
일반적으로 현재의 프로세서는 동적 분기 예측기를 가지고 있으며 동적으로 분기 예측에 의하여 분기 명령어의 taken 여부를 판단하여 명령어를 fetch 해 가지고 옵니다.
always not taken / always taken 도 역시 분기 예측 기법이며, 동적 분기 예측기를 구현하지 않을 경우에 사용되는 분기 기법 중 하나이며 일반적으로 하드웨어로 구현하기 쉬운 always not taken 기법이 사용됩니다.
always not taken 분기 예측 기법은 명령어를 차례로 읽어 오기 때문에 분기 명령어가 taken 되면 분기 명령어 이후에 fetch 하였던 명령어는 flush 해야 합니다. 하지만 always taken 분기 예측 기법은 분기 명령어 다음에 읽어 오는 명령어가 분기 한 이후의 pc 값의 명령어 이기 때문에 분기 명령어가 taken 되지 않았을 때 분기 명령어 이후에 fetch 하였던 명령어를 flush 해야 합니다.
이러한 분기 예측은... 예측이기 때문에 코드의 실행 결과에는 아무런 영향을 미치지 않습니다.
하지만 동일한 코드라 하더라고 성능차이는 존재 하게 됩니다.
당연히 컴파일러에서 하드웨어의 분기 예측 기법을 고려하여 코드를 생성해 줄것입니다.
(그렇지 않더라도 결과에는 문제가 없습니다. 성능에만 영향을 미치겠지요. )
그래서 용욱님이 말씀하신 1번의 경우 always taken 분기 예측 기법이 적용된 하드웨어라면 불합리 하지 않을까 싶습니다.
(물론 동적 분기 예측기가 구현되어 있는 프로세서라면 이런 논의는 할 필요가 없겠지요. ^^)
-
김남형
2011.07.11 23:24
http://kldp.org/node/108246#comment-503144
.
감사합니다. 예상했던 결과이네요 ^^
추가적으로 해당 프로세서가 동적 분기 예측기의 존재 여부와
분기 처리 기법을 always taken 혹은 always not taken 기법인지 알면 더 좋을것 같은데요.
어떤 프로세서를 타겟으로 컴파일 하신것 인가요???