#1 개념

1-1. 배경

  멀티 프로세싱이 널리 사용되면서 CPU 소켓 당 코어 수, 메모리 컨트롤러, 메모리 채널 및 마더보드의 CPU 소켓 수 등이 증가했다. 이러한 환경은 다수의 코어를 활용하여 연산 효율을 높이는 동시에 메모리 오버헤드 또한 발생시켰다. 각 코어가 임의의 데이터에 접근하기 위해 메모리 컨트롤러에 접근하는 것은 하드웨어적인 물리적 거리에 따른 지연시간을 초래한다. 간단한 예로, 아래 그림에서 CPU 소켓 0번의 코어가 CPU 소켓 1번에 연결된 메모리에 접근하려 할 때, 최대 2배의 지연시간이 발생할 수 있다. 이러한 이슈를 보완하기 위해 NUMA라는 개념이 도입되었다.

그림 1. NUMA architecture

1-2. 정의

   NUMA(Non-Uniform Memory Access)의 의미는 불균일 메모리 접근이라는 뜻으로 코어들의 메모리 접근 시간이 균일하지 않다는 것을 나타내며, 이는 주로 여러 CPU 소켓 및 여러 메모리 컨트롤러에 의해 지연 시간이 발생하는 시스템을 지칭한다. NUMA 아키텍처에서는 메모리 접근 시간을 균일화하는 것이 주요 과제로 다뤄지며, 이를 위해 같은 지역의 메모리를 사용하는 코어들을 그룹화하여 코어들의 메모리 접근 지연시간을 최소화하려는 노력이 이루어진다.

그림 2. NUMA Node Example

#2 사용법

2-1. 조회

  기본적으로 NUMA 노드와 관련된 명령어는 numactl을 사용하며 아래와 같은 명령어로 현재 시스템의 NUMA 구성을 조회활 수 있다.

numactl --show
numactl --hardware

2-2. 기타 명령어

# 프로세스 특정 메모리 바인딩
numactl --membind=0,1 --your_program_name 

# 프로세스 특정 코어 바인딩
numactl --physcpubind=0,2,4,6 -- your_program_name

# NUMA 노드 0에서 프로세스 실행
numactl --cpunodebind=0 --membind=0 your_program_name

 

 

참고 자료

'컴퓨터 과학 > 컴퓨터 구조' 카테고리의 다른 글

메모리 구조 (Memory Architecture)  (0) 2024.05.14
Memory Mapped I/O (MMIO)  (0) 2024.04.24

#1 아키텍처

1-1. Background

  흔히 RAM을 메모리라고 지칭하기도 하는데 정확한 범주에서는 RAM의 정의가 임의로 접근 가능한 메모리이기 때문에 메모리, SSD, HDD 등과 같은 보조기억장치도 포함하는 개념이다. 여기서 특징은 메모리는 휘발성 메모리이고, 디스크는 비휘발성 메모리라는 것이다. 이 글에서는 메모리에 대해 주로 다루고자 한다.

  • RAM(Random Access Memory): 임의 접근 메모리
  • VM(Volatile Memory): 휘발성 메모리
  • NVM(Non-Volatile Memory): 비휘발성 메모리

1-2. 세부 컴포넌트

  데이터를 저장하는 DRAM과 이를 연산하는 CPU, 이들 간의 데이터를 전달할 수 있는 인터페이스들까지 우리는 메모리라 일컫는다. DRAM은 메모리 모듈에 구성되어 마더보드와 연결되고, 마더보드는 CPU와 메모리 모듈이 데이터를 주고 받을 수 있도록 하고, 전원을 공급하는 역할을 한다. 각 인터페이스는 다음과 같다.

  • 마더보드: 하드웨어 구성 요소들을 연결하는 플랫폼으로써 전원을 공급하고 시스템 버스를 통해 데이터 및 제어 신호를 전달하여 상호 작용을 가능하도록 한다.
  • 메모리 컨트롤러: CPU 내부에 위치한 하드웨어로 코어의 메모리 엑세스 및 제어를 담당한다.
  • 메모리 버스: 마더 보드에 존재하며 CPU와 메모리 간의 데이터 및 제어 신호를 전송하는 통로이다.
  • 메모리 모듈: 흔히 말하는 DRAM 찹을 탑재하는 모듈로써 메모리 버스에 직접 연결되어 CPU의 메모리 컨트롤러를 통해 데이터를 주고 받는다.

그림 1. Memory overview

#2 메모리 컨트롤러

2-1. 위치 변화

  모놀리식 구조의 컴퓨터 구조에서 메모리 컨트롤러는 FSB를 통해 마더보드 내부의 노스브릿지와 연결되어 CPU가 메모리 컨트롤러로 요청을 보내면 메모리 컨트롤러가 DIMM과의 상호 작용을 통해 데이터를 전송하는 방식의 구조였다. 하지만 마이크로프로세서 구조로 넘어가면서 메모리 레이턴시를 줄이기 위해 CPU 내부로 메모리 컨트롤러의 위치를 옮겨가게 되었다. 이는 성능의 향상을 가져오기도 했지만 반대로 메모리가 CPU 타입에 귀속되는 결과도 가져오게 되었다.

2-2. 채널

  메모리 채널은 메모리 컨트롤러가 메모리 모듈과 연결되는 통로로 하낭의 채널은 하나의 메모리 모듈과 연결된다. 메모리 채널의 대역폭은 메모리 채널의 전송 속도와 비트 수를 곱한 것과 같다. 대역폭을 쉽게 늘리기 위한 수단으로 멀티/코어/옥타 채널도 요즘은 많이 사용한다.

그림 2. Quad channel overview

 

#3 DIMM (Dual In-line Memory Module)

3-1. 구성 요소

  • RCD: 시스템 클럭 신호를 버퍼링하여 CPU와 DIMM 사이의 연산 상호작용을 수행하는 칩
  • DRAM: 동적 임의 접근 메모리
  • Rank: 여러 DRAM 칩을 묶어 한 Rank를 구성
  • Bank: DRAM 칩의 물리적인 한 섹션
  • Row: bank 내의 행
  • Col: bank 내의 열

3-2. 동작

  비트 수에 따라 주소 구성 달라짐 페이징 기법에서 메모리 프레임 번호가 row/col + rank + bank + channel의 조합

 

 

 

참고 자료

'컴퓨터 과학 > 컴퓨터 구조' 카테고리의 다른 글

NUMA (Non-Uniform Memory Access)  (0) 2024.05.16
Memory Mapped I/O (MMIO)  (0) 2024.04.24

#1 Isolated I/O

  MMIO는 컴퓨터 구조에서 디바이스와 CPU 간의 통신 최적화 과정에서 개발되었다. MMIO를 이해하기 위해서는 MMIO 이전의 컴퓨터 구조를 살펴볼 필요가 있다. 이전의 컴퓨터 구조에서는 여러 디바이스가 같이 사용하는 공통 버스와 각각의 디바이스를 위한 제어 버스가 존재하였다. 공통 버스는 CPU와 디바이스 사이의 주소 공간을 전달하는 주소 버스와 데이터를 전달하는 데이터 버스로 이루어져 있고, 제어 버스는 각 디바이스에게 I/O 명령어를 보내기 위한 제어 라인 버스가 있다. 

그림 1. Isolated I/O Bus Overview

 

  하지만 이는 디바이스가 점점 많아지는 현대의 컴퓨터 구조에서는 아래와 같은 이유들로 비효율적이다. 

  • 각 디바이스 메모리를 주소 공간에 매핑하기 위한 별개의 주소 공간 -> 많은 디바이스 주소 공간들이 모두 메모리에 할당
  • 각 디바이스 메모리 주소 공간을 사용하기 위한 별개의 명령어들 -> 여러 개의 CPU 명령어, 구현하기에 복잡함, 느림
  • 버스의 수가 늘어나기 때문에 하드웨어 구조가 복잡해짐

#2 MMIO

  위의 단점들을 해결하는 방법으로 MMIO가 등장하였다. MMIO의 기본 원리는 디바이스 메모리를 메모리 주소 공간에 매핑하는 것이다. 이를 통해 CPU가 각 디바이스들의 주소 공간을 이용하기 위해 여러 개의 명령어를 사용하던 것과 달리 메모리 주소 공간만 사용할 수 있게 되었으며, 하나의 공통 제어 버스를 사용하여 여러 디바이스에 I/O 명령을 할 수 있게 되었다.

그림 2. MMIO Bus Overview

 

  이런 MMIO는 다음과 같은 장점들을 갖는다.

  • CPU가 디바이스에 메모리와 같은 속도로 접근할 수 있게 됨 -> 빨라짐
  • 메모리와 디바이스 주소 공간에 접근하는 명령어가 하나로 단순화 됨 -> 구현이 쉬워짐
  • 메모리 주소 공간 안에 여러 개의 디바이스 메모리 주소 공간을 매핑 -> 효율적인 메모리 사용

그림 3. Address space overview

하지만 MMIO가 갖고 있는 단점들도 있다.

  • 메모리 주소 공간에 여러 개의 디바이스 메모리 주소 공간을 매핑하기 때문에 디바이스를 위한 주소 공간이 제한됨
  • 디바이스의 처리 속도가 느리기 때문에 제어 버스에 병목점이 발생할 수 있음 -> 메모리 접근이 느려질 수 있음

#3 MMIO operation

        MMIO store는 단방향 소통으로 CPU가 메모리 주소 공간에 매핑된 디바이스 메모리의 주소를 통해 CPU 캐시의 데이터를 전송한다. 반면에 load는 양방향 소통으로 CPU가 디바이스 메모리 주소를 디바이스에 요청하면, 디바이스가 CPU 캐시에 데이터를 전송한다. 따라서 store는 호스트의 관점에서 명령을 전달하면 요청이 완료되지만, load는 데이터를 전달받기까지 데이터를 폴링하고 있어야 한다.

그림 4. MMIO operation

 

  위와 같은 상황에서 store 연산과 load 연산이 동시에 발생한다고 가정하면, 일관성과 동시성 문제에 있어서 순서를 보장하는 것이 매우 중요하다. 리눅스의 경우 커널 단위에서 아토믹 연산과 lock을 통해 순서 보장을 지원한다. 하지만 디바이스의 메모리는 이런 순서 보장에 취약하기 때문에 PCIe 상에 inflight 되는 요청은 하나만 가능하다. 따라서 store 연산은 연속된 요청이 들어와도 하나씩만 수행 가능하기 때문에 throughput이 매우 떨어지게 된다. 이를 해결하기 위해 커널에서는 Write-Combining Buffer(WC)를 이용하여 store 연산을 batching을 통해 throughput을 향상한다. MMIO는 일반적으로 작은 단위의 데이터 전달을 수행하기 때문에 WC의 사이즈는 64B cache-alined이며, 연산 간의 순서 및 버퍼 플러쉬를 보장하기 위해 sfence와 같은 알고리즘과 같이 동작한다.

 

 

 

그림 출처

- 그림 1: https://www.geeksforgeeks.org/memory-mapped-i-o-and-isolated-i-o/

- 그림 2:https://www.geeksforgeeks.org/memory-mapped-i-o-and-isolated-i-o/ 

- 그림 3: https://www.baeldung.com/cs/memory-mapped-vs-isolated-io

'컴퓨터 과학 > 컴퓨터 구조' 카테고리의 다른 글

NUMA (Non-Uniform Memory Access)  (0) 2024.05.16
메모리 구조 (Memory Architecture)  (0) 2024.05.14

+ Recent posts