2022/09/16(金)kv-0.4.55

久しぶりに、kvを0.4.55にアップデートしました。

今年の1月に、M1 macの区間演算は遅い?という記事を書きました。このときに、ARM CPUでのinline assemblerによる丸めの向きの変更のコードを追加していたのですが、大して面白い変更では無かったので放置していました。気づいたら8ヶ月も経ってしまい、細かい修正も溜まってきたのでここでいったん公開することにしました。

というわけで、今回の変更はARM CPUで-DKV_FASTROUNDを付けるとinline assemblerによる丸めの向きの変更が使えるようになる、というものです。ARM 64bitだけでなく、一応ARM 32bitでも動くようにしたつもりですが、あまりテストされていません。

詳細は丸めモードの変え方とコンパイルオプションまとめの「6. ベンチマーク」に書きましたが、一般的にARM CPUでは丸めのモードを変更すると実行時間で大きなペナルティがあるようで、Intel CPUに比べてかなり遅いです。ARM CPUではハードウェアによる丸め変更を一切行わずにソフトウェアで方向付き丸めをエミュレートするのが一番速いという、残念な状況になっています。これを、精度保証に向かないCPUが普及しつつあって残念と見るか、エミュレーションのアルゴリズムを開発しておいて良かった、と見るか。

以下、とある区間演算を多用したプログラムを、端点がdouble精度の区間演算と、端点がdd精度の区間演算の場合について、オプションを変えながら実行したときの実行時間を上のページから抜き出しておきます。爆速のはずのM1 chipの計算速度が遅く、-DNOHWROUND (ソフトウェアエミュレートによる丸め変更) が一番まともになっているのが分かります。

core i5 11400

計算精度(端点の型) コンパイルオプション
(-O3 -DNDEBUGに加えて)
計算時間
-DKV_USE_TPFMAなし -DKV_USE_TPFMAあり
double なし 6.65 sec
-DKV_FASTROUND 3.74 sec
-DKV_NOHWROUND 7.88 sec 6.05 sec
-DKV_USE_AVX512 -mavx512f 2.74 sec
dd なし 37.20 sec 33.58 sec
-DKV_FASTROUND 25.08 sec 21.52 sec
-DKV_NOHWROUND 92.24 sec 71.81 sec
-DKV_USE_AVX512 -mavx512f 16.47 sec

M1 MacBook Air

計算精度(端点の型) コンパイルオプション
(-O3 -DNDEBUGに加えて)
計算時間
-DKV_USE_TPFMAなし -DKV_USE_TPFMAあり
double なし 24.45 sec
-DKV_FASTROUND 22.36 sec
-DKV_NOHWROUND 9.08 sec 6.03 sec
dd なし 108.8 sec 100.6 sec
-DKV_FASTROUND 102.4 sec 94.64 sec
-DKV_NOHWROUND 84.60 sec 53.76 sec

2022/06/13(月)Ubuntu LinuxでVMware Workstation pro/playerを使うときの注意

割と長いこと(15年くらい?)、windowsにVMwareを入れて(というかVMwareしか入れない)、そこにFreeBSDやLinuxを入れて、その中で生活する、という生活を続けてきました。LinuxなどのPC-UNIXはハードウェアの違いを吸収する力が弱く、windowsをハードウェアの違いを吸収するためだけに使う、という考え方でした。しかし、ここ2年くらい、Linux (Ubuntu) の完成度は十分高くなり、デスクトップなら当然、ノートPCでも、普通にインストールすれば大体普通に動くようになってきました。そこで、ホストとゲストを逆転させて、PCには基本的にUbuntuを入れてそこにLinux版のVMwareを入れ、どうしてもwindowsを使いたいときだけ仮想で飼っているwindowsを使うようになりました。

UbuntuでVMwareを使うときの特別な設定を備忘録も兼ねて書いておきます。誰かの役に立つかもしれないので。

ゲストが異常に重くなる現象への対策

特に複数ゲストを起動したときなどに、ゲストがほとんど操作不能なレベルで重くなってしまい、そのときホストではkcompactd0というプロセスのCPU使用率が100%になっている、という現象が見られることがあります。数分待つと解消しますが、またすぐに再発します。これは多くの人が悩まされ決定的な対策はなかなか見つからなかったのですが、
にあるように最近対策が見つかりました。rootで(sudo suとかした後に)、
echo 0 > /proc/sys/vm/compaction_proactiveness
とすると立ちどころに収まります。永続的にこれを設定するには、/etc/sysctl.confに
vm.compaction_proactiveness=0
と書き加えて再起動すればいいようです。

Ubuntu 22.04でVMware Workstationを使う

現時点でVMware Workstationの最新版は16.2.3-19376536ですが、これはまだUbuntu 22.04の新しいカーネルに対応していないようで、初回起動時のカーネルモジュールのコンパイルでエラーになってしまい、起動することができません。そのうち対応するでしょうけど、とりあえず、
にあるように、
git clone https://github.com/mkubecek/vmware-host-modules
cd vmware-host-modules
make clean
make
sudo make install
sudo modprobe -a vmw_vmci vmmon vmnet
sudo service vmware restart
で起動するようになりました。

NATを使ったとき、断続的にネットワークがON/OFFを繰り返す

ゲストOSのネットワークをNATにしたとき、ゲストOSの種類には関係なく、断続的に(10秒周期くらい?)ゲストのネットワークがON/OFFを繰り返す、という困った現象に遭遇しました。Ubuntu 22.04にVMware Workstationを入れたときに発生したのですが、別のマシンにUbuntu 22.04とVMware Workstationを入れて発生しないケースもあったので、発生する条件はよく分かりません。 (2022/6/15追記: その別のマシンでもこの現象を確認しました。当方の環境では、Ubuntu 22.04にしたことで2/2で発生。) 検索してみると、
このようにかなり以前からこの現象は発生していたようです。いろいろ検索したところ、解決策を見つけました。
によれば、vmware-natdがDHCPのleaseを頻繁に行っており、それ自身はIPが変わらなければ問題ないが、それが仮想マシンのネットワークの頻繁な切断を引き起こしてしまうのが原因らしい。実際、ホストの/var/log/syslogにはゲストのネットワーク切断と同期して
May 21 17:43:44 exa kernel: [14661.785888] userif-3: sent link up event.
May 21 17:43:47 exa kernel: [14664.977941] userif-3: sent link down event.
May 21 17:43:47 exa kernel: [14664.977949] userif-3: sent link up event.
May 21 17:43:52 exa kernel: [14669.758177] userif-3: sent link down event.
May 21 17:43:52 exa kernel: [14669.758186] userif-3: sent link up event.
May 21 17:44:00 exa kernel: [14677.442456] userif-3: sent link down event.
May 21 17:44:00 exa kernel: [14677.442465] userif-3: sent link up event.
May 21 17:44:03 exa kernel: [14680.650489] userif-3: sent link down event.
のようなログが残っていました。そこで、前の節で入れたカーネルモジュールのvmware-host-modules/vmnet-only/userif.cに、強引ですが
*** userif.c.original   2022-05-15 22:05:24.140904301 +0900
--- userif.c    2022-05-21 17:43:37.199281561 +0900
***************
*** 1002,1007 ****
--- 1002,1010 ----
        return -EINVAL;
     }
  
+    /* never send link down events */
+    if (!linkUp) return 0;
+ 
     if (userIf->eventSender == NULL) {
        /* create event sender */
        retval = VNetHub_CreateSender(hubJack, &userIf->eventSender);
のようにlink downイベントを発生しないようにパッチを当ててモジュールを再インストールしたら、問題は解決しました。

おわりに

おそらく、VMwareがバージョンアップしたら不要になる情報かもしれませんが、自分がこれらの情報に行き着くまでに結構苦労したので、こうしてまとめておけば誰かの役に立つかもしれないと思い、こうして情報を残しておきます。

2022/05/13(金)Ubuntu 22.04のBLAS (dgemm) をベンチマーク

以前、Ubuntu 20.04のBLAS (dgemm) をベンチマークという記事を書きましたが、Ubuntu 22.04で同じことをやってみた、という記事です。

BLAS, LAPACKとは何か、個々のBLASの特徴などは、20.04のときの記事を見て下さい。前回と同様、Reference BLAS, ATLAS, OpenBLAS, BLIS, MKLの5つのパッケージをaptでインストールし、dgemmを呼び出して計算時間を計測するプログラムを使って、update-alternativesの機能でlibblas.soを切り替えながらベンチマークを取り、計算時間を比較します。前回と大雑把な傾向はほとんど変わっていないのですが、MKLのパッケージが怪しげな挙動を示した(ような気がした)ので備忘録として書いています。

各BLASのインストール方法

  • Reference BLAS
apt install libblas-dev
  • ATLAS
apt install libatlas-base-dev
  • OpenBLAS
apt install libopenblas-base
apt install libopenblas-dev
  • BLIS
apt install libblis-dev
  • MKL
apt install intel-mkl
最後のMKLですが、aptの実行中に
Use libmkl_rt.so as the default alternative to BLAS/LAPACK? [yes/no]
と聞かれます。これには「no」と答えました。「yes」と答えると、「-lblas」を付けてコンパイルしたものはlibblas.soがリンクされずにMKL(libmkl_rt.so)がリンクされてしまってupdate-alternativesでlibblas.soの実体を切り替える作戦が不可能になってしまいました。何か自分が勘違いしてるのかも知れません。

これらのライブラリは、
update-alternatives --config libblas.so-x86_64-linux-gnu
とすると
There are 5 choices for the alternative libblas.so-x86_64-linux-gnu (providing /usr/lib/x86_64-linux-gnu/libblas.so).

  Selection    Path                                                   Priority   Status
------------------------------------------------------------
  0            /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so   100       auto mode
  1            /usr/lib/x86_64-linux-gnu/atlas/libblas.so              35        manual mode
  2            /usr/lib/x86_64-linux-gnu/blas/libblas.so               10        manual mode
* 3            /usr/lib/x86_64-linux-gnu/blis-openmp/libblas.so        80        manual mode
  4            /usr/lib/x86_64-linux-gnu/libmkl_rt.so                  1         manual mode
  5            /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so   100       manual mode

Press <enter> to keep the current choice[*], or type selection number:
と表示され、libblas.soの実体をsymbolic linkで切り替えることができます。libblas.so.3の方も同様に
update-alternatives --config libblas.so.3-x86_64-linux-gnu
There are 5 choices for the alternative libblas.so.3-x86_64-linux-gnu (providing /usr/lib/x86_64-linux-gnu/libblas.so.3).

  Selection    Path                                                     Priority   Status
------------------------------------------------------------
  0            /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3   100       auto mode
  1            /usr/lib/x86_64-linux-gnu/atlas/libblas.so.3              35        manual mode
  2            /usr/lib/x86_64-linux-gnu/blas/libblas.so.3               10        manual mode
* 3            /usr/lib/x86_64-linux-gnu/blis-openmp/libblas.so.3        80        manual mode
  4            /usr/lib/x86_64-linux-gnu/libmkl_rt.so                    1         manual mode
  5            /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3   100       manual mode

Press <enter> to keep the current choice[*], or type selection number:
と切り替えることができ、前回と同様、両方を同じものに切り替えて実験を行いました。

ベンチマーク

dgemmの実行時間計測に使ったプログラムは、以下のようなものです。前回の20.04のときと同じです。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

// prototype declaration
void dgemm_(char *transA, char *transB, int *m, int *n, int *k, double *alpha, double *A, int *ldA, double *B, int *ldB, double *beta, double *C, int *ldC);

int main(int argc, char **argv)
{
	int i, j;
	int m, n, k;
	int size;
	double *a, *b, *c;
	double alpha, beta;
	int lda, ldb, ldc;
	struct timespec ts1, ts2;

	size = atoi(argv[1]);

	m = size;
	n = size;
	k = size;

	a = (double *)malloc(sizeof(double) * m * k); // m x k matrix
	b = (double *)malloc(sizeof(double) * k * n); // k x n matrix
	c = (double *)malloc(sizeof(double) * m * n); // m x n matrix

	for (i=0; i<m; i++) {
		for (j=0; j<k; j++) {
			a[i + m * j] = rand() / (1.0 + RAND_MAX);
		}
	}

	for (i=0; i<k; i++) {
		for (j=0; j<n; j++) {
			b[i + k * j] = rand() / (1.0 + RAND_MAX);
		}
	}

	for (i=0; i<m; i++) {
		for (j=0; j<n; j++) {
			c[i + m * j] = 0;
		}
	}

	alpha = 1.;
	beta = 0.;
	lda = m; 
	ldb = k; 
	ldc = m; 

	// dgemm_(TransA, TransB, M, N, K, alpha, A, LDA, B, LDB, beta, C, LDC)
	// C = alpha * A * B + beta * C
	// A=M*K, B=K*N, N=M*N
	// Trans: "N"/"T"/"C"
	// LDA = number of row of A

	clock_gettime(CLOCK_REALTIME, &ts1);
	dgemm_("N", "N", &m, &n, &k, &alpha, a, &lda, b, &ldb, &beta, c, &ldc);
	clock_gettime(CLOCK_REALTIME, &ts2);

	printf("%g\n", (ts2.tv_sec - ts1.tv_sec) + (ts2.tv_nsec - ts1.tv_nsec) / 1e9);

	free(a);
	free(b);
	free(c);

	return 0;
}
単なる比較のための、単純な三重forループによる行列積のプログラムは、以下の通り。これも前回と同じ。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

double **alloc_matrix(int n, int m)
{
	double **a;
	int i;

	a = (double **)malloc(sizeof(double *) * n);
	a[0] = (double *)malloc(sizeof(double) * n * m);
	for (i=1; i<n; i++) {
		a[i] = a[0] + i * m;
	}

	return a;
}

void free_matrix(double **a)
{
	free(a[0]);
	free(a);
}

// a: n x m, b: m x s, c: n x s
void m_m_mul(double **a, double **b, double **c, int n, int m, int s)
{
	int i, j, k;
	int i1, j1, k1;

	for (i=0; i<n; i++) {
		for (j=0; j<s; j++) {
			c[i][j] = 0.0;
		}
	}

	for (i=0; i<n; i++) {
		for (j=0; j<s; j++) {
			for (k=0; k<m; k++) {
				c[i][j] += a[i][k] * b[k][j];
			}
		}
	}
}

int main(int argc, char **argv)
{
	int i, j, n;
	double **a;
	double **b;
	double **c;

	struct timespec ts1, ts2;

	n = atoi(argv[1]);

	a = alloc_matrix(n,n);
	b = alloc_matrix(n,n);
	c = alloc_matrix(n,n);

	for (i=0; i<n; i++) {
		for (j=0; j<n; j++) {
			a[i][j] = rand()/(1.0 + RAND_MAX);
			b[i][j] = rand()/(1.0 + RAND_MAX);
		}
	}

	clock_gettime(CLOCK_REALTIME, &ts1);
	m_m_mul(a, b, c, n, n, n);
	clock_gettime(CLOCK_REALTIME, &ts2);

	printf("%g\n", (ts2.tv_sec - ts1.tv_sec) + (ts2.tv_nsec - ts1.tv_nsec) / 1e9);

	free_matrix(a);
	free_matrix(b);
	free_matrix(c);

	return 0;
}
これらは、
cc -O3 dgemm.c -lblas
cc -O3 forloop.c
のようにコンパイルします。ただし、dgemm.cの方のコンパイルをするときに、update-alternativesの選択をMKL以外にする必要がありました。MKLの状態でコンパイルすると、libblas.soがリンクされずにlibmkl_rt.soがリンクされてしまって、update-alternativesによる事後切り替えが不可能なbinaryができてしまいました。これもまた自分の勘違いかも。

さて、ベンチマークの結果は以下のようになりました。使ったCPUはcore i7 1195G7 (ノートPC) で、前回と異なるので絶対値には意味がないかも。
result.png

前回と似たような結果ですね。最速はOpenBLAS, BLIS, MKL。小サイズでMKLが妙に遅いのも同じ。

2022/04/30(土)ubuntu 22.04 インストール (リンク集)

2022/04/30(土)ubuntu 22.04 インストール (10)

その他入れた細々としたもの。
sudo apt install openssh-server
これでsshログイン出来るようになります。
sudo apt install git
sudo apt install curl
このへんはまあ必要か。
sudo apt install unar
これを使うと、日本語ファイル名を含んだzipファイルを展開したときに文字化けしないです。

後は個人的に必要なもの。
sudo apt install lv
sudo apt install checkinstall
sudo apt install ghex
Firefoxだけで過ごしたいところですが、ときどきに必要になるのでchromiumも。
sudo apt install chromium

ホームディレクトリにある「ダウンロード」等を英語表記に

ホームディレクトリに作られる「ダウンロード」などのディレクトリが日本語だと何かと不便なので、英語表記に直します。ターミナルで、
LANG=C xdg-user-dirs-gtk-update
として、「Don't ask me this again」をチェックして「Update Names」をクリックします。これでホームディレクトリが
ダウンロード  デスクトップ  ビデオ    ミュージック
テンプレート  ドキュメント  ピクチャ  公開
から
Desktop    Downloads  Pictures  Templates
Documents  Music      Public    Videos
に変わりました。元に戻すにはLANG=Cなしで単に「xdg-user-dirs-gtk-update」。

ctrl←→caps

ctrlとcapsを入れ替えるのが好きな場合は、
sudo apt install gnome-tweaks
を入れてgnome-tweaksを起動し、キーボードとマウス→追加のレイアウトオプション
→Ctrl Position→CtrlとCaps Lockを入れ替える、とします。

gnome terminalの設定

gnome terminalで「→」などの文字の幅がおかしい場合は、右クリック->設定->互換性 で「曖昧幅の文字」を「全角」にします。

また、22.04になって、gnome terminalが妙に縦に間延びして表示されるようになってしまいました。20.04の表示に近づけようと、右クリック->設定->文字 で「フォントを指定」をチェックし、フォントを「IPAゴシック 13」に設定しました。
OK キャンセル 確認 その他