블로그 이전했습니다. https://jeongzero.oopy.io/
[Linux Kernel] NUMA란?
본문 바로가기
컴퓨터 관련 과목/운영체제 & 커널

[Linux Kernel] NUMA란?

728x90

NUMA?

numa를 설명하기 앞서 이전에 smp, amp에 대해서 설명한 적이 있다.

kernel of linux - interrupt(0)
저번 시간에 스케줄링시 사용되는 timeslice에 대해서 학습하였다. 이번 시간에는 timeslice를 커널이 어떻게 관리를 하는지에 대해서 간략하게 설명하고, 인터럽트에대해서 학습할 것이다. 손목시계를 생각해보자. HZ란 1초동안 몇번 째깍 거렸나를 나타내는 지표이다. 1000HZ는 1초동안 천번 째깍거렸다는 의미이다. 이는 물리시간에 배우는 의미이고 컴퓨터적인 의미로 해석하면 다음과 같다 매크로 상수로 선언된 해당 의미는 1초에 1000번 인터럽트가 걸린다는 의미이다.
https://wogh8732.tistory.com/292?category=807175

멀티 프로세싱 환경에서 여러개의 CPU가 하나의 공유된 메모리, 입출력 버스를 사용하는 멀티 프로세싱 아키텍쳐이다.

장점

SMP 시스템은 다중 CPU를 지원하기 때문에 병렬 프로그래밍 쉽고 각 프로세스들의 작업 부하를 효율적으로 분배 할 수 있다는 장점이 있다.

단점

단일 버스를 공유하여 사용하기 때문에 많은 수많은 복수개의 CPU 중 하나의 CPU가 메모리에 접근하기 되면 나머지 CPU들은 block되어 메모리의 처리가 늦어진다. 이를 병목현상이라 부른다.

따라서 SMP 시스템에서 확장되어 NUMA 시스템이 나오게 되었다

SMP 시스템에서의 가장 큰 문제점은 바로 병목현상이였다. 카페 알바로 예를 들어보자. 엄청 큰 카페가 새로 오픈하였고 일할 직업을 100명 뽑았다. 하지만 커피머신은 하나를 사용해서 커피를 뽑는다.

커피를 뽑을 수 있는 사람이 100명이여도 실제 한번에 하나의 커피만을 뽑을 수 있기 때문에 주문이 엄청 밀릴것이다. 그렇다면 커피 머신을 개조해서 한번에 4개씩 커피를 뽑을 수 있게 하면 전보다 훨신 더 많은 양의 일을 처리 할 수 있을 것이다.

바로 이런 단점을 해결한 것이 NUMA 시스템이다. NUM 시스템에서는 CPU를 몇개의 그룹으로 나누고 각 그룹에게 별도의 지역 메모리를 할당해준다

NUMA 구조 (https://cheonee.tistory.com/entry/Automatic-NUMA-Baleancingㅇㅇ?category=537099)

위 그림은 NUMA 구조를 잘 표현한다. 4개의 CPU를 각 그룹으로 나누고 메모리 일부(bank)를 연결 지었다. 이렇게 분류된 CPU-메모리 를 하나의 Node라 지칭하며 동일한 CPU 내의 메모리 접근은 Local Access라 부르고, 서로 다른 노드들간의 메모리 접근을 Remote Access라 한다

좀더 직관적으로 살펴보면 다음과 같다

2개의 CPU 그룹에는 각각 구분된 메모리 지역을 할당해준것을 볼 수 있다. Local memory란 실제 CPU 근처에 위치해 있는 메모리이다. (흔히 말하는 RAM)

램은 실제 아래처럼 생겼다

길다란 칩 단면을 Rank라 부르며 Rank에 달려있는 검윽색 놈들을 bank라고 부른다

RAM의 각 뱅크들이 각 CPU들에게 할당된다고 보면 된다. NUMA 시스템은 메모리에 접근하는 시간이 메모리와 프로세서간의 상대적인 위치에 따라 달라진다. 상대적인 위치에 따라 달라진단 의미는 아래의 그림을 보면 쉽게 이해 할 수 있다

메인 보드 구성도이다. 현재 보이는 메모리 단면이 Rank_0이고 그 뒷면이 Rank_1로 이해하면 된다.

대충 메인보드의 주 부품을 나열해봤다. 저기서 램의 각 뱅크들이 실제 CPU들과 연결되어 있고, 메모리와-CPU 사이의 거리가 가까울수록 메모리에 접근하는 시간이 빨라진다는 의미이다.

2. NUMA 구조

위에서 설명한 NUMA 구조도 결국 코드로 구현되어 관리된다. x86에서 NUMA 시스템을 위한 초기화 설정 부분은 x86_numa_init 함수에서 동작한다

void __init x86_numa_init(void)
{
	if (!numa_off) {
#ifdef CONFIG_ACPI_NUMA
		if (!numa_init(x86_acpi_numa_init))
			return;
#endif
#ifdef CONFIG_AMD_NUMA
		if (!numa_init(amd_numa_init))
			return;
#endif
	}

	numa_init(dummy_numa_init);
}

x86_numa_init 내부에서 numa_init 를 호출한다. 해당 함수안에서도 또 다양한 함수가 호출되는데 중요 flaw는 다음과 같다.

💡
x86_numa_init ⇒ numa_init ⇒ numa_init_array ⇒ numa_set_node

를 통해서 cpu에 NUMA 노드를 설정한다. (자세한건 소스코드를 분석하길 하면 알 수 있다)

NUMA의 각 메모리 Node들은 struct pglist_data로 관리된다

/*
 * On NUMA machines, each NUMA node would have a pg_data_t to describe
 * it's memory layout. On UMA machines there is a single pglist_data which
 * describes the whole memory.
 *
 * Memory statistics and page replacement data structures are maintained on a
 * per-zone basis.
 */
typedef struct pglist_data {
	struct zone node_zones[MAX_NR_ZONES];
	struct zonelist node_zonelists[MAX_ZONELISTS];
	int nr_zones;
#ifdef CONFIG_FLAT_NODE_MEM_MAP	/* means !SPARSEMEM */
	struct page *node_mem_map;
#ifdef CONFIG_PAGE_EXTENSION
	struct page_ext *node_page_ext;
#endif
#endif
#ifndef CONFIG_NO_BOOTMEM
	struct bootmem_data *bdata;
#endif
#ifdef CONFIG_MEMORY_HOTPLUG
	/*
	 * Must be held any time you expect node_start_pfn, node_present_pages
	 * or node_spanned_pages stay constant.  Holding this will also
	 * guarantee that any pfn_valid() stays that way.
	 *
	 * pgdat_resize_lock() and pgdat_resize_unlock() are provided to
	 * manipulate node_size_lock without checking for CONFIG_MEMORY_HOTPLUG.
	 *
	 * Nests above zone->lock and zone->span_seqlock
	 */
	spinlock_t node_size_lock;
#endif
	unsigned long node_start_pfn;
	unsigned long node_present_pages; /* total number of physical pages */
	unsigned long node_spanned_pages; /* total size of physical page
					     range, including holes */
	int node_id;
	wait_queue_head_t kswapd_wait;
	wait_queue_head_t pfmemalloc_wait;
	struct task_struct *kswapd;	/* Protected by
					   mem_hotplug_begin/end() */
	int kswapd_order;
	enum zone_type kswapd_classzone_idx;

	int kswapd_failures;		/* Number of 'reclaimed == 0' runs */

#ifdef CONFIG_COMPACTION
	int kcompactd_max_order;
	enum zone_type kcompactd_classzone_idx;
	wait_queue_head_t kcompactd_wait;
	struct task_struct *kcompactd;
#endif
#ifdef CONFIG_NUMA_BALANCING
	/* Lock serializing the migrate rate limiting window */
	spinlock_t numabalancing_migrate_lock;

	/* Rate limiting time interval */
	unsigned long numabalancing_migrate_next_window;

	/* Number of pages migrated during the rate limiting time interval */
	unsigned long numabalancing_migrate_nr_pages;
#endif
	/*
	 * This is a per-node reserve of pages that are not available
	 * to userspace allocations.
	 */
	unsigned long		totalreserve_pages;

#ifdef CONFIG_NUMA
	/*
	 * zone reclaim becomes active if more unmapped pages exist.
	 */
	unsigned long		min_unmapped_pages;
	unsigned long		min_slab_pages;
#endif /* CONFIG_NUMA */

	/* Write-intensive fields used by page reclaim */
	ZONE_PADDING(_pad1_)
	spinlock_t		lru_lock;

#ifdef CONFIG_DEFERRED_STRUCT_PAGE_INIT
	/*
	 * If memory initialisation on large machines is deferred then this
	 * is the first PFN that needs to be initialised.
	 */
	unsigned long first_deferred_pfn;
	/* Number of non-deferred pages */
	unsigned long static_init_pgcnt;
#endif /* CONFIG_DEFERRED_STRUCT_PAGE_INIT */

#ifdef CONFIG_TRANSPARENT_HUGEPAGE
	spinlock_t split_queue_lock;
	struct list_head split_queue;
	unsigned long split_queue_len;
#endif

	/* Fields commonly accessed by the page reclaim scanner */
	struct lruvec		lruvec;

	/*
	 * The target ratio of ACTIVE_ANON to INACTIVE_ANON pages on
	 * this node's LRU.  Maintained by the pageout code.
	 */
	unsigned int inactive_ratio;

	unsigned long		flags;

	ZONE_PADDING(_pad2_)

	/* Per-node vmstats */
	struct per_cpu_nodestat __percpu *per_cpu_nodestats;
	atomic_long_t		vm_stat[NR_VM_NODE_STAT_ITEMS];
} pg_data_t;

결국 하나의 노드는 pg_data_t 구조체를 통해 관리되고 . 이 구조체는 해당 노드에 속해있는 물리메모리의 실제 양(node_present_pages)이나 해당 물리메모리가 메모리 맵의 몇 번지에 위치하고 있는지를 나타내기 위한 변수(node_start_pfn) 등이 정의 되어 있다.

출처 : https://neohtux.tistory.com/11

위 그림은 NUMA 구조의 Node를 잘 표현되어 있다

이제 NUMA가 먼지 개념은 잡을 수 있을 것이다. 끝으트으읕

Referrence

728x90