컴퓨터 구조 강의

컴퓨터를 설계함에 있어 위대한 아이디어인 자주 생기는 일을 빠르게(make common cae fast) 를 추구함에 있어 하드웨어 및 소프트웨어 설계자들이 필연적으로 고민하게 된느 문제 중의 하나는 “성능을 개선하려는 나의 노력이 얼마나 효과가 있는지 어떻게 평가할 수 있는가?” 이다.

열심히 성능을 개선하려는 노력을 했다면 그것이 얼마나 효과가 있는지 궁금해 하는 것은 당연하다.
이러한 질문들에 대한 정석적인 해답은 다음과 같다.

“성능을 개선하려는 노력이 얼마나 효과가 있는지는 그 사건이 얼마나 많이 발생하는지와 관련이 있다.”

이러한 법칙은 얼핏 보면 당연해 보이지만 많은 경우 우리에게 명확한 직관을 줄 수 있다.

간단한 예를 통해 Amdahl의 법칙 의 활용을 알아보자.
가령 프로그램의 실행 시간이 100초가 걸리는 데 그 중 80초는 곱하기 계산에 소요된다고 하자. 이 프로그램이 5배 빠르게 실행되기 위해서 곱셈 속도는 얼마나 개선되어야 하는지에 대한 문제가 있다고 하자.

이는 Amdahl 의 법칙 에 의해 다음과 같이 표현된다.

개선 후 실행시간
= (개선에 의해 영향을 받는 실행 시간)/개선의 크기 + 영향을 받지 않는 실행 시간

이 문제의 경우는

개선 후 실행시간 = 20초 = 80초 / n + (100-80)초

즉, 0=80초 / n

이라는 식을 얻을 수 있다.

이는 바로 곱셈의 성능을 백날 개선해 보아도 시스템의 성능을 5배로 올리는 것은 불가능 하다는 깨우침을 우리에게 준다.
이는 일상생활에서 수확체감의 법칙과도 연관되어 있다.

이처럼 Amdahl의 법칙을 통해 어떤 개선안이 전체 성능에 얼마만큼의 성능 개선을 가져다 줄 지를 예측 할 수 있다.
이 법칙은 CPU 성능식과 함께 잠재적 성능 개선율을 평가하는 편리한 도구이다.


RISC(Reduced Instruction Set Computer) 란?

RISC 란 Reduce Instruction Set Computer 의 약자로 말 그대로 축소 명령어 세트 컴퓨터를 의미합니다.
여기서 명령어 세트가 축소되었다는 말은 말 그대로 명령어의 개수가 적은 것을 말합니다. 핵심적인 명령어를 기반으로 최소한의 명령어 세트를 구성함으로써 파이프라이닝 이라는 획기적인 기술을 도입할 수 있어 빠른 동작 속도와 하드웨어의 단순화와 효율화를 시킬 수 있었고, 가격 경쟁력에서도 우위를 점했습니다.

즉, RISC란 CISC의 길고 복잡한 명령어들을 짧고 처리가 가능한 여러개의 명령어로 체계적으로 바꾼 것입니다.

RISC의 특징

  1. 적은 명령어 세트
  2. 간단한 명령어로 빠른 실행속도
  3. 고정적인 명령어 길이
  4. 워드, 데이터 버스 크기가 동일하고 실행 사이클도 모두 동일
  5. 회로 구성이 단순함
  6. 프로그램을 구성할 때 상대적으로 많은 명령어가 필요
  7. 파이프 라이닝을 사용함
  8. 명령어 개수가 적어서 컴파일러가 단순하게 구현됨

CISC(Complex Instruction Set Computer) 란?

연산을 처리하는 복잡한 명령어들을 수백개 이상 탑재하고 있는 프로세서입니다. CISC는 명령어 개수 증가에 따라 프로세서 내부구조가 매우 복잡해 지고, 고속으로 적동되는 플세서를 만들기 힘듭니다.

여기서 명령어가 복잡하다는 것의 의미는 하나의 명령어가 할 수 있는 일의 양이 RISC 대비하여 많다는 것을 의미합니다. 명령어 마다 길이가 다르고, 실행에 필요한 사이클 수도 다르기 때문에 pipelining 설계가 어려우며 한 바이트 명령어 부터 100바이트 이상되는 명령어 들도 있습니다.

이렇게 CISC는 RISC에 비해 성능이 많이 떨어지지만 다음과 같은 이유 때문에 아직도 쓰이고 있습니다.

CISC의 특징

  1. 명령어의 개수가 많음
  2. 명령어 길이가 다양하며, 실행 사이클도 명령어 마다 다름
  3. 회로구성이 복잡함
  4. 프로그램을 만들 때 적은 명령어로 구현 가능
  5. 다양한 명령어를 사용하기 때문에 컴파일러가 복잡함

CISC를 사용하는 이유

  1. 아직 너무도 많은 프로세서가 CISC 모델로 구축되어 있고, 이것을 전부 바꾸는 것은 너무 큰 비용이 든다.
  2. CISC 성능의 취약점은 RISC와 같은 파이프라인을 일부 사용하고 집적도는 더 높임으로써 부분적으로 보완이 가능하다.
  3. RISC에 비해 호환성이 좋다.

캐시란 무엇인가요?

캐시란 메모리와 프로세서 사이에 있는 메모리 계층을 나타내기 위해 선택된 이름이며, 오늘날 대부분의 컴퓨터가 캐시 메모리를 사용하고 있습니다.
위의 도서관에서의 예처럼 캐시는 ‘책상’ 의 역할을 수행합니다. 우리는 도서관에서 책상위의 책들을 뒤적거려 책을 찾는다면 캐시는 어떻게 정보를 찾을 까요? 캐시는 다양한 형태로 구성되지만 이번 강의에서는 가장 대표적인 캐시 내의 정보를 찾는 방법으로 직접 사상 캐시 를 기반으로 하여 설명을 진행합니다. 직접 사상 이란 바로 메모리 주소에 기반하며 메모리 주소 하나당 캐시 내의 정확한 하나의 물리적 위치가 사상되는 방식입니다. 이러한 직접 사상 방식에서 실제 물리 메모리는 주소값 을 가지는데 이 주소값의 마지막 몇자리를 인덱스로 하여 캐시에 저장이 됩니다. 가령 물리 메모리의 주소값이 0101100101 이고, 블록의 수가 8개 라면 끝의 3자리(log2_8)는 인덱스 필드로 캐시 내에서의 주소를 담당합니다.
모든 직접 사상 캐시는 블록을 찾기 위하여 다음의 사상 방식을 사용합니다.

(블록주소) modulo (캐시 내에 존재하는 전체 캐시 블록 수)

위의 사상 방식을 따르면 10101011, 11101011, 00101011 처럼 끝의 인덱스 필드가 같은 메모리의 정보들을 캐시 메모리에서 같은 블록에 사상될 것입니다. 이렇게 되면 가져온 블록이 정말 원하는 정보인지 알 수 있어야 하며 이를 위해 태그 필드가 존재합니다. 이 태그 필드는 주소 중에서 인덱스 필드를 제외하고 남은 숫자들이며 이를 통해 해당 블록이 찾고자 하는 블록인지 알 수 있습니다.

캐시 블록은 항상 유효한 숫자를 가지고 있을까요?
만약 캐시가 비어있고나 혹은 올바르지 못한 값을 가지고 있는 경우가 있을 수 있습니다. 심지어 이 데이터는 물리 주소에 없는 값일 수도 있고요, 그렇다면 이러한 블록을 어떻게 표기해야 할까요?
이를 위해 캐시에는 유효 비트 라는 것이 존재합니다. 이 비트가 1로 설정되어 있지 않으면 유효한 블록이 없는 것으로 간주합니다.

이처럼 캐시는 예측 기법 을 통해 자료의 찾는 속도를 빠르게 해 주는 역할을 하며, 현대 컴퓨터에서 캐시 예측 적중률은 95% 이상입니다.

필요한 캐시의 사이즈는 어떻게 알 수 있나요?
필요한 캐시의 사이즈는 전체 블록의 수와 블록의 크기를 가지고 알 수 있습니다.
여기서 가장 중요한 점은 캐시는 몇개의 블록으로 구성되지만 블록이 정확한 값을 들고 있는지 알기 위해서 태그 필드유효 비트(1비트) 를 별도로 필요하게 되며, 이것은 블록의 사이즈와 별도로 필요한 공간 이라는 점입니다. 또한, 인덱스 필드 의 경우는 캐시 메모리에 영향을 주지 않는데, 그것은 바로 인덱스 필드는 별도로 비트 필드를 가지지 않아도 하드웨어에서 물리적인 주소로 바로 연결이 되는 것이기 때문에, 인덱스를 가르쳐 주기 위한 별도의 비트는 필요하지 않습니다.

예를 들어,
32비트의 직접 사상 캐시가 있고, 2^n개 블록 을 가지고 있다고 하면 당연히 n개의 비트는 인덱스 필드 에 사용됩니다.
또 실제 캐시에서는 블록의 크기가 1워드보다 보통 크기 때문에, 만약 블록의 크기가 2^m개 워드 라고 하면 m개 비트는 블록 내부에서 워드를 구분 하는 데에 사용되며 하나의 워드는 4바이트로 구성되므로 2 개의 비트는 주소 중 바이트 구별용 으로 사용됩니다.

이 경우 태그 필드의 길이는

32-(m+n+2) 가 되며,

직접 사상 캐시의 전체 비트 수는
2^n * (블록 크기+태그 크기+유효 비트 크기) 이므로

2^n _ (2^m _ 32 + 32-n-m-2 + 1) = 2^n(32*2^m+31-n-m) 비트 이다.

캐시 실패의 경우는 어떻게 처리되나요?
만약 캐시에서 원하는 정보를 찾지 못하는 경우에는 임시 레지스터와 프로그래머에게 보이는 레지스터의 내용을 그대로 유지한 채 메모리로부터 데이터가 오기를 기다리면서 전체 시스템이 지연되게 됩니다. 캐시 실패의 처리 단계는 다음과 같습니다.

  1. 원래의 PC값(현재 PC 값 -4)을 메모리로 보낸다.
  2. 메인 메모리에 읽기 동작을 지시하고 메모리가 접근을 끝낼 때까지 기다린다.
  3. 메모리에서 인출된 데이터를 데이터 부분에 쓰고, 태그 필드에 주소의 상위 비트를 쓰고 유효 비트를 1로 만들어서 캐시 엔트리에 쓰기를 수행한다.
  4. 명령어 수행을 첫 단계부터 다시 시작하여 캐시에 명령어를 가져온다. 이제는 필요한 명령어를 캐시에서 찾을 수 있다.

캐시에 데이터 쓰기

캐시에 데이터를 수정하고 저장하는 경우 데이터 캐시에만 작성 되고 메인 메모리에는 쓰지 않아지는 불일치 가 나타날 수 있습니다. 이를 해결하는 방법 중 하나는 즉시쓰기(write through) 이며, 통해 데이터를 항상 메모리와 캐시에 동시에 작성하게 됩니다. 하지만 이는 프로세서의 성능을 심하게 저하시키고 보통은 쓰기 버퍼 를 활용하여 일단 캐시에만 작성하고 천천히 메모리에 작성되는 방식으로 처리합니다.

두번째 방법은 나중 쓰기(write-back) 입니다.
이 방식에서는 쓰기가 발생했을 때 새로운 값을 캐시 내의 블록에만 쓰고, 나중에 해당 블록이 캐시에서 쫓겨나는 경우 쓰기에 의해 내용이 바뀐 블록이라면, 메모리 계층 구조의 더 낮은 계층에 씌어집니다.

두 방식 모두 장단점이 있는데 이는 다음과 같습니다.

나중쓰기(write-back) 의 장점

  1. 각각의 워드는 프로세서에 의해 메인 메모리가 아닌 캐시가 받아들일 수 있는 속도로 쓰인다.
  2. 다수의 쓰기가 행해진 블록을 계층의 하위 계층에 한 번만 쓰면 된다.
  3. 블록들이 하위 수준에 쓰일 때, 전체 블록을 한꺼번에 쓰기 때문에 높은 대역폭을 효과적으로 사용할 수 있다.

즉시쓰기(write-through) 의 장점

  1. 실패가 발생해도 하위 수준 블록을 쓸 필요가 없으므로 간단하고 비용이 적게 든다.
  2. 즉시 쓰기는 나중 쓰기보다 구현이 간단하다, 하지만 실제적으로 즉시 쓰기 캐시는 쓰기 버퍼를 요구한다.

가상 메모리 시스템에서는 계층의 하위 수준에 쓰기를 수행할 때 매우 큰 지연시간이 발생하기 때문에 나중 쓰기 방식이 유일한 실용적인 대안이다.

캐시 성능의 측정

캐시가 무엇인지 알았다면 실제 캐시의 성능을 측정하고 분석하는 방법을 배워 봅시다.

캐시의 성능을 측정할 때의 기준은 필요한 메모리를 인출한 시간이라고 볼 수 있으며, 그에 따른 CPU 시간은 다음과 같습니다.

CPU 시간 = (CPU 클럭 사이클 + 메모리 지연 클럭 사이클) X 클럭 사이클 시간

위의 식에서 메모리 지연 클럭 사이클은 주로 캐시 실패 때문에 생기며 다음과 같이 읽기 지연 사이클과, 쓰기 지연 사이클로 나누어 지며 그 값 또한 다음과 같이 계산 할 수 있습니다.

메모리 지연 클럭 사이클 = 읽기 지연 사이클 + 쓰기 지연 사이클

읽기 지연 사이클 = 읽기 접근 횟수 / 프로그램 X 읽기 실패율 X 읽기 실패 손실

쓰기 지연 사이클 = (쓰기 접근 수 / 프로그램 X 쓰기 실패율 X 쓰기 실패 손실) + 쓰기 버퍼 지연

캐시 성능의 향상

앞에서는 직접 사상 으로 구성된 캐시와 캐시의 성능 측정에 대해 알아보았습니다.

직접 사상 캐시의 개념도

이번에는 캐시의 성능을 향상시키기 위한 방법을 알아봅시다.

유연한 블록 배치를 통한 캐시 실패 줄이기

기존에는 메모리 블록을 캐시에 넣을 때 각 블록이 캐시의 정확한 한 곳에만 들어갈 수 있는 단순한 배치 방법을 사용하였고, 이를 직접 사상 이라고 불렀습니다. 하지만, 실제로는 블록을 배치하는 다양한 방법이 존재하는데, 블록의 배치 방법에 따라 완전 연관 방식집합 연관 방식 이 있습니다.

완전 연관 방식

완전 연관 방식에서는 블록이 캐시 내의 어느 곳에나 위치할 수 있으며, 때문에 블록 하나를 찾기 위해서 캐시 내의 모든 엔트리를 검색해야 합니다. 물론 이러한 방법은 하드웨어 비용을 크게 증가시키기 때문에 블록을 적게 갖는 캐시에서만 유용합니다.

집합 연관 방식

m-way 집합 연관 캐시의 개념도

집합 연관 방식 은 직접 사상과 완전 연관 사상의 중간 방식입니다. 집합 연관 사상 캐시에서는 한 블록이 들어갈 수 있는 자리가 고정되어 있습니다. 가령 각 블록당 n개의 배치 가능한 위치를 갖는 집합 연관 캐시가 있다면 이를 n-way 집합 연관 캐시라고 부릅니다.

집합 연관 방식에서 메모리의 각 블록은 인덱스 필드에 의해 캐시 내의 한 집합으로 사상 되며, 때문에 일치하는 블록을 찾기 위해서는 집합 내의 모든 블록들을 검색 하여야 합니다. 직접 사상 캐시는 단순히 1-way 집합 연관 캐시라고도 볼 수 있습니다.

이렇게 연관 정도를 늘리는 것의 장점은 대개 실패율이 줄어든다는 것이며, 단점은 적중 시간의 증가입니다.
그 이유는 간단히 생각해 보면 이해할 수 있습니다. 가령 특정 블록을 찾을 때에 기존의 직접 사상 방식에서는 하나의 인덱스에 오직 하나의 블록만이 들어갈 수 있기 때문에, 다른 블록이 들어왔다면 기존의 블록을 삭제하고 새로운 블록을 저장하기 때문에 실패율이 높을 수 밖에 없습니다. 하지만 연관 방식 사상 을 통해서는 하나의 인덱스가 집합을 이루고 과거에 찾아진 블록이 해당 집합에 들어 있다면 캐시에 저장되어 있어 찾을 수 있으므로 실패율이 줄어들게 됩니다. 단점인 적중 시간의 증가도 같은 원리로 만약 하나의 블록을 특정 집합에서 찾았다면 기존의 직접 사상 방식에서는 각 집합마다 블록이 유일하게 존재하므로 집합 내에서 검색이 필요하지 않았습니다. 하지만 n-way 집합 연관 방식에서는 특정 집합을 찾을 이후에도 집합 내에서 n 개의 엔트리 중에서 일치하는 태그인 블록을 찾는 시간이 추가되기 때문에 적중 시간이 증가 하게 됩니다.

집합 연관 방식에서 집합 내의 블록은 어떻게 교체될까요?
집합 연관 방식 사상을 할 때 집합 내에는 정해진 수의 블록 만이 들어갈 수 있으므로, 집합이 가득 찾다면 기존의 블록이 새로운 블록으로 교체되어야 합니다. 이 경우 가장 많이 쓰이는 방법은 LRU 교체 방식 을 사용합니다. 즉, 가장 오래전에 사용된 블록이 교체 됩니다.

집합 연관 방식에서는 캐시 내에서 블록을 어떻게 찾을까요?
직접 사상 캐시에서와 같이 집합 연관 캐시 내의 블록도 블록 주소를 나타내는 주소 태그 를 가지고 있습니다. 선택된 집합 내 모든 블록의 태그는 프로세서로 부터 나온 태그와 일치하는 지를 검사하게 됩니다. 여기서 빠른 속도가 매우 중요하기 때문에 선정된 집합 내 모든 태그는 병렬로 검색이 수행됩니다.
완전연관 캐시 의 경우에는 실제로 한 개의 집합 만이 존재하며 모든 블록들은 병렬로 검사가 되게 됩니다.

다단계 캐시를 이용한 실패 손실 줄이기

현대의 모든 컴퓨터는 캐시를 사용하고 있으며, 프로세서의 빠른 클럭 속도와 상대적으로 점점 느려지는 메모리 접근 시간 사이의 차이를 줄이기 위해, 고성능 마이크로프로세서들은 캐시를 한 계층 더 사용합니다.

여기서 각 단계의 캐시들을 L1, L2, L3, L4 로 부르고 각각은 1차, 2차, 3차, 4차 캐시를 의미합니다.
다단계 캐시를 이용한 CPU 에서 1차 캐시에서 미스가 발생하면 2차 캐시에서 다시 검색을 하고 2차 캐시에서도 미스가 발생하면 메인 메모리 접근이 필요하게 되고 더 큰 실패 손실이 발생하게 됩니다.

1차 캐시와 2차 캐시의 설계 시에는 각자 다른 것을 우선시 합니다. 가령 1차 캐시의 경우에는 어차피 실패를 해도 2차 캐시에서 데이터를 찾는 작업이 일어나므로 메모리 접근이 필요 없기 때문에 실패율이 그다지 높지 않아도 됩니다. 대신, 제일 많이 접근이 되는 만큼 적중 시간의 최소화 에 초점을 맞추어 설계를 진행합니다. 반대로 2차 캐시 의 경우에는 실패가 일어나면 메인 메모리 접근이 필요하게 되기 때문에 긴 메모리 접근 시간으로 인한 손실을 줄일 수 있도록, 실패율이 중점을 맞춘 설계 를 합니다. 같은 원리로 1차 캐시는 실패 손실을 줄이기 위해 블록 크기가 더 작으며, 2차 캐시는 실패율을 줄이기 위해 크기가 더 크고, 높은 연관정도가 많이 사용된다.

본 강의에서는 컴퓨터 구조에서 파이프라이닝 이 무엇이며 어떤 역할을 수행하는 지를 알아봅니다.

파이프라이닝이란

파이프라이닝 이란 마치 조립 라인처럼 어떤 명령어가 중첩되어 실행되는 구현기술입니다.
보통 파이프라이닝을 설명할 때에는 세탁소에서 세탁을 하는 절차를 비유하여 많이 이용하며 세탁소가 세탁을 하는 절차를 컴퓨터에 빗대어 설명을 해보도록 하겠습니다.
세탁소에서 세탁을 하기 위해서는 먼저 다음과 같은 순서로 세탁물을 처리합니다.

  1. 세탁기에 한 아름의 더러운 옷을 넣는다.
  2. 세탁기 작동이 끝나면 젖은 옷을 건조기에 넣는다.
  3. 건조기 작동이 끝나면 건조된 옷을 탁자 위에 놓고 접는다.
  4. 접는 일이 끝나면 같은 방 친구에게 옷을 장롱에 넣어달라고 부탁한다.

하지만, 위 순서대로 차례차례 일을 진행하는 것 만큼 바보같은 짓은 없을 것이다.
세탁기가 다 돌아가기를 기다렸다가 세탁이 다 되면 젖은 옷을 건조기에 넣고 건조기가 다 돌아가면 접어서 장롱에 넣는 일련의 전차들은 사실 각 단계 를 담당하는 별도의 자원(세탁기, 건조기, 나, 친구) 들이 있는 한은 모두 동시에 처리될 수 있다.

이 작업을 파이프라이닝을 한다면 다음과 같을 것이다.

  1. 첫번째 빨래가 다 돌아가면 건조기에 빨래를 넣고 나는 다시 세탁기에 옷을 집어 넣는다.
  2. 건조기와 세탁기가 다 돌아가면 나는 건조된 옷을 접고, 세탁이 된 빨래를 건조기에 넣고, 새로운 빨래를 세탁기에 넣는다.
  3. 옷을 다 접었으면 친구에게 옷을 장롱에 넣어달라고 하고, 다시 빨래를 개고, 건조기에 세탁이 된 옷을 넣고, 새로운 빨래를 세탁기에 넣는다.

위처럼 동시에 처리 가능한 일들을 동시에 처리함으로써 처리량 을 올리는 것이 파이프라이닝의 핵심이다.

이 경우 중요한 점은 각 단계를 수행하는 속도가 빨라지지는 않느다는 점이다. 모든 단계는 원래의 동작속도대로 일을 해 나가지만 병렬적으로 처리를 함으로써 쉬는 시간을 없애어 전체 처리량 을 올려 많은 작업을 빠른 시간 내에 처리 할 수 있도록 하는 것이다.

위 과정에서 알 수 있듯이 할 일이 충분히 많다면 파이프라이닝에 의한 속도 향상은 파이프라인의 단계 수와 같다. 위의 예에서는 세탁, 건조, 빨래 개기, 장롱에 넣기 의 4 단계로 파이프라이닝이 진행되므로 4배 빠른 시간에 작업량을 처리 한 것이 되고 처리량은 4배 증가 한 것이 된다.

여기서 또 유의깊에 보아야 할 부분은 각 단계별 걸린 시간이다.
세탁, 건조, 개기, 넣기 4가지의 작업을 하는 각 단계별로 걸리는 시간은 물론 전부 다를 것이다. 하지만, 파이프라이닝을 한 경우에 우리는 제일 빠른 단계의 작업이 끝나도 전체 작업이 다 끝나는 것을 기다렸다가 다음 단계로 넘어갈 수 밖에 없다. 가령 건조가 빨리 다 끝나더라도 세탁기가 덜 돌아갔다면 세탁기가 다 돌아가기를 기다려야 하는 것이다. 컴퓨터 시스템에서 이러한 한 단계를 처리하는 시간을 컴퓨터의 클럭 사이클 이라고 하며, 파이프라이닝에서 클럭 사이클은 전체 단계 중 가장 시간이 오래걸리는 것을 기준으로 한다.

이처럼 이상적으로 파이프라인 프로세서에서 속도향상은 파이프 단계 수와 거의 같아야 하지만 위와 같은 문제 때문에 향상 률은 단계수보다는 조금 적으며, 파이이프라이닝 되지 않은 컴퓨터와 파이프라인 컴퓨터에서의 실제 프로그램의 전체 실행시간의 비율은 명렁어 사이의 시간 비율에 가깝다.

파이프라인 해저드

각 명령어가 다음 클럭 사이클에 실행되지 못하는 상황을 파이프라인 해저드라고 하며 3가지 종류의 해저드가 있다.

구조적 해저드

첫번째 해저드는 구조적 해저드 라 불리는데, 이는 가은 클럭 사이클에 실행하기를 원하는 명령어의 조합을 하드웨어가 지원할 수 없기 때문에 발생하는 해저드이다.
가령, 세탁소의 예를 들면 세탁기와 건조기가 붙어있다던지, 혹은 장롱에 개어진 세탁물을 넣어줄 친구가 없다던지 하는 경우이다. 이러한 해저드를 없애기 위해서는 설계자가 파이프라인을 설계하는 시점에서 구조적 해저드를 피하는 것이 비교적 용이하다.

데이터 해저드

두번째 해저드인 데이터 해저드 는 어떤 단계가 다른 단계가 끝나기를 기다려야 하기 때문에 파이프라인이 지연되는 경우 생기는 것으로, 컴퓨터 파이프라인에서는 앞선 명령어에 종속성을 가질 때데이터 해저드가 일어난다. 가령, add 명령어를 사용하여 %s0 레지스터에 값을 저장하고, 바로 다음 명령어에서 sub 명령어 혹은 기타 명령어를 통해 &s0에 저장된 값을 사용하는 경우 첫번째 명령어에서 미처 데이터가 레지스터에 저장되기도 전에 해당 레지스터를 참조하게 되어 연산이 이루어 질 수가 없게 된다.

이를 해결하기 위한 방법 중 하나는 바로 전방전달(forwarding) 혹은 우회전달(bypassing) 이다.
이것은 별도의 하드웨어를 추가 하여 정상적으로는 얻을 수 없는 값을 내부 자원으로부터 일찍 받아오는 것을 의미하는데, 레지스터나 메모리에 아직 나타나지 않은 데이터를 기다리지 않고 데이터패스를 추가로 하드웨어에 연결하여 내부 버퍼로 부터 가져오는 것이다.

앞의 add 연산 뒤에 바로 sub 연산을 처리하는 경우를 예로 들면, 하드웨어 자체에 앞에서 계산한 결과가 나오는 부분에서 다음 연산의 뺄셈의 입력 부분으로 새롭게 데이터 패스를 연결하여 데이터가 레지스터에 씌어지기 전에 비트값으로 값을 받아와 연산에 활용하여 데이터 해저드 를 해결 할 수 있다.

하지만, 위의 예인 add와 sub 연산의 연속적 사용이 아닌 데이터 적재 명령어를 사용하는 경우 문제는 더 커진다. 이 경우에는 메모리의 적재까지 4단계 정도의 오랜 시간이 소요되고 이것을 기다리는 것은 너무도 큰 성능 저하를 불러 일으키는데 이러한 적재 명령어 사용에 따른 데이터 해저드를 별도로 적재 사용 데이터 해저드 라고 부른다. 이것은 파이프라인 지연(pipeline stall) 의 대표적인 예이며 거품(bubble) 이라는 별명으로도 지칭된다.

제어 해저드(control hazard) / 분기 해저드(branch hazard)

세번째 해저드인 제어 해저드분기 명령어 처럼 다른 명령어들이 실행 중에 한 명령어의 결과 값에 기반을 둔 결정 을 할 필요가 있을 때 일어납니다.
보다 쉽게 이해하기 위해 다시 세탁소의 예를 들어봅시다. 어떤 세탁소의 점원이 옷들을 세탁할 때 세탁 세제와 물의 온도를 선택함에 있어 옷들이 상하지는 않는 한도 내에서 강한 세제와 높은 온도를 통해 옷을 깨끗하게 세척을 해야 합니다. 하지만, 이 때 세탁소의 점원은 그 옷의 성질을 알지 못하므로 일단 한번 세탁을 한 뒤 말려보아야 올바른 세탁 세제와 물의 온도를 사용했는지를 알 수 있습니다. 이를 해결하기 위해서는 다음과 같은 세가지 해결법 이 있습니다.

지연

첫번째는 지연 으로, 첫번째 묶음의 옷들이 건조될 때까지 그냥 순차적으로 작업하되 올바른 비율이 결정될 때까지 계쏙 순차적 작업을 반복하는 것입니다. 위의 세탁소의 예를 들면 일단 옷을 세탁하고 말리는 작업까지를 했다면 그 결과값이 나올때까지 다음 세탁을 대기한 뒤 결과가 나오면 다시 파이프라이닝을 시켜 세탁을 시작합니다. 하지만, 이렇게 계속 반복적으로 분기 명령어 마다 지연을 시킨다면 훨씬 더 큰 속도 저하를 초래할 것입니다 때문에 다른 방법을 필요로 하게 되었고 만들어 진 것이 예측 기법입니다.

예측

예측을 수행하는 가장 간단한 방법은 분기가 항상 실패한다고 예측하는 것 입니다. 예측이 옳으면 파이프라인은 최고 속도로 진행되고, 실제로 분기가 일어날 때만 파이프라인이 지연이 됩니다. 좀 더 정교한 버전은 동적 하드웨어 예측기 를 이용하는 것으로 각 분기가 일어났지는 지록함으로써 최근의 과거 이력을 사용하여 미래를 예측하는 것입니다.

delayed branch

세번째 방법은 분기 지연 입니다. 이 방법은 분기가 필요한 명령어의 결과값이 나오는 동안 해당 분기와 관련이 없는 다양 명령어를 먼저 실행하여 시간이 지연되지 않도록 하는 방법이며, 이를 위해서는 명령어를 적합한 순서에 따라 배치해야하며 주로 컴파일 최적화 를 통해 이루어 질 수 있습니다.


왜 메모리 계층구조가 필요한가?

컴퓨터 내에서 프로그램이 동작하기 위해서는 프로그램이 메모리 위에 적재되어야 하고, 이상적으로 모든 프로그램이 메모리 위해 적재 될 수 있는것을 많은 프로그래머들은 바래왔습니다.
즉, 무제한의 크기를 가지는 빠른 메모리는 모든 프로그래머들을 꿈 이라고 볼 수 있습니다. 하지만, 메인 메모리는 메우 비싸기 때문에 이러한 무제한의 크기를 가지는 메인 메모리는 사실상 구현 불가능 하기에 메모리 계층 구조를 통해 한정된 메모리를 가지고 최대한 큰 크기의 메모리를 사용하는 것 처럼 컴퓨터가 행동하도록 노력했고, 그 결과 메모리 계층 구조가 도입되게 되었습니다.

메모리 계층 구조를 이해할 때에 흔히 도서관에서 공부를 하는 상황에 대입하여 생각해 볼 수 있습니다. 도서관에는 수많은 책들이 꽂혀 있고 언제든지 가져와서 책을 볼 수 있지만, 한번 책을 가져올 때 마다 상당히 귀찮고 오랜 시간이 소요되게 됩니다. 컴퓨터의 경우도 마찬가지 입니다. 여기서 도서관에 해당하는 것이 컴퓨터의 자기 디스크 입니다. 자기 디스크는 아주 크기가 크고 막대한 양의 자료가 들어갈 수 있지만 한번 접근하려면 오랜 시간이 걸리게 됩니다.

이 문제를 어떻게 해결해야 할까요?
보통 도서관에서 공부를 할 때 우리는 필요한 책들을 쭉 뽑아서 책상위에 쌓아두고 공부를 시작합니다. 이렇게 하면 우리가 필요한 대부분의 정보들은 책상 위에서 빠르게 얻을 수 있고, 사실 도서관 전체에는 나와 관련이 없는 많은 자료들이 있는 것에 반해 책상 위에 뽑아 놓은 책에는 내게 필요한 정보들이 존재하게 됩니다. 이렇게 필요한 책을 뽑아 우리가 필요할 만한 정보들을 주변에 배치해 놓는 것처럼 컴퓨터 에서도 우리가 자주 사용할 만한 정보들을 가까운 곳에 복사해 놓게 되고 이것을 우리는 캐시 라고 합니다.

캐시에 들어갈 정보들은 어떤 식으로 선별이 될까요?
이는 마치 도서관에서 책을 뽑아오는 것과 같은 논리이며 지역성의 원칙 에 따라 선별됩니다. 도서관에는 필요한 책들이 종류별로 분류되어 있고, 아마 내게 필요한 정보는 주변에 붙어 있을 확률이 높습니다. 내가 A라는 책을 가져오면서 혹시 몰라서 A 책 주변의 다양한 책들을 가져오는 것이 이러한 지역성의 원칙 을 따른 캐싱이라고 볼 수 있습니다. 또는, 내가 예전에 한번 봤던 책들에 내가 필요한 정보가 담겨있을 확률도 높습니다.
위처럼 내가 필요한 정보 주변의 책에 필요한 정보가 있을 확률이 높은 것을 공간적 지역성 이라 하고, 또 예전에 내가 사용했던 책에 필요한 정보가 있을 확률이 높은 것을 시간적 지역성 이라고 합니다. 이러한 두가지 지역성을 원칙에 따라 우리는 책을 가져오고 컴퓨터 에서는 캐싱 을 통해 이러한 작업을 수행합니다.

도서관에서 책 무더기를 가져오듯이 한번에 가져오는 정보의 최소 단위를 블록 이라고 합니다. 컴퓨터가 어떤 정보가 필요하다면 그 정보가 담긴 블록을 통으로 가져와서 작업을 수행하게 됩니다. 만약 필요한 정보가 이렇게 한번 가져온 블럭 중에 있는 경우를 적중(hit) 했다고 하고, 그 확률을 적중률 이라고 하며, 그 시간을 적중 시간 이라고 합니다.

만약 가져온 블록 중에 필요한 정보가 없는 경우는 어떨까요?
이 경우를 컴퓨터에서는 실패 라고 하며, 그 확률을 실패율 이라고 합니다. 이렇게 실패에 따른 손실은 실패 손실 이라고 하며 이는 하위 계층에서 블록을 가져와서 상위 계층 블록과 교체하는 시간에 그 블록을 프로세서에 보내는 데 걸리는 시간을 더한 값입니다.

이처럼 컴퓨터는 사용할 확률이 높은 정보들을 CPU에 가까지 적재하고 다른 정보들을 메모리 계층의 아래쪽에 위치시킴으로써 보다 빠르게 정보를 탐색할 수 있도록 하며, 때문에 메모리는 계층 구조 로 이루어져 있습니다.

메모리의 종류에는 어떤 것들이 있나요?

메모리 계층 구조에서 프로세서와 가장 가까운 캐시 는 SRAM이 사용되며, 메인 메모리 에는 DRAM 이 사용됩니다. SRAM은 어떤 데이터든지 접근 시간이 같고 리프레시가 필요없어 DRAM에 비해 아주 빠릅니다. DRAM 은 SRAM에 비해 아주 느립니다.


명령어 집합 구조가 구현의 여러 가지 측면을 어떻게 결정 하는지, 또 여러가지 구현 전략이 클럭 속도와 CPI에 어떻게 영향을 미치는지 살펴볼 기회를 갖게 될 것이다.
명령어 종류에 관계없이 어떤 명령어 던지 처음 두 단계는 다음과 같이 동일하다.

  1. 프로그램 카운터(PC)를 프로그램이 저장된 메모리로 보내어 메모리로부터 명령어를 가져온다.
  2. 읽은 레지스터를 선택하는 명령어 필드를 사용하여 하나 또는 두 개의 레지스터를 읽는다.

파이프라이닝에 대한 개관

파이프라이닝이란 여러 명령어가 중첩되어 실행되는 구현기술로써 기존의 단일 사이클 구조에서는 ALU 등 여러 장치가 다른 명령어를 실행하는 동안에는 동작하지 않는 것이 효율이 매우 떨어지기에 각 명령어를 처리할 수 있는 자원이 존재한다면 이를 병렬로 실행시켜 처리량을 올리는 기술이다.

서론

컴퓨터 하드웨어에게 일을 시키려면 하드웨어가 알아들을 수 있는 언어로 말을 해야하며, 컴퓨터 언어에서의 단어를 명령어 라고 하며 그 집합을 명령어 집합 이라고 한다.
본 강의에서는 명령어 집합의 하드웨어 표현방식 및 상위 수준 언어와의 관계를 보이며, 이를 통해 내장 프로그램의 개념을 이해한다.

하드웨어 연산

기본적으로 컴퓨터는 산술연산을 할 수 있으며 다음과 같은 명령어를 사용한다.

1
add a, b, c

위의 명령어는 b+c를 한 결과값을 a에 담는 식이다.

3. 피연산자

레지스터 라고 하는 하드웨어로 직접 구현된 특수 위치 몇 곳에 있는 것만 사용할 수 있다.
MIPS 구조에서 이러한 레지스터의 크기는 32비트(4 byte) 이며 총 32개로 레지스터의 갯수가 제한 되어 있으며 본 강의에서는 각 레지스터 마다의 성질을 보여주기 위해 $뒤의 숫자 가령 $t0와 같은 방식으로 레지스터를 표기한다.
레지스터의 수가 제한된 이유는 레지스터가 아주 많아지면 전기 신호가 더 멀리까지 전달되어야 하므로 클럭 사이클이 길어지기 때문이다.

레지스터 안에는 변수, 명령어 등이 저장될 수 있는데,프로그래밍 언어에는 단순한 변수 이외에도 레지스터 개수보다 훨씬 많은 데이터 원소수가 있을 수 있다.
산술연산은 레지스터에 의해서만 실행되므로 메모리의 값을 레지스터에 옮겨오기 위해서는 이들 사이에 데이터를 주고받기 위한 명령어가 필요한데, 이를 데이터 전송 명령어 라고 한다. 메모리에서 레지스터로 데이터를 옮기는 실제 명령어는 다음과 같다.

1
lw t0, 8($s3)

한 주소블록은 32비트(즉, 4byte)를 기준으로 하기 때문에
위 명령은 t0에 $s3에서부터 8번째 데이터를 담는 것이다.
즉 실제 주소는: $s3 + 8*4byte에 위치한다.

레지스터 연산을 할때 상수를 더하는 경우가 있는데, 이 경우에는 상수만을 위한 명령어 addi 등을 사용한다.
이 경우 상수값을 메모리에서 가져오는 것이 아니라 프로세서 내에서 바로 더해 줌으로써 훨씬 빠르게 처리를 할 수 있다.

상수 덧셈의 예

1
addi $s3, $s3, 4

어셈블리어의 기계어 표현

레즈스터 내의 기계어 명령어 필드

R타입

op rs rt rd shamt funct
연산자 피연산자 피연산자2 목적지 자리이동 양 기능
6bit 5bit 5bit 5bit 5bit 6bit

I 타입
| op | rs | rt | constant+address |
|:—- |:—- | —- | —————- |
| 6bit | 5bit | 5bit |21bit|

하드웨어의 프로시저 지원

프로시저는 일종의 함수 역할을 하는 것으로 전달인수 레지스터4개와 반환 레지스터 2개, 복귀주소 1개로 이루어져 있다.

서론

1940년 전자식 컴퓨터가 등장한 이래로 컴퓨터는 정보 혁명을 주도하며 컴퓨터와 관련 사업을 빠르게 발전시켰다.
스마트 가전제품 부터 슈퍼 컴퓨터 까지 삶의 다양한 분야에서 컴퓨터가 활용되고 있으며 크게 다음과 같은 세가지 응용분야에서 사용된다.

  • 개인용 컴퓨터
  • 서버
  • 임베디드 컴퓨터

개인용 컴퓨터는 많은 사람들이 잘 알고있듯이 가정 내에 보급된 pc를 말하며, 가정 및 비즈니스에서 산업용으로도 사용되고 있다.
서버는 과거 대형 컴퓨터로 불리던 것의 현대적 형태로써 보통 네트워크를 통해 접근되며 소규모 비즈니스 서버 등 주로 산업에서 인터넷을 통한 서비스 공급의 목적으로 사용되고 있다.
가장 많이 사용되는 임베디드 컴퓨터는 한 가지 응용을 수행하거나 서로 연관된 일련의 프로그램을 실행하도록 설계된 컴퓨터로 많은 가전기기 및 제품들에 탑재되어 있다.

단순 컴퓨터의 출생이 가지는 의미를 넘어 컴퓨터의 영향으로 세계 IT 산업은 송두리째 뒤흔들리고 있는 분야가 있는데, 그것은 바로 개인 휴대용 기기(PMD)클라우드 컴퓨팅 을 기반으로 한 sass 이다.

개인 휴대용 기기를 통해 사람들은 어디에서나 인터넷에 연결되어 진정한 초연결 사회로 거듭나게 되었으며, 엄청난 컴퓨팅 파워가 기반이 되어야 사용 가능했던 많은 컴퓨터 기반의 서비스들이 창고 규모의 컴퓨팅(WSC: Warehouse Scale Computing)으로 알려진 클라우드 컴퓨팅을 통해 서비스 로서의 소프트웨어(sass)로 제공되고 있다.

본 강의는 David A. Patterson과 John L. Hennessy의 책을 토대로 공부한 내용을 정리하며, 다음과 같은 내용을 배운다.

  1. 상위 수준으로 작성된 프로그램이 어떻게 하드웨어로 번역되고 동작하는가?
  2. 소프트웨어와 하드웨어 사이의 인터페이스는 무엇이며, 소프트웨어는 어떻게 필요한 일을 하드웨어에게 지시하는가?
  3. 프로그램의 성능을 결정하는 요소는 무엇이며, 프로그래머는 어떻게 성능을 개선하는가?
  4. 성능 개선을 위해 하드웨어 설계자는 어떤 기술을 사용하는가?
  5. 에너지 효율성을 개선하기 위해 하드웨어 설계자는 어떤 기술을 사용할 수 있는가?
  6. 최근 순차처리에서 병렬처리로 넘어가는 이유는 무엇이며 결과는 어떠한가?
  7. 컴퓨터 구조 분야의 어떤 위대한 아이디어들이 컴퓨팅의 기초를 닦았는가?

컴퓨터를 조작하는 명령어는 어떻게 작동하는가?

컴퓨터 하드웨어는 아주 단순한 명령을 실행 할 수 있도록 설계되어 있으며, 많은 현대 프로그래머들이 작성하는 복잡한 코드는 적절한 변환을 통해 컴퓨터가 알기 쉬운 언어로 번역되어 하드웨어를 동작한다. 프로그래머는 코드를 작성하면서 하드웨어의 구체적인 동작은 배제하고 프로그램을 작성이 가능한데, 이는 인간의 상위 언어인 프로그램 언어를 하드웨어와 무관하게 자유롭게 작성할 수 있도록 하는 추상화 의 일환이다.
즉, 프로그래머는 추상화된 언어인 상위 언어들을 사용함으로써 컴퓨터 내의 복잡한 일들을 신경쓰지 않고 더욱 정교한 시스템을 만들어 갈 수 있다.

소프트웨어와 하드웨어의 상호작용은 다음과 같이 일어난다.

_1. 상위 수준 언어로 코드를 작성

  1. 컴파일러가 상위수준 언어를 하위 언어인 어셈블리어로 변환시켜 줌
  2. 어셈블러가 어셈블리어를 컴퓨터가 알아들을 수 있는 이진수 체계로 변환시켜 줌_

컴퓨터 구조 분야의 8가지 위대한 아이디어

  1. 무어의 법칙을 고려한 설계
  2. 설계를 단순화하는 추상화
  3. 자주 생기는 일을 빠르게
  4. 병렬 처리
  5. 파이프라이닝을 통한 성능 개선
  6. 예측을 통한 성능 개선
  7. 메모리 계층구조
    최상위 계층에는 비트당 가격이 제일 바싸지만 작고 빠른 메모리를 사용하고, 최하위 계층에는 느리지만 크고 비트당 가격이 제일 싼 메모리를 사용한다.
  8. 여유분을 이용한 신용도 개선

컴퓨터의 구성과 기본 기능

컴퓨터는 기본적으로 다음과 같은 5가지 항목으로 구성된다.

  1. 입력 유닛
  2. 출력 유닛
  3. 메모리 유닛
  4. 데이터패스 유닛
  5. 제어 유닛

출력

컴퓨터의 출력은 주로 그래픽 디스플레이를 통해 이루어 진다.
오늘날의 LCD 디스플레이는 수만개의 화상으로 이루어져 있으며, 각 화상마다 작은 트랜지스터가 배치되어 있어 전류를 정밀하게 제어하는 능동 행렬을 사용한다.
각 화상은 화소의 행렬로 구성되며, 이것을 비트맵이라 부르는 비트들의 행렬로 포현한다.
컬러 디스플레이는 각각마다 8비트씩, 모두 24비트를 사용하여 수백만 가지의 색을 표시할 수 있다.

그래픽을 지원하는 하드웨어의 중심이 되는 것은 비트맵을 기억하는 프레임 버퍼 라고 하는 부분이며, 스크린에 표시될 화상을 프레임 버퍼에 자장하였다가, 기억된 각 화소들의 비트 패턴을 재생 속도에 맞추어 그래픽 디스플레이로 보낸다.

프로세서

디바이스 안에는 집적회로라 불리는 장치들이 있는데, 이는 프로그램의 지시대로 일을 하며, 데이터패스와 제어 유닛으로 나뉜다.
또한 프로세서 내에서 처리할 데이터를 잠깐 보관하기 위해 이를 캐시 메모리 라고 한다.

성능

컴퓨터의 성능이란 두 컴퓨터에서 같은 프로그램을 실행시키는 경우에 먼저 끝나는 쪽이 더 빠른 컴퓨터라고 할 수 있을 것이다.
하지만 사용하는 사람과 컴퓨터의 목적에 따라 다른 성능 척도가 필요 하다.
가령, 개인의 입장에서는 작업 개에서 종료까지의 시간인 응답시간 이 성능의 중요한 척도일 것이고, 데이터 센터 관리자에게는 일정 시간동안 처리하는 작업의 양인 처리량 혹은 대역폭 이 더 중요한 성능의 척도일 것이다.

다양한 성능 인자들

_프로그램의 CPU 실행 시간

프로그램의 CPU 클럭 사이클 수 * 단위 클럭 사이클 시간 = 프로그램의 CPU 클럭 사이클 수 / 클럭 속도

명령어당 클럭 사이클 수(CPI)
명령어 수 * 명령어당 평균 클럭 사이클 수

CPU 시간
명령어 개수 CPI 클럭 사이클 시간

IPC(Instructions Per clock Cycle)
클럭 사이클 당 명령어 수

MIPS(Million Instructions Per Second)
명령어 개수 / (실행시간*10^6)

예제

다음은 명령어당 클럭 사이클 수를 통한 성능 비교를 보여주는 표이다.

시스템 이름 명령어 수 CPI 소요 시간
A 5 2 250ps
B 6 1.2 500ps

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×