TIL - 컴퓨터 시스템 - 1

김수인·2025년 5월 16일

크래프톤 정글

목록 보기
3/17
post-thumbnail

컴퓨터 시스템은 하드웨어와 시스템 소프트웨어로 구성되며, 이들이 함께 동작해 응용프로그램을 실행한다. 시스템의 구현방법은 시간에 따라 바뀔 수 있지만, 근본적인 개념들은 변하지 않는다.

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

// hello.c
#include <stdio.h>

int main()
{
  printf("hello, world\n");
  return 0;
}

작성한 글자는 컴파일러나 시스템에 의해 ASCII 코드 등의 숫자로 변환되고, 그 숫자는 비트(0과 1)로 바뀌어 메모리와 저장장치에 기록된다.
이런 변환은 모든 텍스트 처리의 기본 과정이며, 컴퓨터 시스템이 텍스트를 이해하고 처리하는 방식이다.
컴퓨터가 "글자를 이해한다."는 말의 실질적인 의미다.

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

linux> gcc -hello hello.c

C 소스 파일 hello.c가 최종적으로 실행 가능한 프로그램 hello로 변환되기까지는 단순한 비트 변환 그 이상으로, 여러 단계의 번역 과정을 거친다. 이 과정을 GCC 컴파일러 드라이버가 관리하며, 일반적으로 다음의 4단계를 거친다.

GCC 컴파일

컴파일 과정 그림

1. 전처리 (Preprocessing)

전처리기(cpp)는 본래의 C 프로그램을#문자로 시작하는 디렉티브(directive)에 따라 수정한다.

예시

  • #include<stdio.h>는 전처리기에 시스템 헤더파일인 stdio.h를 프로그램 문장에 직접 삽입을 지시한다.
  • #define PI 3.14PI를 3.14로 치환하는 매크로를 정의한다.
  • 외 다수 있음

핵심 요점

  • 전처리는 컴파일 전에 텍스트 수준으로 코드 수정을 수행한다.
  • 복잡한 조건부 컴파일, 매크로 처리 등은 전처리기로 모두 해결된다.
  • 최종적으로 수정된 C 코드가 컴파일러 단계로 넘어간다.

2. 컴파일 (Compilation)

컴파일러(cc1)는 텍스트파일 hello.i를 텍스트파일인 hello.s로 번역한다.

  • 컴파일러는 함수 선언이 아니라 함수 정의를 어셈블리 코드로 바꾼다.
    • 어셈블리 코드는 CPU가 실행할 수 있는 명령어들을 기호로 표현한 텍스트 형식의 언어다.
  • main 함수는 프로그램의 시작점(entry point) 역할을 하므로, 정의가 없다면 실행 가능한 코드가 생성되지 않는다.

3. 어셈블 (Assembly)

어셈블러(as)가 hello.s를 기계어 인스트럭션으로 번역하고, 이들을 재배치가능 목적프로그램의 형태로 묶어서 hello.o라는 목적파일에 그 결과를 저장한다.

  • 이 파일은 main 함수의 인스트럭션들을 인코딩하기 위한 17바이트를 포함하는 바이너리 파일이다.
  • hello.o 파일을 텍스트 편집기로 열어보면 쓰레기 같은 데이터로 보일 것이다.

4. 링크 (Linking)

printf 처럼 다른 파일이나 라이브러리에 정의된 함수들을 프로그램에 붙여서 실행 가능하게 만드는 과정이다.

링크 과정에서 벌어지는 일

  • hello.o 안에 printf를 사용한 흔적이 있음.
  • 링커가 libc 또는 libc.a, libc.so 같은 표준 라이브러리 파일을 뒤져서 printf의 구현을 찾음.
  • 찾은 구현을 프로그램에 붙임.
  • 이제 실행 파일 안에는 main도 있고, printf도 있게됨.

컴파일 시스템을 이해해야하는 이유

  • 최신 컴파일러들은 프로그래머가 효율적인 코드를 작성하기 위해서 컴파일러 내부 동작을 알 필요는 없다.
    - 하지만 C 언어에서는 알 필요가 있다.
  • 보안 약점을 피하는 데 매우 직접적인 관련이 있다.
    - 실제 해킹, 취약점 분석, 시스템 침해가 컴파일러와 바이너리 수준의 오작동 또는 허점을 파고들기 때문이다.
  • 소스 코드에는 문법적 문제가 없지만, 컴파일된 코드에서는 문제가되는 경우가 있다.
    - 함수 정의가 빠졌거나 외부 라이브러리 연결이 누락되는 경우 (링크 에러)

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

컴파일 시스템은 hello라는 실행 파일을 생성해 디스크에 저장하며, 이 파일은 쉘을 통해 실행할 수 있다.

linux> ./hello
hello, world
linux>

시스템의 하드웨어 조직

전형적인 시스템의 하드웨어 구성

버스(Buses)

시스템 내를 관통하는 전기적 배선군을 버스라고 하며, 컴포넌트들 간에 바이트 정보들을 전송한다. 일반적으로 워드(word)라고 하는 고정 크기의 바이트 단위로 데이터를 전송하도록 설계된다.

32bit OS: 4Byte, 64bit OS: 8Byte의 워드 크기를 가진다.

입출력 장치(I/O)

시스템과 외부 세계와의 연결을 담당한다. 키보드와 마우스, 디스플레이, 디스크 드라이브 등이 I/O 버스에 연결되어 정보를 주고 받는다.

메인 메모리

프로세서가 프로그램을 실행하는 동안 데이터와 프로그램을 모두 저장하는 임시 저장장치다. 물리적으로 메인 메모리는 DRAM(Dynamic Random Access Memory) 칩들로 구성돼 있고, 논리적으로 메모리는 연속적인 바이트들의 배열로, 각각 0부터 시작해서 고유의 주소(배열의 인덱스)를 가지고 있다.

프로세서

주처리장치(CPU)또는 간단히 프로세서는 메모리에 저장된 기계어 명령(인스트럭션)을 하나씩 읽고 실행하는 장치다. 이 과정을 전원이 꺼질 때까지 반복한다.

  1. 가져오기
  • PC(Program Counter)가 가리키는 메모리 주소에서 인스트럭션 1개를 읽음
  1. 실행 준비 및 실행
  • 읽은 인스트럭션의 비트들을 해석
  • CPU가 무슨 동작을 해야 할지 결정하고 실행
  1. PC 업데이트
  • 다음 인스트럭션을 실행하기 위해 PC 값을 다음 주소로 이동시킴
  • 점프 명령이 있다면 다른 주소로 이동
[인스트럭션 읽기] → [해석하고 실행] → [다음 인스트럭션 주소로 이동] → (반복)

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

적재(Load) -> 작업(Operate) -> 저장(Store) -> 점프(Jump)

적재(Load)

메인 메모리에서 레지스터에 한 Byte 또는 Word를 이전 값에 덮어쓰는 방식으로 복사한다.

작업(Operate)

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

저장(Store)

레지스터에서 메인 메모리로 한 Byte 또는 Word를 이전 값을 덮어쓰는 방식으로 복사한다.

점프(Jump)

인스트럭션 자신으로부터 한 개의 Word를 추출하고, 이것을 PC에 덮어쓰기 방식으로 복사한다.

예를 들어:

if (a + b > 10) x = 1;
  1. Load a, b 값을 메모리에서 가져온다.
  2. Operate a + b 계산
  3. Jump 조건 비교 후 결과에 따라 분기
    • 현재 명령의 실행을 중단하고, PC(Program Counter)를 새로운 주소로 강제로 바꾼다.
  4. Store x = 1 결과를 메모리에 저장

캐시가 중요하다.

캐시는 메인 메모리보다 훨씬 빠른 임시 저장소이며, CPU가 데이터를 훨씬 빠르게 접근할 수 있도록 도와준다.

  • CPU가 메모리를 직접 접근하면 느리다.
  • 캐시는 CPU 바로 옆에 있으므로, 메인 메모리보다 약 10배 이상 빠르게 접근 가능하다.
  • 그러나 캐시도 결국 CPU 자체보다 느리다.
    • CPU 레지스터보다 약 5배 정도 느리다고 함

CPU(프로세서)는 빠르게 발전하지만, 메모리는 상대적으로 느리게 발전하고 있다.

  • CPU는 매년 수십 %씩 속도, 병렬성, 명령어 처리 능력이 향상된다.
  • 반면, 메모리 속도는 그렇게 빠르게 늘지 않는다.
  • 메모리 응답을 기다리는 시간이 많아져 성능에 문제가 생긴다.

그래서 캐시가 중요하다.

  • 캐시는 이 속도 차이를 중간에서 완충해준다.
    • 자주 쓰는 데이터는 빠른 캐시
    • 덜 쓰는 데이터는 느린 메모리에 두는 방식으로 전체 속도 손실을 최소화하려 한다.

지역성 원리 활용

프로그램은 일반적으로 최근에 참조했던 데이터나 코드, 그리고 그 주변의 데이터나 코드를 다시 참조하는 경향이 있다. 캐시는 이러한 지역성 원리를 활용하여 자주 사용될 것으로 예상되는 데이터나 명령어를 빠른 캐시 메모리에 미리 가져다 놓음으로써, 프로세서가 필요로 하는 데이터를 빠르게 찾을 확률을 높입니다.

캐시가 전체 시스템에 미치는 영향

캐시의 성능은 전체 시스템 속도를 좌우하는 핵심적인 요소다. 프로세서가 캐시에서 필요한 데이터를 빠르게 찾을 수 있다면, 메인 메모리나 디스크까지 접근할 필요 없이 빠르게 작업을 계속할 수 있어 프로그램 실행 속도가 크게 향상된다.

결론적으로 캐시는 프로세서와 주 저장장치 사이의 치명적인 속도 차이를 효과적으로 완화하고, 프로그램의 지역성 원리를 활용하여 데이터 접근 속도를 비약적으로 높이기 때문에 컴퓨터 시스템 성능 향상에 있어 매우 중요하다.

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

메모리 계층 구조 사진

컴퓨터 시스템의 저장장치는 속도와 비용에 따라 여러 단계의 계층 구조를 이룬다. 레지스터, 캐시(L1, L2, L3), 주기억장치(메인 메모리), 디스크 저장소 등이 포함된다. 계층 구조에서 더 빠르고 작은 저장장치는 느리고 큰 저장장치보다 상위에 위치한다.

  • L0: CPU 레지스터
  • L1-L3: 캐시
  • L4: 주 기억장치(메인 메모리)
  • L5: 로컬 보조 저장장치(로컬 디스크)
  • L6: 원격 보조 저장장치(분산 파일 시스템, 웹 서버)

캐싱의 기본적인 역할은 자주 사용되는 데이터를 느린 저장장치에서 더 빠른 저장장치로 가져와 임시로 보관하는 것이다. 이를 통해 프로세서가 데이터를 필요로 할 때 느린 저장장치까지 가지 않고 빠른 캐시에서 데이터를 바로 얻을 확률(Cache Hits)을 높여 전반적인 성능을 향상시킨다.

네트워크 시스템에서 캐싱

다른 시스템의 디스크에 저장된 데이터(L6)는 로컬 시스템의 관점에서는 느린 원격 저장소에 있는 데이터다. 로컬 디스크(L5)는 이 원격 저장소보다 빠르므로, 자주 접근하는 원격 데이터를 로컬 디스크에 복사하여 저장해 두면 다음 번 접근 시 네트워크를 통해 원격 시스템에서 다시 가져오는 것보다 훨씬 빠르게 데이터를 읽을 수 있다.

운영체제와 하드웨어

운영체제는 하드웨어 장치(CPU, Main Memory, I/O Devices, Bus)를 관리하고, 응용 프로그램과 하드웨어 사이에서 중재자 역할을 한다.

  1. 악의적이거나 잘못 작성된 응용 프로그램으로부터 하드웨어를 보호한다.
  2. 응용 프로그램이 복잡한 저수준 하드웨어 장치들을 조작할 수 있도록 단순하고 균일한 메커니즘을 제공한다.

두 번째 목적, 하드웨어 사용을 단순화하기 위해 운영체제는 "추상화(Abstraction)" 개념을 사용한다.

프로세스(Processes)

프로세서, 주기억장치, 입출력 장치 등 시스템의 핵심 자원들을 추상화한 것이다. 프로세스는 실행 중인 프로그램의 인스턴스로, 운영체제는 여러 프로세스가 마치 자신만이 시스템 자원을 독점하는 것처럼 느끼게 한다. 하지만 실제로는 이러한 자원들을 효율적으로 할당하고 관리한다.
운영체제는 문맥 교환(Context Switch) 방식을 사용하여 여러 프로세스가 CPU 시간을 공유하는 것처럼 보이게 한다.

쉽게 말하자면,

gcc hello.c -o hello
./hello
  • ./hello를 입력하면 운영체제가 hello라는 프로그램을 실행한다.
  • 그 순간, 운영체제는 프로세스 하나를 만든다.
    • 메모리 공간을 잡는다.
    • 파일 접근 권한을 설정한다.
    • CPU 시간을 나눠준다.
    • 실행 상태를 관리한다.

운영체제는 프로세스를 통해 각 프로그램이 서로 간섭하지 않도록 완전히 독립되게 관리하고, 각 프로세스는 자기만의 메모리, 자기만의 상태를 갖고 돌아간다.

CPU 시간을 나눠준다의 의미
보통 컴퓨터에는 CPU 코어가 많아야 4개, 8개 정도인데, 동시에 실행되는 프로그램(프로세스)은 수십 개, 심지어 수백 개일 수도 있다. 그래서 운영체제는 하나의 CPU를 여러 프로세스가 돌아가며 사용하게 만들어야 한다.

예를 들어:
1. 브라우저를 켜둔다.
2. 동시에 음악 플레이어를 켠다.
3. 백그라운드에서 메신저가 메시지를 기다린다.

모두 동시에 실행 중처럼 보이지만, 사실은 운영체제가 CPU를 아주 빠르게 번갈아 줘가면서 실행시키는 것이다.

가상 메모리(Virtual Memory)

프로세스가 실제 물리 메모리를 직접 다루지 않고, 운영체제가 제공하는 논리적 메모리 공간이다. 프로세스가 마음껏 메모리를 쓰는 것처럼 보이게 해 주는 운영체제의 환상 기술이다. 실제 메모리가 부족해도, 각 프로그램은 마치 충분한 메모리를 독립적으로 쓰는 것처럼 실행된다.

파일(Files)

입출력 장치, 특히 디스크를 추상화한 것이다. 프로그래머는 복잡한 디스크의 물리적 구조나 접근 방식 대신, 파일 시스템 인터페이스를 통해 데이터를 파일 단위로 편리하게 다룰 수 있다.

커널

  • 커널은 운영체제 코드 자체를 의미하며, 운영체제의 핵심 부분이다.
  • 커널 코드는 항상 메인 메모리에 상주한다.
  • 커널의 주요 역할은 응용 프로그램이 운영체제에게 어떤 작업을 요청할 때, 그 요청된 작업을 수행하는 것이다.
  • 응용 프로그램은 시스템 호출(System Call) 방식을 사용하여 운영체제의 커널에게 작업을 요청한다.
    • 예를 들어, 파일 읽기/쓰기나 기타 입출력 관련 작업을 수행할 때 커널의 도움이 필요하며 시스템 호출을 통해 커널에게 제어권이 넘어간다.
  • 요청을 받은 커널은 응용 프로그램을 대신하여 필요한 하드웨어 자원(프로세서, 메모리, 입출력 장치 등)을 관리하고 제어하여 작업을 수행한다.
    • 응용 프로그램으로부터 하드웨어 보호
    • 응용 프로그램이 복잡한 저수준 하드웨어 장치를 조작할 수 있는 단순하고 균일한 메커니즘 제공
  • 커널은 별도의 프로세스가 아니라 운영체제의 관리하에 실행되는 코드이다.
  • 프로세스의 가상 메모리 공간에서 맨 윗부분은 커널을 위해 예약되어 있다.
    • 사용자 프로그램이 커널 영역에 직접 접근하는 것은 금지되어 있다.
    • 이는 시스템의 안정성과 보안을 유지하기 위함이다.

다른 시스템과 통신

컴퓨터 시스템은 네트워크를 사용하여 다른 시스템과 통신할 수 있다. 네트워크는 서로 연결된 컴퓨터 시스템들의 집합체로 간주한다.

시스템이 네트워크를 통해 다른 시스템과 통신하는 과정:

  1. 데이터 전송 요청: 한 시스템의 응용 프로그램이나 운영체제가 네트워크를 통해 다른 시스템으로 데이터를 보내거나 다른 시스템의 테이터를 요청한다.
  2. 하드웨어 인터페이스 사용: 이러한 통신은 시스템에 장착된 네트워크 어댑터와 같은 입출력 장치를 통해 이루어진다. 이 장치는 버스를 통해 CPU 및 주기억장치와 연결된다.
  3. 데이터 복사: 네트워크를 통한 통신은 한 기계의 주기억장치에서 다른 기계의 주기억장치로 데이터를 복사하는 방식으로 이루어진다.

인터넷의 출현과 글로벌 네트워크의 확산으로 인해 컴퓨터의 활용이 크게 증가했으며, FTP, 이메일, 웹 브라우징, telnet과 같은 일반적인 네트워크 응용 프로그램들은 모두 네트워크를 통해 데이터를 복사하는 기능으 사용한다.

Amdahl의 법칙

  • 암달의 법칙은 초창기 계산기 과학자였던 Gene Amdahl이 병렬 시스템의 성능 향상 효율에 대해 관찰한 근본적인 법칙이다.
  • 이 법칙은 시스템의 일부가 빨라졌을 때 전체 시스템의 성능이 얼마나 향상되는지를 정량적으로 나타내는 것이다.
  • 시스템의 한 부분을 개선하는 것이 전체 시스템의 성능에 얼마나 영향을 미치는지를 이해하는 데 도움이 된다.
    • 병렬 시스템뿐만 아니라 많은 종류의 시스템 및 작업에 적용될 수 있는 일반적인 원칙이다.

Amdahl의 법칙의 중요한 시사점

  • 전체 시스템의 성능 향상은 개선될 수 없는 부분의 비율에 의해 제한된다.
  • k 값이 무한대로 커지더라도, 즉 개선된 부분이 이론상 무한히 빨라지더라도, 전체 시스템의 최대 속도 향상은 1 / (1 - a)를 넘을 수 없다.
  • 전체 시스템 성능을 크게 향상시키려면 시스템의 매우 큰 부분, 즉 a값이 큰 부분을 개선해야 한다는 것을 의미한다. 일부만 개선해서는 전체 성능 향상에 한계가 있다.
profile
헤맨 만큼 내 땅이다

0개의 댓글