시스템 토폴로지

CMP (Chip-level Multi Processor)

  • 최근 CPU는 하나의 소켓에 멀티 코어로 구성 (하나의 칩에 여러 개의 프로세서)

cmp

SMP (Symmetric Multi Processor) / UMA (Uniform Memory Access)

  • 멀티코어 CPU를 여러 개 장착한 시스템의 경우 메모리를 2개 이상의 CPU가 접근
  • CPU와 메모리 사이를 네트워크로 연결하여 접근이 필요
  • 메모리를 공유하므로 한 번에 한 개의 프로세서만 하나의 메모리에 접근 가능 → 프로세서가 증가할수록 성능 문제 야기

smp

NUMA (Non-Uniform Memory Access)

  • 각 프로세서가 독립적인 로컬 메모리를 보유
  • 프로세서의 위치에 따라 메모리 접근 속도가 다름
  • 프로세서가 로컬 메모리에 접근할 때에는 다른 프로세서의 대기가 불필요하며 빠른 속도로 접근 가능
  • 각 CPU가 각 로컬 메모리에 접근하는 것은 동시에 일어날 수 있어서 성능 향상
    • 로컬 메모리에 접근하는 것을 로컬 액세스(Local Access)라고 함
  • 로컬 메모리가 아닌 다른 CPU에 붙어있는 메모리에 접근이 필요한 경우 메모리 접근 시간 증가
    • 다른 노드의 메모리에 접근하는 것을 리모트 액세스(Remote Access)라고 함
  • 로컬 메모리에서 일어나는 메모리 접근 횟수가 성능 향상에 중요한 인자

numa

NUMA 관련 커널/BIOS 파라미터

SNC (Sub NUMA Clustering)

  • 1개의 NUMA 노드를 두 개의 NUMA 노드로 쪼개는 것
    • 물리 CPU는 2개인데 시스템 상에서 인식하는 NUMA 노드는 4개
  • SNC가 켜지면 CPU의 리소스를 절반으로 나누어서 각각의 NUMA 도메인이 구성
    • LLC, 코어, 메모리 컨트롤러, 채널이 두 영역으로 나누어짐
  • 이상적인 경우에 메모리 레이턴시가 감소하는 이점
  • 단, worst case에 대해서는 일반 NUMA보다 메모리 레이턴시가 증가
    • Node N번 LLC 확인 → Node N번 컨트롤러/채널에서 확인 (best) → 같은 프로세서에 위치한 Node N+1번의 컨트롤러/채널에서 확인 (good) → 다른 프로세서에 위치한 노드의 컨트롤러/채널 확인 (worst)
  • BIOS 상에서 설정
    • 일반적으로는 디폴트로 disable 설정

BIOS의 Node interleaving

  • BIOS에서 NUMA를 기존의 SMP처럼 사용하도록 설정하는 기능을 제공
  • BIOS 상에서 Node interleaving이라는 설정 값으로 존재
    • Node interleaving - disabled가 NUMA 사용
    • Node interleaving - enabled가 NUMA 미사용
  • SMP 시스템처럼 전체 메모리에 일관된 주소로 접근 가능하지만 NUMA 구조를 SMP처럼 흉내내는 것이므로 SUMA(Sufficiently Uniform Memory Architecture)라고 불리기도 함
  • 어플리케이션이 NUMA와 맞지 않거나 최적화를 통한 빠른 성능보다는 균일한 응답속도와 대량의 메모리를 SMP처럼 사용하는 환경에 더 적합하다면 node interleaving을 활성화

Kernel의 NUMA balancing

  • 커널 레벨에서 NUMA 밸런싱을 제공하는 기능
    • 주기적으로 프로세스의 메모리 매핑을 해제하고 메모리를 프로그램이 실행되는 노드로 옮기거나 태스크를 메모리에 가깝게 옮기는 기능 수행
  • 커널 3.10부터 기본적으로 활성화 되어있음
  • /proc/sys/kernel/numa_balancing 값으로 확인 가능
    • 디폴트: 1 (활성화)
root@test:~# cat /proc/sys/kernel/numa_balancing
1

Kernel의 vm.zone_reclaim_mode

  • 커널은 메모리를 사용 용도에 따라 zone이라 부르는 영역으로 구분하여 관리
    • zone 정보는 /proc/buddyinfo를 통해 확인 가능
      [root@test ~]# cat /proc/buddyinfo
      Node 0, zone      DMA      0      0      0      0      0      0      0      0      1      1      2
      Node 0, zone    DMA32      7     11      6      8      5      8      8      9      8      4    304
      Node 0, zone   Normal     66     53     14      4      1      3      2      3      1      2    189
      Node 1, zone   Normal     74     33      8      2      0      2      3      7     36     52   1172
    
  • DMA, DMA32는 Direct Memory Access를 위한 영역 (주로 오래된 하드웨어 동작을 위한 영역. 현재는 해당 영역을 필요로 하는 하드웨어 거의 없음)
  • Normal은 일반적인 용도의 영역
    • 커널, 프로세스 등이 메모리를 필요로 할 때 Normal 영역에서 메모리를 할당받아서 사용
  • vm.zone_reclaim_mode는 이 영역들 사이에서 특정 영역의 메모리가 부족할 경우 다른 영역의 메모리를 할당할 수 있게 함
    • 4가지 값이 존재하나 실질적으로 0과 1이 중요
    • 0은 disable. zone 안에서 재할당하지 않음 → 다른 zone에서 가져와서 사용
      • page cache 등과 같은 재할당 대상 메모리들이 반환되지 않고 다른 노드에 있는 메모리를 할당 받아 사용
      • 메모리의 로컬 액세스로 인한 이득 < 많은 양의 page cache를 확보함으로써 생기는 이득인 경우
      • 일반적으로는 0이 유리
    • 1은 enable. zone 안에서 재할당 → 메모리 부족한 경우 해당 zone 안에서 재할당할 수 있는 메모리 영역을 먼저 찾아서 필요한 만큼 재할당하여 재사용. 그렇지 않은 경우 다른 zone에서 메모리 할당 받아 사용
      • 메모리의 로컬 액세스로 인한 이득 > page cache 확보로 인한 이득인 경우
root@test:~# cat /proc/sys/vm/zone_reclaim_mode
0

리눅스 NUMA CLI 툴

numactl

  • 프로세스의 NUMA 사용 정보 확인 및 정책 설정 가능
root@test:~# numactl -s
policy: default
preferred node: current
physcpubind: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
cpubind: 0 1
nodebind: 0 1
membind: 0 1
root@test:~# numactl -H
available: 2 nodes (0-1)
node 0 cpus: 0 1 2 3 4 5 6 7 16 17 18 19 20 21 22 23
node 0 size: 15410 MB
node 0 free: 13070 MB
node 1 cpus: 8 9 10 11 12 13 14 15 24 25 26 27 28 29 30 31
node 1 size: 16083 MB
node 1 free: 15229 MB
node distances:
node   0   1
  0:  10  21
  1:  21  10
  • available : NUMA 노드 개수 확인 가능
  • node # cpus/size/free : 각각의 노드에 해당하는 CPU 번호와 노드에 할당된 메모리 크기 확인 가능
  • node distances : 각 노드의 메모리에 접근하는데 걸리는 시간
    • 0번 노드 → 1번 노드 메모리 접근에 걸리는 시간이 21이라는 뜻
    • 절대적인 시간은 아니고 상대적인 값
    • 0번 노드 → 0번 노드 메모리보다 2.1배 시간이 필요하다고 해석 가능.

numastat

  • numactl 패키지에 포함된 상태 확인 커맨드
  • 현재 NUMA 운영 상태 확인
[root@test ~]# numastat
                           node0           node1
numa_hit                17424515        12929757
numa_miss                      0         2128172
numa_foreign             2128172               0
interleave_hit           5273354         5273840
local_node               7187999        10706546
other_node              10236516         4351383
  • 현재 NUMA 메모리 확인
[root@test ~]# numastat -m

Per-node system memory usage (in MBs):
Token Node not in hash table.
Token Node not in hash table.
Token Node not in hash table.
Token Node not in hash table.
Token Node not in hash table.
Token Node not in hash table.
Token Node not in hash table.
Token Node not in hash table.
                          Node 0          Node 1           Total
                 --------------- --------------- ---------------
MemTotal                15346.38        16066.98        31413.36
MemFree                 12278.76        15093.87        27372.62
MemUsed                  3067.62          973.11         4040.74
Active                     28.92          351.93          380.85
Inactive                   62.17          195.05          257.21
Active(anon)                0.09            2.12            2.21
Inactive(anon)             11.14           49.48           60.62
Active(file)               28.83          349.81          378.64
Inactive(file)             51.03          145.56          196.59
Unevictable                 0.00            0.00            0.00
Mlocked                     0.00            0.00            0.00
Dirty                       0.00            0.00            0.00
Writeback                   0.00            0.00            0.00
FilePages                  81.21          511.11          592.33
Mapped                      0.29           55.20           55.49
AnonPages                  10.04           36.03           46.07
Shmem                       0.08           15.21           15.29
KernelStack                 4.13            3.32            7.45
PageTables                  0.93            4.00            4.93
NFS_Unstable                0.00            0.00            0.00
Bounce                      0.00            0.00            0.00
WritebackTmp                0.00            0.00            0.00
Slab                      369.82          244.15          613.96
SReclaimable               60.18           79.33          139.51
SUnreclaim                309.64          164.82          474.46
AnonHugePages               0.00            0.00            0.00
ShmemHugePages              0.00            0.00            0.00
ShmemPmdMapped              0.00            0.00            0.00
HugePages_Total             0.00            0.00            0.00
HugePages_Free              0.00            0.00            0.00
HugePages_Surp              0.00            0.00            0.00
  • 특정 프로세스의 NUMA 메모리 사용 정보 확인
[root@test ~]# numastat -p bash

Per-node process memory usage (in MBs) for PID 51870 (bash)
                           Node 0          Node 1           Total
                  --------------- --------------- ---------------
Huge                         0.00            0.00            0.00
Heap                         0.07            1.58            1.66
Stack                        0.01            0.09            0.11
Private                      0.02            3.57            3.59
----------------  --------------- --------------- ---------------
Total                        0.11            5.25            5.36

numactl을 통한 프로세스 NUMA 정책 설정

  • –membind / -m : 지정된 노드에만 메모리 할당. 메모리 부족시 할당 실패
  • –cpunodebind / -N : 지정된 노드의 CPU에서만 프로세스 실행. 하나의 노드가 여러 CPU를 가질 수 있음
  • –physcpubind / -C : 지정된 CPU 번호에만 프로세스를 실행
  • –preferred / -p : 선호하는 node 지정. 리소스가 부족한 경우 다른 노드로부터 할당
  • –interleave / -i : 메모리를 RR로 지정된 노드들에 할당. all인 경우에 모든 노드들에 할당. 지정된 노드들로부터 메모리 할당에 실패하면 다른 노드들에 할당
root@test:~# numactl --physcpubind=0 -- ./a.out
root@test:~# numactl --preferred=0 -- ./a.out
root@test:~# numactl --interleave=all -- ./a.out

numad

  • 현재 실행 중인 전체 프로세스에 대해서 리소스 사용 현황을 살피고 CPU, memory에 대한 affinity를 조절하는 툴
  • 각 프로세스가 동일한 노드의 CPU, 메모리를 사용하도록 조절
    • 하나의 시스템에 수십, 수백개의 어플리케이션이 실행되거나 여러 가상 게스트 시스템이 동작하는 집약적 시스템 환경에 적합
  • numad -i 5는 numad가 시스템을 스캔하는 주기를 5초로 설정
    • numactl로 interleave 설정을 했음에도 RR로 고루 분산되는 것이 아니라 numad에 의해 한쪽 노드로 쏠리게 할당
    • numad의 옵션 중 -K 옵션이 기본적으로 0으로 설정. -K 0은 interleave된 메모리를 로컬 메모리로 모으려고 함.
[root@test ~]# numad -i 5
[root@test ~]# numactl --interleave=all ./a.out &
[1] 51997
[root@test ~]# numastat -p a.out

Per-node process memory usage (in MBs) for PID 51997 (a.out)
                           Node 0          Node 1           Total
                  --------------- --------------- ---------------
Huge                         0.00            0.00            0.00
Heap                         0.00            0.00            0.00
Stack                        0.01            0.00            0.01
Private                   2320.49         2321.58         4642.07
----------------  --------------- --------------- ---------------
Total                     2320.50         2321.59         4642.09
[root@test ~]# numastat -p a.out

Per-node process memory usage (in MBs) for PID 51997 (a.out)
                           Node 0          Node 1           Total
                  --------------- --------------- ---------------
Huge                         0.00            0.00            0.00
Heap                         0.00            0.00            0.00
Stack                        0.01            0.00            0.01
Private                   2768.62         5362.45         8131.08
----------------  --------------- --------------- ---------------
Total                     2768.63         5362.46         8131.09
[root@test ~]# numastat -p a.out

Per-node process memory usage (in MBs) for PID 51997 (a.out)
                           Node 0          Node 1           Total
                  --------------- --------------- ---------------
Huge                         0.00            0.00            0.00
Heap                         0.00            0.00            0.00
Stack                        0.00            0.01            0.01
Private                   6898.71        13582.44        20481.15
----------------  --------------- --------------- ---------------
Total                     6898.71        13582.45        20481.17
[root@test ~]# numastat -p a.out

Per-node process memory usage (in MBs) for PID 51997 (a.out)
                           Node 0          Node 1           Total
                  --------------- --------------- ---------------
Huge                         0.00            0.00            0.00
Heap                         0.00            0.00            0.00
Stack                        0.00            0.01            0.01
Private                   6898.71        13582.44        20481.15
----------------  --------------- --------------- ---------------
Total                     6898.71        13582.45        20481.1
  • numad -K 1 옵션 사용시 interleave 된 메모리를 로컬 메모리로 모으지 않음
[root@test ~]# numad -K 1 -i 5
[root@test ~]# numactl --interleave=all ./a.out &
[1] 52071
[root@test ~]# numastat -p a.out

Per-node process memory usage (in MBs) for PID 52071 (a.out)
                           Node 0          Node 1           Total
                  --------------- --------------- ---------------
Huge                         0.00            0.00            0.00
Heap                         0.00            0.00            0.00
Stack                        0.01            0.00            0.01
Private                   2819.45         2820.42         5639.88
----------------  --------------- --------------- ---------------
Total                     2819.46         2820.43         5639.89
[root@test ~]# numastat -p a.out

Per-node process memory usage (in MBs) for PID 52071 (a.out)
                           Node 0          Node 1           Total
                  --------------- --------------- ---------------
Huge                         0.00            0.00            0.00
Heap                         0.00            0.00            0.00
Stack                        0.01            0.00            0.01
Private                   4388.39         4389.35         8777.74
----------------  --------------- --------------- ---------------
Total                     4388.39         4389.36         8777.75
[root@test ~]# numastat -p a.out

Per-node process memory usage (in MBs) for PID 52071 (a.out)
                           Node 0          Node 1           Total
                  --------------- --------------- ---------------
Huge                         0.00            0.00            0.00
Heap                         0.00            0.00            0.00
Stack                        0.01            0.00            0.01
Private                   8942.25         8943.22        17885.47
----------------  --------------- --------------- ---------------
Total                     8942.26         8943.23        17885.49
[root@test ~]# numastat -p a.out

Per-node process memory usage (in MBs) for PID 52071 (a.out)
                           Node 0          Node 1           Total
                  --------------- --------------- ---------------
Huge                         0.00            0.00            0.00
Heap                         0.00            0.00            0.00
Stack                        0.01            0.00            0.01
Private                  10240.04        10241.00        20481.04
----------------  --------------- --------------- ---------------
Total                    10240.04        10241.01        20481.05

참고자료