Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

print types more verbosely in page profiler #53256

Merged
merged 1 commit into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -317,9 +317,10 @@ $(BUILDDIR)/debuginfo.o $(BUILDDIR)/debuginfo.dbg.obj: $(addprefix $(SRCDIR)/,de
$(BUILDDIR)/disasm.o $(BUILDDIR)/disasm.dbg.obj: $(SRCDIR)/debuginfo.h $(SRCDIR)/processor.h
$(BUILDDIR)/gc-debug.o $(BUILDDIR)/gc-debug.dbg.obj: $(SRCDIR)/gc.h
$(BUILDDIR)/gc-pages.o $(BUILDDIR)/gc-pages.dbg.obj: $(SRCDIR)/gc.h
$(BUILDDIR)/gc.o $(BUILDDIR)/gc.dbg.obj: $(SRCDIR)/gc.h $(SRCDIR)/gc-heap-snapshot.h $(SRCDIR)/gc-alloc-profiler.h
$(BUILDDIR)/gc.o $(BUILDDIR)/gc.dbg.obj: $(SRCDIR)/gc.h $(SRCDIR)/gc-heap-snapshot.h $(SRCDIR)/gc-alloc-profiler.h $(SRCDIR)/gc-page-profiler.h
$(BUILDDIR)/gc-heap-snapshot.o $(BUILDDIR)/gc-heap-snapshot.dbg.obj: $(SRCDIR)/gc.h $(SRCDIR)/gc-heap-snapshot.h
$(BUILDDIR)/gc-alloc-profiler.o $(BUILDDIR)/gc-alloc-profiler.dbg.obj: $(SRCDIR)/gc.h $(SRCDIR)/gc-alloc-profiler.h
$(BUILDDIR)/gc-page-profiler.o $(BUILDDIR)/gc-page-profiler.dbg.obj: $(SRCDIR)/gc-page-profiler.h
$(BUILDDIR)/init.o $(BUILDDIR)/init.dbg.obj: $(SRCDIR)/builtin_proto.h
$(BUILDDIR)/interpreter.o $(BUILDDIR)/interpreter.dbg.obj: $(SRCDIR)/builtin_proto.h
$(BUILDDIR)/jitlayers.o $(BUILDDIR)/jitlayers.dbg.obj: $(SRCDIR)/jitlayers.h $(SRCDIR)/llvm-codegen-shared.h
Expand Down
24 changes: 18 additions & 6 deletions src/gc-page-profiler.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ gc_page_profiler_serializer_t gc_page_serializer_create(void) JL_NOTSAFEPOINT
gc_page_profiler_serializer_t serializer;
if (__unlikely(page_profile_enabled)) {
arraylist_new(&serializer.typestrs, GC_PAGE_SZ);
serializer.buffers = (char *)malloc_s(GC_PAGE_PROFILER_SERIALIZER_INIT_CAPACITY);
serializer.cursor = 0;
}
else {
serializer.typestrs.len = 0;
Expand All @@ -34,13 +36,16 @@ void gc_page_serializer_init(gc_page_profiler_serializer_t *serializer,
serializer->typestrs.len = 0;
serializer->data = (char *)pg->data;
serializer->osize = pg->osize;
serializer->cursor = 0;
serializer->capacity = GC_PAGE_PROFILER_SERIALIZER_INIT_CAPACITY;
}
}

void gc_page_serializer_destroy(gc_page_profiler_serializer_t *serializer) JL_NOTSAFEPOINT
{
if (__unlikely(page_profile_enabled)) {
arraylist_free(&serializer->typestrs);
free(serializer->buffers);
}
}

Expand Down Expand Up @@ -71,8 +76,9 @@ void gc_page_profile_write_preamble(gc_page_profiler_serializer_t *serializer)
JL_NOTSAFEPOINT
{
if (__unlikely(page_profile_enabled)) {
char str[GC_TYPE_STR_MAXLEN];
snprintf(str, GC_TYPE_STR_MAXLEN,
const size_t large_enough_str_size = 4096;
char str[large_enough_str_size];
snprintf(str, large_enough_str_size,
"{\"address\": \"%p\",\"object_size\": %d,\"objects\": [",
serializer->data, serializer->osize);
ios_write(page_profile_stream, str, strlen(str));
Expand Down Expand Up @@ -102,29 +108,35 @@ void gc_page_profile_write_comma(gc_page_profiler_serializer_t *serializer) JL_N
void gc_page_profile_write_to_file(gc_page_profiler_serializer_t *serializer)
JL_NOTSAFEPOINT
{
size_t large_enough_str_size = 4096;
if (__unlikely(page_profile_enabled)) {
// write to file
uv_mutex_lock(&page_profile_lock);
gc_page_profile_write_comma(serializer);
gc_page_profile_write_preamble(serializer);
char str[GC_TYPE_STR_MAXLEN];
char *str = (char *)malloc_s(large_enough_str_size);
for (size_t i = 0; i < serializer->typestrs.len; i++) {
const char *name = (const char *)serializer->typestrs.items[i];
if (name == GC_SERIALIZER_EMPTY) {
snprintf(str, GC_TYPE_STR_MAXLEN, "\"empty\",");
snprintf(str, large_enough_str_size, "\"empty\",");
}
else if (name == GC_SERIALIZER_GARBAGE) {
snprintf(str, GC_TYPE_STR_MAXLEN, "\"garbage\",");
snprintf(str, large_enough_str_size, "\"garbage\",");
}
else {
snprintf(str, GC_TYPE_STR_MAXLEN, "\"%s\",", name);
while ((strlen(name) + 1) > large_enough_str_size) {
large_enough_str_size *= 2;
str = (char *)realloc_s(str, large_enough_str_size);
}
snprintf(str, large_enough_str_size, "\"%s\",", name);
}
// remove trailing comma for last element
if (i == serializer->typestrs.len - 1) {
str[strlen(str) - 1] = '\0';
}
ios_write(page_profile_stream, str, strlen(str));
}
free(str);
gc_page_profile_write_epilogue(serializer);
page_profile_pages_written++;
uv_mutex_unlock(&page_profile_lock);
Expand Down
93 changes: 88 additions & 5 deletions src/gc-page-profiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,29 @@
extern "C" {
#endif

#define GC_TYPE_STR_MAXLEN (512)
#define GC_PAGE_PROFILER_SERIALIZER_INIT_CAPACITY (4096)

typedef struct {
arraylist_t typestrs;
char *data;
int osize;
char *buffers;
size_t cursor;
size_t capacity;
} gc_page_profiler_serializer_t;

// mutex for page profile
extern uv_mutex_t page_profile_lock;
// whether page profiling is enabled
extern int page_profile_enabled;

// Serializer functions
gc_page_profiler_serializer_t gc_page_serializer_create(void) JL_NOTSAFEPOINT;
void gc_page_serializer_init(gc_page_profiler_serializer_t *serializer, jl_gc_pagemeta_t *pg) JL_NOTSAFEPOINT;
void gc_page_serializer_init(gc_page_profiler_serializer_t *serializer,
jl_gc_pagemeta_t *pg) JL_NOTSAFEPOINT;
void gc_page_serializer_destroy(gc_page_profiler_serializer_t *serializer) JL_NOTSAFEPOINT;
void gc_page_serializer_write(gc_page_profiler_serializer_t *serializer, const char *str) JL_NOTSAFEPOINT;
void gc_page_serializer_write(gc_page_profiler_serializer_t *serializer,
const char *str) JL_NOTSAFEPOINT;
// Page profile functions
#define GC_SERIALIZER_EMPTY ((const char *)0x1)
#define GC_SERIALIZER_GARBAGE ((const char *)0x2)
Expand All @@ -42,13 +49,89 @@ STATIC_INLINE void gc_page_profile_write_garbage(gc_page_profiler_serializer_t *
gc_page_serializer_write(serializer, GC_SERIALIZER_GARBAGE);
}
}
STATIC_INLINE char *gc_page_profile_request_buffer(gc_page_profiler_serializer_t *serializer, size_t size) JL_NOTSAFEPOINT
{
while (serializer->cursor + size >= serializer->capacity) {
serializer->capacity *= 2;
serializer->buffers = (char *)realloc_s(serializer->buffers, serializer->capacity);
}
char *p = &serializer->buffers[serializer->cursor];
memset(p, 0, size);
serializer->cursor += size;
return p;
}
STATIC_INLINE void gc_page_profile_write_live_obj(gc_page_profiler_serializer_t *serializer,
jl_taggedvalue_t *v,
int enabled) JL_NOTSAFEPOINT
{
if (__unlikely(enabled)) {
const char *name = jl_typeof_str(jl_valueof(v));
gc_page_serializer_write(serializer, name);
jl_value_t *a = jl_valueof(v);
jl_value_t *t = jl_typeof(a);
ios_t str_;
int ios_need_close = 0;
char *type_name = NULL;
char *type_name_in_serializer = NULL;
if (t == (jl_value_t *)jl_get_buff_tag()) {
type_name = "Buffer";
type_name_in_serializer =
gc_page_profile_request_buffer(serializer, strlen(type_name) + 1);
strcpy(type_name_in_serializer, type_name);
}
else if (jl_is_string(a)) {
type_name = "String";
type_name_in_serializer =
gc_page_profile_request_buffer(serializer, strlen(type_name) + 1);
strcpy(type_name_in_serializer, type_name);
}
else if (jl_is_symbol(a)) {
type_name = jl_symbol_name((jl_sym_t *)a);
type_name_in_serializer =
gc_page_profile_request_buffer(serializer, strlen(type_name) + 1);
strcpy(type_name_in_serializer, type_name);
}
else if (jl_is_simplevector(a)) {
type_name = "SimpleVector";
type_name_in_serializer =
gc_page_profile_request_buffer(serializer, strlen(type_name) + 1);
strcpy(type_name_in_serializer, type_name);
}
else if (jl_is_module(a)) {
type_name = jl_symbol_name_(((jl_module_t *)a)->name);
type_name_in_serializer =
gc_page_profile_request_buffer(serializer, strlen(type_name) + 1);
strcpy(type_name_in_serializer, type_name);
}
else if (jl_is_task(a)) {
type_name = "Task";
type_name_in_serializer =
gc_page_profile_request_buffer(serializer, strlen(type_name) + 1);
strcpy(type_name_in_serializer, type_name);
}
else if (jl_is_datatype(a)) {
ios_need_close = 1;
ios_mem(&str_, 0);
JL_STREAM *str = (JL_STREAM *)&str_;
jl_static_show(str, a);
type_name = str_.buf;
type_name_in_serializer =
gc_page_profile_request_buffer(serializer, str_.size + 1);
memcpy(type_name_in_serializer, type_name, str_.size);
}
else {
ios_need_close = 1;
ios_mem(&str_, 0);
JL_STREAM *str = (JL_STREAM *)&str_;
jl_static_show(str, t);
type_name = str_.buf;
type_name_in_serializer =
gc_page_profile_request_buffer(serializer, str_.size + 1);
memcpy(type_name_in_serializer, type_name, str_.size);
}
gc_page_serializer_write(serializer, type_name_in_serializer);
if (ios_need_close) {
ios_close(&str_);
}
jl_may_leak(type_name_in_serializer);
}
}
void gc_enable_page_profile(void) JL_NOTSAFEPOINT;
Expand Down
37 changes: 25 additions & 12 deletions src/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ jl_ptls_t* gc_all_tls_states;
gc_heapstatus_t gc_heap_stats = {0};
int next_sweep_full = 0;
const uint64_t _jl_buff_tag[3] = {0x4eadc0004eadc000ull, 0x4eadc0004eadc000ull, 0x4eadc0004eadc000ull}; // aka 0xHEADER00
JL_DLLEXPORT uintptr_t jl_get_buff_tag(void)
JL_DLLEXPORT uintptr_t jl_get_buff_tag(void) JL_NOTSAFEPOINT
{
return jl_buff_tag;
}
Expand Down Expand Up @@ -1659,18 +1659,32 @@ int gc_sweep_prescan(jl_ptls_t ptls, jl_gc_padded_page_stack_t *new_gc_allocd_sc
void gc_sweep_wake_all(jl_ptls_t ptls, jl_gc_padded_page_stack_t *new_gc_allocd_scratch)
{
int parallel_sweep_worthwhile = gc_sweep_prescan(ptls, new_gc_allocd_scratch);
jl_atomic_store(&gc_allocd_scratch, new_gc_allocd_scratch);
if (!parallel_sweep_worthwhile) {
if (parallel_sweep_worthwhile && !page_profile_enabled) {
jl_atomic_store(&gc_allocd_scratch, new_gc_allocd_scratch);
uv_mutex_lock(&gc_threads_lock);
for (int i = gc_first_tid; i < gc_first_tid + jl_n_markthreads; i++) {
jl_ptls_t ptls2 = gc_all_tls_states[i];
assert(ptls2 != NULL); // should be a GC thread
jl_atomic_fetch_add(&ptls2->gc_sweeps_requested, 1);
}
uv_cond_broadcast(&gc_threads_cond);
uv_mutex_unlock(&gc_threads_lock);
return;
}
uv_mutex_lock(&gc_threads_lock);
for (int i = gc_first_tid; i < gc_first_tid + jl_n_markthreads; i++) {
jl_ptls_t ptls2 = gc_all_tls_states[i];
assert(ptls2 != NULL); // should be a GC thread
jl_atomic_fetch_add(&ptls2->gc_sweeps_requested, 1);
if (page_profile_enabled) {
// we need to ensure that no threads are running sweeping when
// collecting a page profile.
// wait for all to leave in order to ensure that a straggler doesn't
// try to enter sweeping after we set `gc_allocd_scratch` below.
for (int i = gc_first_tid; i < gc_first_tid + jl_n_markthreads; i++) {
jl_ptls_t ptls2 = gc_all_tls_states[i];
assert(ptls2 != NULL); // should be a GC thread
while (jl_atomic_load_acquire(&ptls2->gc_sweeps_requested) != 0) {
jl_cpu_pause();
}
}
}
uv_cond_broadcast(&gc_threads_cond);
uv_mutex_unlock(&gc_threads_lock);
jl_atomic_store(&gc_allocd_scratch, new_gc_allocd_scratch);
}

// wait for all threads to finish sweeping
Expand Down Expand Up @@ -1813,8 +1827,7 @@ static void gc_sweep_pool(void)
}

// the actual sweeping
jl_gc_padded_page_stack_t *new_gc_allocd_scratch = (jl_gc_padded_page_stack_t *) malloc_s(n_threads * sizeof(jl_gc_padded_page_stack_t));
memset(new_gc_allocd_scratch, 0, n_threads * sizeof(jl_gc_padded_page_stack_t));
jl_gc_padded_page_stack_t *new_gc_allocd_scratch = (jl_gc_padded_page_stack_t *) calloc_s(n_threads * sizeof(jl_gc_padded_page_stack_t));
jl_ptls_t ptls = jl_current_task->ptls;
gc_sweep_wake_all(ptls, new_gc_allocd_scratch);
gc_sweep_pool_parallel(ptls);
Expand Down
2 changes: 1 addition & 1 deletion src/julia_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -536,7 +536,7 @@ JL_DLLEXPORT jl_value_t *jl_gc_alloc(jl_ptls_t ptls, size_t sz, void *ty);
// defined as uint64_t[3] so that we can get the right alignment of this and a "type tag" on it
const extern uint64_t _jl_buff_tag[3];
#define jl_buff_tag ((uintptr_t)LLT_ALIGN((uintptr_t)&_jl_buff_tag[1],16))
JL_DLLEXPORT uintptr_t jl_get_buff_tag(void);
JL_DLLEXPORT uintptr_t jl_get_buff_tag(void) JL_NOTSAFEPOINT;

typedef void jl_gc_tracked_buffer_t; // For the benefit of the static analyzer
STATIC_INLINE jl_gc_tracked_buffer_t *jl_gc_alloc_buf(jl_ptls_t ptls, size_t sz)
Expand Down