Linux memo 2020/10/17

● CMAメモリ領域
CMA(contiguous memory allocator)は、DMAのように使えるメモリ領域を提供するが、そのメモリ領域を普段は通常の用途にも使えるように適合させたLinuxの汎用の仕組み。「MOVABLE」なメモリ割り当て要求のときに限りCMAメモリ領域を渡すようにしておくことで、いざ本当にCMA用途のメモリ割り当て要求が来たときでも、先に渡したメモリ割り当てをmigrateさせて「どかせる」ことで、CMA用途のメモリ割り当て要求にも応えることができるようにしている。
A reworked contiguous memory allocator [LWN.net]
https://lwn.net/Articles/447405/
A deep dive into CMA [LWN.net]
https://lwn.net/Articles/486301/
しかし、実際に使ってみると、そんな理想通りにはなかなかいかない。

● CMAの使いづらさ
Linux の CMA と THP その 1 - コグノスケ
http://www.katsuster.net/index.php?arg_act=cmd_show_diary&arg_date=20170929
より、まさにここで言及されているようなことが起こる。
- 1) THP に CMA 占領されちゃう問題
- 2) ユーザプロセスが CMA 全然使わない問題
それ以外にも、
- 3) cma開放時にpcpリストへ繋がれるためcma以外が空いててもCMAばかり使われ続けてしまう。
- 4) 大量のwriteでdirtyなページキャッシュがたくさんあるケースにて、いざCMAがほしいときにmigrateさせようとするとpage outでディスク書き込みが発生し長時間待たされてしまう
など。最近のLinuxでは改善が入っていたりしていて、1)にはCMA allocでTHPをmigrateさせる変更が、2)にはCMAが使われやすいくする変更が、3)にはpcp入りをやめる提案がされていて(これは結局採用されてない)、などがあるものの、どうも対応にアドホック感がある。ALLOC_CMAをなくす取り組みがrevertされてたりと、正直あるべき姿すらブレていて迷走している。
kswapd0とOOMの発動条件にも悪影響を与えているようで、正直CMAなんてやめて、昔からよくある専用メモリ領域を作って管理したほうが面倒事が少なくて済むように思えてならない。実は誰もCMAをマジメには使っていない?スマホがAndroiでION_HEAPとしてバリバリ使ってるって感じでもないのか?

● OOMの発生しづらさと発生時の予測不能なスラッシングやデッドロック
ケースごとに見ていけばいろいろとあるんだろうけど、下記でXFSにて起こる1例が提示されてる。
The OOM CTF
http://i-love.sakura.ne.jp/The_OOM_CTF.html
FilesystemやディスクI/Oが絡むと「成功してもらわないと困る」メモリアロケーションも多く、そことOOMに選ばれたプロセスへのSIGKILLが重なると、ライブロックや3者間ロックが容易に起こる。以前私がQiitaに書いたこの記事もそんな例の一つになる。
Linux+squashfs+swapなし環境でOOM時にハングする問題 - Qiita
https://qiita.com/rarul/items/843e05a7bc18278e3188
ちなみに、もとのCTF記事中にある「order が 3 以下のメモリ割り当て要求は成功するまで永遠にリトライする」は、PAGE_ALLOC_COSTLY_ORDERのことの模様。上記から言及されてるLWN.netの記事より、
The "too small to fail" memory-allocation rule [LWN.net]
https://lwn.net/Articles/627419/
LinuxのOOMやメモリ管理も、2.6.xやらのころと別物のように変わっているので、OOM発動条件すらが相当理解しにくい。スワップも複雑に絡む。下記の記事も参考に。
スワップの弁護:よくある誤解を解く
https://chrisdown.name/ja/2018/01/02/in-defence-of-swap.html

● ディスクによもsyncが必要な理由
ddコマンドではconv=fsyncなオプションが使えるが、of=がディスクの場合にもこれが必要なことがある。
最近のディスクはハードウェア的なwriteback機能を持っていて、それを積極的に利用するためdisk queueにも非同期で要求を突っ込めるようになっている。
CONFIG_BLK_WBT, QUEUE_FLAG_FUA, QUEUE_FLAG_WC, blk-wbt.c, あたりがキーワードか。

● zlib-ngなど
zlibとのバイナリコンパチと性能改善をうたうzlib-ngというライブラリがある。
https://github.com/zlib-ng/zlib-ng
プロジェクト自体は長く続いているので、適当に採用してもそこそこ使えるだろうと思って試していたら、なんてことはないアプリがクラッシュしやがる。仕方なくいろいろ調べると、arm64のchunkmemset_3()がバグっていることに気づく。報告でもしようかと詳細確認していると、ちょうど直前にchunkmemset_3()とchunkmemset_6()がバグってると削除されてた。プロジェクトがstableバージョンという概念を持ってないようだったので、結局採用するのはやめておいた。
ただまぁ、例えば画像でも、惰性でpngやjpegを使ったりせず、積極的に新しいものを試していかないといけないと思った。opting, zopflipng, brotli, webp, など。webpのlossyで十分だという理由からなのか知らないけど、JPEG 2000は今もほとんど聞かない。
libpng/libzのAPI互換を崩していい(フォーマット互換は維持)なら、minizとかlibspngとかもあるらしい。
https://libspng.org/
これまで何度も宣伝してきたけど、良記事なので、また宣伝しておく。
2016年のOSS圧縮ツール選択カタログ - Qiita
https://qiita.com/nishemon/items/818cc64dc2f8577edd87

Linux memo 2020/07/26

● ぼくのかんがえたさいきょうのmemcpy()
※ただしC言語に限る
https://github.com/rarul/algorithm_bench/blob/master/memcpy/common/memcpy.c
- 実用上は32bitか64bitの2か4のループアンローリングくらいで十分っぽい?
- gccの-O3だとヘタに自分で展開するより早かったりする、勝手にループアンローリングやってる?
- __int128のgcc拡張が使えるという知見を得た(gcc-4.4.7は使えなかった)
- alignment合ってなくてもCPUでなんとかしちゃうx86ずるい
- x86_64は、alignment乗ってると早いし、乗ってなくてもちゃんと動くし、alignmentチェックする価値がなさそう
- __int128は、x86_64でもalignmentエラーで落ちた
- 結局glibcのmemcpy()が一番早い、次点でgcc -O3
- asm使った最適化は猛者の総ツッコミが来そうなので語らないことにする

● その他
ネタはあったはずなのに最近やる気が出なくて作業が進まない...

Linux memo 2020/07/01

● ~(Tilde, チルダ)って何?
たぶんちゃんとしたUNIX規格とかあるんだろうけど、現状のLinuxとしては、
- 「~」(※\0含む)や「~/」はホームディレクトリを表す
- 「~strings/」は、/があるとこまでをユーザ名とみなして、そのユーザのホームディレクトリを表す
となる(bashのtilde.cあたり)
bashのいうホームディレクトリとは、
- 環境変数$HOMEのこと
- $HOMEが空のときは、getpwuid()とかで取れるやつ(==つまり/etc/passwdに書いてあるもの)
- bashはログインシェルとして振る舞うとき、起動時にgetpwuid()で取得したやつを$HOMEに設定する
となる。つまりすべてシェルのお仕事。
このため、自作プログラムとかにおもむろに「~rarul/memo.txt」とか書いても何もしてくれない。
あとこんなことができる
[rarul@tina bash-4.4.18]$ echo ~
/home/rarul
[rarul@tina bash-4.4.18]$ export HOME=hogehoge
[rarul@tina bash-4.4.18]$ echo ~
hogehoge

● ヌル島 (Null Island)
ヌル島 - Wikipedia
緯度0経度0はアフリカギニア湾の沖合いになるが、実装の都合上そこに何かがあったほうがいいということで設定された島。
ヌルオブジェクトパターンのようなイメージなのかな。
現在位置がここになっている技術者は世界中にたくさんいると思われる。

Linux memo 2020/04/14

● LANケーブル(UTP)
- Cat5 100Mbps (距離規定なし?) 100MHz 100Base-TXまで
- Cat5e 1Gbps 100m 100MHz 1000Base-Tまで
- Cat6 1Gbps 100m 250MHz 1000Base-TXまで
- Cat6A 10Gbps 100m 500MHz 10GBase-Tまで
1000Base-TXはほとんどど使われていないため、規格的にはCat5eかCat6Aでいい。
まぁ、電気信号的にはちゃんとしたケーブルを使うに越したことはないけど。
Cat7やCat7Aは、UTPじゃなくてSTPだったり、RJ-45じゃなくてGG-45だったりと、理解せずに手を出すのはやめておいたほうがよい。

● faketime
時刻をごまかしてプログラムを実行するfaketime(1)というプログラムがあるが、これは結局LD_PRELOADでlibc関数をラップすることで実現している。ラップしているのは下記、
- stat, fstat, fstatat, lstat
- stat64, fstat64, fstatat64, lstat64
- time, ftime, gettimeofday, clock_gettime
- pthread_cond_timedwait, pthread_cond_init, pthread_cond_destroy
- timer_settime, timer_gettime
- nanosleep, usleep, sleep, alarm
- poll, ppoll, epoll_wait, epoll_pwait, select, pselect
- sem_timedwait, utimes, utime
意外と多かった。

● 今どきのメモリ負荷テストツール
memtest86, memtest86+で事足りたのはいつのころだったか、今はCPUだけじゃなくてメモリまでも電圧・クロックが変動するため、単純なboot onlyテストでは役に立たない。結局今どきのOSを動かして、負荷に応じた電圧・クロックの変動を与え、正しく動いているかのチェックをさせる、というまっとうな方法を取らざるを得ない。そういう手法なので、同時に、発熱や電力供給も確認する必要が出る。だから、Prime95やOCCTを長時間動かすというやり方になっちゃうのか。
Linuxだとどういうのがあるのだろうか。ググった感じだとrowhammer-testmemtester(8)が見つかったけど、何が定番なのかよくわからない。

● git gcでメモリ不足
CPU数が多いマシンで巨大.gitをgit gc --aggressiveするとメモリ不足になる。gitがCPUコア数を識別してパラで走らせてしまうのが主な原因。なので.gitconfigにこんな感じのを書いておく。
[pack]
threads = 4
他にもメモリサイズやファイルサイズを制限するやり方があるようだけど、まぁこれでいいや。
ちなみに、CPUコア数が増えると使用するRAMも比例して増える点を見落としている人が時々いるので要注意。

● oomネタ
このへんのネタを調べてメモっておこうと思っていたけど、思い始めてはや*週間、なかなか進まないのでToDoとしてメモしておく。読者らの宿題にする(マテ
lowmemkiller
/proc/[PID]/status
/proc/meminfo
zram

Linux memo 2020/04/07 ext4編

● discard(block)
mqが入ってきたあたりから設計の変更がよくわからん、、
ioctlからはBLKDISCARD BLKSECDISCARDができる。
secure(BLKDEV_DISCARD_SECURE)はioctlからしか来ない。
これらioctlを叩くためのコマンドとしてblkdiscard(util-linux)がある、BLKZEROOUTもできるらしい。
fstrimコマンド(util-linux)は、ioctlでFITRIMをFilesystemに送る。
ext4に限らずFilesystemは、このioctlに対し、すべての未使用領域へblk discardする。

● discard(Filesystem)
ext4: デフォルトオプションでdiscardが指定されている場合、もしくはmount時にdiscardを指定すると、ファイルを消したときに__blkdev_issue_discard()などからREQ_OP_DISCARDなどを発行する。
fat: discardのmountオプションを指定すると、ファイルを消したときにsb_issue_discard()からREQ_OP_DISCARDなどを発行する
f2fs: discardオプションはデフォルトで有効っぽい?foreground(同期ガベコレ)とbackground(issue_discard_thread())とでやってるっぽい。
ただ、Filesystemで都度DISCARDするやり方は最近は、パフォーマンス面であまり選ばれない。よほど大きいサイズ限定でやるか、fstrimのようなメンテ時だけの処理にするか、な感じかと思う。
f2fsだけは、Filesystemの構造が違う点からも、実際はどう使われてんのかよくわからない。

● 書き込み回数サマリ
/proc/sys/vm/block_dumpを見れば、submit_bio()したcomm, pid, W/R, bi_sector, devname, countがわかる。
blktraceで書き込みログを取る方法もある。
あとはこんな記事。
https://qiita.com/takeoverjp/items/7d5d74858220d1dff46d
eMMCの場合は、泥臭くても、ops->request()の直前(__mmc_start_request())にpr_infoでも入れるのが簡単だと思う

● ext4のcrtime対応
ext4にはinodeにi_crtimeを含むが、これを取り出す方法が長らくdebugfsコマンドくらいしかなかった。Linux-4.11からstatxシステムコールが追加されて、これを取り出せるようになった。
kernel/fs/stat.cのcp_statx()
kernel/fs/ext4/inode.cのext4_getattr()

● statfsの空き容量の話
kernel/fs/ext4/super.cのext4_statfs()
ext4_r_blocks_count()と、clusterのs_resv_clusters(オンメモリ)が関連する。
前者は、superblockに書かれたs_r_blocks_countで、rootしか使えない予約領域を表す。
後者は、ext4_set_resv_clusters()で設定される値で、extentが有効な場合にcluster部分に2%(か4096ブロック)の予約を入れるようだ。
ちなみに、関連する似たようなシステムコールは思いの外たくさんあることをはじめて知った。
statfs, fstatfs, statfs64, fstatfs64, statvfs, ustat

● mke2fs.confのルール
Qiitaにまとめたのでこちらを参照。
ext4フォーマットするときはmke2fs.confに注意しようという話
https://qiita.com/rarul/items/0f8e426d6e2d3ff643dd

Linux memo 2020/04/05 eMMC編

● 雑多情報メモ
http://trac.gateworks.com/wiki/MMC
https://www.slideshare.net/VijayGESYS/emmc-embedded-multimedia-card-overview
https://www.micron.com/-/media/client/global/documents/products/technical-note/emmc/tn5205_emmc_linux_enablement.pdf(PDF注意)

● Linuxのmmcドライバのコードを読むときの注意点
kernelバージョンによりちょっとずつ動きが変更されていたり、
ベンダー固有のホストコントローラドライバで変なことをやっていたり、
Vanilla LinuxとAndroid Linuxとでも微妙にコードが違っていたり、
ので、特に細かいCMDの処理について、ネット上の情報を鵜呑みにせず、実際に動かして確認しないと怖い。
素直に、CMDをprintkするやり方が無難かと思う。blockのread,writeはスキップしとかないと大変なことになる。

● mmc-utils
https://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc-utils.git
./mmc extcsd read /dev/mmcblk0
とかでEXT_CSDを出せる。
/sys/block/mmcblk0/
/sys/class/mmc_host/mmc0/mmc0:0001
あたりにもext_csd(他いろいろ)が生えているが、これは、初期化時にSEND_EXT_CSDしたときの値になっている。
./mmc extcsdは、コマンド叩いたときにSEND_EXT_CSDを送って取得しているので、長時間動かしている場合は値の違いに注意。
ちなみに、resume時はeMMCの電源入れ直してmmc_init()からやり直すので、raw_ext_csdが更新されることになる、スマホの場合注意。

● ブロックサイズ
EXT_CSD_HC_ERASE_GRP_SIZE 224 RO
EXT_CSD_ERASE_GROUP_DEF 175 R,W
hc_erase_size(==HC_ERASE_GRP_SIZE)がいわゆるブロックサイズっぽいけど、ガベコレが高度化した現代のmanagedフラッシュだと、secure eraseとか以外ではあんまり意味をなさない値じゃないかなと思う。
ERASE_GROUP_DEFに1を書く必要があるけど、まぁ現在はこれをせずにeMMCを使うことはほぼありえないと思う。

● eMMCのJEDEC規格バージョン
EXT_CSD_REV 192 RO
ただ、JEDEC書を読まんとわからんレベルの値のテーブルになってる。

● HPI(High Priority Interrupt)
EXT_CSD_HPI_MGMT 161 R,W
EXT_CSD_HPI_FEATURES 503 RO
HPI_FEATURESのビット0が立っている場合、HPI_MGMTに1を立てて有効にする。
実際にHPI機能を使って止めたいときはCMDを送る。
ビット1が立っている場合は、STOP_TRANSMISSTIONを、そうでない場合はSEND_STATUSを送って止める。
Sanitizeなどのキャンセルに使える。

● Background Operation
EXT_CSD_BKOPS_EN 163 R,W
EXT_CSD_BKOPS_START 164 W
EXT_CSD_OUT_OF_INTERRUPT_TIME 198 RO
EXT_CSD_BKOPS_STATUS 246 RO
EXT_CSD_BKOPS_SUPPORT 502 RO

EXT_CSD_BKOPS_LEVEL_2 0x2
EXT_CSD_MANUAL_BKOPS_MASK 0x01
EXT_CSD_AUTO_BKOPS_MASK 0x02
EXT_CSD_BKOPS_MANUAL_EN BIT(0)
EXT_CSD_BKOPS_AUTO_EN BIT(1)
MMC_BKOPS_TIMEOUT_MS (120 * 1000) /* 120s */

BKOPS_ENにBKOPS_MANUAL_ENを書くことで、manual background operationが使えるようになる(write once)。
BKOPS_STATUSを見て、BKOPS_LEVEL_2以上だったら、BKOPS_STARTにBKOPS_MANUAL_ENを書いてbackground operationを行う。

BKOPS_ENにBKOPS_AUTO_ENを書くことで、auto background operationが有効になる(write once)
あとは放っておくだけで良い。
msm-kernelではautoのほうを使うようになっていて、Vanillaとはコードが異なっている?

● Power Off Notification
EXT_CSD_POWER_OFF_NOTIFICATION 34 R,W
起動時にPOWER_OFF_NOTIFICATIONに1を書くことで機能が使えるようになる。
Linuxでは、suspend時にSHORT, shutdown時にLONGの値を書くという使い方をしているようだ。

● Cache
EXT_CSD_FLUSH_CACHE 32 W
EXT_CSD_CACHE_CTRL 33 R,W
EXT_CSD_CACHE_SIZE 249 RO
CACHE_SIZE(からの4byte)がサイズを表し、0より大きいと、CACHE機能を持っている。
CACHE_CTRLに1を書くと有効になる。
FLUSH_CACHEに1を書くと、FLUSHする。
CMDQの場合はまた異なるようだけど、詳細まだわからず。

● CMDQ
EXT_CSD_CMDQ_MODE_EN 15 R,W
EXT_CSD_CMDQ_SUPPORT 308 RO
EXT_CSD_CMDQ_SUPPORTED BIT(0)
CMDQ_SUPPORTにCMDQ_SUPPORTEDが立っていると、機能を持っている。
hostが対応している(MMC_CAP2_CQE_DCMD)ならば、CMDQ_MODE_ENに1を書いて、cmdqを有効化する。
Linux-4.16でCQE対応が入った。
block-mqにつながるので、block-mq側の対応がbuggyだったりしないかは注意点となるか。
block-mqについても、改めてもっと突っ込んで調査しておく必要がある気がしてる。

● DISCARD(eMMC)
MMC_ERASE_ARG 0x00000000
MMC_SECURE_ERASE_ARG 0x80000000
MMC_TRIM_ARG 0x00000001
MMC_DISCARD_ARG 0x00000003
MMC_SECURE_TRIM1_ARG 0x80000001
MMC_SECURE_TRIM2_ARG 0x80008000
MMC_SECURE_ARGS 0x80000000
MMC_TRIM_ARGS 0x00008001
startセクタを指定してMMC_ERASE_GROUP_STARTを送り、endセクタを指定してMMC_ERASE_GROUP_ENDを送り、eraseの種別をargに指定してMMC_ERASEを送る。
DISCARD, TRIM, ERASEの順で使えるかどうかを判断して使おうとする。
drivers/mmc/core/block.c mmc_blk_mq_issue_rq()あたりを読むべし。
新しめのLinuxではREQ_BARRIERはなくなった?

ソフトウェアの権利は著作権で保護されている。ので、団体の著作権は著作権法第53条にのっとり公表後70年なので、70年たったソフトはコピーし放題となる。現時点では70年前のソフトなんて実質価値がなく、ここ20年くらいは同じような状況が続くだろうけど、30年くらいたつとこの問題が顕著になってくると思う。

音楽とかマンガとかは、個人の著作あつかいので死後70年となり、デジタルな無劣化コピーが騒がれるのはソフトウェアよりは先になりそう。

映画は影響がでかそう。ただ、ミッキーマウス法の前例があるので、70年からまだまだ伸ばされていくのかもしれない。

とかいう目で見たら、MicrosoftがわざわざMS-DOSをオープンソースにしたのは、「著作権切れしたものはパブリックドメインになる」の意向を汲み取って、役割の終えたものは自ら開放していくべきだという考えからなのかもしれない。
オープンソース化されたMS-DOSのソースコードがGitHubで公開される
https://gigazine.net/news/20181001-source-code-ms-dos-github/

最近のコメント

アイテム

月別 アーカイブ

ウェブページ

Powered by Movable Type 5.2.13