LXCコンテナの中でDockerを使用するための設定

/var/lib/lxc/[container名]/configに以下の設定を追加し、コンテナを(再)起動する。

なるべく安全な方法

lxc.apparmor.profile = generated
lxc.apparmor.allow_nesting = 1

とにかく権限を与える方法

上記で駄目な場合、以下ならほとんどのケースで起動可能。上記にlxc.cap.drop =を加えて、Dockerを起動できる場合もあり。
lxc.apparmor.profile = unconfined
lxc.cgroup.devices.allow = a
lxc.cap.drop =

Ethernet、UDP、TCPパケットの構造

Ethernetパケット

ヘッダサイズ: 14B (802.1Q VLANタグがある場合18B)、チェックサムサイズ: 4B
サイズ (B)説明
6送信先MAC
6送信元MAC
[4]802.1Qタグ (VLANタグ)
2Ethernet type/size. IPv4:0x0800, IPv6:0x86dd
-ペイロード(IPなど)
4FCS (Frame Check Sequence; CRC)
参考: Wikipedia: イーサーネットフレーム

IPv4

ヘッダサイズ: 20B (拡張情報を除く)
サイズ (B)説明
1バージョン(MSB 4bit)、ヘッダ長(LSB 4bit) 4オクテット単位
1サービス種別
2全長(IPヘッダを含む)
2識別子
2フラグ(MSB 3bit)、フラグメントオフセット(LSB 13bit)
1TTL (Time to Live)
1上位プロトコル. ICMP: 0x01, TCP:0x06, UDP:0x11
2IPヘッダのチェックサム
4送信元アドレス
4送信先アドレス
[2]拡張情報
-データ
参考: Wikipedia: IPv4

UDP

ヘッダサイズ: 8B
サイズ (B)説明
2送信元ポート
2送信先ポート
2データ長
2チェックサム
-ペイロード(IPなど)
参考: Wikipedia: UDP

TCP

ヘッダサイズ: 20B >
サイズ (B)説明
2送信元ポート
2送信先ポート
4シーケンス番号
4確認応答番号
2ヘッダ長(MSB 4bit)[32bit単位]、予約(3bit)、フラグ(9bit)
2Windowサイズ
2チェックサム
2緊急ポインタ
[4-40]オプション
-ペイロード
参考: Wikipedia: TCP

QEMUでLinuxカーネルをGDBでデバッグする

QEMUの起動

以下の2つのオプションを使う
オプション説明
-sTCP 1234番でGDBのリモートコクションをオープンします
-SGDBにアタッチされるまでゲストの実行を待機します。カーネルの起動後にアタッチしても問題ない場合、不要です。

Linuxの起動オプション

QEMUで起動されるLinuxカーネルのコマンドラインオプションにnokaslrを付与する。通常、GRUBなどのブートローダーに指定する。このオプションは、カーネルの関数の配置アドレスのランダム化を抑止する。このオプションを指定しない場合、カーネルのデバッグ情報に記載されているアドレスと、実際のアドレスがことなり、GDBの操作が期待どおりに行われない。

デバッグ情報の入手

ターゲットのカーネルに対応するデバッグ情報ファイルを取得する。

Debianの場合の例

sudo apt install linux-image-5.10.0-22-amd64-dbg
あるいは、APT repositoryから直接取得する。
wget http://ftp.debian.org/debian/pool/main/l/linux/linux-image-5.10.0-22-amd64-dbg_5.10.178-3_amd64.deb
sudo dpkg -i linux-image-5.10.0-22-amd64-dbg_5.10.178-3_amd64.deb

自分でビルドしたカーネルの場合

カーネルのビルドディレクトリにvmlinuxがあるのでそれを使う。ただし、ビルド時、以下の点に留意
  • 以下のCONFIGを有効化
    • CONFIG_DEBUG_INFO_DWARF5、または、CONFIG_DEBUG_INFO_DWARF4
    • CONFIG_GDB_SCRIPTS
    • CONFIG_FRAME_POINTER
  • 以下のCONFIGを無効化
    • CONFIG_DEBUG_INFO_REDUCED
参考: https://docs.kernel.org/dev-tools/gdb-kernel-debugging.html

GDBの起動

デバッグ情報付きのvmlinuxを引数にしてGDBを起動する
gdb /usr/lib/debug/vmlinux-5.10.0-22-amd64
GDB起動後、以下のコマンドを実行する
(gdb) target remote [QEMU起動マシンのアドレス]:1234

グローバル変数の表示例

(gdb) p jiffies
$1 = 4295462764

ブレークポイントの例

do_sys_openにブレークポイントを仕掛けて、ゲストOSでファイルを開く操作をすると以下のようにブレークする
(gdb) b do_sys_open
Breakpoint 2 at 0xffffffff812d6ff0: do_sys_open. (11 locations)
(gdb) c
Continuing.

Breakpoint 2.4, do_sys_open (mode=0, flags=557056, filename=0x7f153b8cabe7 "/etc/ld.so.cache", dfd=-100) at fs/open.c:1201
1201    fs/open.c: No such file or directory.
(gdb) bt
#0  do_sys_open (mode=0, flags=557056, filename=0x7f153b8cabe7 "/etc/ld.so.cache", dfd=-100) at fs/open.c:1201
#1  __do_sys_openat (mode=0, flags=557056, filename=0x7f153b8cabe7 "/etc/ld.so.cache", dfd=-100) at fs/open.c:1218
#2  __se_sys_openat (mode=0, flags=524288, filename=139729170115559, dfd=4294967196) at fs/open.c:1213
#3  __x64_sys_openat (regs=<optimized out>) at fs/open.c:1213
#4  0xffffffff818f7e00 in do_syscall_64 (nr=<optimized out>, regs=0xffffc9000027bf58) at arch/x86/entry/common.c:46
#5  0xffffffff81a000a9 in entry_SYSCALL_64 () at /build/linux-ts3hOX/linux-5.10.178/arch/x86/entry/entry_64.S:125

実行中のプロセスのtask_structの表示例

上記のブレーク例は、lsを実行したときのものである。このときのプロセスが確かにlsであることと、そのプロセスIDを確認する。
(gdb) set $curr = (struct task_struct **)($gs_base + (void *)&current_task)
(gdb) p $curr
$2 = (struct task_struct **) 0xffff88803d01fbc0
(gdb) p $curr->comm
$3 = "ls\000h\000\000\000)\000\000\000\000\000\000\000"
(gdb) p $curr->pid
$4 = 552
上記について補足する。実行中のプロセスのtask_struct構造体へのポインタは、CPUごとの変数領域の中にあり、グローバル変数current_taskの値は、その領域におけるオフセットである。また、CPUごとの変数領域の開始位置はGSセグメントレジスタに格納されている。そのため、両者を加算したアドレス位置に実行中のプロセスに関するtask_struct領域へのポインタが格納されている。

参考

ふるさと納税でおおすすめの返礼品: バンバーグ編

ハンバーグ大好きな私が、ふるさと納税の返礼品でおすすめのハンバーグを紹介します。一概に優劣はつけにくいが、好きなものから順に紹介する。

兵庫県淡路市: 淡路島玉ねぎのBIG生ハンバーグ 200g×10個

玉ねぎ入り。けど玉ねぎが強すぎず、いい意味で肉感が減少して、すこしあっさり目で飽きない。

岩手県一関市:《格之進》金格ハンバーグ120g×6個

やや小ぶりだが、その分、美味しさが凝縮されている。高いレベルでバランスが良い。

佐賀県吉野ヶ里町: 佐賀牛入り 黒毛和牛 ハンバーグ 12個 大容量 1.8kg (150g×12個)

肉感が高く、肉の香り、肉汁が溢れ出している。とにかく肉好きにはおすすめ。

福岡県新宮町: どーんと3㎏!4種ハンバーグセット【150g×20個】

レンジでできるのありがたい。

QEMUでホストのディレクトリをゲストに9pで共有する

ホスト側

QEMUに起動時に次のオプションを付与する。青字のIDは適宜変更可能。紫のタグについても適宜変更。
-fsdev local,path=$(pwd),security_model=mapped-xattr,id=fsdev1 \
-device virtio-9p-pci,fsdev=fsdev1,mount_tag=tag1

参考

パラメータの詳細

QEMU起動の全体のパラメータ

ゲスト側

tag1の部分は、QEMU起動時にホスト側で指定した文字列と同じものを指定します。
mount -t 9p -o trans=virtio tag1 /mnt/dir_tag1 -oversion=9p2000.L

プログラミング言語の実行速度比較(2023/5)

はじめに

先月、プログラミング言語の実行速度比較(2023/4)という記事を投稿した。 思ったより多くの方に見ていただき、有用なコメントやPull Requestをいただいたので、それらを踏まえ以下の更新を行い結果を再投稿する。
  • 明示的な型をもつ言語では、それぞれ32bit、64bit長型の変数を使った場合についてそれぞれ測定
  • C言語については前回の結果で固定長配列とrealloc()を使った場合で大きな違いがなかったのでrealloc()版のみエントリ
  • C/C++では、実用上ほぼ使用されない最適化なしをドロップ
  • Go版では、@kaoriyaさんから、数値の型(int)をint32に変えると性能が向上する旨のコメントを頂いた。Go版もint32とint64で測定した
  • Scala版では、@windymeltさんから、GraalVMを使った場合の性能向上について情報を頂いた。JVM上で動作するプログラムについては、実行環境としてGraalVMを使った場合の結果も追加した
  • PHP版では、sj-iさんからJITを有効にするPull Requestをいただいたのでそれも追加
  • Ruby版を追加
  • 前回、低消費電力が特徴のIntel Core i7-8559Uで測定を行った。これに加えて、比較的能力の高いIntel Core i9-12900Kでも測定を行った
また、当然だがこの投稿で使った素数の算出は様々なワークロードの中のひとつ。実用上、CPUだけぶん回しているタスクはむしろ少数派かも。

速度比較

方法

  • シングルスレッドで、逐次既知の素数で割ることで素数を100,000,000まで求める(ソースはここ)。いわゆる試し割り法
  • その際の実行時間と最大物理メモリ使用量を計測する
  • 素数の数は5,761,455個なので、数値が32bitの場合、それらを格納するには少なくとも約22MiBのメモリが必要(64bitの場合、約44MiB)
  • 言語の比較なので、なるべくユーザモードで動作するコードとして素数の算出を選んだ。カーネルが関係するのはメモリのアロケーション時が中心だが、実行時間の1%もない

評価環境

CPU1 (C1)

CPU2 (C2)

OS

  • Debian 12 (sid)

結果

表の横幅が画面に収まりきらない場合、横スクロールしてご覧ください。
Category 言語 数値型 時間 (sec) 最大使用
物理メモリ
(MiB)
算出素数格納
コンテナ
備考
C1 C2 C1 C2
AOT
Compile
C int 12.6 7.5 23.6 23.6 realloc() gcc 12.2.0 最適化-O3
C long 41.6 12.5 45.5 45.6 realloc() 〃
C++ int 12.7 7.7 36.5 36.5 std::vector 〃
C++ long 41.9 12.5 67.6 68.7 std::vector 〃
Rust i32 14.2 7.6 25.8 24.0 Vec rust 1.63.0
Rust i64 14.1 7.6 46.2 46.0 Vec 〃
Golang int32 19.2 7.7 105.8 92.4 slice C1: Go 1.19.6, C2: Go 1.19.8
Golang int64 48.9 12.7 171.5 202.0 slice 〃
JVM Java int (Integer) 19.5 8.2 230.4 248.0 ArrayList 〃
Java long (Long) 53.0 13.3 269.1 294.1 ArrayList 〃
Java (GraalVM) int 21.8 8.2 247.2 260.1 ArrayList GraalVM CE 22.3.2
Java (GraalVM) long 49.3 13.2 281.2 306.4 ArrayList 〃
Kotlin Int 19.6 8.1 256.1 276.6 List Kotlin 1.8.20
Kotlin Long 51.8 13.1 294.1 323.0 List 〃
Kotlin (GraalVM) Int 17.3 8.1 272.0 294.8 List Kotlin 1.8.20, GraalVM CE 22.3.2
Kotlin (GraalVM) Long 46.6 13.1 310.2 330.9 List 〃
Scala Int 24.9 9.5 1081.8 1449.0 mutable.ArrayBuffer Scala 3.2.2
Scala Long 59.8 14.3 662.7 1430.6 mutable.ArrayBuffer 〃
Scala (GraalVM) Int 19.3 8.2 245.0 321.8 mutable.ArrayBuffer Scala 3.2.2, GraalVM CE 22.3.2
Scala (GraalVM) Long 50.8 13.4 609.8 706.0 mutable.ArrayBuffer 〃
Script JavaScript (Node.js) Number 17.3 7.8 196.1 203.2 Array Node.js 18.13.0
PHP integer 108.7 43.3 149.1 149.2 array PHP 8.2.2
PHP (JIT) integer 71.9 13.4 152.4 152.5 array 〃
Python3 int 289.4 160.0 231.5 232.8 list Python 3.11.2
Ruby Integer 380.0 160.8 57.6 57.7 Array Ruby 3.1.2

グラフ

薄い青: AOT Compile (32bit)  濃い青: AOT Compile (64bit)  薄い赤紫: JVM (32bit)  濃い赤紫: JVM (64bit)  薄い紫: JVM/GraalVM (32bit)  濃い紫: JVM/GraalVM (64bit)  橙色: Script

CPU1 (Core i7-8559U)での実行時間

CPU2 (Core i9-12900K)での実行時間

コメント・感想

全般的な実行時間の傾向

  • AOT (Ahead-Of-Time)コンパイル型の言語は、おおよそ同じオーダーの実行性能で速い
  • 次いでJVM上で実行される言語が続く。多少の差はあるが、これらの実行時間もだいたい同じ
  • GraalVM上での実行では、OpenJDKより若干よいケースもある
  • Script系の言語は、Node.jsが群を抜いて速い
  • PHPのJITも一定の効果はある(約1.5〜3倍)

32bit長と64bit長の整数型について

  • 概して64bit長の数値型を使った場合、32bit長の数値型を使った場合の1.5〜4倍程度、実行時間を要した
  • ただし、Rustでは、i32とi64を使った場合でほぼ同じ。最大メモリ使用量は期待に近いが、実行時間が32bitとほぼ同じなのはなぜ?(コードの誤り?)
  • Core i9-12900Kのほうが32bit長と64bit長整数の乖離が小さい傾向にある
  • メモリ使用量は、32bit長と64bit長整数で大きな差はない。JVM系に関しては64bit長のほうがやや使用量が多いように思える。これは実行環境の搭載メモリ量が多いで単に多くヒープを使用しているだけかもしれない

Template/Generics

  • C++, Rust, Goでは、32bit長と64bit長版をなるべく共通のコードとするためにTemplate/Genericsを用いた。同じ条件なら前回の結果と大きく変わらなかったので、Template/Genericsによる性能のオーバーヘッドもほぼないと考えられる
  • Java, Kotlinに関しては、そもそもGenericsで実現する方法が分からなかった。ベースクラスで基本的な計算をして、型に固有の処理をサブクラスでオーバーライドするような設計も考えたが、他の言語と実装が乖離しそうなのでそのアプローチも諦めた。単純に同じコードで数値型の異なるクラスを2つ用意した。
  • Scalaに関しては、Integral traitで実現しようとしたが、かなり(3〜4倍)実行時間が増加しそうだったので、Genericsの使用を諦めた