Quick Flow
fetch instruction
-> decode opcode and operands
-> read registers / memory
-> execute operation
-> write result
-> advance or change instruction pointerCPU는 명령을 하나씩만 단순 반복하는 장치가 아닙니다. 현대 CPU는 여러 명령 단계를 겹쳐 처리하고, 분기를 예측하며, 가능한 연산을 순서를 바꾸어 실행하되 프로그램이 관찰하는 결과는 명령 집합의 규칙에 맞게 유지합니다.
핵심 상태
레지스터는 CPU가 매우 빠르게 접근하는 작은 저장 공간입니다. 일반 연산 값 외에도 다음에 실행할 위치를 가리키는 instruction pointer, 함수 호출과 지역 상태에 연결되는 stack pointer, 비교 결과를 담는 flags 같은 상태가 있습니다.
명령어는 opcode와 operand로 읽습니다. opcode는 더하기·이동·분기처럼 수행할 일을, operand는 레지스터·즉시값·메모리 주소처럼 대상을 나타냅니다. 고급 언어의 한 문장이 기계어 한 개와 정확히 대응한다고 가정하면 안 됩니다.
파이프라인과 분기
파이프라인은 명령의 fetch, decode, execute 단계를 겹쳐 처리해 처리량을 높입니다. 조건 분기의 다음 경로를 미리 예측하면 대기 시간을 줄일 수 있지만 예측이 틀리면 잘못 준비한 작업을 버리고 올바른 경로를 다시 채워야 합니다.
따라서 같은 Big-O의 반복문도 데이터 접근 패턴과 분기 예측 가능성에 따라 실제 시간이 다를 수 있습니다. 다만 코드 수준 최적화는 측정 뒤에 해야 하며, 분기 하나를 없애기 위해 읽기 어려운 코드를 만드는 것을 기본값으로 두지 않습니다.
자주 틀리는 점
- CPU clock이 두 배라고 프로그램 전체가 정확히 두 배 빨라지지는 않습니다.
- instruction count만으로 실행 시간을 확정할 수 없습니다. cache miss, branch miss, 의존성과 대기가 함께 작용합니다.
- 여러 core는 같은 thread 하나를 자동으로 나누어 실행하지 않습니다. 병렬화 가능한 실행 단위가 있어야 합니다.
- debugger의 한 줄 실행은 소스 문장 기준이며 내부 기계어 단계와 일대일 대응하지 않을 수 있습니다.
참고 링크
1 sources