본문 바로가기

컴퓨터 시스템 이야기

Chapter 1 컴퓨터 시스템으로의 여행(1.8 ~ 끝)

1.8 시스템은 네트워크를 사용하여 다른 시스템과 통신한다

개별 시스템의 관점에서 볼 때, 네트워크는 단지 또 다른 입출력 장치로 볼 수 있다. 시스템이 메인 메모리로부터 네트워크 어댑터로 일련의 바이트를 복사할 때, 데이터는 로컬 디스크 드라이브 대신에 네트워크를 통해서 다른 컴퓨터로 이동된다. 마찬가지로 시스템은 다른 컴퓨터로부터 받은 데이터를 읽어서 메인 메모리에 복사할 수 있다.

네트워크는 일종의 입출력장치다

hello 예제로 돌아가서 , telnet응용을 사용하여 hello프로그램을 다른 곳에 위치한 컴퓨터에서 실행할 수 있다. telnet 클라이언트를 사용하여 로컬 컴퓨터를 원격 컴퓨터의 telnet 서버와 연결하려 한다고 하자. 원격지 컴퓨터에 로그인하고 쉘을 실행시킨 후에 원격지 쉘은 입력 명령을 기다린다. 다음은 과정 예시입니다.

 

  • "hello" 스트링을 telnet 클라이언트에 입력하고 엔터 키를 누른 후, 클라이언트 프로그램은 이 스트링을 telnet 서버로 보낸다. telnet 서버가 네트워크에서 스트링을 받은 후에, 원격 쉘 프로그램에 이들을 전달한다. 다음으로, 원격 쉘은 hello 프로그램을 실행하고 출력을 다시 telnet 서버로 전달한다. 마지막으로 telnet 서버는 네트워크를 거쳐 출력 스트링을 telnet 클라이언트로 전달하고, 클라이언트 프로그램은 출력 스트링을 자신의 로컬 터미널에 표시한다.

1.9 중요한 주제들

1.9.1 Amdahl의 법칙

Gene Amdahl은 성능 개선의 효율성에 대해 간단하지만 직관적인 관찰을 함. 우리가 어떤 시스템의 한 부분의 성능을 개선할 때, 전체 시스템 성능에 대한 효과는 그 부분이 얼마나 중요한가 와 이 부분이 얼마나 빨라졌는가에 관계된다는 것이다. 어떤 응용을 실행하는 데 걸리는 시간이 $T_{old}$ 라 하자. 만일 이 시스템의 어떤 부분이 이 시간의 a비율만큼만을 소모하고, 이것의 성능을 k배 개선하려 한다고 하자. 즉, 이 컴포넌트는 본래 $ \alpha*T_{old} $ 시간을 요구하였으며, 이제는 $ (\alpha*\frac {T_{old}}{k}) $ 시간을 요구한다.

전체 실행 시간은 다음과 같다 $$ T_{new} = (1-\alpha)*T_{old} +{(\alpha T_{old})}/{k} $$ 이것으로부터 개선된 속도 $S= \frac {T_{old}}{T_{new}}$ 를 다음과 같이 구한다
$$ S= \frac {1}{(1-\alpha) + \frac {\alpha}{k}} $$ 일례로 전체 시간의 60%(a=0.6)만 소모한 이 시스템의 일부분이 3배(k=3) 속도가 빨라진다고 생각해보면 속도 향상은 $ \frac {1}{(0.4) + \frac {0.6}{0.3}} =1.67 $ 을 얻는다. 따라서 주요 부분에 대해 실질적인 개선을 하였지만, 총 속도 향상은 매우 적다. 전체 시스템을 상당히 빠르게 하기 위해서는 전체 시스템의 매우 큰 부분의 성능을 개선해야 한다.

한 가지 Amdahl의 법칙이 특별한 경우는 k를 ${\infty}$ 로 설정하는 효과에 대해 생각해보는 것이다. 즉, 시스템의 일부를 택해서 그 성능을 무시할 수 있을 정도의 시간이 걸리는 지멎까지 속도를 올릴 수 있다. 그러면 다음과 같은 결과를 얻음 $$ S_{\infty} = \frac {1}{1-\alpha} $$ 예를 들어, 우리가 시스템으 60%를 시간이 거의 걸리지 않는 지점까지 속도를 올릴 수 있다면, 총 속도 개선율은 2.5배 밖에 되지 않음. Amdahl의 법칙은 모든 작업을 개선하기 위한 일반적인 원칙을 설명한다.

 


1.9.2 동시성과 병렬성

컴퓨터 역사에서 두 개의 요구가 지속적으로 성능개선을 주도했다. 이러한 요구 모두 프로세서가 한 번에 더 많은 일을 할 때 개선되는 특징이 있다. 동시성 concurrency이라는 용어는 다수의 동시에 벌어지는 일을 갖는 시스템에 관한 일반적인 개념을 말할 때 사용하며, 병렬성 parallelism이라는 용어는 동시성을 사용해서 시스템을 보다 빠르게 동작하도록 하는 것을 말할 때 사용한다. 병렬성은 컴퓨터 시스템의 다양한 수준의 추상화에서 활용할 수 있다

 

스레드 수준 동시성

스레드를 이용하면 한 개의 프로세스 내에서 실행되는 다수의 제어 흐름을 가질 수도 있다. 1960년대 초반 시간 공유 기법의 출현으로 동시 실행에 대한 지원이 컴퓨터 시스템에 나타났다. 관습적으로 이 동시 실행은 시뮬레이션 형태로 실행되었으며,  한 개의 커뮤터가 실행하는 프로세스를 빠르게 전환하는 방법을 사용한다. 최근까지도 대부분의 실질적인 계산은 한 개의 프로세서에 의해 이루어지고 있다. 이것은 그 프로세서가 다수의 태스크들 간에 전환을 해야만 하는 경우에도 그렇다. 이러한 시스템 구성을 단일 프로세서 시스템이라고 한다.

어떤 시스템이 여러 개의 프로세서를 가지고 하나의 운영체제 커널의 제어 하에 동작하는 경우를 멀티 프로세서 시스템이라고 한다. 이런 시스템은 1980년대 이래로 대규모 계산에 이용되었지만, 보다 최근에는 멀티코어 프로세서들과 하이퍼 쓰레딩 기법의 출현으로 일반적인 환경이 되었다. 

멀티코어 프로세서는 여러 개의 CPU를 하나의 집적화된 칩에 내장하고 있다. 멀티 쓰레딩이라고도 하는 하이 퍼쓰 레딩은 하나의 CPU가 여러 개의 제어 프름을 실행할 수 있게 해주는 기술이다. 이것은 프로그램 카운터나 레지스터 파일 같은 여러 개의 동일한 CPU 하드웨어를 가지고 있는 반면, 부동소수 연산 기와 같은 다른 부분들은 한 개의 하드웨어만 가지고 있는 구조와 관련되어 있다.

프로세스 유형의 분류

기존의 프로세서가 스레드들 간의 전환을 하는 데 약 2만 클럭 사이클이 요구되는 반면, 하이퍼스레드 프로세서에서는 매 사이클마다 실행할 스레드를 결정한다. 예를 들어 어느 스레드가 데이터를 캐시에 로딩하기 위해 대기해야 한다면, CPU는 다른 스레드를 실행할 수 있다.

멀티프로세싱의 이용은 시스템 성능을 두 가지 방법으로 개선할 수 있다. 

  1. 다수의 태스크를 실행할 때, 동시성을 시뮬레이션할 필요를 줄여준다.
  2. 멀티 프로세싱으로 한 개의 응용프로그램을 빠르게 실행할 수 있지만, 프로그램이 병렬로 효율적으로 실행할 수 있는 멀티스레드의 형태로 표현되었을 때에만 가능하다. 따라서 멀티코어와 하이 퍼쓰 레딩 시스템의 출현이 하드웨어에 의해 가능해진 스레드 수준 병렬성을 활용할 수 있는 응용 프로그램의 작성 방법을 찾고자 하는 욕구를 크게 증대시킴.

인스트럭션 수준 병렬성

최근의 프로세서들은 훨씬 낮은 수준에서의 추상화로 여러 개의 인스트럭션을 한 번에 실행할 수 있다. 이전에는 한 개의 인스트럭션을 실행하는 데 여러 클럭이 필요했지만, 최근은 클럭마다 2.4개의 인스트럭션을 실행할 수 있다. 인스트럭션들은 시작부터 종료까지 훨씬 긴 시간이 필요하다(20사이클 이상). 하지만 4장에서 파이프라이닝을 배우는데, 파이프라이닝에서는 하나의 인스트럭션을 실행하기 위해 요구되는 일들을 여러 단계로 나누고 프로세서 하드웨어가 일련의 단계로 구성되어 이들 단계를 하나씩 각각 수행한다. 이들 단계는 병렬로 동작할 수 있으며, 서로 다른 인스트럭션의 다른 부분을 이용하여 작동한다. 매우 단순한 하드웨어 설계로도 사이클당 한 개의 인스트럭션 실행에 근접하는 실행 속도를 유지할 수 있다. 사이클당 한 개 이상의 인스트럭션을 실행할 수 있는 프로세서를 슈퍼 스케일러라고 한다.

싱글 인스트럭션, 다중 데이터 병렬성(SIMD)

많은 최신 프로세서들은 최하위 수준에서 싱글 인스트럭션, 다중 데이터, 즉 SIMD병렬성이라는 모드로 한 개의 인스트럭션이 병렬로 다수의 연산을 수행할 수 있는 특수 하드웨어를 가지고 있다.


1.9.3 컴퓨터 시스템에서 추상화의 중요성

추상화의 사용은 전산학에서 가장 중요한 개념이다. 예를 들면, 좋은 프로그래밍 연습의 한 가지 측면은 함수들을 간단한 응용프로그램 인터페이스 API로 정형화하는 것으로, 프로그래머가 그 내부의 동작을 고려하지 않으면서 코드를 사용할 수 있도록 해준다. 

프로세서 측면에서, 인스트럭션 집합 구조는 실제 프로세서 하드웨어의 추상화를 제공한다. 이러한 추상화로 인해 기계어 코드 프로그램은 마치 한번에 하나의 인스트럭션을 실행하는 프로세서에서 실행되는 것처럼 동작한다. 실제 하드웨어는 훨씬 더 정교해서 여러 개의 인스트럭션을 병렬로, 그러나 항상 간단한 순차적인 모델에 의거한 방식으로 실행한다. 동일한 실행모델을 유지하기 때문에 다른 프로세서에 구현될 때도 다양한 범위의 비용과 성능을 나타내지만, 동일한 기계어 코드를 실행할 수 있게 된다.