diff --git a/base/timing.jl b/base/timing.jl index 375ff7aaea60e..e033f01cd793e 100644 --- a/base/timing.jl +++ b/base/timing.jl @@ -27,6 +27,15 @@ struct GC_Num total_mark_time ::Int64 last_full_sweep ::Int64 last_incremental_sweep ::Int64 + strings_allocd_poolmem_count ::Int64 + strings_allocd_poolmem_size ::Int64 + strings_freed_poolmem_count ::Int64 + strings_freed_poolmem_size ::Int64 + strings_allocd_malloc_count ::Int64 + strings_allocd_malloc_size ::Int64 + strings_freed_malloc_count ::Int64 + strings_freed_malloc_size ::Int64 + strings_realloc_count ::Int64 end gc_num() = ccall(:jl_gc_num, GC_Num, ()) diff --git a/src/array.c b/src/array.c index 0b582296774b5..34fac9c7cccf5 100644 --- a/src/array.c +++ b/src/array.c @@ -503,11 +503,21 @@ JL_DLLEXPORT jl_value_t *jl_alloc_string(size_t len) // We call `jl_gc_pool_alloc_noinline` instead of `jl_gc_pool_alloc` to avoid double-counting in // the Allocations Profiler. (See https://github.com/JuliaLang/julia/pull/43868 for more details.) s = jl_gc_pool_alloc_noinline(ptls, (char*)p - (char*)ptls, osize); + + jl_atomic_store_relaxed(&ptls->gc_num.strings_allocd_poolmem_count, + jl_atomic_load_relaxed(&ptls->gc_num.strings_allocd_poolmem_count) + 1); + jl_atomic_store_relaxed(&ptls->gc_num.strings_allocd_poolmem_size, + jl_atomic_load_relaxed(&ptls->gc_num.strings_allocd_poolmem_size) + osize); } else { if (allocsz < sz) // overflow in adding offs, size was "negative" jl_throw(jl_memory_exception); s = jl_gc_big_alloc_noinline(ptls, allocsz); + + jl_atomic_store_relaxed(&ptls->gc_num.strings_allocd_malloc_count, + jl_atomic_load_relaxed(&ptls->gc_num.strings_allocd_malloc_count) + 1); + jl_atomic_store_relaxed(&ptls->gc_num.strings_allocd_malloc_size, + jl_atomic_load_relaxed(&ptls->gc_num.strings_allocd_malloc_size) + jl_bigalloc_size(s)); } jl_set_typeof(s, jl_string_type); maybe_record_alloc_to_profile(s, len, jl_string_type); diff --git a/src/gc.c b/src/gc.c index 0f0b62b752b5a..cf40d68c0014b 100644 --- a/src/gc.c +++ b/src/gc.c @@ -1179,6 +1179,10 @@ static bigval_t **sweep_big_list(int sweep_full, bigval_t **pv) JL_NOTSAFEPOINT #ifdef MEMDEBUG memset(v, 0xbb, v->sz&~3); #endif + if (jl_typeis(jl_valueof(&v->header), jl_string_type)){ + gc_num.strings_freed_malloc_count ++; + gc_num.strings_freed_malloc_size += v->sz&~3; + } gc_invoke_callbacks(jl_gc_cb_notify_external_free_t, gc_cblist_notify_external_free, (v)); jl_free_aligned(v); @@ -1253,6 +1257,15 @@ static void combine_thread_gc_counts(jl_gc_num_t *dest) JL_NOTSAFEPOINT dest->poolalloc += jl_atomic_load_relaxed(&ptls->gc_num.poolalloc); dest->bigalloc += jl_atomic_load_relaxed(&ptls->gc_num.bigalloc); dest->freecall += jl_atomic_load_relaxed(&ptls->gc_num.freecall); + dest->strings_allocd_poolmem_count += jl_atomic_load_relaxed(&ptls->gc_num.strings_allocd_poolmem_count); + dest->strings_allocd_poolmem_size += jl_atomic_load_relaxed(&ptls->gc_num.strings_allocd_poolmem_size); + dest->strings_freed_poolmem_count += jl_atomic_load_relaxed(&ptls->gc_num.strings_freed_poolmem_count); + dest->strings_freed_poolmem_size += jl_atomic_load_relaxed(&ptls->gc_num.strings_freed_poolmem_size); + dest->strings_allocd_malloc_count += jl_atomic_load_relaxed(&ptls->gc_num.strings_allocd_malloc_count); + dest->strings_allocd_malloc_size += jl_atomic_load_relaxed(&ptls->gc_num.strings_allocd_malloc_size); + dest->strings_freed_malloc_count += jl_atomic_load_relaxed(&ptls->gc_num.strings_freed_malloc_count); + dest->strings_freed_malloc_size += jl_atomic_load_relaxed(&ptls->gc_num.strings_freed_malloc_size); + dest->strings_realloc_count += jl_atomic_load_relaxed(&ptls->gc_num.strings_realloc_count); } } } @@ -1274,6 +1287,15 @@ static void reset_thread_gc_counts(void) JL_NOTSAFEPOINT jl_atomic_store_relaxed(&ptls->gc_num.poolalloc, 0); jl_atomic_store_relaxed(&ptls->gc_num.bigalloc, 0); jl_atomic_store_relaxed(&ptls->gc_num.freecall, 0); + jl_atomic_store_relaxed(&ptls->gc_num.strings_allocd_poolmem_count, 0); + jl_atomic_store_relaxed(&ptls->gc_num.strings_allocd_poolmem_size, 0); + jl_atomic_store_relaxed(&ptls->gc_num.strings_freed_poolmem_count, 0); + jl_atomic_store_relaxed(&ptls->gc_num.strings_freed_poolmem_size, 0); + jl_atomic_store_relaxed(&ptls->gc_num.strings_allocd_malloc_count, 0); + jl_atomic_store_relaxed(&ptls->gc_num.strings_allocd_malloc_size, 0); + jl_atomic_store_relaxed(&ptls->gc_num.strings_freed_malloc_count, 0); + jl_atomic_store_relaxed(&ptls->gc_num.strings_freed_malloc_size, 0); + jl_atomic_store_relaxed(&ptls->gc_num.strings_realloc_count, 0); } } } @@ -3657,7 +3679,7 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) if (collection == JL_GC_AUTO) { //If we aren't freeing enough or are seeing lots and lots of pointers let it increase faster - if (!not_freed_enough || large_frontier) { + if (not_freed_enough || large_frontier) { int64_t tot = 2 * (live_bytes + gc_num.since_sweep) / 3; if (gc_num.interval > tot) { gc_num.interval = tot; @@ -4164,6 +4186,19 @@ jl_value_t *jl_gc_realloc_string(jl_value_t *s, size_t sz) gc_big_object_link(newbig, &ptls->heap.big_objects); jl_value_t *snew = jl_valueof(&newbig->header); *(size_t*)snew = sz; + + // update stats + jl_atomic_store_relaxed(&ptls->gc_num.strings_freed_malloc_size, + jl_atomic_load_relaxed(&ptls->gc_num.strings_freed_malloc_size) + oldsz); + jl_atomic_store_relaxed(&ptls->gc_num.strings_freed_malloc_count, + jl_atomic_load_relaxed(&ptls->gc_num.strings_freed_malloc_count) + 1); + jl_atomic_store_relaxed(&ptls->gc_num.strings_allocd_malloc_size, + jl_atomic_load_relaxed(&ptls->gc_num.strings_allocd_malloc_size) + allocsz); + jl_atomic_store_relaxed(&ptls->gc_num.strings_allocd_malloc_count, + jl_atomic_load_relaxed(&ptls->gc_num.strings_allocd_malloc_count) + 1); + jl_atomic_store_relaxed(&ptls->gc_num.strings_realloc_count, + jl_atomic_load_relaxed(&ptls->gc_num.strings_realloc_count) + 1); + return snew; } @@ -4441,6 +4476,9 @@ JL_DLLEXPORT void jl_gc_schedule_foreign_sweepfunc(jl_ptls_t ptls, jl_value_t *o arraylist_push(&ptls->sweep_objs, obj); } +size_t jl_bigalloc_size(jl_value_t* val){ + return bigval_header(jl_astaggedvalue(val))->sz; +} #ifdef __cplusplus } #endif diff --git a/src/gc.h b/src/gc.h index d181f3dea8e19..921b2cadc4df5 100644 --- a/src/gc.h +++ b/src/gc.h @@ -87,6 +87,15 @@ typedef struct { uint64_t total_mark_time; uint64_t last_full_sweep; uint64_t last_incremental_sweep; + uint64_t strings_allocd_poolmem_count; + uint64_t strings_allocd_poolmem_size; + uint64_t strings_freed_poolmem_count; // FIXME: not accounted, yet + uint64_t strings_freed_poolmem_size; // FIXME: not accounted, yet + uint64_t strings_allocd_malloc_count; + uint64_t strings_allocd_malloc_size; + uint64_t strings_freed_malloc_count; + uint64_t strings_freed_malloc_size; + uint64_t strings_realloc_count; } jl_gc_num_t; // Array chunks (work items representing suffixes of diff --git a/src/julia.h b/src/julia.h index a5d3259ad0d3f..9f6f1b195ba04 100644 --- a/src/julia.h +++ b/src/julia.h @@ -126,6 +126,7 @@ static inline void jl_set_typeof(void *v, void *t) JL_NOTSAFEPOINT jl_atomic_store_relaxed((_Atomic(jl_value_t*)*)&tag->type, (jl_value_t*)t); } #define jl_typeis(v,t) (jl_typeof(v)==(jl_value_t*)(t)) +size_t jl_bigalloc_size(jl_value_t*); // Symbols are interned strings (hash-consed) stored as an invasive binary tree. // The string data is nul-terminated and hangs off the end of the struct. diff --git a/src/julia_threads.h b/src/julia_threads.h index f69f9dd4baacf..d8c9e20185b71 100644 --- a/src/julia_threads.h +++ b/src/julia_threads.h @@ -135,6 +135,15 @@ typedef struct { _Atomic(uint64_t) poolalloc; _Atomic(uint64_t) bigalloc; _Atomic(uint64_t) freecall; + _Atomic(uint64_t) strings_allocd_poolmem_count; + _Atomic(uint64_t) strings_allocd_poolmem_size; + _Atomic(uint64_t) strings_freed_poolmem_count; + _Atomic(uint64_t) strings_freed_poolmem_size; + _Atomic(uint64_t) strings_allocd_malloc_count; + _Atomic(uint64_t) strings_allocd_malloc_size; + _Atomic(uint64_t) strings_freed_malloc_count; + _Atomic(uint64_t) strings_freed_malloc_size; + _Atomic(uint64_t) strings_realloc_count; } jl_thread_gc_num_t; typedef struct {