1강 컴퓨터 시스템으로의 여행

CSAPP 공부

1.1 정보는 비트**와** 컨텍스트**로 이루어진다.**

비트(Bit) : binary digit의 준말. 0과 1로 이루어진 가공된 데이터(정보)의 최소 단위이다.

보통 8bit = 1byte이지만, 반드시 그렇게 정의된 것만은 아니다.

1Mb 와 1MB는 다르며, 전자를 8로 나눈 결과가 후자이다. 우리가 흔히 광고에서 보는 인터넷 속도도 100Mbps도 초당 12.5MB의 속도라는 뜻이다.

컨텍스트(Context) : 단순한 정보 원본 이상으로 문맥, 상황에 따라 어떤 해석이 가미되어 이해되는 한차원 높은 공간을 의미한다. 하드웨어나 운영체제 관점에서 프로세서 안에 있는 레지스터, 플래그등의 현재 값 상태들의 집합를 의미한다. 소프트웨어 관점에서는 상황에 맞게끔 실행/결정/판단 해야 하는 부분을 의미한다. 더 나아가 문맥 교환(context switching)은 멀티태스킹 작업 수행시 태스크 상태 정보를 레저스터들에 저장 또는 이전 상태를 불러오기 위한 작업을 의미한다. 여기서 태스크 상태 정보는 CPU 레지스터, 메모리 스택을 의미한다.

따라서 문맥 교환은 하드웨어(CPU)와 소프트웨어(운영체제)간에 협동으로 이루어지는, 스레드 실행 상태의 저장과 복원 작업이다.

“hello world“를 print하는 간단한 프로그램(C 프로그래밍 언어)

프로그래머가 에디터로 작성한 소스 프로그램(소스파일)

Hello.c라는 텍스트 파일로 저장

소스 프로그램: 0 또는 1로 표시되는 비트들의 연속, 8비트 단위 구성(바이트)

바이트 : 프로그램의 텍스트 문자를 나타냄

대부분의 컴퓨터시스템 : 아스키 표준을 사용해 텍스트 문자 표시

아스키 표준 : 각 문자를 바이트 길이의 정수 값으로 나타냄

위 프로그램 : 연속된 바이트들로 파일에 저장

Ex) hello 는 104 101 108 108 111 로 저장

텍스트 파일 : 아스키 문자들로만 이루어짐

바이너리 파일: 다른 모든 파일

모든 시스템 내부의 정보 : 비트들로 표시

*내부의 정보 : 디스크 파일, 메모리상의 프로그램, 데이터, 네트워크를 통해 전송되는 데이터 등

서로 다른 객체 구분 방법 : 바라보는 컨텍스트

소스 프로그램(소스파일)

컴퓨터 프로그램을 사람이 읽을 수 있는 프로그래밍 언어로 쓴 텍스트파일

바이너리 파일

저장,처리 목적으로 0,1로만 나타낸 인코딩 파일

UTF-8

많은 문자를 binary 형태로 나타낼 때를 위해 정해 놓은 규격이자 가변 길이 유니코드 인코딩

예를들어, ‘가’를 0001,’나’를 0010이라 하면 ‘가나가나’는 0001 0010 0001 0010 또는

00010010 00010010 두가지로 쓸 수 있음

전자는 4바이트, 후자는 2바이트

이를 정한 규칙이 UTF-8

UTF-16도 있음

1.2 프로그램은 다른 프로그램에 의해 다른 형태로 번역된다.

위 프로그램은 인간이 형태를 이해하고 읽을수 있음 => 고급 C 프로그램

각 문장들은 다른 프로그램에 의해 저급 기계어 인스트럭션들로 번역됨

인스트럭션 => 실행가능 목적 프로그램 형태로 합쳐져 바이너리 디스크 파일로 저장

목적 프로그램 = 실행가능 목적 프로그램

컴파일 시스템

전처리 단계 -> 컴파일 단계 -> 어셈블리 단계 -> 링크 단계

전처리 단계(cpp) : 본래의 C 프로그램을 #문자로 시작하는 디렉티브에 따라 수정

첫줄은 전처리기(cpp)에게 시스템 헤더파일인 stdio.h를 프로그램 문장에 직접 삽입하라고 지시

그 결과 .i로 끝나는 새로운 C 프로그램 생성

컴파일 단계(ccl) : 텍스트 파일 hello.i를 텍스트파일인 hello.s로 번역

이 파일(hello.s)에는 어셈블리어 프로그램(main 함수의 정의 포함) 저장

*어셈블리어 프로그램 여러 상위수준 언어의 컴파일러들을 위한 공통의 출력언어 제공

어셈블리 단계(as) : 어셈블러(as)가 hello.s를 기계어 인스터럭션으로 번역

재배치가능 목적프로그램의 형태로 묶어 hello.o(목적파일)에 저장

바이너리 파일(Main 함수의 인스터력션들을 인코딩하기 위한 17바이트 포함)

Hello.o 우리가 열어서 보면 못알아는 데이터 모양

링크 단계(ld) : hello 프로그램이 표준 C 라이브러리(from C 컴파일러)에 들어있는 printf 함수를 호출

Printf 함수 : 이미 컴파일된 별도의 목적파일인 printf.o에 들어있음

Printf.o : hello.o파일과 어떤 형태로든 결합되야함 => 링커 프로그램(ld)이 수행

결과 : hello 파일은 실행가능 목적파일(실행파일)로 메모리에 적재되어 시스템에 의해 실행

프로그래밍 언어 : 저급어와 고급어로 나뉜다.

저급어 : 기계어, 어셈블리어

고급어 : C,Python,java 등

고급언어 : 프로세서 종류는 상관 없음 -> CPU의 종류가 달라도 코드에 지장이 없음, 사전 지식 필요 없음, 간단하고 이해하기 쉬운 문법, 적은 코드 양과 용이한 디버깅

어셈블리어 : 동일한 종류의 프로세서만 실행, 프로세서에 대한 사전지식 필요함, 메모리,입출력장치, 레지스터 등의 구성요소를 직접 다룰수 있음, 컴퓨터의 실행과정 이해가 쉬움

어셈블러 : 기계어 형태의 오브젝트를 코드로 해석해주는 언어 번역 프로그램. 어셈블리어 프로그램 입력, 하나의 어셈블리 명령은 하나의 기계코드에 대응. 종류로는 MASM, NASM, GAS등이 있음

컴파일러

고급 언어프로그램 입력

구문오류 검사

목적로드 생성

한 문장을 여러개의 기계코드로 변환한다.

헤더파일(인클루드 파일)

컴파일러에 의해 다른 소스파일에 자동으로 포함된 소스코드의 파일. 일반적으로 첫 부분에 있음. 함수원형, 매크로정의, 형정의 등이 담겨있음

인스트럭션

컴퓨터에게 일을 시키는 단위, 기계어로 이루어진 지시 or 명령, 명령부(op)와 처리부(operand)로 구성

명령부 : 동작을 의미, ‘동사’

처리부 : 동작의 대상, ‘목적어’, 직접 혹은 기억된 레지스터, 기억장치의 주소 등

1.3 컴파일 시스템이 어떻게 동작하는지 이해하는 것은 중요하다****

프로그램 성능 최적화 : 컴파일러가 어떻게 C 문장들을 기계어 코드로 번역하는지 알아야 함

Ex) switch문 vs if-else문의 연속 사용 : 항상 switch문이 효율적일까?, 함수 호출시 발생하는 오버헤드 등

링크 에러 이해: 정적변수와 전역변수 차이, 정적 라이브러리와 동적 라이브러리의 차이 등

보안 약점(security hole) 피하기: 버퍼 오버플로우(buffer overflow) 취약성은 신뢰할 수 없는 곳에서 획득한 데이터의 양과 형태를 주의 깊게 제한할 필요에 대한 인식 부족 때문

프로그램 스택에 데이터와 제어 정보가 저장되는 방식 때문에 생겨나는 영향 이해 필요

버퍼 오버플로우(buffer overflow)

하나의 프로그램은 수 많은 함수(지역변수, 복귀주소를 스택에 저장하는)로 구성되어 있다. 함수 종료시 OS가 함수를 호출한 프로그램에게 제어권을 넘겨준다. ‘복귀주소’가 이때 필요하다. 데이터 길이,내용 등으로 복귀주소를 바꾸면? => 프로그램은 비정상적으로 종료

1.4 프로세서는 메모리에 저장된 인스트럭션을 읽고 해석한다.

소스프로그램 : 실행가능한 목적파일로 번역되어 디스크에 저장(by 컴파일 시스템)

유닉스 시스템: 쉘(응용 프로그램의 하나) 이용

쉘 : 커맨드라인 인터프리터로 프롬프트 출력, 명령어 라인 입력 받아 실행

명령어 라인이 내장 쉘 명령어가 아니면? : 실행파일의 이름으로 판단하고 로딩하여 실행

1.4.1 시스템의 하드웨어 조직

소스프로그램 실행시 일어나는 일은 시스템의 하드웨어 조직 이해 필요

버스(Buses) : 시스템 내를 관통하는 전기적 배선군, 컴포넌트들 간에 바이트 정보들을 전송

워드(word)라고 하는 고정 크기의 바이트 단위로 데이터 전송하도록 설계됨.

한 개의 워드를 구성하는 바이트 수 : 시스템 마다 보유하는 기본 시스템 변수

ex) 일반적으로 4바이트(32비트), 8바이트(64비트)

입출력 장치 : 시스템과 외부세계와의 연결 담당

Ex) 입력용 키보드와 마우스, 출력용 디스플레이, 데이터와 프로그램의 장기 저장을 위한 디스크 드라이브

입출력 장치는 입출력 버스와 컨트롤러나 어댑터를 통해 연결(차이 : 패키징(packaging))

컨트롤러 : 디바이스 자체가 칩셋이거나 시스템의 인쇄기판(머더보드)에 장착

어댑터 : 머더보드의 슬롯에 장착되는 카드

메인 메모리: 프로세서가 프로그램을 실행하는 동안 데이터와 프로그램을 모두 저장하는 임시 저장장치

물리적 구성 : DRAM(Dynamic Random Access Memory)

논리적 구성 : 연속적인 바이트들의 배열, 각각 0부터 시작해서 고유의 주소(배열의 인덱스) 가짐

한개의 프로그램을 구성하는 각 기계어 인스트럭션은 다양한 바이트 크기를 갖는다.

C 프로그램 변수들의 데이터 크기 : 데이터 형에 따라

Ex) x86-64 컴퓨터(리눅스) : short type = 2byte, float = 4byte, long,double = 8byte

프로세서(주처리장치(CPU) = 프로세서) : 메인 메모리에 저장된 인스트럭션들을 해독(실행)하는 엔진

중심에 워드 크기의 저장장치(or 레지스터)인 프로그램 카운터(PC)가 있다.

즉 PC => 메인 메모리의 기계어 인스트럭션 지칭 (Personal Couputer 혼동 주의)

시스템에 전원 공급 시작~끝 : 프로세서는 프로그램 카운터가 가리키는 곳의 인스트럭션을 반복적으로 실행, PC값이 다음 인스트럭션의 위치를 가리키도록 업데이트

프로세서 : 자신의 인스트럭션 집합 구조(Instruction set architecture)로 정의되는 매우 단순한 인스트럭션 실행 모델을 따라 작동하는 것처럼 보임

이 모델에서 인스트럭션 : 규칙적인 순서로 실행, 여러 단계를 수행 => 한 개의 인스트럭션 실행

프로세서 : PC가 가리키는 메로리에서 인스트럭션 읽어옴 -> 인스트럭션에서 비트들을 해석 => 인스트럭션이 지정하는 간단한 동작 실행 => PC를 다음 인스트럭션 위치로 업데이트

새로운 위치 : 메모리상에서 이전 인스트럭션과 연속적일수도, 아닐수도

위 동작들은 메인 메모리, 레지스터 파일, 수식/논리 처리기(ALU) 주위를 순환

레지스터 파일 : 각각 고유의 이름을 갖는 워드 크기의 레지스터 집합으로 구성

ALU : 새 데이터와 주소 값을 계산

ex)인스트럭션 요청에 의해 CPU가 실행하는 단순한 작업

적재(Load) : 메인 메모리에서 레지스터에 한 바이트 또는 워드를 이전 값에 덮어쓰는 방식으로 복사

저장(Store) : 레지스터에서 메인 메모리로 한 바이트 또는 워드를 이전 값을 덮어쓰는 방식으로 복사

작업(Operate) : 두 레지스터의 값을 ALU로 복사하고 두 개의 워드로 수식연산을 수행한 뒤, 결과를 덮어쓰기 방식으로 레지스터에 저장

점프(Jump) : 인스트럭션 자신으로부터 한 개의 워드를 추출, 이것을 PC에 덮어쓰기 방식으로 복사

프로세서가 자신의 인스트럭션 집합 구조를 단순 구현? X

최신 프로세서 : 프로그램의 실행 속도 높이기 위해 더 복잡한 방식 사용

프로세서의 마이크로구조(microarchiteucture)와 인스트럭션 집합 구조 구별 필요

마이크로프로세서가 인식해서 기능을 이해하고 실행할 수 있는 기계어 명령어

1.4.2 hello 프로그램의 실행

쉘 프로그램 : 자신의 인스트럭션 실행, 사용자가 명령을 입력하기를 기다림

“.\hello” 입력시 쉘 프로그램은 각각의 문자를 레지스터에 읽어들인 후 메모리에 저장

키보드에서 엔터(Enter) 키를 누르면 쉘은 명령 입력이 끝난 것을 알게 됨

이후 쉘은 파일 내의 코드와 데이터를 복사하는 일련의 인스트럭션을 실행

실행파일 hello를 디스크에서 메인 메모리로 로딩

데이터 부분은 최종적으로 출력되는 문자 스트링인 “hello, world\n”을 포함

데이터는 직접 메모리 접근(DMA)이라고 알려진 기법으로 프로세서 거치지 않고 디스크에서 메인 메모리로 직접 이동

hello 목적파일의 코드와 데이터가 메모리에 적재된 후, 프로세서는 hello 프로그램의 main 루틴의 기계어 인스트럭션을 실행

인스트럭션은 ”hello, world\n“ 스트링을 메모리로부터 레지스터 파일로 복사, 거기로부터 디스플레이 장치로 전송하여 화면에 글자 표시

1.5 캐시가 중요하다

시스템이 정보를 한 곳에서 다른 곳으로 이동시키는 일에 많은 시간이 필요

Hello 프로그램 : 본래 하드디스크에 저장, 로딩 시 메인 메모리로 복사

프로세서가 실행할 때 인스트럭션들은 메인 메모리에서 프로세서로 복사, ‘hello’ 데이터 스트링도 같음

복사과정 : 프로그램의 ”실제 작업“을 느리게하는 오버헤드 => 빠르게 해야하는게 설계자의 목적

*오버헤드 : 특정한 목표를 달성하기 위해 간접적 혹은 추가적으로 요구되는 시간, 메모리, 대역폭 혹은 다른 컴퓨터 자원

큰 저장장치의 속도 < 작은 저장장치의 속도 (물리)

일반적인 레지스터 파일: 수백 바이트의 정보 저장

메인 메모리 : 10억개의 바이트 저장

프로세서 : 레지스터 파일의 데이터 읽는 속도 = (메모리 경우의 속도) * 100

이 격차는 점차 증가 : 메인 메모리보다 프로세서를 빨리 동작하도록 만드는 것이 쉽고 싸다

격차에 대응 : 시스템 설계자는 작고 빠른 캐시 메모리(캐시)라고 부루는 저장장치 고안

프로세서가 단기간에 필요로 할 가능성이 높은 정보를 임시로 저장

L1 캐시 : 수천 바이트의 데이터 저장, 레지스터 파일만큼 빠른 속도로 엑세스

L2 캐시(좀더 큼) : 수백 킬로바이트 ~ 수 메가 바이트의 용량, 프로세서와 전용 버스를 통해 연결

프로세서가 L2보단 L1 엑세스할때 5배 빠름 : 그래도 L2는 메인 메모리 엑세스보단 5~10배 빠름

L1,L2 캐시 : SRAM(Static Random Access Memory) 하드웨어 기술 이용해 구현 (L3도 있음)

캐시 시스템 : 지역성(locality : 프로그램이 지엽적인 영역의 코드와 데이터를 엑세스 하는 경향)을 활용하여 시스템이 매우 크고 빠른 메모리 효과를 얻음

자주 액세스할 가능성이 높은 데이터 : 캐시가 보관 => 빠른 캐시를 이용해서 대부분의 메모리 작업 수행

캐시를 활용하여 프로그램 성능을 개선할 수 있다.

1.6 저장장치들은 계층구조를 이룬다

작고 빠른 저장장치(ex. 캐시메모리)를 프로세서와 좀 더 크고 느린 장치(ex. 메인 메모리) 사이에 끼워 넣는 개념은 일반적인 아이디어.

메모리 계층구조 : 밑으로 갈수록 저장장치는 느리고, 크고, 바이트당 가격이 저렴

한 레벨의 저장장치는 다음 하위레벨 저장장치의 캐시 역할을 한다.

일부 분산 파일시스템을 가지는 네트워크 시스템에서 : 로컬 디스크는 다른 시스템의 디스크에 저장된 데이터의 캐시 역할 수행

로컬디스크 : 원격 네트워크 서버에서 파일들을 가져와 보관

L0 : Regs

L1 : L1 cache (SRAM)

L2 : L2 cache (SRAM)

L3 : L3 cache (SRAM)

L4 : Main memory (DRAM)

L5 : Local secondary storage (local disks)

L6 : Remote secondary storage (distributed file systems, Web servers)

1.7 운영체제는 하드웨어를 관리한다.

쉘 프로그램이 hello 프로그램 로드, 실행했을 때와 hello 프로그램이 메시지를 출력할 때 : 프로그램의 키보드,

디스플레이, 디스크나 메인 메모리에 직접 엑세스 X

운영체제(Operation System)가 제공하는 서비스를 활용

운영체제 : 하드웨어(Processor, Main memory, I/O devices)와 소프트웨어(Application programs) 사이에 위치한 소프트웨어 계층

응용프로그램의 하드웨어 제어 : 운영체제를 통해서만

목적 : 1. 제멋대로 동작하는 응용프로그램들이 하드웨어를 잘못 사용하는 것을 막음

  1. 응용프로그램들이 단순하고 균일한 메커니즘을 사용하여 복잡하고 매우 다른 저수준 하드웨어 장치들을 조작할 수 있도록 함

파일(Files) : 입출력장치의 추상화

가상메모리(Virtual memory) : 메인 메모리와 디스크 입출력 장치의 추상화

프로세스(Processes) : 프로세서, 메인 메모리, 입출력장치 모두의 추상화

1.7.1 프로세스

hello 프로그램 실행시 : 운영체제는 (1) 시스템에서 이 한 개의 프로그램만 실행되는 것?

(2) 프로세서, 메인 메모리, 입출력장치를 모두 독차지?

(3) 프로세서는 프로그램 내의 인스트럭션들을 다른 방해 없이 순차적으로 실행?

(4) 프로그램의 코드와 데이터가 시스템 메모리의 유일한 객채?

처럼 보이게 함.

프로세스 : 실행 중인 프로그램에 대한 운영체제의 추상화

다수의 프로세스 : 동일한 시스템에서 *동시에 실행 가능, 각 프로세스는 하드웨어를 배타적으로 사용하는 것처럼 느낌

*동시에(concurrently) : 한 프로세스의 인스트럭션들이 다른 프로세스의 인스트럭션들과 섞인다

보통 프로세스를 실행할 CPU의 숫자보다 더 많은 프로세스가 존재

문맥 전환(context switching) : 운영체제가 교차실행을 수행하는 방식

운영체제 : 프로세스가 실행하는 데 필요한 모든 상태정보(context)의 변화 추적

상태정보 : PC, 레지스터 파일, 메인 메모리의 현재 값을 포함

어느 한순간, 단일 프로세서 시스템은 한 개의 프로세스의 코드만을 실행할 수 있음

운영체제가 현재 프로세스에서 다른 새로운 프로세스로 제어를 옮기려고 할 때: 문맥전환을 실행

현재 프로세스의 컨텍스트를 저장, 새 프로세스의 컨텍스트를 복원시켜 제어권을 새 프로세스로 넘겨줌

새 프로세스는 이전에 중단했던 바로 그 위치부터 다시 실행

Ex: 두 개의 동시성(concurrent) 프로세스(쉘 프로세스. Heelo 프로세스)

  1. 쉘 프로세스가 혼자서 동작하고 있다가 명령줄에서 입력을 기다린다.
  2. Hello 프로그램을 실행하라는 명령을 받으면, 쉘은 시스템 콜이라는 특수 함수를 호출, 운영체제로 제어권을 넘겨줌
  3. 운영체제는 쉘의 컨텍스트를 저장하고 새로운 hello 프로세스와 컨텍스트를 생성한 뒤 제어권을 새 hello 프로세스로 넘겨줌
  4. hello가 종료되면 운영체제는 쉘 프로세스의 컨텍스트를 복구시키고 제어권을 넘겨주면서 다음 명령 줄 입력을 기다림

(하나의 프로세스 -> 다른 프로세스)의 전환 : 운영체제 커널(kernel)에 의해 관리

커널 : 운영체제 코드의 일부분, 메모리에 상주, 별도의 프로세스 아님, 모든 프로세스를 관리하기 위해 시스템이 이용하는 코드와 자료 구조의 집합

응용 프로그램이 운영체제에 어떤 작업 요청 -> 컴퓨터는 파일 읽기나 쓰기와 같은 특정 시스템 콜(system call)을 실행해서 커널에 제어 넘겨줌 -> 커널은 요청된 작업을 수행하고 응용 프로그램으로 리턴

프로세스 추상화 구현 : 저수준의 하드웨어와 운영체제 소프트웨어가 함께 긴밀히 협력

1.7.2 쓰레드(Thread)

프로세스는 쓰레드(Thread)라고 하는 다수의 실행 유닛으로 구성

각각의 쓰레드 : 해당 프로세스의 컨텍스트에서 실행, 동일한 코드와 전역 데이터를 공유

쓰레드 : 다수의 프로세스들에서보다 데이터의 공유가 더 쉬움, 프로세스보다 더 효율적 -> 프로그래밍 모델로 중요해짐

다중 쓰레딩 : 다중 프로세서를 활용할 수 있다면 프로그램의 실행 속도를 빠르게 하는 한 가지 방법

1.7.3 가상메모리

가상메모리 : 각 프로세스들이 메인 메모리 전체를 독점적으로 사용하고 있는 것 같은 환상을 제공하는 추상화

각 프로세스는 가상주소 공간이라고 하는 균일한 메모리의 모습을 가짐

리눅스의 경우 주소공간의 최상위 : 모든 프로세스들이 공통으로 사용하는 운영체제의 코드와 데이터공간

하위 : 사용자 프로세스의 코드와 데이터공간

위로 갈수록 주소 증가

각 프로세스들에게 보여지는 가상주소공간은 몇 개의 정의된 영역으로 구성

Kernel virtual memory ↑ Memory invisible to user code
User stack(created at run time)  
 
Memory-mapped region for shared libraries printf function
 
Run-time heep(created by malloc)  
Read/write data Loaded from the hello excutable file
Read-only code and data  
   

프로세스 가상주소공간(각 영역은 크기에 맞춰서 그린 것은 아니다.)



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

시스템은 하드웨어와 소프트웨어의 분리된 집합체? X

네트워크에 의해 다른 시스템과 연결 될 수 있음.

네트워크는 또 다른 입출력 장치로 볼 수도 있음.

시스템 : from 메인 메모리 -> 네트워크 어댑터로 일련의 바이트 복사할때

데이터는 not 로컬디스크 드라이브, but 네트워크를 통해서 다른 컴퓨터로 이동

또한 다른 컴퓨터로부터 받은 데이터를 읽어서 메인 메모리에 복사 가능

예제) hello 출력 프로그램을 telnet 응용을 사용하여ㅑ 다른 곳에 위치한 컴퓨터에서 실행하기 : telnet 클라이언트를 사용하여 로컬 컴퓨터를 원격 컴퓨터의 telnet 서버와 연결

‘hello’ 스트링을 telnet 클라이언트에 입력 -> 엔터(enter)키를 누른 후, 클라이언트 프로그램은 이 스트링을 telnet서버에 보냄 -> telnet 서버가 네트워크에서 스트링을 받은 후에, 원격 쉘 프로그램에 이들을 전달 -> telnet 서버는 네트워크를 거쳐 출력 스트링을 telnet 클라이언트로 전달 -> 클라이언트 프로그램은 출력 스트링을 자신의 로컬 터미널에 표시

1.9 중요한 주제들

시스템 : 단지 하드웨어 그 이상의 것

응용프로그램의 실행이라는 궁극의 목적을 달성하기 위해 협력해야 하는 하드웨어와 시스템 소프트웨어가 서로 연결된 것

1.9.1 amdahi의 법칙

우리가 어떤 시스템의 한 부분의 성능을 개선할 때, 전체 시스템 성능에 대한 효과는 그 부분이 얼마나 중요한가와 이 부분이 얼마나 빨라졌는가에 관계된다

T(old) = 어떤 응용을 실행하는데 걸리는 시간

α = 이 시스템의 어떤 부분이 이 시간의 α 비율 만큼만을 소모하여

k = 이것의 성능을 k배 개선하려 함

본래 요구 시간 αTold -> 개선 후 시간 요구

전체 실행시간은

$\combi{T}{new}\ =\ \left(1-\alpha \right)\combi{T}{old}+\frac{\alpha \combi{T}{old}}{k}\ =\ \combi{T}{old}\left[\left(1-a\right)+\frac{a}{k}\right]$Tnew = (1−α)Told+αToldk = Told[(1−a)+ak]

개선된 속도

$S=\frac{\combi{T}{old}}{\combi{T}{new}}=\ \frac{1}{\left(1-\alpha \right)+\frac{a}{k}}$S=ToldTnew= 1(1−α)+ak

ex) 초기에는 전체 시간의 60% 소모 => α = 0.6

이 시스템의 일부분이 3배 빨라짐 => k = 3

속도 향상: 1/[0.4+0.6/3] = 1.67

결론 : 전체 시스템을 상당히 빠르게 하기 => 전체 시스템의 매우 큰 부분의 성능 개선 필요

Amdahl의 법칙의 특별한 경우 : k가 infinite라면? => 시스템의 일부를 택해서 그 성능을 무시할 수 있을 정도의 시간이 걸리는 지점까지 속도 올린다면?

$\combi{S}_{\infty }=\frac{1}{1-\alpha }$S∞=11−α

ex) 시스템의 60%을 시간이 거의 걸리지 않는 지점까지 속도를 올린다 => 총 속도개선율 = 1/0.4 = 2.5

(extra)상대성능을 표현하기

성능개선을 표현하는 좋은 방법 :

$\frac{\combi{T}{old}}{\combi{T}{new}}$ToldTnew

형태의 비율 이용

Told = 원본을 위해 요구되는 시간

Tnew = 수정본을 위해 요구되는 시간

실질적인 개선 => 1보다 큰 값 표출

“2.2x”배 = “2.2배“ (x는 접미사로 사용)

1.9.2 동시성과 병렬성

동시성(concurrency) : 다수의 동시에 벌어지는 일을 갖는 시스템에 관한 일반적인 개념을 말할 때 사용

병렬성(parallelism) : 동시성을 사용해서 시스템을 보다 빠르게 동작하도록 하는 것을 말할 때 사용, 컴퓨터 시스템의 다양한 수준의 추상화에서 활용 가능

쓰레드 수준 동시성

프로세스 추상화 개념 => 다수의 프로그램이 동시에 실행되는 시스템 => 동시성

by using 쓰레드 : 한 개의 프로세스 내에서 실행되는 다수의 제어흐름 가질 수 있음

단일 프로세서 시스템 : 하나의 윈도우에 웹 브라우저를, 다른 윈도우에는 문서 편집기를, 그리고 동시에 스트리밍 음악을 플레이하는 것처럼 한 명의 사용자가 다수의 태스크에 동시에 연관될 수 있게 해줌. 실질적인 계산? <- 한 개의 프로세서에 의해

프로세서가 다수의 테스크들 간에 전환할때 등 이 때의 시스템 구성

멀티프로세서 시스템 : 어떤 시스템이 여러 개의 프로세서를 가지고 하나의 운영체제 커널의 제어 하에 동작하는 경우 -> 멀티코어 프로세서, 하이퍼쓰레딩(HyperThreading)기법의 출현으로 일반화됌

여러 개의 CPU(코어)를 하나의 집적화된 칩에 내장

ex) 인텔 i7 프로세서 코어의 구성 : 네 개의 CPU코 코어를 가짐, 각각 별도의 L1,L2 캐시를 가짐, 코어는 메인 메모리 인터페이스 + 상위 수준 캐시 공유

하이퍼쓰레딩(HyperThreading, 멀티쓰레딩) 하나의 CPU가 여러 개의 제어 흐름을 실행할 수 있게 해줌

프로그램 카운터나 레지스터 파일 같은 여러 개의 동일한 CPU 하드웨어를 가짐 but 부동소수 연산기와 같은 다른 부분들은 한 개의 하드웨어만 가지는 구조와 연관

기존의 프로세서 : 쓰레드들 간의 전환 위해 약 2만 클럭 사이클 요구

하이퍼쓰레드 프로세서 : 매 사이클마다 실행할 쓰레드 결정

ex) one 쓰레드 : 데이터를 캐시에 로딩하기 위해 대기 필요

CPU -> another 쓰레드에 실행 가능

멀티프로세싱의 이용 -> 시스템 성능 개선

이유 1 : 다수의 태스크를 실행할 때, 동시성을 시뮬레이션할 필요 줄여줌

이유 2 : 멀티프로세싱으로 한 개의 응용프로그램을 빠르게 실행할 수 있음 but 프로그램이 병렬로 효율적으로 실행할 수 있는 멀티쓰레드의 형태로 표현되었을때만

인스트럭션 수준 병렬성

최근의 프로세서 : 훨씬 낮은 수준에서의 초상화로 여러 개의 인스트럭션을 한 번에 실행 가능 => 인스트럭션 수준 병렬성 (ex. 파이프라이닝)

*파이프라이닝 : 하나의 인스트럭션을 실행하기 위해 요구되는 일들을 여러 단계로 나누고 프로세서 하드웨어가 일련의 단계로 구성되어 이들 단계를 하나씩 각각 수행

각 단계는 병렬적으로 동작, 서로 다른 인스터럭션의 다른 부분을 이용하여 작동 => 단순한 하드웨어 설계로도 사이클당 한 개의 인스트럭션 실행에 근접하는 실행속도 유지

슈퍼스케일러(superscalar) : 사이클당 한 개 이상의 인스트럭션을 실행할 수 있는 프로세서(대부분의 최근 프로세서들 가능)

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

많은 최신 프로세서들은 최하위 수준에서 싱글 인스트럭션, 다중 데이터, 즉 SIMD 병렬성이라는 모드로 한 개의 인스트럭션이 병렬로 다수의 연산 수행 가능

SIMD 인스트럭션 : 보통 영상, 소리, 동영상 데이터 처리를 위한 응용프로그램의 속도를 개선하기 위해 제공, GCC같은 컴파일러에서 지원하는 특스 벡터 데이터 형을 사용하여 프로그램 작성이 안정적

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

추상화의 사용 : 전산학에서 가장 중요한 개념

in 프로세서 측면, 인스트럭션 집합 구저 : 실제 프로세서 하드웨어의 추상화 제공

추상화 : 기계어 코드 프로그램이 마치 한 번에 하나의 인스트럭션을 실행하는 프로세서에서 실행되는 것처럼 동작

but 실제 하드웨어 : 훨씬 더 정교 => 여러 개의 인스트럭션을 병렬로, 그러나 항상 간단한 순차적인 모델에 의거한 방식으로 실행

동일한 실행모델을 유지하기 때문에 다른 프로세서에 구현될 때도 다양한 범위의 비용과 성능을 나타내지만 동일한 기계어 코드 실행 가능

운영체제 측면에서 세 가지 추상화

파일 : 입출력 장치의 추상화

가상메모리 : 프로그램 메모리의 추상화

프로세스 : 실행 중인 프로그램의 추상화

+ 가상머신 : 운영체제, 프로세서, 프로그램 모두를 포함하는 컴퓨터 전체의 추상화 제공.

요약 :

    1. 컴퓨터 시스템은 응용프로그램을 실행하기 위해 함께 동작하는 하드웨어와 시스템 소프트웨어로 구성된다.
    2. 컴퓨터 내의 정보는 상황에 따라 다르게 해석되는 비트들의 그룹으로 표시된다.
    3. 프로그램은 ASCII 문자로 시작해서 컴파일러와 링커에 의해 바이너리 실행파일들로 번역되는 방식으로, 다른 프로그램들에 의해 다른 형태로 번역된다.
    4. 프로세서는 메인 메모리에 저장된 바이너리 인스트럭션을 읽고 해석한다.
    5. 컴퓨터가 대부분의 시간을 메모리, 입출력장치, CPU 레지스터 간에 데이터를 복사하는 데 쓰고 있으므로 시스템의 저장장치들은 계층구조를 형성하여 CPU 레지스터가 최상위에, 하드웨어 캐시 메모리, DRAM 메인 메모리, 디스크 저장장치 등이 순차적으로 위치한다.
    6. 계층구조의 상부에 위치한 저장장치들은 하부의 장치들보다 비트당 단가가 더 비싸고, 더 빠르게 동작한다.
    7. 계층구조 상부의 저장장치들은 하부의 장치들을 위한 캐시 역할을 수행한다.
    8. 프로그래머들은 이러한 메모리 계층구조를 이해하고 활용해서 자신이 작성한 C 프로그램의 성능을 최적화할 수 있다.
    9. 운영체제 커널은 응용프로그램과 하드웨어 사이에서 중간자의 역할을 수행한다.
    10. 운영체제는 세 가지 근본적인 추상화를 제공한다.
    11. 파일은 입출력장치의 추상화다.
    12. 가상메모리는 메인 메모리와 디스크의 추상화다.
    13. 프로세스는 프로세서, 메인 메모리, 입출력 장치의 추상화다.
    14. 네트워크는 컴퓨터 시스템이 서로 통신할 수 있는 방법을 제공한다.
    15. 특정 시스템의 관점으로 볼 때, 네트워크는 단지 또 하나의 입출력장치다.