CPUを複数持つアーキテクチャNUMAとnumactlの説明

複数のCPUとメモリが一つのシステムに乗せられたNUMAアーキテクチャという構成が採用され始めている。
NUMAの目的はI/Oバスの並列化である。
![1system_numa.png](https://qiita-image-store.s3.amazonaws.com/0/89992/bf2eb61b-c87c-ae5d-981c-9fa1bb2b69f2.png)

極端に例えると、コア数が50個あった場合、一つのメモリバスを使った構成よりも、
25コア25コアの2CPUで２つのメモリバスを使った構成の方が早くなる。
14GB/sのメモリバスだった場合、メモリバスを２つにすれば28GB/sの性能がでる。
（１秒間に送れるデータ量が増える。）
このようにNUMAは、コア数が増えることによるメモリバスネックの対策であり、マルチコア化も進んでいるため、今後NUMAにふれる機会が増えてくるはずである。

## どんな時に考える？
多くのメモリ転送を使う計算をするときは、NUMAによる影響が発生するかもしれない。
設定によってはNUMAの影響を大きく受けてしまう可能性もある。

## numaのメモリ割り当てを制御するコマンド
[1] --localallocオプション
<pre><code>numactl --localalloc RUNFILE</code></pre>
NUMA環境を使っていて、高速化したいのであれば、このコマンドを使うだけで良い。
これで自然とデータがCPUに近い方のメモリに割り当てられる。

[2] --interleaveオプション
<pre><code>numactl --interleave=all RUNFILE</code></pre>

環境によっては、このコマンドの方が性能が出る場合もある。
([2]の方が性能が出る場合は、OS側によるメモリ割り当てがあまり賢くなってない場合に多い。
データを均等に各メモリに分割するコマンド。
この場合、多くのメモリを使うプログラムで、numactlを使用せずに./a.outなどでファイルだけの実行をすると性能の振れ幅が10GFlopsであったり20GFlopsであったりかなり大きくなったりする。)

# NUMA(Non-uniform memory access)アーキテクチャとは
複数のCPUによって構成されるアーキテクチャ。
CPUによってメモリ性能が異なるものをNUMAと呼ぶ。
例えばCPUが２つある場合は、このような構成になる。
<img width="701" alt="http://frankdenneman.nl/2016/07/07/numa-deep-dive-part-1-uma-numa/" src="https://qiita-image-store.s3.amazonaws.com/0/89992/ff1e2435-9748-ef76-8c69-7d517977f0ae.png">
(http://frankdenneman.nl/2016/07/07/numa-deep-dive-part-1-uma-numa/ から参照)
メモリアクセスをするときは、当然Local Accessの方が早くなる。
均等に読み込むデータをメモリに分割し、複数のCPUで同時にLocal Accessするのが一番早い。
逆にRemote Accessが発生してしまうとCPUをまたいでメモリアクセスをするので性能に影響が出る。

# ノード(Node)とは
NUMAはCPUとローカルアクセスをするローカルメモリのセットをノードという単位で表す。

# NUMAの影響が発生する状況
スーパーコンピュータによるCPUベースで行う演算
サーバで大容量のメモリを使う演算

# numactlとは
アプリケーションで使用するメモリとCPUを指定できるLinuxコマンド。

# numactlのオプション
numactlを使用して使用するメモリやCPUを操作しましょう！

### --hardware, -H
使用してる環境でのNUMAの構成を表示する。
<pre><code>numactl --hardware
numactl -H
</code></pre><pre><code>available: 2 nodes (0-1)
node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 12 13
node 0 size: 130958 MB
node 0 free: 84791 MB
node 1 cpus: 14 15 16 17 18 19 20 21 22 23 24 25 26 27
node 1 size: 131072 MB
node 1 free: 101191 MB
node distances:
node   0   1 
  0:  10  21 </code></pre>このシステムは、２ノード(2CPU,2メモリ)からなり、コアは0-13,14-27に分離されていることがわかる。

### --show, -s
numaのノード数やコア数を表示
<pre><code>numactl --show
numactl -s
</code></pre>
<pre><code>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 
cpubind: 0 1 
nodebind: 0 1 
membind: 0 1 
</code></pre>
physcpubindは合計のコア数がわかる。
cpubind,nodebind,membindは0,1の、２つのノードがあることがわかる。
policyには、--interleaveオプションをつけるとinterleaveと表示される。(メモリ割り当ての状態が分かる。)


### --interleave=nodes, -i nodes
指定したノードのメモリに均等にデータを分割して保存するようにする。
<pre><code>numactl --interleave=all ./a.out
numactl --interleave=0,1 ./a.out
numactl --interleave=0-1 ./a.out
</code></pre>


### --membind=nodes, -m nodes
使用するメモリをノード単位で指定する。
<pre><code>numactl --membind = 0-1 ./a.out
numactl --membind = 0,1 ./a.out
numactl --membind = 0 ./a.out
</code></pre>

### --cpunodebind =nodes, -m nodes
使用するCPUをノード単位で指定する。
<pre><code>numactl --cpunodebind = 0-1 ./a.out
numactl --cpunodebind = 0,1 ./a.out
numactl --cpunodebind = 0 ./a.out
</code></pre>

### --physcpubind=cpus, -C cpus
使用するCPUをコアの単位で指定する。
<pre><code>numactl --physcpubind = 0-5 ./a.out
numactl --physcpubind = 0,1,2,3,4,5 ./a.out
numactl --physcpubind = 0 ./a.out
</code></pre>

### numastat
各ノードでのNumaの状態を表示する。
<pre><code>numastat</code></pre><pre><code>                           node0           node1
numa_hit              5932784098     10154919387
numa_miss              645547781       144163554
numa_foreign           144163554       645547781
interleave_hit            364243          403249
local_node            5917757532     10154664878
other_node             660574347       144418063
</code></pre>

### free -m
メモリの状態をMB単位で表示する。
<pre><code>free -m</code></pre><pre><code>              total        used        free      shared  buff/cache   available
Mem:         257675       29175      175486         652       53013      202381
Swap:         20003           0       20003
</code></pre>



# CPUの構成
サーバでなどで使われているHaswell-EPシリーズのCPUの内部の構成はこうなっている。
NUMAでは、このQPIによってCPUとCPUを繋いである。
QPIはCPUとCPUを繋ぐバスである。
DDRはCPUとメモリを繋ぐバスである。
実はHaswellアーキテクチャなどではCPUのチップの内部でもさらにNUMA構成となっている。
コア1とコア15だと、各コアから近いメモリがそれそれ存在する。
<img width="376" alt="スクリーンショット 2016-11-08 13.01.09.png" src="https://qiita-image-store.s3.amazonaws.com/0/89992/0a1c1564-05a3-eed8-6a20-7ee0c589a605.png">


# 参考文献
Introduction 2016 NUMA Deep Dive Series
http://frankdenneman.nl/2016/07/06/introduction-2016-numa-deep-dive-series/
numactlリファレンス
https://linux.die.net/man/8/numactl
redhat numactl, numastatの説明
https://access.redhat.com/documentation/ja-JP/Red_Hat_Enterprise_Linux/6/html/Performance_Tuning_Guide/main-cpu.html
CPUアーキテクチャの種類
http://kowadaru.com/codename-list
NUMAアーキテクチャ_WIKIPEDIA
https://ja.wikipedia.org/wiki/NUMA
ルーフラインモデル
https://people.eecs.berkeley.edu/~waterman/papers/roofline.pdf
### ※ふわっと書いています