Abstraction이란? 중요하지 않은 details(세부사항)를 감추는 것. 컴퓨터는 매우 복잡하다. 하지만 우리의 목표는 architecture, micro-architecture layer만 다루는 것이다.
컴퓨터는 application software, system software, hardware로 이루어진다.
또한 linker는 바이너리 코드로 이루어진 object file과 library file을 연결(link)하여 하나의 executable file로 만든다. 컴퓨터는 이 executable file를 실행하여 프로그램을 실행할 수 있다.
컴퓨터의 performance(성능)를 판단하는 기준은 다양하다.
우리는 response time에 집중할 것. performance = 1 / execution time 으로 정의한다. 즉, "X is n times faster than Y"라고 한다면? performance of X / performance of Y = execution time of Y / execution time of X = n 인 것이다.
ex) 어떠한 프로그램을 실행할 때, A는 10초, B는 15초가 걸린다.
=> A is 1.5 times faster than B.
어떠한 application의 response time은 많은 factor들에 영향을 받는다. operation system, other applications, network speed 등...
우리는 CPU time에 집중할 것이다. 다른 factor들은 무시하고, CPU time만 따지는 것.
둘은 역수 관계이다.
CPU time = clock cycles(clock counts) * clock cycle time = clock cycles / clock frequency
즉, 어떠한 CPU time은 그것이 필요로 하는 clock cycle의 개수 * clock cycle 하나 당 걸리는 시간 이다.
clock count나 clock time을 줄이고 clock frequency를 늘림으로써 performance를 향상시킬 수 있다.
ex) Computer A: 2GHz clock, 10s CPU time. 이때, Computer B는 CPU time을 6s로 줄이고 싶다. 이를 위해 faster clock을 사용할 수 있지만, clock count는 1.2배로 증가한다. Computer B의 clock은 얼마나 빨라져야 할까?
=> CPU time of B = clock count of B / clock rate of B = 0.6 * clock count of A / (2 * 10^9) 이다. 이때, clock count of B = 1.2 * clock count of A 이므로, B의 clock rate는 4GHz가 되어야 한다.
필요한 clock의 개수는? 필요한 instruction의 개수에, instruction 하나 당 필요한 clock의 개수를 곱하면 된다. 어떤 task를 하는 데에 5개의 instruction이 필요하고, 한 instruction이 평균적으로 2개의 clock을 필요로 한다면 총 5 * 2 = 10개의 clock이 필요한 것.
clock cycles = instruction count(IC) * cycles per instruction(CPI)
그러므로, CPU time = IC * CPI * clock time 이다.
clock count는 software, clock time은 hardware와 관련된 요소이다.
ex) Computer A: clock time = 250ps, CPI = 2.0
Computer B: clock time= 500ps, CPI = 1.2
Same ISA(instruction set architecture)
A와 B 중 어느 컴퓨터가 더 빠를까?
=> CPU time of A = IC of A * 2.0 * 250 = 500 * IC of A
CPU time of B = IC of B * 1.2 * 500 = 600 * IC of B
이때, IC of A = IC of B 이므로, A가 B보다 1.2배 빠르다.
IC는 ISA와 compiler, program에 의해서 결정된다.
여러 종류의 instructions가 섞여있을 때, average CPI = 총 clock cycles / IC 이다. instruction 하나가 필요로 하는 평균 cycle의 개수인 것.
ex) CPI of add instruction = 1 cycle
CPI of mul instruction = 32 cycles
프로그램 A가 32 add instructions, 1 mul instruction을 가진다고 하자. 이때 total clock cycles는? 32*1 + 1*32 = 64 cycles.
프로그램 B에서, 40%는 add, 60%는 mul이라면, B의 average CPI는? 0.4(B에서 add의 비율)*1(CPI of add) + 0.6(B에서 mul의 비율)*32(CPI of mul) 이다.
MIPS(Millions of Instructions Per Second)란? 1초에 몇 백만 개의 instructions가 수행될 수 있는지를 의미한다. 즉, MIPS가 2라면 1초에 200만 개의 instructions가 수행될 수 있는 것. 그러므로, MIPS = IC / (CPU time * 10^6) = IC / (IC * CPI * clock time * 10^6) = clock rate / (CPI * 10^6) 이다.
MIPS는 unit time에 수행되는 instruction의 개수이므로, MIPS가 높으면 higher performance라고 생각할 수 있다. 하지만 MIPS를 performance 판단의 척도로 섣불리 사용해서는 안 된다. 컴파일러 A와 B가 hello.c라는 파일을 컴파일했다고 하자. 이때 둘이 만들어내는 instructions의 개수는 다를 수 있다. 가령, A는 100만 개, B는 600만 개의 instructions를 만들었다고 하자. 그리고 이를 실행하는 데에 A는 2초, B는 3초가 걸렸다고 하자. 둘 중에 performance가 높은 쪽은?
=> 실행 시간이 적은 A이다. 그러나, MIPS는? A는 0.5, B는 2로 B가 더 높다.
전력 소모량은 capacitive load * voltage^2 * frequency 에 비례하기에, 성능을 높이기 위해 frequency를 증가시키면 전력 소모도 커지고 발열이 증가하게 된다. 이때, 반도체의 크기를 줄임으로써 전력 소모를 늘리지 않고 성능을 증가시킬 수 있다. Dennard scaling.
하지만 반도체 기술의 발전이 한계를 맞이하면서 트랜지스터의 크기를 줄여서 성능을 높이는 것이 힘들어지기 시작했다. End of Dennard scaling.
이러한 uniprocessor(프로세서가 한 개)의 한계를 극복하기 위해 여러 프로세서를 사용하는 multiprocessor 방식이 도입되었다. 여러 쓰레드를 동시에 수행하여, response time은 같아도 throughput을 늘릴 수 있다.
하지만 multiprocessor를 위해서는 parallel programming을 구현해야 하는데, 이는 구현하기 어려우며 기존의 프로그램들 역시 바뀌어야 한다. 또한 overhead가 발생한다. 일꾼이 두 배로 늘어난다고 해서 작업 속도가 두 배로 빨라지지는 않는다. Communication overhead도 있고, some part of work는 divide되기 어렵다. 즉, 코어 개수를 늘린다고 해서, 개수에 비례해 성능도 늘어나지는 않는다. Load balancing이 필요하다.
Moore's law(무어의 법칙)는 매 2년마다 집적회로의 트랜지스터의 개수가 2배로 늘어난다는 예측이다. 이는 일종의 예측 모델로, 이를 기반으로 하여 반도체 개발의 기술적 목표를 세울 수 있다.
하지만 최근에는 Moore's law is ending.
Design for Moore’s Law: 무어의 법칙은 2년의 시간이 흐를 때마다 컴퓨터에 사용되는 집적회로 속 트랜지스터의 개수는 두 배로 늘어나고, 이에 따라 성능도 증가하게 된다는 예측이다. 이에 따라 컴퓨터 구조를 설계할 때, 무어의 법칙을 고려해야 한다. 컴퓨터 설계 시간이 오래 걸릴수록 기술이 발달하게 되어 집적회로의 성능은 점점 증가하게 되기에, 이것을 감안하면서 컴퓨터 구조 및 그것의 성능을 설계해야 한다.
Use abstraction to simplify design: 컴퓨터를 설계할 때, 현재 집중하고 있는 부분을 제외한 나머지 부분은 추상화를 통해 간략화 한다. 즉 다른 부분의 세부 사항들을 숨김으로써 컴퓨터 구조의 설계가 더 용이할 수 있도록 한다.
Make the common case fast: 자주 발생하는 케이스들을 더 빨리 실행할 수 있도록 설계한다. 가령 컴퓨터가 instruction을 사용할 때, 다른 것들보다 더 자주 사용되는 instruction들을 더 빠른 시간 안에 실행될 수 있도록 설계하는 것이 해당된다.
Performance via parallelism: 컴퓨터가 여러 작업들을 처리할 때, 한 작업을 모두 처리한 후 다른 작업을 처리하는 방식보다 여러 작업을 동시에 작업할 수 있도록 설계한다. 즉 병렬적인 작업을 통하여 컴퓨터의 성능을 향상시킨다.
Performance via pipelining: pipelining이란 컴퓨터에서 어떠한 작업이나 명령어들을 병렬적으로 처리할 수 있도록(동시에 여럿을 처리할 수 있도록) 중첩하여 수행하는 것이다. 마치 어떠한 공장의 분업의 형태와 같다고 할 수 있다. 이러한 pipelining을 통해 컴퓨터의 성능을 향상시킨다.
Performance via prediction: 예측을 통하여 컴퓨터의 성능을 향상시킬 수 있다. 어떠한 예측이 틀렸을 때 그것의 복구 비용이 크지 않고, 예측 성공률은 높은 상황일 때, 예측을 하고 어떠한 작업을 미리 수행하는 방법을 통해 성능을 높일 수 있다. 가령, 어떠한 조건 분기의 결과를 예측하거나(branch prediction) 다음에 수행될 instruction을 예측하는 방법 등이 해당된다.
Hierarchy of memories: 컴퓨터의 저장 공간(메모리)에는 여러 계층들이 존재한다. 가장 위의 계층은 access 속도가 매우 빠르지만, 용량은 매우 작다. 아래 계층으로 내려갈수록 access 속도는 느려지지만 용량은 점점 커진다. 위 계층에 해당하는 메모리가 바로 캐시 메모리이다. 캐시 메모리에 자주 사용하게 되는 데이터를 저장하여, 해당 데이터에 매우 빠른 속도로 접근할 수 있도록 한다. 이를 통해 컴퓨터 이용자들은 컴퓨터가 메인 메모리에 빠르게 접근하는 것처럼 느끼게 된다.
Dependability via redundancy (for reliability): 여유분을 준비하여 컴퓨터가 신뢰성을 지닐 수 있도록 한다. 가령, 어떠한 데이터를 컴퓨터의 디스크에 저장할 때 여러 디스크에 저장하게 되면, 한 개의 디스크에서 오류가 발생하더라도 다른 디스크에 접근하여 신뢰성이 있는 정보(옳은 정보)를 도출할 수 있다. 이처럼 어떠한 문제 소자를 대비한 여유분을 통해 신뢰성을 확보할 수 있다.