lkml でお勉強 (その1-1)
○ ページフレーム回収処理のパフォーマンスアップの話 (前編)
GNU/Linux (以下, linux) のカーネルコードを追い、onix を作り、linux コードをいじってきたが、lkml にパッチを送ったりコミュニティーに貢献できる実力はまだまだ不足している。
また本をいくら読んでも lkml で戦う力はつかないので、これからしばらく lkml の patch を使って学習する。
具体的には、(学習当時) 最近投稿された patch のうちで議論が活発なメールをピックアップし、それが一体どういういった内容なのかという事を、バックグラウンドを含めて解説してゆく。
ここでの目的は、patch の検証を行う事では無く patch を通して linux の理解を深める事である。
今回の教材は富士通の kosaki さんが今月の17日に投稿した patch (*1) を取り上げる。
文量が多いので、同 patch を理解する上で必要となるバックグラウンドについての解説を今回行い、patch の詳細な解説については次回に回す。
同 patch に書かれているコメントは、「cs オブジェクトの isolate_pages メソッドを呼び出し、0 が帰ってきたら shrink_page_list() を呼び出す必要がないので、これを迂回する処理を shrink_inactive_list() に書いた」という内容である。
これについて論じる前に、一連の処理のバックグラウンドをおさらいする。尚、参照するコードは lkml をテキストとする為、最新開発版を用いる。適宜 git を使って linus のリポジトリ等をチェックアウトされたし。
shrink_inactive_list() は mm/vmscan.c での内部関数であり、非アクティブなページフレーム郡を回収を行う処理である。またこれは vmscan.c の処理のインターフェイスである shrink_slab()、 try_to_free_pages() そして shrink_all_memory() などから呼び出される。以下では、try_to_free_pages() 処理について解説する。
try_to_free_pages() は、ゾーンリスト (struct zonelist 型) オブジェクトと、回収するページフレームの数を表す 2 の指数を引数に渡し、vmscan.c の内部処理用のデータ構造である scan_control オブジェクトを生>成・初期化し、各メモリゾーンにおいて shrink_zone() を呼び出す。
ゾーンリストオブジェクトは、各メモリゾーン (*2) オブジェクトを持っており、NUMA システムでない限りはシステムにおいて唯一のオブジェクトになる (はず)。
shrink_zone() では get_scan_ratio() を呼び出し、無名ページとページキャッシュどちらに属するページフレームをどれだけ回収するかの重み付けを計算する。
次に、対象ゾーンの各種類のページをどれだけ捜査するのかを決定する。通常各メモリゾーンに所属するページ郡は動的に include/linux/mmzone.h で宣言されている列挙型 lru_list の種類に分類される。そして、各 lru_list のページ郡に対して shrink_list() を実行する。
shrink_list() では引数として受け取った lru_list 列挙型オブジェクトの値に応じて、ページフレームの回収処理を行う。lru_list で非アクティブリストを指定されたり、対象のメモリゾーンにおいて非アクティブリストのページフレームが多数を占めている場合、shrink_inactive_list() が呼ばれる。
ここでようやく、今回の話題である shrink_inactive_list() 処理が実行される。kosaki さんの patch の中身を考察する前に、shrink_inactive_list() の処理について見てみる。
shrink_inactive_list() はまず、作業用データ構造である sca_control オブジェクトの isolate_pages メソッドを呼び出す。この実態は、try_to_free_pages() で isolate_pages_global() 関数に設定されており、間接的に isolate_lru_pages を呼び出す。isolate_lru_pages() の処理は、回収するページを既存の LRU リストから分離して、ページフレーム回収用のリストに結合する。この処理の細部については後で述べる。
この時点で shrink_inactive_list() では、isolate_pages() メソッドの呼出しによって、回収するページフレームが決定した。後は、ページフレームの属性情報の書き換えやら、各種類のページ数の更新を行い、shrink_page_list() 関数を呼び出す。
shrink_page_list() 関数では、引数で受け取ったページリストに属するページを、各ページの種類に応じた方法によって回収してゆく。
以上が、kosaki さんのパッチを解読する上でのバックグラウンドになる。同氏の patch の解説については次回に書くことにする。
(*1) http://lkml.org/lkml/2009/7/15/371
(*2) 各メモリゾーンの種類は include/linux/mmzone.h で宣言されている列挙型 zone_type の __MAX_NR_ZONES の数だけ存在する
- Category(s)
- 学習経過
- The URL to Trackback this entry is:
- http://dev.ariel-networks.com/Members/ohyama/lkml-304a52c95f37-305d306e1-1/tbping
Re:lkml でお勉強 (その1-1)
Re:lkml でお勉強 (その1-1)
まさか小崎さんのような大物からコメントをもらえるとは思いませんでした。
カーネルが仮想メモリ空間を zonetype で示す種類に分断し、それぞれが zone オブジェクトを持っているという事は理解しているつもりなのですが。
try_to_free_pages() に渡されている struct zonelist 型のオブジェクトは NUMA システムでない時に複数存在する理由が不明だったので、struct zonelist 型オブジェクトは唯一だと推測しました。
これについては、僕の推測だけでページフレーム回収の呼び出し元の処理など、よく調べていないので、調べてまた載せます。