sarコマンドを使わないでCPUの数を調べる方法

## 0. はじめに
CPUの数を調べることになったのですが、普段使っている`sarコマンド`が使えない環境下で調べることになり、ググったのでまとめます。


なお、sysstatがインストールされ、sarの設定も完了している環境下で、sarを実行した結果はこのようになります。
本記事では下記の`(4 CPU)をsarコマンドを使わずに確認する方法`を取り上げていきます。

```
[root@$hostname ~]# sar
Linux (略)	(4 CPU)

11:03:41     LINUX RESTART	(4 CPU)

11:10:01 AM     CPU     %user     %nice   %system   %iowait    %steal     %idle
11:20:01 AM     all      0.00      0.00      0.01      0.00      0.00     99.99
Average:        all      0.00      0.00      0.01      0.00      0.00     99.99
[root@$hostname ~]# 

```

## 1.目次

- 2.検証環境/バージョン情報
- 3.【方法①】lscpuコマンドを使ってCPUの数を調べる
- 4.【方法②】sarがやっていることを再現することでCPUの数を調べる
- 5. sarはどうやってCPU[0-9]+を数えているのか
- 6. sarで確認できるCPUとはなんなのか
- 7. 論理プロセッサーと物理コア数、ソケット、スレッドとの関係性
- 8.【余談】sar -rコマンドとfreeコマンドの比較 
- 9. 参考


## 2.検証環境/バージョン情報
- AWS (EC2, VPC, EIP, etc)
  - Red Hat Enterprise Linux release 8.1 (Ootpa)
  - t2.xlarge
  - ストレージはGeneral Purpose SSD (gp2)、16size (t2.xlargeを選択した場合の初期値)
  - sysstat version 11.7.3 

```/etc/cron.d/sysstat

# Run system activity accounting tool every 10 minutes
*/10 * * * * root /usr/lib64/sa/sa1 1 1
# 0 * * * * root /usr/lib64/sa/sa1 600 6 &
# Generate a daily summary of process accounting at 23:53
53 23 * * * root /usr/lib64/sa/sa2 -A
```


## 3.【方法①】lscpuコマンドを使ってCPUの数を調べる

こちらの方法が一番簡単です。

```
[root@$hostname ~]# lscpu | grep -E '^Thread|^Core|^Socket|^CPU\('
CPU(s):              4
Thread(s) per core:  1
Core(s) per socket:  4
Socket(s):           1
[root@$hostname ~]# 
```
出所：[sarインストール＆設定手順](https://qiita.com/fk_2000/items/340ec95b77f73a1f3ad9)


## 4.【方法②】sarがやっていることを再現することでCPUの数を調べる

理由は次章で取り扱いますが、sarは `/sys/devices/system/cpu/cpu[0-9]+`のCPUの数を数えていることが分かりました。

```
[root@$hostname ~]# ls /sys/devices/system/cpu/ | grep -E "cpu[0-9]+"
cpu0
cpu1
cpu2
cpu3
[root@$hostname ~]# ls /sys/devices/system/cpu/ | grep -E "cpu[0-9]+" | wc -l
4
[root@$hostname ~]# 
```

## 5. sarはどうやってCPU[0-9]+を数えているのか
さて、sarはどうやってCPU[0-9]+を数えているのでしょうか。
ここではsarのソースコードをたよりに調査しました。
ソースコードはgithubで公開されています。
下記のとおり`cpu[0-9]+を数えている箇所`と、`cpu[0-9]+を数えている対象のパスが定義されている箇所`を抜粋します。

- cpu[0-9]+を数えている箇所

```
/*
 ***************************************************************************
 * Count number of processors in /sys.
 *
 * IN:
 * @highest	If set to TRUE, then look for the highest processor number.
 * 		This is used when eg. the machine has 4 CPU numbered 0, 1, 4
 *		and 5. In this case, this procedure will return 6.
 *
 * RETURNS:
 * Number of processors (online and offline).
 * A value of 0 means that /sys was not mounted.
 * A value of N (!=0) means N processor(s) (cpu0 .. cpu(N-1)).
 ***************************************************************************
 */
int get_sys_cpu_nr(int highest)
{
	DIR *dir;
	struct dirent *drd;
	struct stat buf;
	char line[MAX_PF_NAME];
	int num_proc, proc_nr = -1;

	/* Open relevant /sys directory */
	if ((dir = opendir(SYSFS_DEVCPU)) == NULL)
		return 0;

	/* Get current file entry */
	while ((drd = readdir(dir)) != NULL) {

		if (!strncmp(drd->d_name, "cpu", 3) && isdigit(drd->d_name[3])) {
			snprintf(line, MAX_PF_NAME, "%s/%s", SYSFS_DEVCPU, drd->d_name);
			line[MAX_PF_NAME - 1] = '\0';
			if (stat(line, &buf) < 0)
				continue;
			if (S_ISDIR(buf.st_mode)) {
				if (highest) {
					sscanf(drd->d_name + 3, "%d", &num_proc);
					if (num_proc > proc_nr) {
						proc_nr = num_proc;
					}
				}
				else {
					proc_nr++;
				}
			}
		}
	}

	/* Close directory */
	closedir(dir);

	return (proc_nr + 1);
}
```

出所：[https://github.com/sysstat/sysstat/blob/master/count.c]
(https://github.com/sysstat/sysstat/blob/master/count.c)

Cのコード自体はあまり詳しくないので、間違っているかもしれませんが、おそらく`SYSFS_DEVCPU`配下の`cpu[0-9]+`を数えているのではないかと思います。

- cpu[0-9]+を数えている対象のパス

```
| /* Files */ |
|:--|:--|:--|:--|
| #define STAT |  |  | PRE "/proc/stat" |
(略)
| #define SYSFS_DEVCPU |  | PRE "/sys/devices/system/cpu" |
(略)
| #define SLASH_DEV |  | PRE "/dev/" |
```
出所：[github.com/sysstat/sysstat/blob/master/common.h](https://github.com/sysstat/sysstat/blob/master/common.h)

## 6. sarで確認できるCPUとはなんなのか

kernelのドキュメントを参考にするかぎり、sarで確認できるCPUは論理プロセッサーと考えてよいでしょう。

>What:		/sys/devices/system/cpu/
(略)
Description:
		A collection of both global and individual CPU attributes
		Individual CPU attributes are contained in subdirectories
		named by the kernel's `logical CPU number`, e.g.:
		`/sys/devices/system/cpu/cpu#/`


出所：[kernel docs sysfs-devices-system-cpu]
(https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-devices-system-cpu)



## 7. 論理プロセッサーと物理コア数、ソケット、スレッドとの関係性

ここで、lscpuを実行して表示された論理プロセッサーと物理コア数、ソケット、スレッドとの関係性が気になったので調べました。

下記のブログではlscpuコマンドの実行結果を例に論理プロセッサーと物理コア数、ソケット、スレッドとの関係性についてこのように紹介しています。

`論理プロセッサー = cpuソケット数 × 物理コア数/ソケット × スレッド数/物理コア数`

>The total number of logical cores = CPU sockets × physical cores per socket × threads per physical core. Therefore, the computer has 2 × 8 × 2 = 32 logical cores in total.
CPU(s):                 32

出所： [How many physical and logical CPU cores in your computer | Wei Bai 白巍](https://baiweiblog.wordpress.com/2017/10/27/how-many-physical-and-logical-cpu-cores-in-your-computer/)

```
[root@$hostname ~]# lscpu | grep -E '^Thread|^Core|^Socket|^CPU\('
CPU(s):              4    # 論理プロセッサー
Thread(s) per core:  1    # スレッド数/物理コア数
Core(s) per socket:  4    # 物理コア数/ソケット
Socket(s):           1    # cpuソケット数
[root@$hostname ~]# 
```
ところで、先日読んでいた[[試して理解]Linuxのしくみ ~実験と図解で学ぶOSとハードウェアの基礎知識](https://www.amazon.co.jp/dp/477419607X)にて、`sar -rコマンドとfreeコマンドの相違点`の解説がわかりやすかったので、紹介させてください。

## 8.【余談】sar -rコマンドとfreeコマンドの比較

|freeコマンドのフィールド|sar -rコマンドのフィールド|内容                             |
|---------------------|-----------------------|-------------------------------|
|total                |該当なし                |システムに搭載されている全メモリの量。|
|free                 |kbmemfree              |見かけ上の空きメモリ。              |
|buff/cache           |kbbuffers + kbcached   |バッファキャッシュ、及びページキャッシュが利用するメモリ。システムの空きメモリが減少してきたら、カーネルによって解放される。|
|available            |該当なし                |実質的な空きメモリ。フィールドの値に、空きメモリが足りなくなってきたら解放できるカーネル内メモリ領域のサイズを足したもの。解放できるメモリにはバッファキャッシュやページキャッシュの大部分、及びその他カーネルメモリの一部が含まれる。|


参考：[[試して理解]Linuxのしくみ ~実験と図解で学ぶOSとハードウェアの基礎知識](https://www.amazon.co.jp/dp/477419607X)(一部筆者改変)

**freeコマンドの実行結果**

```
[root@$hostname ~]# free
              total        used        free      shared  buff/cache   available
Mem:       16256588      239692    14588360       24948     1428536    15692440
Swap:             0           0           0
```

**sar -rコマンドの実行結果**

```
[root@$hostname ~]# sar -r | head
Linux (略)	(4 CPU)

11:03:41     LINUX RESTART	(4 CPU)

11:10:01 AM kbmemfree   kbavail kbmemused  %memused kbbuffers  kbcached  kbcommit   %commit  kbactive   kbinact   kbdirty
11:20:01 AM  14581020  15690700   1675568     10.31      2716   1333316    311968      1.92    399160    993580         0
11:30:01 AM  14580936  15690652   1675652     10.31      2716   1333324    296508      1.82    399204    993332         0
11:40:01 AM  14580064  15689796   1676524     10.31      2716   1333328    315288      1.94    400016    993336         0
11:50:01 AM  14581008  15690804   1675580     10.31      2716   1333336    315288      1.94    399880    992556        20
12:00:01 PM  14580612  15690412   1675976     10.31      2716   1333344    323312      1.99    401148    991320         0
[root@$hostname ~]# 
```

## P.S. Twitterもやってるのでフォローしていただけると泣いて喜びます:)
[@gkzvoice](https://twitter.com/gkzvoice)


## P.P.S. fukabori.fmで聞いたこと
fukabori.fmにて、ちょうど本記事で取り扱ったcpuinfoに関連する話題があがっていたので、少し文字起こしをしました。

タイピングが追いつかず、端折っています。

>Linuxは/devなどハードウェアの情報が格納されているディレクトリやファイルのように扱えるようになっている。
Linuxでいえば、cpuinfoなど
いろんな情報をファイルじゃないものをファイルのように扱うことが出来る。
そして、これはパイプという仕組みを使って後続のプログラムに、ファイルかファイルではない何かを問わず、投げることができる
全てのものをファイルのように扱い、標準入力と標準出力でデータの入り口と出口をつなげるようにする。
難しいことは後続の処理に任せよう。
設計哲学がいろんなことに繋がっている。
これを同じように扱えるというのは強い制約。
高い再利用性が発揮。

出所：[28. 技術選定の審美眼(1) w/ twada](https://fukabori.fm/episode/28)