C에서 프로그램 최적화 .. 더 빠르게 더 짧게.

wsmrdo의 이미지

문득 예전 생각이 나서 적어봅니다.

for(i=0;i<10;i++)

이런거보다.

i=10;
do{
}while(--i);

이런식의 구문이 더 빠르죠.
한때 컴파일후 나온 어셈블리 코드를 보면서 고민했던 기억이 나더군요.
당시 프로젝트가 사용하던 마이컴의 특성상 최적화를 하지 못하면 돌지 못할 지경이라...
다 어셈블리로 하려니 갑갑하고 C로 하려니 어떻게 나오는지 걱정되고.
마이컴 선택 잘해야 합니다.
요즘이야 다들 빨라지고 커져서, 메모리 걱정이라던가 속도문제는 덜 신경을 쓰겠지만 말이죠.

컴파일러가 어떤 형태로 최적화 하는가 구경하는 것도 도움이 되고요.
어셈블리 코드를 만들면서 컴파일러와 경쟁해 보는것도 나름 유희가 되겠죠.

간단한 곱셈 나눗셈도 변수 범위를 벗어나면 어찌 구현해야 되는지 헥깔릴 때도 있고요.
이럴때 컴파일 한거 어셈블리로 보면서 아이디어를 얻을 수도 있습니다.

프로그램을 즐길 수 있는 그날이 올때까지 ...

leonid의 이미지

http://acm.pku.cn/JudgeOnline/

여기서 C 언어등 여러가지 언어로 경쟁할 수 있습니다.

코드의 길이로도 경쟁할 수 있지만 실행 속도로도 할 수 있습니다.

근데 속도 최적화 하시는 분들 보니 대단하더군요 o_O 막 컴파일러를 일일이 뜯어보고, 필요하면 어셈도 왕창 집어넣고

wsmrdo의 이미지

왠지 좀 억울해서...
이런거 만들어 놓으면 서로 도움이 될 터인데.
그 주체가 한국이 아니라니 좀 서글프군요...^^*

어설픈 민족주의자... 였습니다.

더불어 가능하면 리눅스 배포판 국가 프로젝트로 햇으면 한다는... 공무원형태로.
한국 OS도 없는 마당에( 뭐 있기는 합니다만... 현실적으로 )

너무 MS OS에 종속되어간다는 기분에 늘 꿀꿀한 마음을 금할길 없군요.

select99의 이미지

인용--------------------------
for(i=0;i<10;i++)
이런거보다.
i=10;
do{
}while(--i);
-----------------------------

두프로그램을 비교한요지가 for 와 do while 문인가요?
아니면 소스의 간결함과 반대로 성능이 역행하는면을 보이신건가요?

어쨋든 두비교는 좀 잘못되었다 봅니다.

첫번째도

for( i=10; i--; ) 이런식으로 하셔야 공평하죠..

coremaker의 이미지

loop 문에서 ++ 연산보다는 -- 연산이
컴파일러가 최적화 하는데 큰 도움을 준다고 합니다..
그래서 "약간"의 성능 차이를 보인다고 하더군요...

freemckang의 이미지

그냥 어디선가 줏어듣기로는 증가연산보다 감소연산이 빠른 이유가 0하고 비교를 해서라는데... 아키텍처에 대해서는 문외한이라 다른 고수님의 말씀을 기대하고 있습니다.

음... 최적화하니 루프 언롤링에다가 되도 않는 비트연산을 남발한 기억이 새록새록 나는군요... 그런 코딩할때 세련된거야~ 생각했었는데 지금 생각해보니 가독성이 너무 떨어져 도저히 이해할 수 없다는.... -_-;;

항상 하는 이야기지만, 최적화보다는 가독성에 초점을 맞춰야 되는 것이 아닌가 하는 생각이 듭니다 (일반의 경우).

句日新, 日新 日新 又日新.

句日新, 日新 日新 又日新.

wsmrdo의 이미지

말씀대로 for 루프와 while 루프가 형평이 맞질 않는군요. ^^;;
형평을 같게 하면 컴파일러가 같은 결과를 리턴 하였을 수도 있겠군요.

음. 과거 for 루프를 컴파일 한 경우와
do { } while 루프를 컴파일 하여 나온 어셈블리를 비교했었습니다.

8051 시리즈... 어셈블리 명령에 djnz 명령이 있습니다.

do{
.....
.....
}while(--i) <-- 이라인이 djnz 명령 한줄로 치환 됩니다.
변수도 1Byte 짜리(char)를 써야하고요.

음. 2 사이클 명령이라. 12Mhz CPU일때 2uSec 걸리죠.(음 이거 맞을겁니다.어떻든 10년정도 된 과거 기억이라.^^;;)
더 이상 못 줄입니다.
for 루프 다 찾아서. do{}while 형태로 바꾸었다는 .... 전설이...
뭐 함수 만들거도 Call 명령 수행시간 때문에 고민했었으니... 말 다했죠 ^^;;

그때는 이런식으로 걸리는 시간 컴파일 되어 나오는 어셈블리 확인하지 못하면 코드가 느려 져 실행이 제대로 안되는 경우가 있어서 ...

참 신경쓸 일 많은 코딩이었습니다.

이제는 코드 사이즈나 속도에 대한 것에서 거의 자유로와 진 듯합니다.
그전처럼 에셈블리 들여다보면서 컴파일러의 최적화 옵션을 의심하는 행위는 많이 줄었죠.
거의 없다고 해야 하나요? :)

새해의 행복한 코딩 되십시요.

blkstorm의 이미지

djnz와 유사한 기능이 MIPS 프로세서에서 사용된 것으로 알고 있습니다.

그리고 예전에 ARM 프로세서 강사에게서 최적화에 관한 몇가지 팁을 들었는데,

루프문의 비교문에 0이냐 아니냐를 사용함으로써 약간의 성능향상을 볼 수 있다고 합니다.

(물론 해당 루프문 내부에서 인덱스의 증감방향을 뒤집어야한다면 큰 이득은 없겠지만요)

임베디드 프로세서에서는 한클럭한클럭이 아쉽기 때문에 알아두면 좋다고 생각합니다.

질문 하나 추가인데요... 지금 논의되고 있는 주제가 컴파일러에서 어셈으로

변환하는 과정에서 적용되지는 않나요? 즉, 컴파일러에서 알아서 djnz(에 해당하는 기능)를

사용하도록 최적화하는지 알고 싶습니다.

혼자서 공부하기도 힘든게 컴파일러인데, 당췌 이놈의 학교는 컴파일러 수업을 2년에 한번 열까말까하니... -_-;;

wsmrdo의 이미지

음 뭐 지나가면서 간만에 생각난것을 적은것인데요.

컴파일러가 해줍니다. 단 코드에 따라 원하지 않는 방향으로 해줄 때까 있기 때문에 확인해야 합니다.
자신이 상상한 코드와 컴파일러가 만들어낸 코드가 같은가 확인하는 것도 나름 재미있습니다.

0 비교 할때 인스트럭션 사이클이 짧기 때문에 속도에 이득을 보게 되는 것이죠.

컴파일러 마다 다르긴 하지만 점점 진화해서.
나중에 어떠한 부분은 제가 어셈블리로 짠것 보다 더 나을 것으로 판단되는 부분도 보이더라구요. 그럴 때는 "컴파일러님 잘 배웠습니다" 하는 거죠.

IAR 컴파일러 로 기억됩니다. 아르키메데스 컴파일러를 IAR 에서 사서 업그레이드 했을겁니다.
처음엔 아르키메데스 커파일러였던걸로 기억되는 군요.
어떻든 컴파일하면 C Source와 ASM이 같이 출력되어 나오도록 할 수 있습니다.

요즘의 ARM 컴파일러도 디버거 돌리면 어셈블리와 C를 같이 볼 수 있고요.
뭐 이런 기능은 거의 대부분 지원하는 것으로 알고 있으니 어떤 컴파일러 쓰시던 어셈블리와 C소스를 비교해 보시면 어셈블러만 가지고 어셈블리 공부하는것보다 빠르게 실력을 향상 시킬 수 있을겁니다.

최적화는 코드 길이 와 수행 속도 둘로 나뉘어 지는데 대충 코드 줄이면 속도도 같이 올라갑니다.

함수 Call을 줄이고(코드가 늘어난다는 ㅡ.ㅡ;;) 연산 시 빠른 쪽으로 하고. (나눗셈 대신 곱셈을 한다던지. 거의 모든 경우에 있어 나눗셈이 가장 인스트럭션 사이클이 길답니다.)

함수 호출시 인수를 적게 가져 간다던지 하는 것이죠.

C는 기본적으로 보호 코드(?!)가 존재하기에 어셈블리로 직접 짜는거 보다는 좀 덜하기 마련입니다.
익숙해 지시면 (해당 컴파일러 및 CPU에) C로 짜는게 어셈블리로 짜는 거 보다 더 빠를 경우도 있습니다.

한마디로 컴파일러 최적화와 인간 최적화가 서로 상승작용을 ^^*

이게 가장 좋죠.

끝으로 퀵 레퍼런스 하나 옆에 두시고, 하시면 도움이 된다는....
명령어 보다는 로직 구현에 신경쓰심이 발전에 도움이 됩니다.
명령어는 입력 출력만 명확히(라고 쓰고 대충이라 읽습니다) 알고 있으면 나중에 레퍼런스보면서 하면 됩니다. 하다보면 자연히 외우게 됩니다.

행복한 새해 되십시요.

bookgekgom의 이미지

인용-------------------------------------
for( i=10; i--; ) 이런식으로 하셔야 공평하죠..
------------------------------------------------
틀렸습니다.

for( i=10;i<10;i++) 이게 바른거 아닐까요?

인용2-----------------------------------------------
i=10;
do{
}while(--i);
-------------------------------------------------------
이건 로지컬에러 입니다. while(--i); 라니요... 무한 루프입니까?

i=0;
do{
i++;
}while(i<10);

라고 해야죠....

그리고 do while 과 for loop을 비교하기엔 문제가 있는것 같습니다.

----------------------------------------------------------------------------------------------

허접한 페도라 가이드 http://oniichan.shii.org

---------------------------------------------------------------------------------------------------------------
루비 온 레일즈로 만들고 있는 홈페이지 입니다.

http://jihwankim.co.nr

여러 프로그램 소스들이 있습니다.

필요하신분은 받아가세요.

creativeidler의 이미지

zero(0) as false를 이용한 것인 듯. 무한루프는 아닌 것 같네요.

only2sea의 이미지

실수 하신 것 같은데요.

원래 글 쓰신 분이 제대로 쓰신 것이라고 생각합니다만... ;;;

블로그: http://turtleforward.blogspot.com

cppig1995의 이미지

두 루프는 모두 똑같은 작업을 수행합니다.
아직 이해가 되지 않으신 모양인데...

for(i = 10; i--; ) { 반복문_본체; }

이 코드는 i가 10 값에서 시작합니다.
i--는 9이고 이는 0이 아니므로 참입니다. 따라서 반복합니다.
... i--가 0이 될 때 이것은 거짓입니다. 반복문에서 풀리죠.

do-while문도 마찬가지입니다.

만약 조건문에서 --i를 쓰면 어떻게 될까요?
한 번 덜 돕니다.



Drawing FX [2.0] - draw your dream, paint your colour, see your potential
"음. 하늘의 맛은 싱거운 편이야." - 정우 규리하

Real programmers /* don't */ comment their code.
If it was hard to write, it should be /* hard to */ read.

wsmrdo의 이미지

1)
for(i=10;i--;)
printf(" %d",i);
출력 : 9 8 7 6 5 4 3 2 1 0
2)
for(i=10;--i;)
printf(" %d",i);
출력 : 9 8 7 6 5 4 3 2 1

입니다.

가끔 많이 혼동될 때가 있습니다.
등가의 while 을 쓰면 조금 확실해 집니다.

1) i = 10; //초기치
while(i){
i= i-1;
printf(" %d",i);
}
2) i = 10; //초기치
while(i-1){
i= i-1;
printf(" %d",i);
}
이렇게 됩니다.

모두 행복 하세요.

only2sea의 이미지

i < 10의 비교를 하려면 i - 10을 계산해야 하는데 이것을 하지 않아도 되게 해 주니까
--i를 쓰면 더 빠른 코드가 나오는 것이죠. 루프 내에서 i를 쓰지 않는다면 컴파일러가
최적화 할 수 있는 형태라고 생각합니다.

블로그: http://turtleforward.blogspot.com

kalstein의 이미지

요즘엔...세상이 참 좋아져서 ^^;;;

왠만해선...컴퓨팅 파워가 모잘라서 못했다! 어셈으로 짤수밖에 없었다! 가 점점 안먹히는 시대죠...

뭐...근데 어셈이...빠르면 좋긴한데...

엄한 최적화로 인해...컴파일러 최적화보다 그닥 빠르지도 않고;; 보기만 불편한 경우가 제법있다지요 ^^;;;

(정말...어셈은...짜고난담에 5분후에 보면 모를코드라는...ㅡ _-;;)


------------------------------------------
Let`s Smart Move!!
http://kalstein.tistory.com/

wsmrdo의 이미지

들여쓰기도 잘하고 코멘트 잘달고 하면 꽤 볼만 합니다.

물론 저는 해당 사항 없습니다. ㅡ.ㅡ;;

잘 하시는 분이 짠 코드는 멋진 들여쓰기와 코멘트로 보는이에게 행복을 선사합니다.

정태영의 이미지

x++ 는

x 백업
x 증가

이렇게 두 단계로 되고

++x 는

x 증가

이렇게 한 단계로 되기는 하지만

만약 백업된 x 를 사용하는 곳이 없다면 compiler 의 deadcode elimination 에 의해서 x 백업 코드는 제거될 것이므로 어짜피 똑같을 것 같습니다.

for( x = 0 ; x != 10 ; x++ ) 와 for( x = 10 ; x != 0 ; x-- ) 의 경우 cmp x, 10; jnz ... 와 jnz ... 의 비교가 될테니 당연히 후자가 유리하겠지만 이런 것들도 현재 cpu 들이 워낙 빠르다 보니 별 차이를 느끼기 쉽지 않을 것 같네요,

--
오랫동안 꿈을 그리는 사람은 그 꿈을 닮아간다...

http://mytears.org ~(~_~)~
나 한줄기 바람처럼..

오랫동안 꿈을 그리는 사람은 그 꿈을 닮아간다...

http://mytears.org ~(~_~)~
나 한줄기 바람처럼..