詳細Linuxカーネル 15章 ページキャッシュ 5/28
詳細Linuxカーネル 15章 ページキャッシュ 5/28
ページキャッシュの章を読む。
キャッシュは一般的にはディスクデータへのアクセスのキャッシュして
RAM上に保存してシステム高速化するのが目的。
https://kernelreading.doorkeeper.jp/events/42463
15.1章 ページキャッシュとは
ページキャッシュはカーネルが使うディスクキャッシュで、 ディスクへの読み書きの際にページキャッシュを参照する。
read要求があった場合のざっくりの動作。
- 要求のあったデータ(ページ?)がキャッシュ上に在るか検索
- キャッシュ上にあればそのデータを返答
- キャッシュ上になければディスクから読み取りキャッシュにデータ格納。
- 格納したデータを返答
write要求があった場合のざっくりの動作
- 対応するデータ(ページ?)がキャッシュに在るか検索
- キャッシュ上になけれ新しいキャッシュ領域を確保
- キャッシュ上に書き込みデータを格納
- データ書き込みは適当なタイミングで実施
当たり前だがそれぞれの目的は・・・
readキャッシュの目的:同じディスク領域への複数のreadを1回のディスクアクセスにまとめる。
writeキャッシュの目的:同じディスク領域への複数のwriteを1回のディスクアクセスにまとめる。
これらの目的を満たすためには、
単なる2回のディスクアクセスより上記の手順による2回のデータアクセスが早く無いと損するはず。
そのために、以下の要件を満たしてページキャシュが実装されているらしい。
* データを含むページの迅速な検索。
(プロセスからデータアクセス時に指定してる形式はなんだっけ?忘れてる・・・)
* ページ内の内容を読み書きする手段の管理。(管理をつけた意味は?)
15.1.1 アドレス空間構造体
ページキャッシュのメインはアドレス空間(adress_space
)構造体
この構造体はiノードオブジェト内に存在(inode->i_mapping
)する
そのほかの構造体の関係はここがわかりやすい。
http://wiki.bit-hive.com/linuxkernelmemo/pg/PageCache
つまるところ、adress->page_tree
から当該データのページディスクリプタのポインタを検索してページディスクリプタのフラグでページの状態を確認する。
adress->page_tree
は基数ツリーのルートを表す。
基数ツリーの各ノードは、別のノードもしくはページのポインタを64(=26)個(配列slots
)とノード内に存在するポインタ数を持つ。(その他にフラグなどある)
この基数ツリーのノードはルートからの位置index
で一意に指定している。
インデックスはファイルの先頭からのオフセットと同じ意味。
例えば、基数ツリーの深さが2つしか無いならばindex=131=64*2 + 3
は
ルートノードのSlot[2] -> 次のノードのSlot[3]でページディスクリプタのポインタに辿れる。
struct radix_tree_node { unsigned int path; /* Offset in parent & height from the bottom */ unsigned int count; union { struct { /* Used when ascending tree */ struct radix_tree_node *parent; /* For tree user */ void *private_data; }; /* Used when freeing node */ struct rcu_head rcu_head; }; /* For tree user */ struct list_head private_list; void __rcu *slots[RADIX_TREE_MAP_SIZE]; unsigned long tags[RADIX_TREE_MAX_TAGS][RADIX_TREE_TAG_LONGS]; };
基数ツリーの最大インデックスは232-1まで。
4kB単位のページだと最大ファイルサイズは4G個 * 4kB =16TB
メモリが16TB以上とかの世界になったらどうなんだろうって思ったが、
ファイルサイズを最大16TBのことで、使えるキャッシュサイズが16TBでは無いのか。
この前提にページキャッシュの検索について見る。
この時点でざっくり性能を考えてみる。
まずは、アドレス空間構造体からページキャッシュにあるかどうかを判定するまで性能。
ファイルサイズが1GB〜64GBの範囲(階層3)と仮定する。
アドレス空間構造体からページノードにたどり着くまでに、
メモリアクセスが少なくとも4回必要(3つのノード+ページヘのポインタ参照)。
メモリが0.1μs、HDDドライブが100μs、SSDが・・・
ここからは少し考えてみる。
15.1.3 ページキャッシュの操作関数
15.1.3.1 ページの検索
ページ検索はfind_get_page()
関数で
* アドレス空間構造体のポインタとオフセット値を引数にする
次回は検索を見る。