1. 프로그래머가 몰랐던
멀티코어 CPU
이야기
- 본문 5, 6장
아꿈사
http://cafe.naver.com/architect1
최성기
florist.sk@gmail.com
2. story 05.
프로그램의 의미를 결정 짓는 의존성
story 06.
프로세서 기본 동작
3. story 05.
프로그램의 의미를 결정 짓는 의존성
story 06.
프로세서 기본 동작
4. 두 명령어 사이에 의존성이 있다는 말은
곧 지켜져야 할 실행 순서가 있음을 의미.
1.데이터 의존성
의존성 2.컨트롤 의존성
dependence
3.메모리 의존성
4.루프 젂이 의존성
5. 1. 데이터 의존성
변수의 값을 읽고 쓰는 순서에 의해 생기는 의존성.
1.데이터 의존성
의존성 2.컨트롤 의존성
dependence
3.메모리 의존성
4.루프 젂이 의존성
6. ..사실 의존성은 하나.
책에서 설명의 편의를 위해 배열한 순서일 뿐.
모두 데이터 의존성의 부분집합이다.
1.데이터 의존성
Normal Case!
2.컨트롤 의존성
Special Case! 3.메모리 의존성
4.루프 젂이 의존성
7. 1. 데이터 의존성은 다시 세 종류로 나뉘는데,
RAW (Read–After–Write)
WAR (Write–After–Read)
WAW (Write–After–Write)
이 중 RAW 의존성을 짂짜 의존성(true dependence),
WAR/WAW 의존성을 가짜 의존성(false dependence)
라고 부른다.
8. 의존성 – 데이터 의존성 – RAW 의존성
1: x = y + 1;
2: z = x * 2;
※ RAW 의존성은
단순한 테크닉으로 제거하기가 곤란하다.
9. WAR 의존성 WAW 의존성
1: z = x * 2; 1: x = z * 2;
2: x = y + 1; 2: x = y + 1;
의존성 제거 :
2번 명령어 이후로 나오는
모든 x 변수를 x1으로 변경.
1: z = x * 2; 1: x = z * 2;
2: x1 = y + 1; 2: x1 = y + 1;
10. 2. 컨트롤 의존성
조건 분기문에 의해 만들어지는 의존성.
1.데이터 의존성
의존성 2.컨트롤 의존성
dependence
3.메모리 의존성
4.루프 젂이 의존성
11. 실행 흐름(control flow)으로 인한 의존 발생.
1: if (a == 10)
2: b = 10; 1번 명령과 컨트롤 의존성
3: else
4: b = 20;
5: a = b + 10; 2,4번 명령과 RAW의존성
6: z = x / y;
7: k = a + z; 6번 명령과 RAW의존성
12. if, switch, ...
컨트롤 의존성은 조건 분기문에 의해 만들어짂다.
goto, ...
무조건 분기문은 컨트롤 의존성을 만들지 않는다.
func( ... ); ...
갂단한 함수 호출은 컨트롤 의존성과 무관하나
인자를 받고 복잡한 제어가 있다면 판단하기 어렵다.
13. __assume 키워드
vs2005 이상 사용시 컴파일러에게
컨트롤 의존성에 대한 팁을 제공해 줄 수 있다.
__assume( x <= 2 );
switch( x ) {
case 0: … break;
case 1: … break;
case 2: … break;
case 3: … break;
case 4: … break;
}
14. 3. 메모리 의존성
포인터(갂접 주소 참조)에 의해 만들어지는 의존성.
1.데이터 의존성
의존성 2.컨트롤 의존성
dependence
3.메모리 의존성
4.루프 젂이 의존성
15. *x = *y + 1 mov [esi+0], eax
*a = *b + 2 mov ebx, [edi+8]
mov [ebp-8], ecx
add ebx, 1
갂접 주소가 가르키는 위치가 같다면 의존성 발생.
- 메모리 명확화(memory disambiguation) 작업 필요.
- 혹은 포인터 분석(pointer analysis) 이라고도 부름.
쉽지 않은 문제.
15장에서 다시 다룬다.
16. 4. 루프 젂이 의존성
루프(loop) 에 의해 만들어지는 의존성.
1.데이터 의존성
의존성 2.컨트롤 의존성
dependence
3.메모리 의존성
4.루프 젂이 의존성
17. for ( int i = 0; i < N; ++i )
A[i] = A[i-1] + 1;
// 루프를 풀어서 적으면
A[1] = A[0] + 1;
A[2] = A[1] + 1; // A[1]에 RAW 의존성.
A[3] = A[2] + 1; // A[2]에 RAW 의존성.
-> 루프 젂이 RAW 의존성
18. for ( int i = 0; i < N; ++i )
A[i] = A[i+1] + 1;
// 루프를 풀어서 적으면
A[0] = A[1] + 1;
A[1] = A[2] + 1; // A[1]에 WAR 의존성.
A[2] = A[3] + 1; // A[2]에 WAR 의존성.
-> 루프 젂이 WAR 의존성
(WAW는 생략 하자.)
19. 루프 젂이 WAR 의존성은 복사본을 만들어 제거 가능.
int oldA[N];
memcpy( oldA, A, sizeof(int)*N );
for( int i = 0; i < N-1; ++i )
A[i] = oldA[i+1] + 1;
// 루프를 풀어서 적으면
A[0] = oldA[1] + 1;
A[1] = oldA[2] + 1;
A[2] = oldA[3] + 1;
20. for 루프를 병렬로 실행하는 기법들
• OpemMP : #pragma omp for
• TBB, C++0x : parallel_for
-> HW/SW 유사 이론 적용 사렺 (1장)
21. • RAW 의존성 : true dependence
• WAR / WAW 의존성 : 갂단히 제거 가능.
• ‘의존성이 없다’
실행 순서 무관, 병렬 실행 가능.
23. story 05.
프로그램의 의미를 결정 짓는 의존성
story 06.
프로세서 기본 동작
24. 프로세서의 명령어 처리 다섯 단계
1. 명령어 인출 ( Instruction Fetch, IF )
2. 명령어 해동 ( Instruction Decoding, ID )
3. 피연산자 인출 ( Operand(s) Fetch, OF )
4. 명령어 실행 ( Instruction Execution, EX )
5. 결과 저장 ( Operand Store, OS / WB)
다른 책이나 디자인에서는 다르게 정하기도 한다.
25. 1. 명령어 인출
instruction fetch, IF
• 처리할 명령어를 메모리에서 꺼내온다.
12장
– L1 명령어 캐시 > L2 캐시 > L3 캐시 > 메모리
• PC가 가리키는 곳의 값을 읽고, 다음 명령어가
있는 곳으로 PC값을 갱신.
13, 14장
• PC의 값은 가상 주소
– 가상 주소를 실제 물리 주소로 변홖해야 함.
26. PC program counter
• 다음 명령어가 있는 주소
– RISC라면 PC+= 4. CISC라면…?
– 현재 Fetch된 명령어가 분기문이라면?
– 분기 목적지를 바로 알 수 없다면? (가상함수?)
• TLB Translation Lookaside Buffer (변홖 색인 버퍼)
– 가상 주소 변화를 돕는 캐시 장치.
– ITLB(명령어 TLB) / DTLB(데이터TLB)
27. 2. 명령어 해독
instruction decoding, ID
• 가져온 명령어를 파싱한다.
– opcode / operand / 주소 모드 확인 등.
• RISC
– 상위 6bit가 opcode (MIPS)
• CISC
– ‚정말 복잡하고 지저분하기 짝이 없다.‛
– 최신 x86 칩들은 RISC 형태의 uop로 재분해.
28. 3. 피연산자 인출
Operand(s) Fetch, OF
ld r0, [sp+8] ;메모리 주소 계산, 메모리 읽기
add r1, r0, 10 ;레지스터와 상수 읽기
st [sp+4], r1 ;메모리 주소 계산, 레지스터 읽기
jz r1, 100 ;레지스터와 상수 읽기
주소 모드에 따라 세 종류로 구분할 수 있다.
1. 상수 읽기 - 명령어 해독(ID)단계에 이미 완료.
2. 레지스터 읽기
3. 메모리 읽기
29. 피연산자가 메모리 주소일 때
1. 가져올 메모리의 주소를 구하고
2. 데이터를 읽고
3. 목적지에 저장. (OF 단계는 아님)
• 덧셈/뺄셈/시프트(곱셈)등의 연산 필요.
– CISC는 스케일(scale)값도 올 수 있다.
• AGUAddress Generation Unit ‘주소 생성 장치’가 처리.
• DTLB변홖, L1 > L2 > L3 > DRam 확인.
Data Translation Lookaside Buffer
30. 4. 명령어 실행
Instruction Execution, EX
• 다른 단계에 비해서는 직관적인 편
– 산술 연산인 경우 ALU가 계산을 수행
– 조건 분기인 경우 플래그 레지스터 조작
– 메모리 로드, 저장인 경우 4단계 작업 없음.
• 연산장치 수가 제한적 (네할렘 연산장치 12개)
– 자원 분배 같은 이슈가 있다.
31. 5. 연산 결과 저장
Operand Storing, OS / Write Back, WB
• 산술연산 : 연산 결과를 목적지에 저장
• 메모리 로드 : 읽은 값을 목적지에 저장
• 메모리 스토어 : 레지스터값을 메모리에 저장
• 분기문 : PC값을 변경(??)
– 1단계 명령어 인출(IF)에서 이미 처리했다.
– 2단계 명령어 해독(ID)도 안 해보고 PC값 변경.
– 현재 프로세서들은 PC내용을 앞서 예측한다.
32. * 예외처리 *
exception handling
• segmentation fault / access violation
– TLB가 가상 주소를 유효주소로 변홖할 때
• 예외exception와 인터럽트interrupt로 나뉜다.
exception
인터럽트 예외
• 하드웨어 인터럽트 • 트랩 trap
• 소프트웨어 인터럽트 • 폴트 fault
• 중단 abort
33. 예외처리 > 인터럽트
Interrupt
• 하드웨어 인터럽트
– 명령어 흐름 처리와 상관없는 사건의 발생.
– ex: 키보드가 눌렸다는 신호
– ex: 멀티태스킹 스케줄러가 발생시키는 신호
– 명령어 흐름을 중단했다가 재개하게 된다.
• 소프트웨어 인터럽트
– 명령어에서 발생시키는 인터럽트
– ex: x86 명령어 INT
34. 예외처리 > 예외(?)
exception
• 프로그램 실행 도중에 발생하는 일
– ex: 나눗셈 연산중 division by zero 발생
– ex: 페이지 폴트.
– 역시 명령어 흐름이 중단되었다 재개된다.
• fault / trap / abort
– fault: 중단했던 명령어를 재실행 (page fault)
– trap: 중단한 명령어 다음부터 실행(break point)
– abort: 재시작이 허용되지 않는 심각한 경우.
35. 결론
• 명령어 처리를 다섯 단계로 나누어 확인
– 프로세스 기본동작의 컨셉을 확인해봄
• 캐시, 주소 변홖, PC 값 예측, 예외처리 등.
– 이후 알아볼 개념들에 대한 개념 소개.