buddy allocator: compatctionの処理 compaction_suitable()

compaction_suitable()compact_zone()の最初に使う関数で、コンパクションしようとしているzoneをコンパクションするかどうか判断する。

compaction_suitable()自体はたいした処理はなく、__compaction_suitable()が実際にチェックをする。

1259 unsigned long compaction_suitable(struct zone *zone, int order,
1260                                         int alloc_flags, int classzone_idx)
1261 {
1262         unsigned long ret;
1263 
1264         ret = __compaction_suitable(zone, order, alloc_flags, classzone_idx);
1265         trace_mm_compaction_suitable(zone, order, ret);
1266         if (ret == COMPACT_NOT_SUITABLE_ZONE)
1267                 ret = COMPACT_SKIPPED;
1268 
1269         return ret;
1270 }

__compaction_suitable()のコメントを除く割と短めです。

1210 static unsigned long __compaction_suitable(struct zone *zone, int order,
1211                                         int alloc_flags, int classzone_idx)
1212 {
1213         int fragindex;
1214         unsigned long watermark;
1215 

最初のチェックでorderが-1かちぇっくしてますね、これは通常のallocationだとありえませんが、/proc/sys/vm/compact_memoryに値を書き込んでコンパクションを行った場合にorderが-1に設定されます。この場合は常にコンパクションを実行することになります。

1220         if (order == -1)
1221                 return COMPACT_CONTINUE;
1222 

ちなみに、compact_memoryに値を設定してコンパクションを実行する場合は↓のような流れになり、compact_node() のなかでorderを-1に設定しています。

sysctl_compaction_handler() -> compact_nodes() -> compact_node() -> __compact_pgdat() -> compact_zone()

low_wmark_pages()はzoneのlowのwatermarkを読み出します。

1223         watermark = low_wmark_pages(zone);

zone_watermark_ok()は前回の記事で読んだところです。非ゼロが返ってきた場合はwatermarkを下回っていない場合でした。なのでCOMPACT_PARTIALを返します。COMPACT_PARTIALはmm/compaction.hにて定義されていて、コメントによると、部分的にコンパクションされていて、order分のページを割り当てできる状態とのことです。

1228         if (zone_watermark_ok(zone, order, watermark, classzone_idx,
1229                                                                 alloc_flags))
1230                 return COMPACT_PARTIAL;
1231 

次はorderを0にしてチェックします。ここでwatermarkを増やしているのは、コメントに書いてありますが、pageのmigration中は短い時間だけどcopyを持つ必要があるからとなってます。あと、orderを0にするのはこれならcompactionできるはずと言うことみたいです。が、これでもダメなら、このzoneのコンパクションを諦めます。

1237         watermark += (2UL << order);
1238         if (!zone_watermark_ok(zone, 0, watermark, classzone_idx, alloc_flags))
1239                 return COMPACT_SKIPPED;
1240 

最後に呼び出す関数はfragmentation_index()です。ここの内容は無視できないフラグメンテーション問題への解答は?(1/2) − @ITを読んだほうが分かると思いますm(__)m fragmentation_index()の結果が最終的にこのzoneをコンパクションするかどうかという答えになります。

1252         fragindex = fragmentation_index(zone, order);
1253         if (fragindex >= 0 && fragindex <= sysctl_extfrag_threshold)
1254                 return COMPACT_NOT_SUITABLE_ZONE;
1255 
1256         return COMPACT_CONTINUE;
1257 }

compaction_suitable()を呼んでいるcompact_zone()は結果をこのように処理しています。まあ、COMPACT_CONTINUEが返ってきた場合はコンパクションを継続するというそのままですが。

1281         ret = compaction_suitable(zone, cc->order, cc->alloc_flags,
1282                                                         cc->classzone_idx);
1283         switch (ret) {
1284         case COMPACT_PARTIAL:
1285         case COMPACT_SKIPPED:
1286                 /* Compaction is likely to fail */
1287                 return ret;
1288         case COMPACT_CONTINUE:
1289                 /* Fall through to compaction */
1290                 ;
1291         }

すごいHaskellたのしく学ぼう!

すごいHaskellたのしく学ぼう!