Compaction (๋ฉ๋ชจ๋ฆฌ ์กฐ๊ฐ ๋ชจ์)
Linux 7.0 ๋ฉ๋ชจ๋ฆฌ ๊ด๋ฆฌ ๋ถ์ ์๋ฆฌ์ฆ
๊ฐ์ (Overview)
Compaction๋ ๋ฆฌ๋ ์ค ์ปค๋์ ์ธ๋ถ ๋จํธํ(external fragmentation)๋ฅผ ์ํํ๊ธฐ ์ํ ๋ฉ์ปค๋์ฆ์ ๋๋ค. Buddy Allocator๋ 2์ ๊ฑฐ๋ญ์ ๊ณฑ(order) ํฌ๊ธฐ ๋ธ๋ก์ ํ ๋นํ๋๋ฐ, ํ๋ฆฌ ํ์ด์ง๊ฐ ์ถฉ๋ถํ ์์ง๋ง ์ฐ์๋ high-order ๋ธ๋ก์ด ์๋ ๊ฒฝ์ฐ ํ ๋น์ ์คํจํฉ๋๋ค. Compaction์ ์ด๋ ๊ฐ๋ฅํ(movable) ํ์ด์ง๋ฅผ zone์ ํ์ชฝ ๋์ผ๋ก ์ฎ๊ธฐ๊ณ , ๋ฐ๋์ชฝ ๋์ ํ๋ฆฌ ํ์ด์ง๋ค์ ๋ณํฉํ์ฌ high-order ๋ธ๋ก์ ์์ฑํฉ๋๋ค.
Compaction์ ํต์ฌ์ page migration์ ์์กดํฉ๋๋ค. ๋ ๊ฐ์ ์ค์บ๋๊ฐ zone์ ์์ชฝ ๋์์ ์๋ก๋ฅผ ํฅํด ์ด๋ํฉ๋๋ค: migrate scanner๋ ์ด๋ ๊ฐ๋ฅํ ํ์ด์ง๋ฅผ ํ์ํ๊ณ , free scanner๋ ํ๋ฆฌ ํ์ด์ง๋ฅผ ํ์ํฉ๋๋ค. ๋ ์ค์บ๋๊ฐ ๋ง๋๋ฉด compaction์ด ์๋ฃ๋ฉ๋๋ค. ์ปค๋์ Direct compaction (ํ ๋น ์คํจ ์ ์ฆ์ ์คํ), Background compaction (kcompactd ๋ฐ๋ชฌ), Proactive compaction (๋ฐฑ๊ทธ๋ผ์ด๋ ์๋ ๋จํธํ ํด์, ์ปค๋ 5.9+) ์ธ ๊ฐ์ง ๋ชจ๋๋ฅผ ์ง์ํฉ๋๋ค. ์ปค๋ 6.15๋ถํฐ๋ defrag_mode sysctl์ด ์ถ๊ฐ๋์ด ํ์ด์ง ํ ๋น์๊ฐ ๋จํธํ ํํผ๋ฅผ ์ ๊ทน ์ํํ ์ ์์ต๋๋ค.
์ผ์ ๋น์ : Compaction๋ ์ฃผ์ฐจ์ฅ ์ ๋ฆฌ์ ๋น์ทํฉ๋๋ค. ์ฃผ์ฐจ์ฅ์ ๋น ์๋ฆฌ๊ฐ ์ถฉ๋ถํ์ง๋ง ์ฐจ๋ค์ด ํฉ์ด์ ธ ์์ดๅคงๅ ๋ฒ์ค(์ฐ์ 4MB ๋ธ๋ก)๋ฅผ ์ฃผ์ฐจํ ์ ์๋ ์ํฉ์ ๋๋ค. ์ ๋น์ฌ(migrate scanner)๊ฐ ํ์ชฝ ๋์ ์ฐจ(movable ํ์ด์ง)๋ฅผ ๋ชจ๋ ์ฎ๊ธฐ๊ณ , ๋ฐ๋์ชฝ ๋์ ๋น ์๋ฆฌ(free scanner)๋ฅผ ๋ชจ์ผ๋ฉด ํฐ ๋ฒ์ค๋ฅผ ์ฃผ์ฐจํ ์ ์๋ ์ฐ์ ๊ณต๊ฐ์ด ์๊น๋๋ค.
์์ค ํ์ผ ๊ฒฝ๋ก:
mm/compaction.c โ Compaction ํต์ฌ ๋ก์ง (3334์ค)
include/linux/compaction.h โ enum compact_priority, enum compact_result ์ ์
mm/internal.h โ struct compact_control, struct capture_control ์ ์
include/linux/mmzone.h โ zone ๊ตฌ์กฐ์ฒด ๋ด compaction ์บ์ ํ๋
๋น ๋ฅธ ์ ๊ฒ ๋ช ๋ น
# Compaction ํธ๋ฆฌ๊ฑฐ (์ ์ฒด ์์คํ
)
echo 1 > /proc/sys/vm/compact_memory
# NUMA ๋
ธ๋๋ณ compaction ํธ๋ฆฌ๊ฑฐ
echo 1 > /sys/devices/system/node/node0/compact
# ํ์ฌ compaction ํต๊ณ
cat /proc/vmstat | grep -E "compact_|kcompactd"
# Compaction deferred ์ํ ํ์ธ
cat /proc/vmstat | grep "compact_defer_shift"
# ์ธ๋ถ ๋จํธํ ์ง์ ํ์ธ
cat /proc/extfraginfo
# Proactive compaction ํ์ฑํ/๋นํ์ฑํ
cat /proc/sys/vm/compaction_proactiveness # 0~100 (๊ธฐ๋ณธ 20)
# ๋จํธํ ์ ์ ํ์ธ (๋
ธ๋๋ณ)
cat /sys/kernel/mm/compaction/proactiveness
# defrag_mode โ ๋จํธํ ํํผ ๋ชจ๋ (์ปค๋ 6.15+)
cat /proc/sys/vm/defrag_mode # 0: ๋นํ์ฑ (๊ธฐ๋ณธ), 1: ์ ๊ทน์ ๋จํธํ ํํผ
# kcompactd ์ค๋ ๋ ์ํ ํ์ธ
ps -eo pid,comm | grep kcompactd
# zone๋ณ compaction ์บ์ PFN ํ์ธ
cat /proc/zoneinfo | grep -E "compact_cached"
ํต์ฌ ์๋ฃ๊ตฌ์กฐ
1. `struct compact_control` โ Compaction ์ ์ด ๊ตฌ์กฐ์ฒด
Compaction์ ๋ชจ๋ ์ํ์ ํ๋ผ๋ฏธํฐ๋ฅผ ๋ด๋นํ๋ ํต์ฌ ๊ตฌ์กฐ์ฒด์ ๋๋ค. direct compaction, kcompactd, /proc ํธ๋ฆฌ๊ฑฐ ๋ฑ ๋ชจ๋ ์ง์ ์ ์์ ์ฌ์ฉ๋ฉ๋๋ค.
// mm/internal.h:950-988
struct compact_control {
struct list_head freepages[NR_PAGE_ORDERS]; // ํ๋ฆฌ ํ์ด์ง ๋ชฉ๋ก (order๋ณ)
struct list_head migratepages; // ์ด๋ ๋์ ํ์ด์ง ๋ชฉ๋ก
unsigned int nr_freepages; // ๊ฒฉ๋ฆฌ๋ ํ๋ฆฌ ํ์ด์ง ์
unsigned int nr_migratepages; // ์ด๋ ๋์ ํ์ด์ง ์
unsigned long free_pfn; // free scanner ์์ ์์น
unsigned long migrate_pfn; // migrate scanner ์์น (in/out)
unsigned long fast_start_pfn; // ์ ํ ์ค์บ ์์ ์์น
struct zone *zone; // ๋์ zone
unsigned long total_migrate_scanned; // ์ด ์ด๋ ์ค์บ ์
unsigned long total_free_scanned; // ์ด ํ๋ฆฌ ์ค์บ ์
unsigned short fast_search_fail; // fast search ์คํจ ์
short search_order; // fast search ์์ order
const gfp_t gfp_mask; // GFP ๋ง์คํฌ
int order; // ํ ๋น ๋์ order
int migratetype; // ํ ๋น ๋์ migratetype
const unsigned int alloc_flags; // ํ ๋น ํ๋๊ทธ
const int highest_zoneidx; // ์ต๋ zone ์ธ๋ฑ์ค
enum migrate_mode mode; // Async/Sync/Sync_light
bool ignore_skip_hint; // skip ํํธ ๋ฌด์ ์ฌ๋ถ
bool no_set_skip_hint; // skip ํํธ ์ค์ ์ ํจ
bool ignore_block_suitable; // ์ ํฉํ์ง ์์ ๋ธ๋ก ๋ฌด์
bool direct_compaction; // true = direct, false = kcompactd
bool proactive_compaction; // true = proactive
bool whole_zone; // ์ ์ฒด zone ์ค์บ ์ฌ๋ถ
bool contended; // lock ๊ฒฝ์ ๋ฐ์ ์ฌ๋ถ
bool finish_pageblock; // ํ์ฌ pageblock ์ค์บ ์๋ฃ ์ฌ๋ถ
bool alloc_contig; // alloc_contig_range ํ ๋น ์ฌ๋ถ
};
์ฃผ์ ํ๋ ์ค๋ช :
freepages[NR_PAGE_ORDERS]: free scanner๊ฐ ๊ฒฉ๋ฆฌํ ํ๋ฆฌ ํ์ด์ง๋ฅผ order๋ณ๋ก ๋ถ๋ฆฌํ์ฌ ๋ณด๊ดmigratepages: migrate scanner๊ฐ ๊ฒฉ๋ฆฌํ ์ด๋ ๋์ ํ์ด์ง ๋ชฉ๋กmigrate_pfn / free_pfn: ๋ ์ค์บ๋์ ํ์ฌ ์์น. compaction์ด ์งํ๋๋ฉด์ ์๋ก๋ฅผ ํฅํด ์ด๋mode: MIGRATE_ASYNC (๋
ผ๋ธ๋กํน), MIGRATE_SYNC_LIGHT (๊ธฐ๋ณธ), MIGRATE_SYNC (์์ ๋๊ธฐ)direct_compaction: direct compaction์ธ์ง kcompactd/background์ธ์ง ๊ตฌ๋ถ2. `struct capture_control` โ Direct compaction ์บก์ฒ ๊ตฌ์กฐ์ฒด
Direct compaction ์ค IRQ ํธ๋ค๋ฌ๊ฐ ํ๋ฆฌ ํ์ด์ง๋ฅผ ๋ฐํํ๋ฉด ์ฆ์ ์บก์ฒํ์ฌ ํ ๋น์ ํ์ฉํฉ๋๋ค.
// mm/internal.h:994-997
struct capture_control {
struct compact_control *cc; // compaction ์ ์ด ๊ตฌ์กฐ์ฒด ํฌ์ธํฐ
struct page *page; // ์บก์ฒ๋ ํ๋ฆฌ ํ์ด์ง (ํ ๋น ์ฑ๊ณต ์)
};
compact_zone_order()์์ current->capture_control์ ์ค์ ํ๊ณ , IRQ์์ ํ์ด์ง ํด์ ์ __free_pages_core()๊ฐ ์ด ๊ตฌ์กฐ์ฒด๋ฅผ ํตํด ํ์ด์ง๋ฅผ ์บก์ฒํฉ๋๋ค.
3. `enum compact_priority` โ Compaction ์ฐ์ ์์
// include/linux/compaction.h:9-17
enum compact_priority {
COMPACT_PRIO_SYNC_FULL, // 0: ์์ ๋๊ธฐ (์ต๊ณ ์ฐ์ ์์)
MIN_COMPACT_PRIORITY = COMPACT_PRIO_SYNC_FULL,
COMPACT_PRIO_SYNC_LIGHT, // 1: ๊ฐ๋ฒผ์ด ๋๊ธฐ (๊ธฐ๋ณธ)
MIN_COMPACT_COSTLY_PRIORITY = COMPACT_PRIO_SYNC_LIGHT,
DEF_COMPACT_PRIORITY = COMPACT_PRIO_SYNC_LIGHT,
COMPACT_PRIO_ASYNC, // 2: ๋น๋๊ธฐ (์ต์ ์ฐ์ ์์)
INIT_COMPACT_PRIORITY = COMPACT_PRIO_ASYNC
};
4. `enum compact_result` โ Compaction ๊ฒฐ๊ณผ ์ฝ๋
// include/linux/compaction.h:21-56
enum compact_result {
COMPACT_NOT_SUITABLE_ZONE, // ๋ด๋ถ: zone ์ ํฉํ์ง ์์
COMPACT_SKIPPED, // compaction ์์ ์ ํจ
COMPACT_DEFERRED, // ์ด์ ์คํจ๋ก ์ธํด ์ฐ๊ธฐ๋จ
COMPACT_NO_SUITABLE_PAGE, // ๋ด๋ถ: ์ ํฉ ํ๋ฆฌ ํ์ด์ง ์์
COMPACT_CONTINUE, // ๊ณ์ ์งํ
COMPACT_COMPLETE, // ์ ์ฒด zone ์ค์บ ์๋ฃ
COMPACT_PARTIAL_SKIPPED, // ์ผ๋ถ ์์ญ๋ง ์ค์บ
COMPACT_CONTENDED, // lock ๊ฒฝ์์ผ๋ก ์ค๋จ
COMPACT_SUCCESS, // ํ ๋น ์ฑ๊ณต
};
ํต์ฌ ํจ์
1. `try_to_compact_pages()` โ Direct compaction ์ง์ ์
ํ ๋น ์คํจ ์ page allocator์์ ์ง์ ํธ์ถํ๋ ๋ฉ์ธ ์ง์
ํจ์์
๋๋ค. zonelist์ ๊ฐ zone์ ๋ํด compact_zone_order()๋ฅผ ์์ฐจ์ ์ผ๋ก ํธ์ถํฉ๋๋ค.
// mm/compaction.c:2814-2880
enum compact_result try_to_compact_pages(gfp_t gfp_mask, unsigned int order,
unsigned int alloc_flags, const struct alloc_context *ac,
enum compact_priority prio, struct page **capture)
{
// 1. gfp_compaction_allowed() ๊ฒ์ฌ
// 2. zonelist ์ํ
for_each_zone_zonelist_nodemask(zone, z, ac->zonelist, ...) {
// cpuset ๊ฒ์ฌ
// compaction_deferred() ๊ฒ์ฌ โ ์ฐ๊ธฐ๋ zone ๊ฑด๋๋
status = compact_zone_order(zone, order, ...);
if (status == COMPACT_SUCCESS) break;
// ASYNC์์ need_resched() ๋๋ fatal signal โ ์ค๋จ
}
}
๋ถ๊ธฐ ๋ก์ง:
gfp_compaction_allowed() ์คํจ โ ์ฆ์ COMPACT_SKIPPEDcompaction_deferred() ์ฐธ โ COMPACT_DEFERRED (์ด์ ์คํจ๋ก ์ฐ๊ธฐ)COMPACT_SUCCESS โ ๋ฐ๋ณต ์ฆ์ ์ค๋จ (ํ ๋น ์ฑ๊ณต ์์)COMPACT_COMPLETE / COMPACT_PARTIAL_SKIPPED โ defer_compaction() ํธ์ถ2. `compact_zone()` โ Compaction ์ฝ์ด ๋ก์ง
ํ๋์ zone์ ๋ํ compaction์ ์ํํ๋ ํต์ฌ ํจ์์ ๋๋ค. migrate/free ์ค์บ๋๋ฅผ ๊ต๋๋ก ์คํํ๊ณ , ์ด๋ ๊ฐ๋ฅํ ํ์ด์ง๋ฅผ ๊ฒฉ๋ฆฌํ์ฌ migrationํฉ๋๋ค.
// mm/compaction.c:2510-2747
static enum compact_result compact_zone(struct compact_control *cc,
struct capture_control *capc)
{
// 1. ์ค์บ๋ ์ด๊ธฐ ์์น ์ค์ (์บ์๋ PFN ๋๋ zone ๋)
// 2. while (compact_finished() == COMPACT_CONTINUE) ๋ฐ๋ณต:
// a. isolate_migratepages(cc) โ ์ด๋ ๋์ ํ์ด์ง ๊ฒฉ๋ฆฌ
// b. migrate_pages() โ compaction_alloc/free ์ฝ๋ฐฑ์ผ๋ก ์ค์ ์ด๋
// c. check_drain: order > 0์ด๋ฉด lru_add_drain_cpu_zone()
// 3. ํ๋ฆฌ ํ์ด์ง ํด์ ๋ฐ ์บ์ ์
๋ฐ์ดํธ
}
ํต์ฌ ๋ถ๊ธฐ:
compaction_suit_allocation_order() ์คํจ โ ์ฆ์ ๋ฐํ (watermark ๋ฏธ์ถฉ์กฑ)compaction_restarting() โ __reset_isolation_suitable() (์คํต ํํธ ์ด๊ธฐํ)isolate_migratepages() ๊ฒฐ๊ณผ์ ๋ฐ๋ผ ISOLATE_ABORT / ISOLATE_NONE / ISOLATE_SUCCESS ๋ถ๊ธฐmigrate_pages() ์คํจ โ -ENOMEM ์ COMPACT_CONTENDED, ASYNC ์คํจ ์ finish_pageblock ์ค์ 3. `compact_finished()` โ Compaction ์๋ฃ ๊ฒ์ฌ
compaction์ด ๋๋ฌ๋์งๅคๆญํ๋ ํจ์์ ๋๋ค. ๋ ์ค์บ๋๊ฐ ๋ง๋ฌ๋์ง, ํ๋ฆฌ ํ์ด์ง๊ฐ ์ถฉ๋ถํ์ง, watermark๋ฅผ ๋ง์กฑํ๋์ง ํ์ธํฉ๋๋ค.
// mm/compaction.c:2234-2355
static enum compact_result __compact_finished(struct compact_control *cc)
{
// 1. compact_scanners_met(): ๋ ์ค์บ๋๊ฐ ๋ง๋๋ฉด COMPACT_COMPLETE/PARTIAL_SKIPPED
// 2. proactive_compaction: fragmentation ์ ์๋ก ํ๋จ
// - ์ ์ > wmark_low โ COMPACT_CONTINUE
// - ์ ์ โค wmark_low โ COMPACT_SUCCESS
// 3. defrag_mode && kcompactd: NR_FREE_PAGES_BLOCKS ๊ธฐ์ค watermark ๊ฒ์ฌ
// 4. direct compactor: free_area์์ ๋์ migratetype์ ํ๋ฆฌ ํ์ด์ง ํ์ธ
// - ํด๋น migratetype ํ๋ฆฌ โ COMPACT_SUCCESS
// - MIGRATE_MOVABLE โ CMA fallback ํ์ฉ
// - steal ๊ฐ๋ฅํ๋ฉด COMPACT_SUCCESS
// 5. contended || fatal_signal โ COMPACT_CONTENDED
}
ํต์ฌ ๋ถ๊ธฐ:
compact_scanners_met() โ reset_cached_positions() ํ COMPACT_COMPLETEproactive_compaction โ fragmentation_score_zone() vs fragmentation_score_wmark() ๋น๊ตdefrag_mode ํ์ฑํ ์ NR_FREE_PAGES_BLOCKS ๊ธฐ๋ฐ watermark ๊ฒ์ฌ (high watermark ์๊ตฌ)free_area_empty() ์คํจ โ find_suitable_fallback()์ผ๋ก steal ๊ฐ๋ฅ์ฑ ๊ฒ์ฌ4. `isolate_migratepages_block()` โ ํ์ด์ง ๊ฒฉ๋ฆฌ
ํ๋์ pageblock ๋ด์์ ์ด๋ ๊ฐ๋ฅํ ํ์ด์ง๋ฅผ ๊ฒฉ๋ฆฌํ๋ ํจ์์
๋๋ค. LRU ๋ชฉ๋ก์์ ํ์ด์ง๋ฅผ ์ ๊ฑฐํ๊ณ cc->migratepages ๋ชฉ๋ก์ ์ถ๊ฐํฉ๋๋ค.
// mm/compaction.c:836-1308
static int isolate_migratepages_block(struct compact_control *cc,
unsigned long low_pfn, unsigned long end_pfn, isolate_mode_t mode)
{
for (; low_pfn < end_pfn; low_pfn++) {
// PageHuge โ isolate_or_dissolve_huge_folio()
// PageBuddy โ ๊ฑด๋๋
// PageCompound && !alloc_contig โ skip_isolation_on_order() ๊ฒ์ฌ
// PageLRU โ folio ๊ฒฉ๋ฆฌ
// - too_many_isolated() ๊ฒ์ฌ (LRU ๊ฒฉ๋ฆฌ ์ ํ)
// - ISOLATE_ASYNC_MIGRATE โ writeback/dirty ํ์ด์ง ์ ์ธ
// - folio_test_clear_lru() โ LRU์์ ์ ๊ฑฐ
// - COMPACT_CLUSTER_MAX ๋๋ฌ ์ ์ค๋จ
}
}
5. `compaction_alloc()` / `compaction_free()` โ Migration ์ฝ๋ฐฑ
migrate_pages()๊ฐ ํธ์ถํ๋ ์ฝ๋ฐฑ ํจ์์
๋๋ค. compaction_alloc()์ ํ๋ฆฌ ํ์ด์ง ๋ชฉ๋ก์์ ๋์ ํ์ด์ง๋ฅผ ์ ๊ณตํ๊ณ , compaction_free()๋ ์คํจ ์ ํ๋ฆฌ ํ์ด์ง๋ก ๋ฐํํฉ๋๋ค.
// mm/compaction.c:1797-1848
static struct folio *compaction_alloc_noprof(struct folio *src, unsigned long data)
{
struct compact_control *cc = (struct compact_control *)data;
// 1. freepages[]์์ ์๋ง์ order์ ํ๋ฆฌ ํ์ด์ง ํ์
// 2. ์์ผ๋ฉด isolate_freepages() ํธ์ถํ์ฌ ์ถ๊ฐ ๊ฒฉ๋ฆฌ
// 3. ํฐ order ๋ธ๋ก์ splitํ์ฌ ์์ฒญ order๋ก ์ ๊ณต
// 4. nr_freepages, nr_migratepages ๊ฐฑ์
}
static void compaction_free(struct folio *dst, unsigned long data)
{
// ์คํจํ ํ์ด์ง๋ฅผ freepages[]๋ก ๋ฐํ
}
6. `kcompactd()` โ ๋ฐฑ๊ทธ๋ผ์ด๋ Compaction ๋ฐ๋ชฌ
๊ฐ NUMA ๋ ธ๋๋ง๋ค ํ๋์ฉ ์คํ๋๋ ์ปค๋ ์ค๋ ๋์ ๋๋ค. proactive compaction๊ณผ ์์ฒญ ๊ธฐ๋ฐ compaction์ ์ฒ๋ฆฌํฉ๋๋ค.
// mm/compaction.c:3165-3231
static int kcompactd(void *p)
{
pg_data_t *pgdat = (pg_data_t *)p;
long default_timeout = msecs_to_jiffies(HPAGE_FRAG_CHECK_INTERVAL_MSEC);
long timeout = default_timeout;
current->flags |= PF_KCOMPACTD;
set_freezable();
while (!kthread_should_stop()) {
// 1. proactiveness ๋นํ์ฑํ ์ timeout = MAX_SCHEDULE_TIMEOUT
// 2. wait_event_freezable_timeout()์ผ๋ก ๋๊ธฐ
// 3. kcompactd_work_requested() โ kcompactd_do_work() ์คํ
// 4. should_proactive_compact_node() โ compact_node() ์คํ
// - fragmentation_score_node() > wmark_high โ proactive ์์
// - ์ ์ ๊ฐ์ ์์ผ๋ฉด timeout ์ฆ๊ฐ (์ง์ฐ)
timeout = default_timeout;
}
}
proactive compaction ๋ถ๊ธฐ:
sysctl_compaction_proactiveness == 0 โ timeout = MAX_SCHEDULE_TIMEOUT (๋นํ์ฑ)fragmentation_score_node() > wmark_high โ compact_node() ์คํtimeout << COMPACT_MAX_DEFER_SHIFT (์ต๋ 64๋ฐฐ ์ง์ฐ)7. `compact_zone_order()` โ compact_control ์ด๊ธฐํ
Direct compaction์์ compact_control ๊ตฌ์กฐ์ฒด๋ฅผ ์ด๊ธฐํํ๋ ํจ์์ ๋๋ค. ์ฐ์ ์์(prio)์ ๋ฐ๋ผ mode, whole_zone, ignore_skip_hint ๋ฑ์ด ๋ฌ๋ผ์ง๋๋ค.
// mm/compaction.c:2749-2768
static enum compact_result compact_zone_order(struct zone *zone, int order,
gfp_t gfp_mask, enum compact_priority prio,
unsigned int alloc_flags, int highest_zoneidx,
struct page **capture)
{
struct compact_control cc = {
.order = order,
.search_order = order,
.gfp_mask = gfp_mask,
.zone = zone,
.mode = (prio == COMPACT_PRIO_ASYNC) ?
MIGRATE_ASYNC : MIGRATE_SYNC_LIGHT,
.alloc_flags = alloc_flags,
.highest_zoneidx = highest_zoneidx,
.direct_compaction = true,
.whole_zone = (prio == MIN_COMPACT_PRIORITY), // ์ต๊ณ ์ฐ์ ์์์์ ์ ์ฒด zone ์ค์บ
.ignore_skip_hint = (prio == MIN_COMPACT_PRIORITY), // skip ํํธ ๋ฌด์
.ignore_block_suitable = (prio == MIN_COMPACT_PRIORITY) // ์ ํฉ ๋ธ๋ก ๋ฌด์
};
struct capture_control capc = {
.cc = &cc,
.page = NULL,
};
// capture_control์ current์ ์ค์ โ IRQ์์ ํ๋ฆฌ ํ์ด์ง ์บก์ฒ ๊ฐ๋ฅ
WRITE_ONCE(current->capture_control, &capc);
ret = compact_zone(&cc, &capc);
...
}
compact_control ์ด๊ธฐํ ๋ถ๊ธฐ:
COMPACT_PRIO_ASYNC โ MIGRATE_ASYNC (๋
ผ๋ธ๋กํน, ๋ถ๋ถ ์ค์บ)COMPACT_PRIO_SYNC_LIGHT (๊ธฐ๋ณธ) โ MIGRATE_SYNC_LIGHT (์กฐ๊ฑด๋ถ ๋๊ธฐ)MIN_COMPACT_PRIORITY โ whole_zone=true, ignore_skip_hint=true (์ ์ฒด zone, skip ๋ฌด์)ํธ์ถ ํ๋ฆ
Direct Compaction ํ๋ฆ
__alloc_pages() ์คํจ
โโ __alloc_pages_slowpath()
โโ __alloc_pages_direct_reclaim() ์คํจ
โโ __alloc_pages_direct_compact()
โโ try_to_compact_pages() โ Direct compaction ์ง์
โโ compact_zone_order() โ compact_control ์ด๊ธฐํ
โโ compact_zone() โ ์ฝ์ด ๋ฃจํ
โโ compaction_suit_allocation_order() โ watermark ๊ฒ์ฌ
โโ isolate_migratepages() โ ์ด๋ ๋์ ๊ฒฉ๋ฆฌ
โ โโ isolate_migratepages_block() โ pageblock ๋จ์
โโ migrate_pages() โ ์ค์ ์ด๋
โ โโ compaction_alloc() โ ๋์ ํ์ด์ง ํ ๋น
โ โโ compaction_free() โ ์คํจ ์ ๋ฐํ
โโ compact_finished() โ ์๋ฃ ๊ฒ์ฌ
kcompactd ํ๋ฆ
wakeup_kcompactd() โ page allocator์์ ํธ์ถ
โโ wake_up_interruptible()
kcompactd() ์ค๋ ๋ ๊ธฐ์
โโ kcompactd_do_work() โ ์ผ๋ฐ compaction
โ โโ compact_zone()
โโ should_proactive_compact_node() โ proactive compaction
โโ compact_node() โ ์ ์ฒด zone ์ํ
โโ compact_zone()
Free Scanner โ Meet Scanner ๊ตฌ์กฐ
Zone ์์ (low_pfn)
โ
โ โ migrate scanner โ
โ (migrate_pfn: ์์์ ๋ค๋ก)
โ
โ ์ด๋ ๊ฐ๋ฅํ ํ์ด์ง ๊ฒฉ๋ฆฌ โ migratepages
โ
โ โ free scanner
โ (free_pfn: ๋ค์์ ์์ผ๋ก)
โ
โ ํ๋ฆฌ ํ์ด์ง ๊ฒฉ๋ฆฌ โ freepages[]
โ
โโ ๋ ์ค์บ๋๊ฐ ๋ง๋๋ฉด compaction ์ข
๋ฃ
์กฐ๊ฑด๋ณ ๋น๊ต
Compaction ๋ชจ๋ ๋น๊ต
| ํญ๋ชฉ | MIGRATE_ASYNC | MIGRATE_SYNC_LIGHT | MIGRATE_SYNC |
|---|---|---|---|
| **๋ธ๋กํน** | ๋น๋๊ธฐ (๋ ผ๋ธ๋กํน) | ์กฐ๊ฑด๋ถ ๋๊ธฐ | ์์ ๋๊ธฐ |
| **์ฐ์ ์์** | COMPACT_PRIO_ASYNC | DEF_COMPACT_PRIORITY | MIN_COMPACT_PRIORITY |
| **์ค์บ๋ ๋ฒ์** | ๋ถ๋ถ ์ค์บ | ๋ถ๋ถ ์ค์บ | ์ ์ฒด zone (whole_zone) |
| **skip_hint** | ์ฌ์ฉ | ์ฌ์ฉ | ๋ฌด์ (ignore_skip_hint) |
| **์ ํฉ ๋ธ๋ก ๋ฌด์** | ์๋ | ์๋ | ๋ฌด์ (ignore_block_suitable) |
| **isolation stride** | COMPACT_CLUSTER_MAX | 1 | 1 |
| **lock ๊ฒฝ์ ์** | trylock โ ์ค๋จ | lock ๋๊ธฐ | lock ๋๊ธฐ |
Compaction ํธ๋ฆฌ๊ฑฐ ๊ฒฝ๋ก ๋น๊ต
| ๊ฒฝ๋ก | ์ง์ ํจ์ | compact_control ์ค์ | ์ฃผ์ ํน์ง |
|---|---|---|---|
| **Direct compaction** | `try_to_compact_pages()` | direct_compaction=true, whole_zone=false (prio๋ณ) | ํ ๋น ์คํจ ์ ์ฆ์ ์คํ, capture_control๋ก ํ๋ฆฌ ํ์ด์ง ์บก์ฒ |
| **kcompactd** | `kcompactd_do_work()` | direct_compaction=false, whole_zone=false | ๋ฐฑ๊ทธ๋ผ์ด๋ ์คํ, watermark_high ๊ธฐ์ค |
| **Proactive** | `compact_node()` | proactive_compaction=true, whole_zone=true | fragmentation ์ ์ ๊ธฐ๋ฐ, kcompactd ๋ด๋ถ |
| **compact_memory** | `compact_nodes()` | order=-1, whole_zone=true, ignore_skip_hint=true | /proc/sys/vm/compact_memory ํธ๋ฆฌ๊ฑฐ |
| **NUMA node compact** | `compact_node()` | order=-1, whole_zone=true | /sys/devices/system/node/nodeX/compact ํธ๋ฆฌ๊ฑฐ |
Compaction ๊ฒฐ๊ณผ ๋น๊ต
| ๊ฒฐ๊ณผ | ์๋ฏธ | ํ์ ๋์ |
|---|---|---|
| `COMPACT_SUCCESS` | ํ ๋น ๊ฐ๋ฅํ ํ๋ฆฌ ๋ธ๋ก ํ๋ณด | ํ ๋น ์๋ |
| `COMPACT_CONTINUE` | ๊ณ์ ์งํ ๊ฐ๋ฅ | ๋ฐ๋ณต ๋ฃจํ ๊ณ์ |
| `COMPACT_COMPLETE` | ์ ์ฒด zone ์ค์บ ์๋ฃ | `defer_compaction()` (non-MIN) |
| `COMPACT_PARTIAL_SKIPPED` | ๋ถ๋ถ ์ค์บ๋ง ์๋ฃ | `defer_compaction()` |
| `COMPACT_DEFERRED` | ์ด์ ์คํจ๋ก ์ฐ๊ธฐ | ๊ฑด๋๋ |
| `COMPACT_SKIPPED` | compaction ๋ถ๊ฐ (watermark ๋ฏธ์ถฉ์กฑ ๋ฑ) | ๋ค์ zone์ผ๋ก |
| `COMPACT_CONTENDED` | lock ๊ฒฝ์์ผ๋ก ์ค๋จ | ์ฆ์ ๋ฐํ |
์ค์บ๋ skip ํํธ ๋์ ๋น๊ต
| ์กฐ๊ฑด | skip ์ค์ | skip ๊ฒ์ฌ | ์ค๋ช |
|---|---|---|---|
| ๊ฒฉ๋ฆฌ๋ ํ์ด์ง ์์ | `set_pageblock_skip()` | `isolation_suitable()` | ๋น ๋ธ๋ก์ ํฅํ ์ค์บ์์ ๊ฑด๋๋ |
| isolated == 0 && finish_pageblock | `set_pageblock_skip()` | `isolation_suitable()` | ์๋ฃ ์์๋ ์ค์ |
| ignore_skip_hint=true | ์ค์ ์ ํจ | ํญ์ ํต๊ณผ | MIN_COMPACT_PRIORITY์์ ์ฌ์ฉ |
| no_set_skip_hint=true | ์ค์ ์ ํจ | ์ค์ | isolated ํฌ์ง์ ์ ๋ฐ์ดํธ ์ |
| pageblock_skip_persistent | ์ค์ ์ ํจ | ํญ์ ๊ฑด๋๋ | compound >= pageblock_order |
defrag_mode ๋์ ๋น๊ต (์ปค๋ 6.15+)
| defrag_mode | kcompactd ๋์ | compact_finished ๊ธฐ์ค | ์ผ๋ฐ ํ ๋น์ ์ํฅ |
|---|---|---|---|
| `0` (๊ธฐ๋ณธ) | ์ผ๋ฐ compact_zone | free_area์์ ํ๋ฆฌ ํ์ด์ง ํ์ธ | ๊ธฐ์กด๋๋ก ๋์ |
| `1` (์ ๊ทน์ ) | NR_FREE_PAGES_BLOCKS ๊ธฐ์ค | high watermark ์๊ตฌ | ํ ๋น ์ compaction ํํผ ๊ฐํ |
์ฆ์๋ณ ์ง๋จ
minzkn.com์ "๋ฉ๋ชจ๋ฆฌ ์ด์ ํ๋ ์ด๋ถ"๊ณผ ์ ์ฌํ๊ฒ, compaction ๊ด๋ จ ์ฆ์๋ณ ์ง๋จ ํฌ์ธํธ๋ฅผ ์ ๋ฆฌํฉ๋๋ค.
| ์ฆ์ | ์ฐ์ ์ ๊ฒ | ๊ถ์ฅ ์กฐ์น | |
|---|---|---|---|
| **๊ณ ์ฐจ ํ์ด์ง ํ ๋น ์คํจ** (THP 2MB ๋ฑ) | `/proc/buddyinfo`, `cat /proc/vmstat \ | grep compact` | compaction ํ๋, hugepage ์ ์ฑ ์ ๊ฒ, `defrag_mode=1` ์๋ |
| **compact_stall ๊ธ์ฆ** | `cat /proc/vmstat \ | grep compact_stall` | THP `defrag` ๋ชจ๋๋ฅผ `madvise`๋ก ๋ณ๊ฒฝ, proactive_compactiveness ์กฐ์ |
| **compact_fail > compact_success** | `cat /proc/vmstat \ | grep compact_fail` | ๋จํธํ ์ฌํ ์ํ โ `echo 1 > /proc/sys/vm/compact_memory` ์๋ ํธ๋ฆฌ๊ฑฐ |
| **kcompactd ๊ณผ๋ํ CPU ์ฌ์ฉ** | `top -H -p $(pgrep kcompactd)` | `compaction_proactiveness` ๊ฐ์ (0์ผ๋ก ๋นํ์ฑํ ๊ฐ๋ฅ) | |
| **khugepaged ๊ณผ๋ํ CPU** | `top -H -p $(pgrep khugepaged)` | THP defrag๋ฅผ `madvise`๋ก ๋ณ๊ฒฝ, khugepaged ์ค์บ ์ฃผ๊ธฐ ์กฐ์ | |
| **defer_compaction ๋ฐ๋ณต** | `cat /proc/vmstat \ | grep defer` | ๋ฉ๋ชจ๋ฆฌ ๋ถ์กฑ ์ํ โ ํ์ ๊ฒฝ๋ก ์ ๊ฒ, ๋ถํ์ํ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ ํด์ |
| **zone ๋ด fragmentation index ๋์** | `cat /proc/extfraginfo` | memcg ์ ํ ์ฌ์กฐ์ , CMA ์์ญ ํ๋ณด, zonelist ์์ ๋ณ๊ฒฝ |
# compaction ๊ด๋ จ ํต๊ณ ์ ์ฒด ํ์ธ ์คํฌ๋ฆฝํธ
echo "=== Compaction ํต๊ณ ==="
cat /proc/vmstat | grep -E "compact_|kcompactd|defer"
echo ""
echo "=== buddyinfo (๋จํธํ ์ํ) ==="
cat /proc/buddyinfo
echo ""
echo "=== fragmentation index ==="
cat /proc/extfraginfo
echo ""
echo "=== sysctl ํ๋ผ๋ฏธํฐ ==="
sysctl vm.compaction_proactiveness vm.compact_memory vm.extfrag_threshold 2>/dev/null
echo ""
echo "=== defrag_mode (์ปค๋ 6.15+) ==="
cat /proc/sys/vm/defrag_mode 2>/dev/null || echo "ํด๋น ์์"