Linuxの最近のブログ記事

Linux memo 2020/11/15 (NEON)

NEONなんもわからん。

● ARM NEON 超入門
ARM Compiler toolchain Assembler Reference
https://developer.arm.com/documentation/dui0489/g/neon-and-vfp-programming/
ARM NEON Intrinsics - Using the GNU Compiler Collection (GCC)
https://gcc.gnu.org/onlinedocs/gcc-4.9.4/gcc/ARM-NEON-Intrinsics.html
SIMD Assembly Tutorial: ARM NEON (pdf注意)
http://download.xskernel.org/docs/processors/cortex-a53/neon_tutorial.pdf
ARM NEONの使い方 予告編 - おぺんcv
https://atkg.hatenablog.com/entry/2016/09/25/170031

● 超初心者のチート表
n: mov結果を半型にする
h: 計算後に2で割る
d: 計算後に2をかける
q: 桁あふれ時にオーバフローさせず上限張り付き
r: シフト結果を丸める
l: 計算結果の型を倍型にする
hn: 計算結果から上位半分取り出して半型にする
w: 計算元の片側が半型
q: 倍幅で計算

● 初心者の感想
- レジスタへのload, storeがめんどい。NEONフレンドリーなデータ構造・配列にしておかないと効率よくない
- 計算順は大事。積和(vmla)にしないと命令数増えて効率悪い
- 計算幅大事。64bitだとx2なので並列度が上がらない。オーバーフローをうまく処理して32bitのx4や16bitのx8にしないといけない
- パイプラインよくわからん。依存低い並びにしないと処理速度上がらないらしいが、その域はまだよくわかってない

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/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/02/04

● SIGKILLのハンドル
SIGKILLはユーザランドでシグナルハンドリングできずそのままプロセスが終了させられる。が、しょせんはシグナルの扱いなので、kernel内では他のシグナルと同様の扱いをされる。つまり、寝ていたタスクは起こされ、kernel空間の外へ追い出す方向に処理が進み、システムコールの呼び元の直前までいって、そこでタスク終了処理が行われる。

ただ、SIGKILLは、スレッドが終了するだけでなくプロセスが終了するので、SIGKILLをハンドルしたタスク以外の同じプロセスに属する他のタスクも終了する。それがどこで行われているかというと、kernel/kernel/signal.cのcomplete_signal()の後半、sig_fatal()のときにwhile_each_thread()で&t->pending.signalにSIGKILLを立てている。つまり、最初にシグナルを受けたスレッドと比較して起こされるまでちょっとだけ遅延する。

● ext4のinodeのブロックマッピング
filefrag(8)コマンドを使えば、inodeの中身の論理位置とblockデバイスの位置とのマッピングを表示できる。
filegragはioctl(FS_IOC_FIEMAP)で情報を取得している。
ext4のextentでできるだけ物理連続にfilemapを作ろうと思った場合、ioctl(FALLOC_FL_KEEP_SIZE)もしくはposix_fallocate(3)でpreallocするという方法がある。
参考:C言語で、作成したファイルが断片化しないようにする方法。(Linux編) - Qiita
https://qiita.com/Sickly_Life/items/d1c73ca2b497910576fc

● ext4のquotaの設定
ext4でquotaを使うかどうかは、superblockのFilesystem featuresにquotaが立っているかどうかで決まる。
quotaの情報は、Filesystemの中の隠しinodeに記載されている。inode番号は、EXT4_USR_QUOTA_INO(==3), EXT4_GRP_QUOTA_INO(==4)のもの...じゃなくて、superblockのs_usr_quota_inum, s_grp_quota_inum, s_prj_quota_inumに記載された番号になる。通常は、mkfs.ext4やtune2fsがFilesystemを作るときに、EXT4_USR_QUOTA_INO, EXT4_GRP_QUOTA_INOを指定しているはず。(Todo: s_prj_quota_inumの初期値)
quotaを使うためにはCONFIG_QUOTAを有効にする必要がある。ext4はkernel/fs/quota/以下にある共通コードを使ってQUOTA機能を実現する。inodeの中身を直接渡して、中身には踏み込まずに、QUOTQ機能を実装しているようにみえる(ToDo: inodeの中身)
参考:ext4のDisk Quotaあれこれ - Qiita
https://qiita.com/takeoverjp/items/0f4966bbead0b5e3bf4f
ちなみに、quotaに限らず、inodeの中身をダンプしたい場合はdebugfs(8)コマンドのdumpが使える。

Linux memo 2019/11/09

● WindowsでアプリにCPU制限させる
== やりたいこと
とあるWindows上の特殊アプリは実行すると1スレッドでぶん回って処理をする。イベントドリブンじゃなくてポーリングしてそう。不必要にCPUクロックが上がり発熱も増えファンがぶん回りバッテリがすぐ減る。困る。

== CPU binding
タスクマネジャー(Ctrl+Shift+Esc) -> 詳細 -> プロセスを選んで右クリック -> 関係の設定
2スレッド以上でぶんまわってるときは1つのCPUに閉じ込めて低減する方法が使える。が、1つのCPUは引き続きぶん回らせてしまう。
Linuxだと、taskset(1)とかsched_setaffinity(2)とか。

== 周波数の上限
電源オプション(Win+X, O) -> 電源の追加設定 -> プラン設定の変更 -> 詳細な電源設定の変更 -> プロセッサの電源管理 -> 最大のプロセッサの状態 -> %で指定
周波数の上限を設定できる。そこそこのクロックに止めれば発熱が劇的に抑えられる。が、ぶん回ってるアプリ以外の人も処理が遅くなる。
Linuxだと、/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors でgovernorを指定し、/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freqあたり周波数を指定。ただ最近のCPUはクロックも電源管理もアグレッシブに行うので、今どきは下手に下限を固定にするのは危険かもしれない。

== 優先度
タスクマネジャー(Ctrl+Shift+Esc) -> 詳細 -> プロセスを選んで右クリック -> 優先度の設定
ぶん回るアプリと本当にCPUを使わせたいアプリとで取り合いになるのを防げる。が、アプリがぶん回ることに違いはない。
Linuxだと、renice(1)とかchrt(1)とか。

結局、LinuxのcgroupsでCPU使用率**%に制限したグループにぶん回るアプリをつっこむ、みたいなことがやりたかったわけだけど、Windows標準機能ではそういうのはなさそう。その用途だとBattle Encoder Shiraseがあるようだが、どうやって実装してんだろ。定期的に対象プロセスにptraceしてむりやりsleepさせてる感じ?

● Android System Programming

Androidのミドルから下位の層をポーティングするような人向けの本として非常におすすめで、アフィで紹介すればナウでヤングにバカウケでガッポガッポ、と知り合いから聞いたので貼っとく。私はまだ買ってないけど。

● タイトル詐欺じゃね?しかも金儲けとか
いや一応Linuxのことも書いたし...

Linux memo 2019/11/07

● ARMの割り算
浮動小数点は遅かったり演算器がのってなかったりするので注意しましょう...と思っていた時期が私にもありました。
ARM Cortex-Aシリーズには、整数の割り算を行う命令がある(SDIV UDIV)が、これは最近までoptionalで、Virtualizationありのコアから必須となっている。みんな大好きCortex-A9は、たいていの場合は未対応。詳細はArm Compiler armasm User Guideあたりへ。
このため、gccで-mcpu=cortex-a9とか指定すると、gccはlibgccの中の関数(__aeabi_idiv() __aeabi_idivmod() __aeabi_uidiv() __aeabi_uidivmod())へフォールダウンするコードを吐く。...実行が遅い某プログラムのプロファイルを取って上記の名前の関数が出てきて、で調べてみて初めて知った。マジかよこいつNeonも乗ってるのに...なので、浮動小数点のほうが整数割り算より早かったりするのかもしれない。測ってないからしらんけど。
KMC Staff Blog:ARM Cortex-A15の整数除算命令
http://blog.kmckk.com/archives/4170081.html
ちなみに、Cortex-A7は対応してそう。A9からA7に乗り換えてるSoCが多いのは、プロセスノードへの対応もそうだけど、こういうとこも響いてんのかな。

● std::list<>やstd::set<>は使い物にならない?
アルゴリズム的にはstd::listやstd::setをつい使いたくなってしまうが、万とかのオーダにならない限りそこまでの差は出ない。むしろちまちました操作によるオーバヘッドのほうがでかいことも多い。
[C++] STLの型の使い分け - Qiita
https://qiita.com/h_hiro_/items/a83a8fd2391d4a3f0e1c
コンテナ内の検索の速度について - 空想犬猫記
http://xoinu.hatenablog.com/entry/2014/08/14/140105
つまり、たいていのものはstd::vector<>やstd::map<>で事足りる。
また、万とかのオーダになる場合は、どこまで最適化されたコードになるかはコンパイラやライブラリに依存することになり、古いツールチェーンだったり組み込みだったりするとロクに期待できないので、結局必要最小限に独自実装してしまいかねない。
ちなみに、入れ替えやソートをたくさん行う場合、コンテナの中身を実体で保持するとアロケートやコピーのオーバヘッドが大きくなるけど、どうするのがベストプラクティスなんだろ。個人的には、malloc,free(new,delete)の管理手間が増えるのを覚悟の上で、ポインタを保持する実装に置き換えてしまいがち。生ポにするくらいならshared_ptr<>のほうがいいんだろうけど。もちろん理想はフルにstd::moveが効くという前提で何も考えずに実体で保持するやり方のままということなんだろうけど。

● コンパイラの気持ちを考えた最適化
- グローバル変数はできるだけ使わない、使う場合もできるだけstaticつけてスコープを狭める。
- ポインタはできるだけ使わない、レファレンスなどで逃げるようにする、どうしても使わざるを得ない場合でもローカル変数に閉じてかつポインタのポインタなどを避ける。
- ローカル変数はケチらない。コンパイラのほうがうまくケチってくれる。むしろローカル変数を多用したほうがうまくコンパイラがケチってくれる。
- アラインメントとコピーサイズに注意する。char単位でちまちま処理するとたいていは遅い。memcpyの実装のアセンブリのがんばり具合を確認し、できるだけそれらに乗っかることを考えよう。
- CPUの気持ちを考えた最適化まで突っ込みたいものの、ぼく人見知りなので、CPUの個性に応じた最適化とかムリ。
- 最後に、-O2つけ忘れがないかを確認しよう。-Ogついてるだけでもかなり違う。

このアーカイブについて

このページには、過去に書かれたブログ記事のうちLinuxカテゴリに属しているものが含まれています。

次のカテゴリはPCハードウェアです。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

月別 アーカイブ

ウェブページ

Powered by Movable Type 5.2.13