コグノスケ


link 未来から過去へ表示(*)  link 過去から未来へ表示

link もっと前
2017年9月29日 >>> 2017年9月29日
link もっと後

2017年9月29日

LinuxのCMAとTHPその1

目次: Android

Twitterでボヤきまくっていたけど、流れて消えちゃうのでメモ。Linuxのメモリ管理がさっぱりわかりません。CMA(Contiguous Memory Allocator)とTHP(Transparent Huge Pages)の動きが謎過ぎます。

CMAとは、ある領域を特別な領域として定めて、普段はユーザプロセス用のメモリとして使い、ドライバが要求するなどここぞというときにユーザプロセス用のメモリを強制立ち退き(Page Migration)させてDMA用のメモリとして使う技術です。

私が思いつく利点としては、

  • reserved領域などDMA専用のメモリを定義するのに対し
    →ユーザプロセス用のメモリが多く使える
  • 通常のカーネルヒープに対し
    →カーネルヒープから物理連続の領域を取得するのは、先客が居たりして難しい(特に大容量の領域ほど)が、CMAならユーザプロセス用のページを立ち退きさせれば良いので比較的容易

THPは仮想連続の4KBのページを512枚集めてきて、2MB(ARMの場合)のHuge Pageに置き換えてしまう技術。のはずです。あまり調べてないので、違ってたらゴメンなさい。

私が思いつく利点としては、

  • 4KB 512ページに比べて、ページテーブルの容量が節約できる
  • TLBヒット率も上がる、はず

これらの技術のコンセプトは素晴らしいので、ぜひ使いたいと思って使っていますが、動きが謎過ぎて困っています。困っている問題は3つ。

  • THPにCMA占領されちゃう問題
  • ユーザプロセスがCMA全然使わない問題
  • 誰が使ってるのこれ?問題

THPにCMA占領されちゃう問題

THPはkhugepagedというカーネルスレッドが裏でひっそりと活動してページを置き換えます。こいつが使うメモリページはPageCompoundという属性になっていて、なぜかPage Migrationできません。なぜなのか理由はわかりません。

それでいてTHPはCMA領域をガンガン消費します。なぜかはあまり調べていませんが、おそらく、

  • 要求する領域のサイズが大きいこと
  • 後述するようにユーザプロセスはCMA領域を全然使わないので、CMA領域は比較的空いていること
    =連続したページが取りやすい

辺りがCMAから大きいサイズの領域を取りやすい理由だと思います。

しばらく放っておくとCMA領域がTHPで埋まってしまうため、ドライバのdma_alloc() がENOMEMとかで失敗するようになって、ドライバが動かなくなってしまいます。

解決方法を知りたくて、頑張ってBuddy Allocatorまでコード読んでみましたが、khugepagedも結局alloc_pages() でHuge Pageを取っているだけでした。つまり他の用途のメモリの取り方と何ら変わりません。当然ながらCMA領域を避けて取るとか、そんな機構があるようには見えなかったので、この問題を回避する方法はわからないままです。

THPはGFP(Get Free Pages)フラグが少し特殊ですので、Buddy Allocatorでフラグを見てTHPをCMA領域に割り当てないように改造することは出来ましたが、本当にこんな改造が要るんでしょうか?

私が見た範囲では、フラグをチェックしてメモリの割り当て処理を変えている個所は見当たりませんでしたから、何か別の方法が隠れているかもしれません。

誰も困っていないのでしょうか。それとも私の設定がマズいだけでしょうか?

ユーザプロセスがCMA全然使わない問題

Buddy Allocatorの詳細な仕組みはここでは説明しきれませんが、メモリはゾーンという大きな括りで分けられており、各ゾーンには5つのリストがあります。アロケータはこの5つのリストのどれかからページを割り当てます。/proc/pagetypeinfoで各リストの残量を見ることができます。

  • MIGRATE_UNMOVABLE
  • MIGRATE_MOVABLE
  • MIGRATE_RECLAIMABLE
  • MIGRATE_HIGHATOMIC
  • MIGRATE_CMA

カーネルにメモリページの取得リクエストが来ると、基本的には上4つのリストのどれかからページが取得されます。どのリストになるのかはGFP(Get Free Pages)フラグに何を指定したか?によって決まります。ユーザプロセス用のメモリであればMIGRATE_MOVABLEから取られます。

ではMIGRATE_CMAはいつ使われるのか?というと、これが良くわからないんです。

実機でメモリを使いまくるプロセスを立ち上げ(yes | sortとか)/proc/meminfoの様子を見ていると、

  • 空き領域MemFreeが減りまくる(CmaFreeは減らない)
  • ページキャッシュCachedが減りまくる(CmaFreeは減らない)
  • ページキャッシュがなくなったせいでI/Oが多発してシステムが遅くなる
  • やっとCMA領域CmaFreeが減り始める
  • OOM Killerにプロセスを強制終了させられる

こんな動きになります。3番目のページキャッシュ減少が起きると、システムが遅すぎて使い物になりませんので、もっと早めにCMA領域を利用していただきたいのですが、なぜかそうなりません。

Buddy Allocatorのコードを見るとMIGRATE_MOVABLEが枯渇というか、ページ割り当てに失敗したときに初めてMIGRATE_CMAからのページ割り当てに挑戦するようになっているように見えます。

個人的にはMIGRATE_CMA → MIGRATE_MOVABLEの順に割り当てた方が良かったのではないか?と思いました。ドライバがCMA領域を使う時はPage Migrationがあるわけですから。

MIGRATE_MOVABLE → MIGRATE_CMAの順に割り当てMIGRATE_MOVABLEを先に使い果たしてしまうと、CMA領域からユーザプロセス用のページをMigrationしようにも移動させる先がありません。これではPage Migrationが役に立ちません。

どうもイマイチです。設定か何かが間違っているのでしょうか。

誰が使ってるのこれ?問題

あまりに訳の分からない動きをしているので、CMAが正常に動いている例が見たかったのですが、手元のAndroidデバイスでCMAを使っているシステムが全くありませんでした。ショック。

CMAは組み込みのように制約の多いハードウェア、かつ、メモリ容量に制限のあるシステム向けの機能です。AndroidであればION Carveout Heapだとメモリ占有が多すぎて耐えられないボンクラハードウェアや、メモリの搭載量が非常に少ないシステム向けの最終兵器のはずです。

GoogleもAOSPで紹介している(Low RAM Configuration | Android Open Source Project のCarveouts, Ion and Contiguous Memory Allocation (CMA) の節)ほどなのになあ。

でも身の回りの製品では誰も使っていません。CMAって誰が使ってるんだろう??

編集者:すずき(2023/09/24 08:49)

コメント一覧

  • hdkさん(2017/10/06 21:37)
    CMA は噂によれば、ビデオのハードウェアデコーダーがフル HD や 4K などのフレームを扱うのに大きなサイズの RAM が必要なので、という話がありましたが、近年は非連続アドレスでも扱えるようになってきちゃって必要性はそんなにないのかも? ビデオのデコードでもしなければそもそも使われなさそうです。

    Transparent Huge Page は身近なところでは QEMU などで大きな容量の RAM を仮想マシンに割り当てた時に勝手に使われているみたいですが、組み込み環境ではどうなんですかね...
  • すずきさん(2017/10/07 12:26)
    会社ではビデオ系ハード、グラフィクス、デコーダ、サウンド系と、あらゆるハードが大容量の物理連続領域を要求してくるので、困っています。

    うちの会社のハードがヘボいというか、世の中に追いつけてないんだと思いますけど……。

    THP 自体は良いんですが、CMA との共存ができない点がイマイチです。単に CMA の実装がイケてないだけかもしれませんが、私には良くわからなかった。
  • hdkさん(2017/10/09 00:35)
    非連続物理アドレスは IOMMU を使って仮想アドレスにマップしちゃうのが今時の流行り (?) のようです。

    Hugepages は Intel DPDK がやっているみたいに意図的に使う方法もありますので、THP はある程度自動でやってくれるという、おまけみたいなものなんですかね。
  • すずきさん(2017/10/09 22:41)
    私も IOMMU と DDR のインタリーブアクセスがあれば、今風アーキテクチャなのになあ、とは思いますが、色々あって積んでないままです。

    Intel DPDK は初めて知りました。ネットワーク超特化のアーキテクチャで、TLB ミスヒットが大きなペナルティとして認識されているんですね。

    THP は何かの基準でページを選んで、空き時間を使って統合してくれているように見えました。残念ながらコンセプトを語れるほど、わかってませんけど……。
open/close この記事にコメントする



link もっと前
2017年9月29日 >>> 2017年9月29日
link もっと後

管理用メニュー

link 記事を新規作成

<2017>
<<<09>>>
-----12
3456789
10111213141516
17181920212223
24252627282930

最近のコメント5件

  • link 21年3月13日
    すずきさん (03/05 15:13)
    「あー、このプログラムがまずいんですね。ご...」
  • link 21年3月13日
    emkさん (03/05 12:44)
    「キャストでvolatileを外してアクセ...」
  • link 24年1月24日
    すずきさん (02/19 18:37)
    「簡単にできる方法はPowerShellの...」
  • link 24年1月24日
    KKKさん (02/19 02:30)
    「追伸です。\nネットで調べたらマイクロソ...」
  • link 24年1月24日
    KKKさん (02/19 02:25)
    「私もエラーで困ってます\n手動での回復パ...」

最近の記事3件

  • link 23年4月10日
    すずき (03/19 11:48)
    「[Linux - まとめリンク] 目次: Linuxカーネル、ドライバ関連。Linuxのstruct pageって何?Linu...」
  • link 24年3月18日
    すずき (03/19 11:47)
    「[画面のブランクを無効にする] 目次: LinuxROCK 3 model CのDebian bullseyeイメージは10分...」
  • link 24年3月3日
    すずき (03/19 11:07)
    「[解像度の設定を保存する] 目次: LinuxRaspberry Pi 3 Model B (以降RasPi 3B)のHDMI...」
link もっとみる

こんてんつ

open/close wiki
open/close Linux JM
open/close Java API

過去の日記

open/close 2002年
open/close 2003年
open/close 2004年
open/close 2005年
open/close 2006年
open/close 2007年
open/close 2008年
open/close 2009年
open/close 2010年
open/close 2011年
open/close 2012年
open/close 2013年
open/close 2014年
open/close 2015年
open/close 2016年
open/close 2017年
open/close 2018年
open/close 2019年
open/close 2020年
open/close 2021年
open/close 2022年
open/close 2023年
open/close 2024年
open/close 過去日記について

その他の情報

open/close アクセス統計
open/close サーバ一覧
open/close サイトの情報

合計:  counter total
本日:  counter today

link About www.katsuster.net
RDFファイル RSS 1.0

最終更新: 03/19 11:48