[컴퓨터 구조] Instruction Set Architecture와 프로그램 성능 분석
컴파일러 최적화의 효과(Effect of Compiler Optimization)
- gcc로 컴파일한 결과 -O1, -O2, -O3 최적화 옵션을 줄수록 명령어 수 감소, 클록 사이클 감소, CPI도 소폭 감소되는 경향을 확인할 수 있다.
- 최적화가 많을수록 코드 성능이 향상됨을 확인할 수 있다.
프로그래밍 언어와 알고리즘의 영향(Effect of Language and Algorithm)
- 같은 알고리즘이라도 언어/컴파일 방식에 따라 성능 차이가 발생한다.
- 버블 정렬 vs 퀵정렬 성능 차이도 크다. -> 알고리즘 선택이 핵심
- 아무리 최적화해도 바보같은 알고리즘은 고쳐지지 않는다.
배열 vs 포인터 성능 비교
- 배열 접근 : index * size + base (곱셈과 주소 계산 필요)
- 포인터 접근 : 주소 직접 증가시키므로 연산이 적고 빠르다.
- 최적화 컴파일러는 포인터 방식과 동일한 효율을 낼 수 있다. -> 명확하고 안전한 코드를 쓰는게 더 중요하다.
아키텍쳐별 구조와 성능 차이
우리가 사용하는 컴퓨터 속 프로세서(또는 CPU)는 모두 어떤 ‘언어’를 의미한다. 이 언어를 ISA(Instruction SEt Architexture)라고 하는데, 이 ISA에 따라 같은 프로그램이라도 속도, 크기, 성능이 완전히 달라질 수 있다.
MIPS교육용이나 임베디드 시스템에서 많이 사용되는 RISC(간단한 명령어 집합) 구조이다. 모든 명령어가 32비트로 일정하고, 메모리 접근은 lw, sw 같은 로드/스토어 명령만 가능하다. 덕분에 설계는 단순하고 빠르며, 에측하기 쉬워서 학습에 적합하다.
- 주소공간 : 32비트 평면
- 레지스터 : 32개(일반 목적)
- 메모리 접근 : 메모리-맵 방식
- 장점 : 규칙적이고 파이프라이닝에 최적화
ARM은 MIPS와 비슷하게 RISC 구조지만, 더 풍부한 주소 지정 방식과 기능이 있다. 특히 ARMv7까지는 각 명령어에 조건 실행 필드를 넣어 if문 없이도 분기 없이 연산이 가능하다. ARMv8부터는 64비트로 완전히 넘어가면서 구조가 정리되고 MIPS와 더 유사해졌다. 스마트폰, 태블릿, 라즈베리파이 등에 많이 사용된다.
- 레지스터 32개(v8에서는 GPR 확장됨)
- 조건 코드로 분기를 최소화
- ARMv8 : 64비트 확장, 나뉜 명령어 필드, divide 명령 추가
- 장점 : 전력 효율이 좋아서 모바일에 최적이다.
x86은 오랜 시간 진화를 거듭한 CISC(복잡한 명령어 집합) 구조이다. 1970년대 8080부터 시작해서 80386, 팬티엄, 코어 i 시리즈로 이어지며 엄청나게 많은 명령어와 기능이 추가됐다. 이 ISA는 매우 복잡해서, 실행 시 내부적으로 RISC처럼 잘게 쪼개어 처리(micro-op)한다.
- 명령어 길이 : 가변 길이(1~15바이트)
- 레지스터 : 16개 이상(64비트 확장 후 더 많아졌다.)
- 주소 계산 : 복잡한 스케일, 오프셋, 인덱스 조합 가능
- 장점 : 하위 호환성 덕분에 OS, 게임, 앱과의 호환성이 뛰어나다.
현대 컴퓨터는 단순한 명령어만 가지고도 충분히 빠를 수 있다. 복잡한 명령어(CISC)가 무조건 빠른 건 아니며, 오히려 구현이 어렵고 비효율적일 수도 있다. “단순하고 자주 쓰이는 경우를 빠르게 만들자” 이게 바로 좋은 아키텍쳐 설계의 핵심이다. 그리고 또 하나 중요한 것은, 하드웨어 구조보다 더 큰 영향을 주는 건 알고리즘과 프로그램 구조이다. 최적화된 C 코드도 나쁜 알고리즘을 썼다면 성능이 떨어지고, java도 JIT 컴파일러 덕분에 꽤 좋은 성능을 낼 수 있다.