Skip to content

Commit 6ead533

Browse files
d-nettonickrobinson251
authored andcommitted
add some instrumentation to measure page utilization per size class (JuliaLang#52164)
One of the limitations is that it's only accurate right after the GC. Still might be helpful for observability purposes.
1 parent 9465dc5 commit 6ead533

File tree

2 files changed

+42
-0
lines changed

2 files changed

+42
-0
lines changed

src/gc.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1390,6 +1390,38 @@ int jl_gc_classify_pools(size_t sz, int *osize)
13901390

13911391
// sweep phase
13921392

1393+
gc_fragmentation_stat_t gc_page_fragmentation_stats[JL_GC_N_POOLS];
1394+
1395+
extern gc_fragmentation_stat_t gc_page_fragmentation_stats[JL_GC_N_POOLS];
1396+
1397+
STATIC_INLINE void gc_update_page_fragmentation_data(jl_gc_pagemeta_t *pg) JL_NOTSAFEPOINT
1398+
{
1399+
#ifdef GC_MEASURE_PAGE_FRAGMENTATION
1400+
gc_fragmentation_stat_t *stats = &gc_page_fragmentation_stats[pg->pool_n];
1401+
jl_atomic_fetch_add(&stats->n_freed_objs, pg->nfree);
1402+
jl_atomic_fetch_add(&stats->n_pages_allocd, 1);
1403+
#endif
1404+
}
1405+
1406+
STATIC_INLINE void gc_dump_page_utilization_data(void) JL_NOTSAFEPOINT
1407+
{
1408+
#ifdef GC_MEASURE_PAGE_FRAGMENTATION
1409+
for (int i = 0; i < JL_GC_N_POOLS; i++) {
1410+
gc_fragmentation_stat_t *stats = &gc_page_fragmentation_stats[i];
1411+
double utilization = 1.0;
1412+
size_t n_freed_objs = jl_atomic_load_relaxed(&stats->n_freed_objs);
1413+
size_t n_pages_allocd = jl_atomic_load_relaxed(&stats->n_pages_allocd);
1414+
if (n_pages_allocd != 0) {
1415+
utilization -= ((double)n_freed_objs * (double)jl_gc_sizeclasses[i]) / (double)n_pages_allocd / (double)GC_PAGE_SZ;
1416+
}
1417+
jl_safe_printf("Size class %d: %.2f%% utilization\n", jl_gc_sizeclasses[i], utilization * 100.0);
1418+
jl_atomic_store_relaxed(&stats->n_freed_objs, 0);
1419+
jl_atomic_store_relaxed(&stats->n_pages_allocd, 0);
1420+
}
1421+
jl_safe_printf("-----------------------------------------\n");
1422+
#endif
1423+
}
1424+
13931425
int64_t buffered_pages = 0;
13941426

13951427
// Returns pointer to terminal pointer of list rooted at *pfl.
@@ -1498,6 +1530,7 @@ static void gc_sweep_page(jl_gc_pool_t *p, jl_gc_page_stack_t *allocd, jl_gc_pag
14981530
push_lf_back(&global_page_pool_lazily_freed, pg);
14991531
}
15001532
}
1533+
gc_update_page_fragmentation_data(pg);
15011534
gc_time_count_page(freedall, pg_skpd);
15021535
jl_ptls_t ptls = gc_all_tls_states[pg->thread_n];
15031536
jl_atomic_fetch_add(&ptls->gc_num.pool_live_bytes, GC_PAGE_SZ - GC_PAGE_OFFSET - nfree * osize);
@@ -1711,6 +1744,7 @@ static void gc_sweep_pool(void)
17111744
#else
17121745
gc_free_pages();
17131746
#endif
1747+
gc_dump_page_utilization_data();
17141748
gc_time_pool_end(current_sweep_full);
17151749
}
17161750

src/gc.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,14 @@ STATIC_INLINE jl_gc_pagemeta_t *pop_lf_back(jl_gc_page_stack_t *pool) JL_NOTSAFE
219219
}
220220
}
221221

222+
// data structures for tracking fragmentation in the pool allocator
223+
// #define GC_MEASURE_PAGE_FRAGMENTATION
224+
225+
typedef struct {
226+
_Atomic(size_t) n_freed_objs;
227+
_Atomic(size_t) n_pages_allocd;
228+
} gc_fragmentation_stat_t;
229+
222230
#ifdef _P64
223231
#define REGION0_PG_COUNT (1 << 16)
224232
#define REGION1_PG_COUNT (1 << 16)

0 commit comments

Comments
 (0)