- 投稿日:2021-04-03T18:25:20+09:00
SpackでGPU対応PyTorchをインストールする
毎回調べている気がするのでGPUを使えるPyTorchの構築をSpackで行う際のメモしておく。 必要なパッケージを一つづつ入れていってもいいのだが、コンパイラやcudaの依存関係やインストール時の最適化を簡単に解決してくれるスパコン向けのパッケージマネージャであるSpack (https://spack.io/)を利用することにより少ない手間で一貫した環境が構築可能となる。Spackの使い方は最低限のことしか触れないため公式ドキュメントやABCIの説明ページ などを参照。 Ubuntu 20.04.2 LTS (GNU/Linux 5.8.0-48-generic x86_64) と NVIDIA A100 の環境で構築。 GPUドライバを入れるところだけは管理者権限が必要だが、それ以降は一般ユーザー権限でよい。 管理者が入れて一般ユーザがパッケージを使う場合はspackのupstream機能を使うことになると思う。 GPUドライバが入っており、対応するGCCやclangコンパイラがシステムに入っていれば一般ユーザーで適当なディレクトリを作りその中で $ git clone https://github.com/spack/spack.git $ cd spack $ . share/spack/setup-env.sh $ spack compiler find $ spack -v install -j 10 py-torch とするだけで必要なパッケージを全て導入してくれる可能性は高い。ただし、パッケージのバージョンやオプションなど下記で説明するパッケージファイルによって指定することにより、今後の環境構築は楽になる。 GPUドライバの確認、導入 すでにGPUドライバが導入されていたら不要。 Ubuntuなので下記の方法が最も簡単。 $ sudo add-apt-repository ppa:graphics-drivers/ppa $ ubuntu-drivers devices == /sys/devices/pci0000:20/0000:20:03.1/0000:21:00.0 == modalias : pci:v000010DEd000020F1sv000010DEsd0000145Fbc03sc02i00 vendor : NVIDIA Corporation driver : nvidia-driver-460 - third-party non-free recommended # 現環境ではこれが推奨されている driver : nvidia-driver-450-server - distro non-free driver : nvidia-driver-450 - third-party non-free driver : nvidia-driver-460-server - distro non-free driver : xserver-xorg-video-nouveau - distro free builtin ppa:graphics-drivers/ppa リポジトリを追加し、ubuntu-drivers devices コマンドで現環境についているGPUの推奨ドライバを確認。 推奨ドライバがすでに入っていれば次はスキップし、入っていなければ今あるドライバを削除。 $ sudo apt purge nvidia-\* # 推奨ドライバが入っていればpurgeは不要 $ sudo apt autoremove ドライバのインストール。 $ sudo apt install nvidia-driver-460 or $ sudo apt install aptitude # aptで入らなかったらaptitudeで入れる $ sudo aptitude install nvidia-driver-460 $ sudo reboot 再起動して確認。 $ nvidia-smi +-----------------------------------------------------------------------------+ | NVIDIA-SMI 460.67 Driver Version: 460.67 CUDA Version: 11.2 | |-------------------------------+----------------------+----------------------+ | GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. | | | | MIG M. | |===============================+======================+======================| | 0 A100-PCIE-40GB Off | 00000000:21:00.0 Off | 0 | | N/A 29C P0 32W / 250W | 4MiB / 40536MiB | 0% Default | | | | Disabled | +-------------------------------+----------------------+----------------------+ | 1 A100-PCIE-40GB Off | 00000000:81:00.0 Off | 0 | | N/A 28C P0 32W / 250W | 4MiB / 40536MiB | 0% Default | | | | Disabled | +-------------------------------+----------------------+----------------------+ GPUが見えていたらドライバの導入は完了。ここまではUbuntuに特化した説明だが以降はLinuxディストリビューションに関係なく同じ。 CUDAやコンパイラバージョンの確認 nvidia-smi の結果に CUDA Version: 11.2 とあるのでcudaのバージョンは11.2が導入可能。https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html から確認できる情報ではUbuntu 20.04ではCUDA 11.2を入れる際にGCCバージョンが9.xである必要がある。 以降はGCCコンパイラを元に説明していくがclangを使いたい場合はコンパイラ部分を変更すればいいはず。 Spackで対応GCCのインストール Ubuntu 20.04 LTSではデフォルトのコンパイラは $ which gcc /usr/bin/gcc $ gcc --version gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0 Copyright (C) 2019 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. バージョンが9.3.0なのでこのまま使うこともできるが、システムアップデートなどでバージョン更新されると不便なのでSpackを使用してバージョンを固定したGCCコンパイラを導入する。spackのパッケージを入れる適当なディレクトリを作成し、その中でspackをダウンロードして環境を適用する。 $ git clone https://github.com/spack/spack.git $ cd spack $ . share/spack/setup-env.sh $ echo $SPACK_ROOT # このパスの中にパッケージ類が入る /home/hoge/spack 以降、spackの機能を使う際はログインしたときに $SPACK_ROOT/share/spack/setup-env.sh をドットコマンドで読み込む。 最初に使えるコンパイラの登録をする。コンパイラ情報はユーザーのホームディレクトリの下の ~/.spack/linux/compilers.yaml に作られる。 $ spack find compiler $ spack compiler list spack compiler list ==> Available compilers -- clang ubuntu20.04-x86_64 ------------------------------------- clang@10.0.0 -- gcc ubuntu20.04-x86_64 --------------------------------------- gcc@9.3.0 この段階でのコンパイラー情報は次のようになっている。 ~/.spack/linux/compilers.yaml compilers: - compiler: spec: clang@10.0.0 paths: cc: /usr/bin/clang cxx: /usr/bin/clang++ f77: fc: flags: {} operating_system: ubuntu20.04 target: x86_64 modules: [] environment: {} extra_rpaths: [] - compiler: spec: gcc@9.3.0 paths: cc: /usr/bin/gcc cxx: /usr/bin/g++ f77: /usr/bin/gfortran fc: /usr/bin/gfortran flags: {} operating_system: ubuntu20.04 target: x86_64 modules: [] environment: {} extra_rpaths: [] 次にシステムのgcc@9.3.0を使い、spackのgcc@9.3.0を構築する。 $ spack info gcc $ spack spec gcc@9.3.0%gcc@9.3.0 $ spack -v install -j 8 gcc@9.3.0%gcc@9.3.0 spack infoでgccパッケージについて確認 spack specでインストールされるパッケージの依存関係やオプションなどを確認。 @9.3.0はバージョン指定 %gcc@9.3.0で構築するコンパイラ指定。別バージョンのgccやclangなどが混在しているときのために明示的に指定している。 specで問題なければinstall。 -vは詳細表示。 -j 8は8並列でビルド。 構築までかなりの時間がかかるがインストールが終わったら確認。 $ spack find # spackで入れたパッケージが全て表示される ==> 24 installed packages -- linux-ubuntu20.04-zen2 / gcc@9.3.0 --------------------------- autoconf@2.69 bzip2@1.0.8 gdbm@1.19 help2man@1.47.16 libtool@2.4.6 mpc@1.1.0 perl@5.32.1 tar@1.34 automake@1.16.3 diffutils@3.7 gettext@0.21 libiconv@1.16 libxml2@2.9.10 mpfr@3.1.6 pkgconf@1.7.4 xz@5.2.5 berkeley-db@18.1.40 gcc@9.3.0 gmp@6.2.1 libsigsegv@2.12 m4@1.4.18 ncurses@6.2 readline@8.1 zlib@1.2.11 $ spack find -x # 明示的に指定して入れたパッケージが表示される ==> 1 installed package -- linux-ubuntu20.04-zen2 / gcc@9.3.0 --------------------------- gcc@9.3.0 インストールしたgccをloadしてみる。 $ spack load gcc@9.3.0 $ which gcc /home/hoge/spack/opt/spack/linux-ubuntu20.04-zen2/gcc-9.3.0/gcc-9.3.0-bbkkmscclawlbad4ds72wh7ouuuvc74u/bin/gcc $ gcc --version gcc (Spack GCC) 9.3.0 Copyright (C) 2019 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. コンパイラリストに登録。 $ spack compiler find $ spack compiler list ~/.spack/linux/compilers.yaml - compiler: spec: gcc@9.3.0 paths: cc: /home/hoge/spack/opt/spack/linux-ubuntu20.04-zen2/gcc-9.3.0/gcc-9.3.0-bbkkmscclawlbad4ds72wh7ouuuvc74u/bin/gcc cxx: /home/hoge/spack/opt/spack/linux-ubuntu20.04-zen2/gcc-9.3.0/gcc-9.3.0-bbkkmscclawlbad4ds72wh7ouuuvc74u/bin/g++ f77: /home/hoge/spack/opt/spack/linux-ubuntu20.04-zen2/gcc-9.3.0/gcc-9.3.0-bbkkmscclawlbad4ds72wh7ouuuvc74u/bin/gfortran fc: /home/hoge/spack/opt/spack/linux-ubuntu20.04-zen2/gcc-9.3.0/gcc-9.3.0-bbkkmscclawlbad4ds72wh7ouuuvc74u/bin/gfortran flags: {} operating_system: ubuntu20.04 target: x86_64 modules: [] environment: {} extra_rpaths: [] ~/.spack/linux/compilers.yamlのパスが上のwhichのものになっていれば完了。 今回のようにシステムのデフォルトがで入れたものと同じ名前、アーキテクチャでうまく上書きされないようなら、一旦 compilers.yaml に登録されている(今はシステムの)gcc@9.3.0情報を名前を変えるか削除して登録し直す。 $ spack compiler remove gcc@9.3.0 $ spack compiler find $ spack compiler list SpackでPyTorchのインストール これからPyTorchのインストールを行うが、パッケージによって必要なオプションがあれば ~/.spack/packages.yaml に記述しておけばinstall行でオプションを指定する必要はなくなる。このようなファイルを作っておけば別環境でも同じバージョン、オプションを指定した環境が容易に再現可能となる。バージョン指定をしなければ基本的に最新の安定版がインストールされる。指定可能なバージョンやオプションの候補はspack infoで全て確認できる。 cuda_archに指定するCompute Capabilityは https://developer.nvidia.com/cuda-gpus で確認できる。 ~/.spack/packages.yaml packages: python: variants: tkinter= True py-matplotlib: variants: movies= True backend= tkagg openmpi: version: [4.0.5] compiler: [gcc] fftw: version: [3.3.9] compiler: [gcc] variants: mpi= True openmp= True pfft_patches= True precision= float,double providers: mpi: [openmpi] cuda: version: [11.2.2] cudnn: version: [8.1.1.33-11.2] py-torch: variants: ### V100, GF 2080 Ti 75, A100 80 cuda_arch= 80 distributed= True nccl= True gloo= True py-torch-nvidia-apex: variants: ### V100, GF 2080 Ti 75, A100 80 cuda_arch= 80 all: compiler: [gcc] providers: mpi: [openmpi] permissions: read: world write: user 上記のような packages.yaml を作っておけば $ spack spec py-torch%gcc@9.3.0 Input spec -------------------------------- py-torch%gcc@9.3.0 Concretized -------------------------------- py-torch@1.8.1%gcc@9.3.0~binary~caffe2+cuda+cudnn+distributed~fbgemm~ffmpeg+gloo~leveldb~lmdb~magma~miopen+mkldnn+nccl~nnpack~opencv+openmp~qnnpack~redis~rocm~tbb~test~xnnpack~zstd cuda_arch=80 arch=linux-ubuntu20.04-zen2 ^cmake@3.20.0%gcc@9.3.0~doc+ncurses+openssl+ownlibs~qt build_type=Release arch=linux-ubuntu20.04-zen2 ... ^cuda@11.2.2%gcc@9.3.0~dev arch=linux-ubuntu20.04-zen2 ... ^cudnn@8.1.1.33-11.2%gcc@9.3.0 arch=linux-ubuntu20.04-zen2 ^eigen@3.3.9%gcc@9.3.0~ipo build_type=RelWithDebInfo arch=linux-ubuntu20.04-zen2 ^gloo@master%gcc@9.3.0~ipo build_type=RelWithDebInfo arch=linux-ubuntu20.04-zen2 ^nccl@2.8.3-1%gcc@9.3.0+cuda cuda_arch=none arch=linux-ubuntu20.04-zen2 ... ^python@3.8.8%gcc@9.3.0+bz2+ctypes+dbm~debug+libxml2+lzma~nis~optimizations+pic+pyexpat+pythoncmd+readline+shared+sqlite3+ssl~tix+tkinter~ucs4+uuid+zlib patches=... ^expat@2.2.10%gcc@9.3.0+libbsd arch=linux-ubuntu20.04-zen2 ^libbsd@0.10.0%gcc@9.3.0 arch=linux-ubuntu20.04-zen2 ^libffi@3.3%gcc@9.3.0 patches=26f26c6f29a7ce9bf370ad3ab2610f99365b4bdd7b82e7c31df41a3370d685c0 arch=linux-ubuntu20.04-zen2 ^sqlite@3.35.3%gcc@9.3.0+column_metadata+fts~functions~rtree arch=linux-ubuntu20.04-zen2 ^tcl@8.6.11%gcc@9.3.0 arch=linux-ubuntu20.04-zen2 ^tk@8.6.10%gcc@9.3.0+xft+xss arch=linux-ubuntu20.04-zen2 ^libx11@1.7.0%gcc@9.3.0 arch=linux-ubuntu20.04-zen2 ^inputproto@2.3.2%gcc@9.3.0 arch=linux-ubuntu20.04-zen2 ^util-macros@1.19.1%gcc@9.3.0 arch=linux-ubuntu20.04-zen2 ^kbproto@1.0.7%gcc@9.3.0 arch=linux-ubuntu20.04-zen2 ... のように表示され、cuda, cudnnのバージョンやpythonのtkオプションも指定したものがインストールされることを確認できる。 $ spack -v install -j 20 py-torch%gcc@9.3.0 で上記で確認した依存関係を含めてインストール。インストールが完了したら $ spack find -ldpfv py-torch でオプションや依存関係やインストール場所が表示されるので一応確認しておく。その他、必要なpythonパッケージがあれば導入する。 $ spack -v install -j 20 py-numpy%gcc@9.3.0 $ spack -v install -j 20 py-ipython%gcc@9.3.0 $ spack -v install -j 20 py-scipy%gcc@9.3.0 ... spackでloadしたpythonのpipから入れることもできるが、それだとHPC用の最適化オプションが効いていないため、上記のようにspackからいちいちパッケージを導入したもののほうが高速に動作すると思われる 逆に言えばspackに用意されていないパッケージはpythonをloadしてpipで入れられる(この場合はpipで入れたパッケージはspackのpythonの下に作られるためシステムのpythonと競合することもない) GPU対応Pytorchの確認 py-torchパッケージをloadするとPATHやLD_LIBRARY_PATHに反映され使えるようになる。 $ which python3 /usr/bin/python3 $ spack load python py-torch py-ipython $ which python3 /home/hoge/spack/opt/spack/linux-ubuntu20.04-zen2/gcc-9.3.0/python-3.8.8-7tijmoltswgxk4jlxn55fpsunnpkj3hq/bin/python3 GPUの確認。pytorchからGPUが見えていたら成功。 $ ipython ipython Python 3.8.8 (default, Apr 2 2021, 17:44:13) Type 'copyright', 'credits' or 'license' for more information IPython 7.21.0 -- An enhanced Interactive Python. Type '?' for help. In [1]: import torch In [2]: torch.cuda.is_available() Out[2]: True In [3]: torch.cuda.get_device_name(0) Out[3]: 'A100-PCIE-40GB' In [4]: torch.cuda.get_device_name(1) Out[4]: 'A100-PCIE-40GB' Pythonパッケージのactivate 今のままではpythonをloadしただけでは依存関係のないpy-ipythonやpy-matplotlibはいちいちloadしないと使えない。インストールしたpythonパッケージを全部ロードするようなaliasを作ってもいいがspackのactivate機能を使えばpythonをloadしただけで、activateしたパッケージを使えるようになる。 $ spack extensions python $ ==> 49 installed: -- linux-ubuntu20.04-zen2 / gcc@9.3.0 --------------------------- llvm@11.1.0 py-h5py@3.2.1 py-numpy@1.20.2 py-pygments@2.6.1 py-threadpoolctl@2.0.0 meson@0.57.1 py-ipython@7.21.0 py-parso@0.8.1 py-pyparsing@2.4.7 py-toml@0.10.2 py-argparse@1.4.0 py-ipython-genutils@0.2.0 py-pexpect@4.7.0 py-python-dateutil@2.8.1 py-torch@1.8.1 ... ==> None activated. この段階では50個近くpythonパッケージがあるが直接importする可能性のあるものだけactivateしておけばそれに依存するパッケージも一緒にavtivateされる。 $ spack activate py-torch $ spack activate py-numpy $ spack activate py-matplotlib ... $ spack extensions python ==> 36 activated: -- linux-ubuntu20.04-zen2 / gcc@9.3.0 --------------------------- py-argparse@1.4.0 py-jedi@0.18.0 py-pickleshare@0.7.5 py-python-dateutil@2.8.1 py-tqdm@4.59.0 py-backcall@0.1.0 py-joblib@1.0.1 py-pillow@7.2.0 py-pyyaml@5.3.1 py-traitlets@5.0.4 ... この状態になっていれば次からspack load pythonでこれらのパッケージも使えるようになる。 キャッシュや不要パッケージの削除 spackでは依存関係も含めて1から構築するためダウンロードしたソースやビルド時に生成された中間ファイルが大量にできるので一通り環境構築が終わったらspack cleanで不要なキャッシュの削除をしておいてもよい。削除のレベルにいくらかあるので適当に選ぶ。 $ spack clean -h usage: spack clean [-hsdfmpba] ... remove temporary build files and/or downloaded archives positional arguments: specs one or more package specs optional arguments: -h, --help show this help message and exit -s, --stage remove all temporary build stages (default) -d, --downloads remove cached downloads -f, --failures force removal of all install failure tracking markers -m, --misc-cache remove long-lived caches, like the virtual package index -p, --python-cache remove .pyc, .pyo files and __pycache__ folders -b, --bootstrap remove software needed to bootstrap Spack -a, --all equivalent to -sdfmpb 以下は不要なものは全部削除している。 $ spack clean --all 目的のパッケージを構築するために作られる大量の中間パッケージも不要ならばspack gc でガベージコレクションできる。ただし、これを行うと次に同様のパッケージを追加するときにまた膨大な時間がかかることになるので注意。 spack gc ==> The following packages will be uninstalled: -- linux-ubuntu20.04-zen2 / gcc@9.3.0 --------------------------- vyivrsu at-spi2-atk@2.34.2 jpk2juk gtkplus@3.24.26 yggsngn m4@1.4.18 tib7bzf perl-test-needs@0.002005 rtrmwji at-spi2-core@2.38.0 kzme4an harfbuzz@2.6.8 53hqjji mesa@21.0.0 3lirbfz perl-try-tiny@0.28 x7xrjvc atk@2.36.0 n3h5krl help2man@1.47.16 xmt43zs meson@0.57.1 5xvxinf perl-uri@1.72 ... ==> Do you want to proceed? [y/N] N ==> Aborting uninstallation spack gcで削除するパッケージ一覧が出てくるのが、これらを削除したとしても明示的にインストールしたパッケージは動作する。もし消したくないパッケージが一覧にある場合はspack install パッケージ名をしてspack find -xに出てくるようにしておく。 $ spack install llvm $ spack find -x ==> 12 installed packages -- linux-ubuntu20.04-zen2 / gcc@9.3.0 --------------------------- gcc@9.3.0 py-argparse@1.4.0 py-h5py@3.2.1 py-matplotlib@3.4.1 py-numpy@1.20.2 py-scipy@1.6.2 python@3.8.8 llvm@11.1.0 py-cython@0.29.22 py-ipython@7.21.0 py-mpi4py@3.0.3 py-scikit-learn@0.24.1 py-torch@1.8.1 この一覧に出てくるパッケージとそれに依存するものは削除されなくなる。
- 投稿日:2021-04-03T18:00:54+09:00
メモリ
メモリとキャッシュ Linux におけるメモリの状態を大きく分けると「使用中のメモリ」「キャッシュ」「空きメモリ」「スワップ」の 4 つ 使用中のメモリとはカーネルやアプリケーションなどのプロセスによって使用されているメモリの事です。キャッシュとは HDD アクセスなど I/O の高速化を行うためのキャッシュとして利用されるメモリの事です。 使用中のメモリが増えると、空きメモリが減る。 空きメモリがある限り、基本的にキャッシュはどんどん増加する。 空きメモリが無くなれば、使用中のメモリの増加に応じて、キャッシュが減る。 キャッシュに割り当てられるメモリが無くなると、I/O のパフォーマンスは低下する。 使用中のメモリが実メモリより大きくなりそうになると、あふれる部分をスワップへ書き出す。 これを見ればわかるとおり、必要とされるメモリが増えると、キャッシュに使用できるメモリが減るため、I/O のパフォーマンスが低下しますし、メモリがあふれるとスワップが使用されるために I/O のパフォーマンスはますます低下します。 そのため、使用中のメモリが実メモリよりも小さく、キャッシュが確保され、スワップが使用されない状態が理想であり、恒常的にスワップが利用される状況の場合には、メモリの増設などを検討しなければなりません。 メモリの状態を確認する free vmstat なおキャッシュには 2 種類があり、cache で示されるページキャッシュと buff で示されるバッファキャッシュが存在します。 ページキャッシュ: ファイルシステムに対するキャッシュであり、ファイル単位でアクセスするときに使用されるキャッシュです。例えば、ファイルへデータを書き込んだときは、ページキャッシュにデータが残されるため、次回の読み込み時には HDD にアクセスすることなくデータを利用できます。 バッファキャッシュ: ブロックデバイスを直接アクセスするときに使用されるキャッシュです。 キャッシュについて考察する それでは、dd と vmstat を使用してページキャッシュの挙動を見てみたいと思います。 おそらくスワップはまだ利用されていないと思いますが、念のためにスワップをオフ/オンし、スワップが利用されていない状態にします。 # free total used free shared buffers cached Mem: 1924020 448076 1475944 0 3396 272788 -/+ buffers/cache: 171892 1752128 Swap: 4128760 74952 4053808 # swapoff -a && swapon -a # free total used free shared buffers cached Mem: 1924020 401084 1522936 0 3524 273492 -/+ buffers/cache: 124068 1799952 Swap: 4128760 0 4128760 free コマンドの表示を見ると、スワップアウトが 0 であることが分かります。 次にキャッシュをクリアしておきます。 # echo 1 > /proc/sys/vm/drop_caches 次に dd を実行し、HDD に書き込みを行います。 # dd if=/dev/zero of=test bs=1M count=512 512+0 records in 512+0 records out 536870912 bytes (537 MB) copied, 1.76426 s, 304 MB/s vmstat の表示を見るとファイルへの書き込み(io の bo)が発生し、IO ウェイト(cpu の wa)が上昇していることがわかります。 またページキャッシュの使用量が 500MB 強ほど増えており、ファイルを書き込んだタイミングでページキャッシュが使用されたことが分かります。 procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 0 0 0 1717524 184 8280 0 0 0 0 13 9 0 0 100 0 0 0 2 0 1326248 1328 455184 0 0 176 177156 653 286 1 32 0 67 0 0 1 0 1248508 1332 531856 0 0 160 125952 421 199 0 9 0 91 0 0 0 0 1250740 1336 531860 0 0 4 90108 253 32 0 3 16 81 0 0 0 0 1257064 1336 531872 0 0 0 0 118 11 0 0 100 0 0 ~中略(30秒間)~ 0 1 0 1248260 1352 531864 0 0 4 98308 90 22 0 3 83 14 0 0 0 0 1255700 1352 531880 0 0 0 32764 214 13 0 1 77 22 0 ちなみに、ファイルへの書き込みは 1.76 秒で終了していますが、遅延書き込み(ライトバック)が有効な環境では flush というカーネルスレッドによって非同期で HDD への書き込みが行われます。 上記の例でも、書き込み直後は 393,216 ブロック(384MB)のみ書き込まれており、30 秒後の書き込みをあわせて 524,288 ブロック(512MB)となっていることが分かります。 procs の b が一時的に 2 になっているのは、dd とは別に flush が動作しているためです。dd がすでに終了している、30 秒後の書き込み時に procs の b が 1 になっているのも、flush が動作して非同期書き込みしたためです。 次に先ほど書き込んだデータを読み込んでみます。 # dd if=test of=/dev/null bs=1M count=512 512+0 records in 512+0 records out 536870912 bytes (537 MB) copied, 0.277886 s, 3.9 GB/s ページキャッシュに保存されているため 0.28 秒と一瞬で完了しており、vmstat の結果を見るとディスク IO は発生せず(bi が 0 になっている)、IO ウェイトもありません。 procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 0 0 0 1255064 2272 532704 0 0 0 0 139 27 0 11 89 0 0 これで、書き込みしたデータがページキャッシュにキャッシュされ、読み込み時に使用されたことが分かりました。 遅延書き込みを確認する 先ほど、flush というカーネルスレッドにより非同期で HDD への書き込みがおこなわれていることを解説しました。iotop コマンドを利用すればリアルタイムに IO の状況を確認できますので、iotop を実行しながら書き込みを試してみましょう。 vmstat を実行しているターミナルもしくは、新しいターミナルを開き、iotop コマンドを実行してください。 # iotop まずは、direct オプションを付けて、ページキャッシュを使わない指定をして実行します。 # dd if=/dev/zero of=test bs=1M count=512 oflag=direct すると、iotop では dd プロセスだけが IO を使用していることが分かります。 Total DISK READ: 0.00 B/s | Total DISK WRITE: 59.42 M/s TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND 2069 be/4 root 0.00 B/s 59.42 M/s 0.00 % 99.49 % dd if=/dev/zero of=test bs=1M count=1024 oflag=di 1 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % init 2 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [kthreadd] ちなみに、このときの vmstat は以下のようになり、test というファイルに割り当てられていた 500MB強のページキャッシュが解放されたことが分かります。また、procs の b は 1 であり、1 プロセスのみが IO を利用していることが分かります。 procs -----------memory---------- ---swap-- -----io0---- -system-- -----cpu------ r b swpd free buff cache si so bi bo in cs us sy id wa st 0 0 0 1039880 40100 700096 0 0 0 0 25 25 0 0 100 0 0 0 1 0 1570468 40108 175808 0 0 0 32824 159 131 0 7 69 24 0 0 1 0 1570468 40108 175808 0 0 0 140288 343 421 0 3 0 97 0 0 1 0 1570468 40108 175808 0 0 0 118784 293 366 0 4 0 96 0 次に、direct オプションを付けずに実行します。 # dd if=/dev/zero of=test bs=1M count=512 すると、iotop では dd プロセスとともに[flush-253:0]というプロセスが IO を使用していることが分かります。 Total DISK READ: 0.00 B/s | Total DISK WRITE: 136.81 M/s TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND 1009 be/4 root 0.00 B/s 51.47 K/s 0.00 % 96.35 % [flush-253:0] 2071 be/4 root 0.00 B/s 81.78 M/s 0.00 % 93.61 % dd if=/dev/zero of=test bs=1M count=512 1 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % init vmstat を見ると、再びページキャッシュが確保されて 500MB ほど増加し、procs の b は 2 プロセスとなりました。 procs -----------memory---------- ---swap-- -----io0---- -system--- -----cpu------ r b swpd free buff cache si so bi bo in cs us sy id wa st 0 0 0 1571468 40160 175808 0 0 0 0 26 25 0 0 100 0 0 0 2 0 1167220 40160 566272 0 0 0 120836 409 107 0 28 61 11 0 0 2 0 1053264 40160 676856 0 0 0 114688 440 253 0 12 0 88 0 0 2 0 1030448 40160 700088 0 0 0 133120 373 13150 0 5 0 95 0 つまり、direct の場合にはプロセスと同期して HDD への書き込みがおこなわれ、通常の場合にはページキャッシュを経由して非同期に HDD への書き込みがおこなわれることが分かります。 なお、読み込みの頻度が少なく容量の大きなファイルを書き込むときには、ページキャッシュを利用しないほうが速くなることもあります。例えば、VM のイメージやバックアップデータなど、書き込んだまま使用をしばらくしないようなデータの場合が該当します。 また、メモリを大量に搭載したサーバにおいては、メモリがプロセスなどによって利用されない限り、多くのメモリがページキャッシュに割り当てられるため、一見書き込みが高速なように見えても flush中に IO がボトルネックになり、いわゆる「息継ぎ」が発生することもあります。 その為、用途によって遅延書き込みの使用可否、direct オプションの使用などを検討すればよいでしょう。 title: いまさら聞けないLinuxとメモリの基礎&vmstatの詳しい使い方 tags: さくらインターネット Linux author: kunihirotanaka slide: false さくらインターネット Advent Calendar最終日は、硬派にLinuxのメモリに関する基礎知識についてみてみたいと思います。 最近はサーバーを意識せずプログラミングできるようになり、メモリの空き容量について意識することも少なくなりましたが、いざ低レイヤーに触れなければいけないシチュエーションになった際に、OSを目の前に呆然とする人が多いようです。 基本的にLinux のパフォーマンスについて、メモリをたくさんつめばいいとか、スワップさせないほうが良い とか、このあたりは良く知られたことだと思います。 ただ、なんとなく ps コマンドや free コマンド などの結果を見るだけでなく、もう少しメモリのことについて掘り下げてみてみたいと思います。 メモリとキャッシュ Linux におけるメモリの状態を大きく分けると「使用中のメモリ」「キャッシュ」「空きメモリ」「スワップ」の 4 つに分けられます。 そして、スワップについては HDD に存在し、それ以外は実メモリに存在し、HDD は実メモリより低速です。 もうひとつの 使用中のメモリとはカーネルやアプリケーションなどのプロセスによって使用されているメモリの事です。キャッシュとは HDD アクセスなど I/O の高速化を行うためのキャッシュとして利用されるメモリの事です。 使用中のメモリが増えると、空きメモリが減る。 空きメモリがある限り、基本的にキャッシュはどんどん増加する。 空きメモリが無くなれば、使用中のメモリの増加に応じて、キャッシュが減る。 キャッシュに割り当てられるメモリが無くなると、I/O のパフォーマンスは低下する。 使用中のメモリが実メモリより大きくなりそうになると、あふれる部分をスワップへ書き出す。 これを見ればわかるとおり、必要とされるメモリが増えると、キャッシュに使用できるメモリが減るため、I/O のパフォーマンスが低下しますし、メモリがあふれるとスワップが使用されるために I/O のパフォーマンスはますます低下します。 そのため、使用中のメモリが実メモリよりも小さく、キャッシュが確保され、スワップが使用されない状態が理想であり、恒常的にスワップが利用される状況の場合には、メモリの増設などを検討しなければなりません。 メモリの状態を確認する 次に、実際のメモリ使用状況を確認してみます。 メモリの使用状況は free コマンド、もしくは vmstat コマンドなどで確認することができます。 # free total used free shared buffers cached Mem: 1924020 206496 1717524 0 184 8280 -/+ buffers/cache: 198032 1725988 Swap: 4128760 0 4128760 # vmstat 1 procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st ~略~ 0 0 0 1717524 184 8280 0 0 0 0 15 13 0 0 100 0 0 この状況では、空きメモリが 1.7GB(1717524KB)ほどあり、キャッシュに 184KB と 8MB(8280KB)使われていることが分かります。 なおキャッシュには 2 種類があり、cache で示されるページキャッシュと buff で示されるバッファキャッシュが存在します。 ページキャッシュはファイルシステムに対するキャッシュであり、ファイル単位でアクセスするときに使用されるキャッシュです。 例えば、ファイルへデータを書き込んだときは、ページキャッシュにデータが残されるため、次回の読み込み時には HDD にアクセスすることなくデータを利用できます。 もうひとつのバッファキャッシュはブロックデバイスを直接アクセスするときに使用されるキャッシュです。 キャッシュについて考察する それでは、dd と vmstat を使用してページキャッシュの挙動を見てみたいと思います。 おそらくスワップはまだ利用されていないと思いますが、念のためにスワップをオフ/オンし、スワップが利用されていない状態にします。 # free total used free shared buffers cached Mem: 1924020 448076 1475944 0 3396 272788 -/+ buffers/cache: 171892 1752128 Swap: 4128760 74952 4053808 # swapoff -a && swapon -a # free total used free shared buffers cached Mem: 1924020 401084 1522936 0 3524 273492 -/+ buffers/cache: 124068 1799952 Swap: 4128760 0 4128760 free コマンドの表示を見ると、スワップアウトが 0 であることが分かります。 次にキャッシュをクリアしておきます。 # echo 1 > /proc/sys/vm/drop_caches 次に dd を実行し、HDD に書き込みを行います。 # dd if=/dev/zero of=test bs=1M count=512 512+0 records in 512+0 records out 536870912 bytes (537 MB) copied, 1.76426 s, 304 MB/s vmstat の表示を見るとファイルへの書き込み(io の bo)が発生し、IO ウェイト(cpu の wa)が上昇していることがわかります。 またページキャッシュの使用量が 500MB 強ほど増えており、ファイルを書き込んだタイミングでページキャッシュが使用されたことが分かります。 procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 0 0 0 1717524 184 8280 0 0 0 0 13 9 0 0 100 0 0 0 2 0 1326248 1328 455184 0 0 176 177156 653 286 1 32 0 67 0 0 1 0 1248508 1332 531856 0 0 160 125952 421 199 0 9 0 91 0 0 0 0 1250740 1336 531860 0 0 4 90108 253 32 0 3 16 81 0 0 0 0 1257064 1336 531872 0 0 0 0 118 11 0 0 100 0 0 ~中略(30秒間)~ 0 1 0 1248260 1352 531864 0 0 4 98308 90 22 0 3 83 14 0 0 0 0 1255700 1352 531880 0 0 0 32764 214 13 0 1 77 22 0 ちなみに、ファイルへの書き込みは 1.76 秒で終了していますが、遅延書き込み(ライトバック)が有効な環境では flush というカーネルスレッドによって非同期で HDD への書き込みが行われます。 上記の例でも、書き込み直後は 393,216 ブロック(384MB)のみ書き込まれており、30 秒後の書き込みをあわせて 524,288 ブロック(512MB)となっていることが分かります。 procs の b が一時的に 2 になっているのは、dd とは別に flush が動作しているためです。dd がすでに終了している、30 秒後の書き込み時に procs の b が 1 になっているのも、flush が動作して非同期書き込みしたためです。 次に先ほど書き込んだデータを読み込んでみます。 # dd if=test of=/dev/null bs=1M count=512 512+0 records in 512+0 records out 536870912 bytes (537 MB) copied, 0.277886 s, 3.9 GB/s ページキャッシュに保存されているため 0.28 秒と一瞬で完了しており、vmstat の結果を見るとディスク IO は発生せず(bi が 0 になっている)、IO ウェイトもありません。 procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 0 0 0 1255064 2272 532704 0 0 0 0 139 27 0 11 89 0 0 これで、書き込みしたデータがページキャッシュにキャッシュされ、読み込み時に使用されたことが分かりました。 遅延書き込みを確認する 先ほど、flush というカーネルスレッドにより非同期で HDD への書き込みがおこなわれていることを解説しました。iotop コマンドを利用すればリアルタイムに IO の状況を確認できますので、iotop を実行しながら書き込みを試してみましょう。 vmstat を実行しているターミナルもしくは、新しいターミナルを開き、iotop コマンドを実行してください。 # iotop まずは、direct オプションを付けて、ページキャッシュを使わない指定をして実行します。 # dd if=/dev/zero of=test bs=1M count=512 oflag=direct すると、iotop では dd プロセスだけが IO を使用していることが分かります。 Total DISK READ: 0.00 B/s | Total DISK WRITE: 59.42 M/s TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND 2069 be/4 root 0.00 B/s 59.42 M/s 0.00 % 99.49 % dd if=/dev/zero of=test bs=1M count=1024 oflag=di 1 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % init 2 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % [kthreadd] ちなみに、このときの vmstat は以下のようになり、test というファイルに割り当てられていた 500MB強のページキャッシュが解放されたことが分かります。また、procs の b は 1 であり、1 プロセスのみが IO を利用していることが分かります。 procs -----------memory---------- ---swap-- -----io0---- -system-- -----cpu------ r b swpd free buff cache si so bi bo in cs us sy id wa st 0 0 0 1039880 40100 700096 0 0 0 0 25 25 0 0 100 0 0 0 1 0 1570468 40108 175808 0 0 0 32824 159 131 0 7 69 24 0 0 1 0 1570468 40108 175808 0 0 0 140288 343 421 0 3 0 97 0 0 1 0 1570468 40108 175808 0 0 0 118784 293 366 0 4 0 96 0 次に、direct オプションを付けずに実行します。 # dd if=/dev/zero of=test bs=1M count=512 すると、iotop では dd プロセスとともに[flush-253:0]というプロセスが IO を使用していることが分かります。 Total DISK READ: 0.00 B/s | Total DISK WRITE: 136.81 M/s TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND 1009 be/4 root 0.00 B/s 51.47 K/s 0.00 % 96.35 % [flush-253:0] 2071 be/4 root 0.00 B/s 81.78 M/s 0.00 % 93.61 % dd if=/dev/zero of=test bs=1M count=512 1 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % init vmstat を見ると、再びページキャッシュが確保されて 500MB ほど増加し、procs の b は 2 プロセスとなりました。 procs -----------memory---------- ---swap-- -----io0---- -system--- -----cpu------ r b swpd free buff cache si so bi bo in cs us sy id wa st 0 0 0 1571468 40160 175808 0 0 0 0 26 25 0 0 100 0 0 0 2 0 1167220 40160 566272 0 0 0 120836 409 107 0 28 61 11 0 0 2 0 1053264 40160 676856 0 0 0 114688 440 253 0 12 0 88 0 0 2 0 1030448 40160 700088 0 0 0 133120 373 13150 0 5 0 95 0 つまり、direct の場合にはプロセスと同期して HDD への書き込みがおこなわれ、通常の場合にはページキャッシュを経由して非同期に HDD への書き込みがおこなわれることが分かります。 なお、読み込みの頻度が少なく容量の大きなファイルを書き込むときには、ページキャッシュを利用しないほうが速くなることもあります。例えば、VM のイメージやバックアップデータなど、書き込んだまま使用をしばらくしないようなデータの場合が該当します。 また、メモリを大量に搭載したサーバにおいては、メモリがプロセスなどによって利用されない限り、多くのメモリがページキャッシュに割り当てられるため、一見書き込みが高速なように見えても flush中に IO がボトルネックになり、いわゆる「息継ぎ」が発生することもあります。 その為、用途によって遅延書き込みの使用可否、direct オプションの使用などを検討すればよいでしょう。 スワップアウトさせてみる ここまで、キャッシュの挙動と IO の関係を見てきました。 ここで、実メモリ以上にメモリ空間を確保してメモリ不足の状況を起こし、スワップとキャッシュがどのような挙動をするか見てみます。 実メモリを確保するために、dd でメモリを 2G バイト指定してコピーを実行します。 # dd if=/dev/zero of=/dev/null bs=2G count=1 0+1 records in 0+1 records out 2147479552 bytes (2.1 GB) copied, 8.88384 s, 242 MB/s すると、みるみるうちにバッファキャッシュとページキャッシュの使用量が減っていき、スワップの使用量が増えてきました。 procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 0 0 0 1259544 440 530032 0 0 0 0 25 26 0 0 100 0 0 1 0 1020 66640 120 374540 0 1020 0 1020 484 48 0 46 54 0 0 0 2 50104 53072 108 20052 0 49048 0 49048 491 193 0 41 0 59 0 1 1 112012 53100 116 20056 0 61916 0 61928 211 184 0 4 0 96 0 0 2 168016 53764 116 19000 0 56004 0 56008 220 95 1 5 0 94 0 1 2 214216 53064 116 17872 32 46204 32 46204 223 80 0 6 0 94 0 0 3 265212 52972 116 17868 96 51004 96 51004 217 81 0 5 0 95 0 0 2 327312 53004 116 17860 96 62112 96 62112 262 126 0 7 0 93 0 0 2 374232 53876 116 16624 0 46932 0 46932 225 78 0 5 0 95 0 0 2 433160 54556 116 16584 0 58948 0 58948 214 75 0 6 0 94 0 0 0 75092 1746180 116 16608 476 168 476 168 217 115 0 7 43 50 0 dd の終了とともに空きメモリは増え、スワップは減りましたが、キャッシュは減ったままになっています。 この状態で先ほど書き込んだデータをもう一度読み込んでみます。 # dd if=test of=/dev/null bs=1M count=512 512+0 records in 512+0 records out 536870912 bytes (537 MB) copied, 0.735082 s, 730 MB/s すると、先ほどは 0.10 秒で完了し 5.2 GB /s だったものが、0.74 秒で 730MB/s と大幅に遅くなって います。 また、ディスクの読み込みが発生し、IO ウェイトも若干ですが発生しています。 procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 2 0 79428 1484132 104 281820 32 0 261880 0 2431 4102 0 35 62 3 0 0 0 79428 1236760 104 529968 0 0 248116 0 2303 3830 0 35 63 2 0 このように、メモリが極端に足りない状況になるとページキャッシュにまわされるメモリ空間が無く なり、IO に負担がかかることが分かります。 ちなみに、一度読み込みを行うと、再びページキャッシュが増えていることが分かります。 試しに先ほどと同じように dd コマンドを実行してみましょう。 # dd if=test of=/dev/null bs=1M count=512 512+0 records in 512+0 records out 536870912 bytes (537 MB) copied, 0.123787 s, 4.3 GB/s 最初にディスク書き込みを行った直後と同じように、一瞬で読み込みが完了し、ページキャッシュが 有効に利用されたことが分かります。 ファイルを削除したときの挙動を確認する ページキャッシュはファイルに対するキャッシュであるという解説をしましたが、該当のファイルが無くなった場合はどうなるのでしょうか? 先ほど作成したファイルを削除してみます。 # rm -f test すると、test というファイルのために確保されていたページキャッシュは解放されました。 procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 0 0 79004 1756304 1152 8736 0 0 0 0 19 19 0 0 100 0 0 バッファキャッシュの挙動を確認する なお、ここまではページキャッシュについてみてきましたが、ブロックデバイスへアクセスした際のバッファキャッシュの動きについても見てみましょう。 次のように、ブロックデバイスから 512MB の読み込みを試します。 # dd if=/dev/vda of=/dev/null bs=1M count=512 512+0 records in 512+0 records out 536870912 bytes (537 MB) copied, 1.19414 s, 450 MB/s 1.19 秒で処理が完了しました。 vmstat の状態を見ると、ディスク読み込みが発生し IO ウェイトが若干高まるとともに、バッファキャッシュの使用量が 500MB 強ほど増加したことが分かります。 procs -----------memory----------- ---swap-- -----io---- --system-- -----cpu------ r b swpd free buff cache si so bi bo in cs us sy id wa st 0 0 0 1255484 2492 534276 0 0 0 0 30 36 0 0 100 0 0 2 0 0 1088200 164236 534260 0 0 161740 0 2593 3053 0 29 66 5 0 0 0 0 715712 526908 534276 0 0 362676 0 6927 8131 0 80 16 4 0 この状態で、再度読み込みを試します。 # dd if=/dev/vda of=/dev/null bs=1M count=512 512+0 records in 512+0 records out 536870912 bytes (537 MB) copied, 0.109901 s, 4.9 GB/s 次は 0.11 秒と劇的に高速化されました。 まとめ ファイルを書き込むとページキャッシュが確保される ファイルを読み込むとページキャッシュが確保される HDD へのアクセス中(IO 中)は、procs の b と、cpu の wa が上昇する HDD への書き込み中は io の bo が、読み込み中は io の bi が上昇する ページキャッシュやバッファキャッシュから読み込むときは io の bi は増えず、大変高速である メモリが足りなくなるとスワップアウトされ、パフォーマンスが低下する メモリが足りなくなるとページキャッシュやバッファキャッシュは解放される なお、一般的に書き込みより読み込みのほう負荷が低いと思われがちですが、上記のとおり書き込みは遅延対応が行えることから HDD 動作を必ずしも待たなくて良いのに対し、読み込みはキャッシュに存在しなければ HDD へのアクセスが発生するため、頻繁にアクセスされるファイルの容量分だけメモリが搭載されていれば、ディスク IO が大きく改善します。 ですので、スワップが発生しないように維持することはもちろんのこと、空きメモリと IO の発生状況(bi の項目)をチェックし、性能を維持することが重要となります。 スワップアウトさせてみる ここまで、キャッシュの挙動と IO の関係を見てきました。 ここで、実メモリ以上にメモリ空間を確保してメモリ不足の状況を起こし、スワップとキャッシュがどのような挙動をするか見てみます。 実メモリを確保するために、dd でメモリを 2G バイト指定してコピーを実行します。 # dd if=/dev/zero of=/dev/null bs=2G count=1 0+1 records in 0+1 records out 2147479552 bytes (2.1 GB) copied, 8.88384 s, 242 MB/s すると、みるみるうちにバッファキャッシュとページキャッシュの使用量が減っていき、スワップの使用量が増えてきました。 procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 0 0 0 1259544 440 530032 0 0 0 0 25 26 0 0 100 0 0 1 0 1020 66640 120 374540 0 1020 0 1020 484 48 0 46 54 0 0 0 2 50104 53072 108 20052 0 49048 0 49048 491 193 0 41 0 59 0 1 1 112012 53100 116 20056 0 61916 0 61928 211 184 0 4 0 96 0 0 2 168016 53764 116 19000 0 56004 0 56008 220 95 1 5 0 94 0 1 2 214216 53064 116 17872 32 46204 32 46204 223 80 0 6 0 94 0 0 3 265212 52972 116 17868 96 51004 96 51004 217 81 0 5 0 95 0 0 2 327312 53004 116 17860 96 62112 96 62112 262 126 0 7 0 93 0 0 2 374232 53876 116 16624 0 46932 0 46932 225 78 0 5 0 95 0 0 2 433160 54556 116 16584 0 58948 0 58948 214 75 0 6 0 94 0 0 0 75092 1746180 116 16608 476 168 476 168 217 115 0 7 43 50 0 dd の終了とともに空きメモリは増え、スワップは減りましたが、キャッシュは減ったままになっています。 この状態で先ほど書き込んだデータをもう一度読み込んでみます。 # dd if=test of=/dev/null bs=1M count=512 512+0 records in 512+0 records out 536870912 bytes (537 MB) copied, 0.735082 s, 730 MB/s すると、先ほどは 0.10 秒で完了し 5.2 GB /s だったものが、0.74 秒で 730MB/s と大幅に遅くなって います。 また、ディスクの読み込みが発生し、IO ウェイトも若干ですが発生しています。 procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 2 0 79428 1484132 104 281820 32 0 261880 0 2431 4102 0 35 62 3 0 0 0 79428 1236760 104 529968 0 0 248116 0 2303 3830 0 35 63 2 0 このように、メモリが極端に足りない状況になるとページキャッシュにまわされるメモリ空間が無く なり、IO に負担がかかることが分かります。 ちなみに、一度読み込みを行うと、再びページキャッシュが増えていることが分かります。 試しに先ほどと同じように dd コマンドを実行してみましょう。 # dd if=test of=/dev/null bs=1M count=512 512+0 records in 512+0 records out 536870912 bytes (537 MB) copied, 0.123787 s, 4.3 GB/s 最初にディスク書き込みを行った直後と同じように、一瞬で読み込みが完了し、ページキャッシュが 有効に利用されたことが分かります。 ファイルを削除したときの挙動を確認する ページキャッシュはファイルに対するキャッシュであるという解説をしましたが、該当のファイルが無くなった場合はどうなるのでしょうか? 先ほど作成したファイルを削除してみます。 # rm -f test すると、test というファイルのために確保されていたページキャッシュは解放されました。 procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 0 0 79004 1756304 1152 8736 0 0 0 0 19 19 0 0 100 0 0 バッファキャッシュの挙動を確認する なお、ここまではページキャッシュについてみてきましたが、ブロックデバイスへアクセスした際のバッファキャッシュの動きについても見てみましょう。 次のように、ブロックデバイスから 512MB の読み込みを試します。 # dd if=/dev/vda of=/dev/null bs=1M count=512 512+0 records in 512+0 records out 536870912 bytes (537 MB) copied, 1.19414 s, 450 MB/s 1.19 秒で処理が完了しました。 vmstat の状態を見ると、ディスク読み込みが発生し IO ウェイトが若干高まるとともに、バッファキャッシュの使用量が 500MB 強ほど増加したことが分かります。 procs -----------memory----------- ---swap-- -----io---- --system-- -----cpu------ r b swpd free buff cache si so bi bo in cs us sy id wa st 0 0 0 1255484 2492 534276 0 0 0 0 30 36 0 0 100 0 0 2 0 0 1088200 164236 534260 0 0 161740 0 2593 3053 0 29 66 5 0 0 0 0 715712 526908 534276 0 0 362676 0 6927 8131 0 80 16 4 0 この状態で、再度読み込みを試します。 # dd if=/dev/vda of=/dev/null bs=1M count=512 512+0 records in 512+0 records out 536870912 bytes (537 MB) copied, 0.109901 s, 4.9 GB/s
- 投稿日:2021-04-03T15:44:11+09:00
LinuxMint Eclipseの日本語化(ランチャ起動)
本記事で解説すること
Eclipseを日本語化し、ランチャから起動させる。
+そこまでの流れ。
[解決方法]以外はおまけのようなものなので、飛ばしてOK経緯
win10でjavaの勉強中、ネットに落ちていたSwingのサンプルコードを使用したところなにを間違ったのかOpenJDKが死んだ。
同じようなエラーが出た人を探すと「再インストールで治った」とのこと。
Win10で再インストールしてもいいなと思っていたが、USBに入れてあるLinux mint 20でJava環境を作ったほうが早いなと考えて方針を切り替えた。
しかし、この男、Linuxはど素人である。
3日間、英語と日本語とLinuxにいじめられた。その中で、LinuxにEclipseを導入するまではなんとかうまく行ったが、日本語化でかなりやられたので備忘録がてら参考にしてほしい。
なお、Qiitaを初めて二作目の記事なので温かい目で。。。Eclipseの導入
今回はこちらのサイトを参考にさせていただいた。
Eclipse(2019年12月版)のインストール,日本語化,基本操作(Ubuntu 上)基本的に、いろいろなサイトを徘徊しながらインストールしたほうが良い。
私のような初心者向けに1から10まで丁寧に解説してくれるサイトは残念ながらない。
荒波に揉まれまくるか、Winに逃げるかの二択なのだ。
多分、私は数日後にWinに逃げる。日本語化
日本語化の大まかな流れもこちらのサイトに解説されている。
Eclipse(2019年12月版)のインストール,日本語化,基本操作(Ubuntu 上)なお、PleiadesのTXTにちゃんと説明がある。
ダウンロードした場所/pleiades/readme/redme_pleiades.txt
ランチャからの起動
同じような症状の人を探すとこちらのサイトがヒットした。
インデックス » 開発環境 » Eclipse を起動したあと時間が経つとエラーがでる。解決方法
結論:フルパスにする
Eclipse/eclipse.ini
先程、ここに入力した
-javaagent:plugins/jp.sourceforge.mergedoc.pleiades/pleiades.jar
を
-javaagent:/home/ユーザー/(eclipse/java-2020-06)※環境によって異なる/eclipse/plugins/jp.sourceforge.mergedoc.pleiades/pleiades.jar
のフルパスに書き換えるだけ。
ちなみに、私はこれに1日を費やした。
- 投稿日:2021-04-03T15:44:11+09:00
LinuxMint Eclipseの日本語化によるエラー
本記事で解説すること Eclipseを日本語化し、ランチャから起動させたときにエラーが出た場合。 win10でjavaの勉強中、ネットに落ちていたSwingのサンプルコードを使用したところなにを間違ったのかOpenJDKが死んだ。同じようなエラーが出た人を探すと「再インストールで治った」とのこと。Win10で再インストールしてもいいなと思っていたが、USBに入れてあるLinux mint 20でJava環境を作ったほうが早いなと考えて方針を切り替えた。しかし、この男、Linuxはど素人である。3日間、英語と日本語とLinuxにいじめられた。その中で、LinuxにEclipseを導入するまではなんとかうまく行ったが、日本語化でかなりやられたので備忘録がてら参考にしてほしい。 私のような初心者へ ・いろいろなサイトを徘徊して、参考にしながらインストールしたほうが良い。 ・私のような初心者向けに1から10まで丁寧に解説してくれるサイトは残念ながらない。 ・一人で悩まずにLinuxに詳しい人を探して質問しよう。 ・荒波に揉まれまくるか、Winに逃げるかの二択なのだ。 →多分、私は数日後にWinに逃げる。 なお、二作目の記事なので温かい目で・・・ Eclipseの導入・日本語化まで 今回はこちらのサイトを参考にさせていただいた。 Eclipse(2019年12月版)のインストール,日本語化,基本操作(Ubuntu 上) なお、PleiadesのTXTにちゃんと説明がある。 ダウンロードした場所/pleiades/readme/redme_pleiades.txt ランチャからの起動 ここで、下のようにランチャから起動しようとした。 そうすると、謎のエラー 同じような症状の人を探すとこちらのサイトがヒットした。 インデックス » 開発環境 » Eclipse を起動したあと時間が経つとエラーがでる。 解決方法 結論:フルパスにする 先程、Eclipse/eclipse.iniに入力した [-javaagent:plugins/jp.sourceforge.mergedoc.pleiades/pleiades.jar] を [-javaagent:/home/ユーザー/~~~/eclipse/plugins/jp.sourceforge.mergedoc.pleiades/pleiades.jar] のフルパスに書き換えるだけ。 ↓変更後 ちなみに、私はこれに1日を費やした。
- 投稿日:2021-04-03T15:28:09+09:00
ユーザ権限でlogrotateをする際に起こったPermission deniedエラーの対処法
ユーザ権限で crontab で logrotate をする際にどうもうまく行かなかったのでその備忘録 userA$ crontab -e # これはだめな設定例 0 3 * * * /sbin/logrotate /var/log/xxxxxx/logrotate.conf > /var/log/xxxxxx/logrotate.log 2>&1 userA$ cat /var/log/xxxxxx/logrotate.log /var/log/xxxxxx/log1 /var/log/xxxxxx/log2 { compress endscript rotate 120 size 0 dateext dateformat _%Y%m%d create 644 userA userA } こんな感じで書いていたが結果のログファイルを見てみると cat /var/log/xxxxxx/logrotate.log error: error creating output file /var/lib/logrotate/logrotate.status.tmp: Permission denied こうなっていた。 logrotateは内部で .statusファイルを使用して最終rotate日を保存してあるのだが、そのパスがroot権限のディレクトリになっていたためのエラーである。参考までにlogrotate.statusファイルは以下のような内容になっている cat logrotate.status logrotate state -- version 2 "/var/log/xxxxxx/log1" 2021-4-3-15:22:1 "/var/log/xxxxxx/log2" 2021-4-3-15:22:1 結論 logrotate -sオプションで.statusファイルをユーザ権限内のディレクトリに変更しましょう userA$ crontab -e 0 3 * * * /sbin/logrotate -s /var/log/xxxxxx/logrotate.status /var/log/xxxxxx/logrotate.conf > /var/log/xxxxxx/logrotate.log 2>&1
- 投稿日:2021-04-03T15:19:17+09:00
Ubuntu20.04 macライクな設定
UI Macライク macのキーボード入力に慣れているが、linuxを使っている。 linuxで入力する時、CapsLockとか、変換/無変換を入力しまくって困ったため調べた 参考記事 https://qiita.com/momokura/items/33cd6ee525553fc91473 Dockの長さを適切に短くする $ gsettings set org.gnome.shell.extensions.dash-to-dock extend-height false 「アプリケーションを表示する」を左端に配置する $ gsettings set org.gnome.shell.extensions.dash-to-dock show-apps-at-top true 「ゴミ箱」をDockに配置する $ gsettings set org.gnome.shell.extensions.dash-to-dock show-trash true UIをMac風 https://www.gnome-look.org/s/Gnome/p/1305429からアイコンをダウンロードし、/usr/share/icons/に展開する # Gitをインストールしていない人だけ $ sudo apt install git curl $ mkdir ~/.themes $ cd ~/.themes/ # 他にもDarkモードなどあるので自分にあったテーマを $ git clone https://github.com/B00merang-Project/macOS.git # iconとかを変えるやつ $ sudo apt install gnome-tweak-tool $ gnome-tweaks gnome-tweaksの設定 タイトルバーの位置を左に ここまででこんな感じになる キー配置をmacライクに 変換/無変換 → かな/英数 https://magidropack.hatenablog.com/entry/2018/11/30/120602 Caps Lock英数 → hyper(control) https://www.komee.org/entry/2018/10/24/150000 xmodmapを作成する $ xmodmap -pke > ~/.Xmodmap_default キーボードの割当keycodeを探す $ xev 書き換える $ vim ~/.Xmodmap_default keycode 66 = Hyper_L # 私の場合は、CapLockキーが66だったため システムログイン時に自動でキーバインドする(ログインスクリプトに追記する) vim ~/.bashrc xmodmap -e 'keycode 66 = Hyper_L' # 私の場合は、ログインスクリプトがbashrcだったため 再起動する bash $ sudo reboot CapsLock + f → https://zenn.dev/skanehira/articles/2021-03-08-linux-autokey Autokeyをインストールする $ sudo apt install autokey-gtk Autokeyを設定する フォルダを作成する GUIで アプリケーション、新規、フォルダ作成 2. フォルダとアプリケーションを紐付ける 3. キーバインドを設定する - Set Hotkey ⇒ Press to Setで、キー設定を行う - 例> hyper + f - Scriptに入力する⇒ keyboard.send_keys("<right>") - 保存 これで完了
- 投稿日:2021-04-03T14:37:20+09:00
localeでエラーが起きた時対応
MacのターミナルではUTF8テキストが文字化けせずにみれるのに、他のターミナルからは文字が化けるということがある。ターミナルからlocaleを送る時と、そうでない時があるようだ。 WSL Terminalからだとこんば化け方(あいうえおと書いてる) localeがおかしいはずなので、localeコマンドをうってみる # locale locale: Cannot set LC_CTYPE to default locale: No such file or directory locale: Cannot set LC_MESSAGES to default locale: No such file or directory locale: Cannot set LC_ALL to default locale: No such file or directory LANG=C.UTF-8 LC_CTYPE="C.UTF-8" LC_NUMERIC="C.UTF-8" LC_TIME="C.UTF-8" LC_COLLATE="C.UTF-8" LC_MONETARY="C.UTF-8" LC_MESSAGES="C.UTF-8" LC_PAPER="C.UTF-8" LC_NAME="C.UTF-8" LC_ADDRESS="C.UTF-8" LC_TELEPHONE="C.UTF-8" LC_MEASUREMENT="C.UTF-8" LC_IDENTIFICATION="C.UTF-8" LC_ALL= いろいろ怒られてる。localeの設定がこと切れてる。じゃぁどのloaleを設定すればいいのさ。 locale -a | less のコマンドを打てば、利用可能な一覧が出てくる。 export LC_ALL=en_US.utf8 というロケール設定で、だいたいは収まる。 以下、en_US.utf8 にしている理由。 コマンドの出力結果が日本語だと想定外になるので、英語のままがいい US以外の英語もあるが、こだわりはないので、en_USでいい 何よりもUTF8の表示がしたいから、UTF8がいい
- 投稿日:2021-04-03T03:00:26+09:00
【Linux】面白いコマンドまとめ
環境はubuntu 18.04.4 LTS xeyes カーソルを追いかける目が出てくる。 pv sudo apt_get install pv でダウンロードする必要あり。 echo "" | pv -qL 10 標準出力がリアルタイムで表示される。 Lは1秒あたりのバイトの制限。 随時、追加予定。



