diff --git a/ddtrace/profiling/collector/_memalloc.c b/ddtrace/profiling/collector/_memalloc.c index 3876517baaf..f3de61a7b2c 100644 --- a/ddtrace/profiling/collector/_memalloc.c +++ b/ddtrace/profiling/collector/_memalloc.c @@ -57,6 +57,28 @@ static alloc_tracker_t* global_alloc_tracker; static void memalloc_init(void); +static void +memalloc_prefork(void) +{ + // Lock the mutex prior to forking. This ensures that the memory profiler + // data structures will be in a consistent state in the child process. + // The rest of the memalloc calls do trylock so we don't run the risk + // of deadlocking if some other fork handler allocates + memlock_lock(&g_memalloc_lock); +} + +static void +memalloc_postfork_parent(void) +{ + memlock_unlock(&g_memalloc_lock); +} + +static void +memalloc_postfork_child(void) +{ + memlock_unlock(&g_memalloc_lock); +} + #ifdef _MSC_VER #pragma section(".CRT$XCU", read) __declspec(allocate(".CRT$XCU")) void (*memalloc_init_func)(void) = memalloc_init; @@ -81,6 +103,9 @@ memalloc_init() } } memlock_init(&g_memalloc_lock, crash_on_mutex_pass); +#ifndef _WIN32 + pthread_atfork(memalloc_prefork, memalloc_postfork_parent, memalloc_postfork_child); +#endif } static void diff --git a/ddtrace/profiling/collector/_memalloc_heap.c b/ddtrace/profiling/collector/_memalloc_heap.c index d2a5cc29eee..11e0d8dba8e 100644 --- a/ddtrace/profiling/collector/_memalloc_heap.c +++ b/ddtrace/profiling/collector/_memalloc_heap.c @@ -36,6 +36,25 @@ static heap_tracker_t global_heap_tracker; static void memheap_init(void); +static void +memheap_prefork(void) +{ + // See memalloc_prefork for an explanation of why this is here + memlock_lock(&g_memheap_lock); +} + +static void +memheap_postfork_parent(void) +{ + memlock_unlock(&g_memheap_lock); +} + +static void +memheap_postfork_child(void) +{ + memlock_unlock(&g_memheap_lock); +} + #ifdef _MSC_VER #pragma section(".CRT$XCU", read) __declspec(allocate(".CRT$XCU")) void (*memheap_init_func)(void) = memheap_init; @@ -60,6 +79,9 @@ memheap_init() } } memlock_init(&g_memheap_lock, crash_on_mutex_pass); +#ifndef _WIN32 + pthread_atfork(memheap_prefork, memheap_postfork_parent, memheap_postfork_child); +#endif } static uint32_t diff --git a/ddtrace/profiling/collector/_memalloc_reentrant.h b/ddtrace/profiling/collector/_memalloc_reentrant.h index cb4aa246961..54a07320236 100644 --- a/ddtrace/profiling/collector/_memalloc_reentrant.h +++ b/ddtrace/profiling/collector/_memalloc_reentrant.h @@ -125,19 +125,6 @@ memlock_trylock(memlock_t* lock) if (!lock) return false; -#ifdef __linux__ - // On Linux, we need to make sure we didn't just fork - // pthreads will guarantee the lock is consistent, but we at least need to clear it - static pid_t my_pid = 0; - if (my_pid == 0) { - my_pid = getpid(); - } else if (my_pid != getpid()) { - // We've forked, so we need to free the lock - memlock_unlock(lock); - my_pid = getpid(); - } -#endif - #ifdef _WIN32 bool result = WAIT_OBJECT_0 == WaitForSingleObject(lock->mutex, 0); // 0ms timeout -> no wait #else @@ -153,6 +140,19 @@ memlock_trylock(memlock_t* lock) return result; } +static inline void +memlock_lock(memlock_t* lock) +{ + if (!lock) + return; + +#ifdef _WIN32 + WaitForSingleObject(lock->mutex, INFINITE); +#else + pthread_mutex_lock(&lock->mutex); +#endif +} + // Cleanup function static inline bool memlock_destroy(memlock_t* lock) diff --git a/releasenotes/notes/profiling-remove-getpid-from-memalloc-74f54043accdfc9e.yaml b/releasenotes/notes/profiling-remove-getpid-from-memalloc-74f54043accdfc9e.yaml new file mode 100644 index 00000000000..1680dba0673 --- /dev/null +++ b/releasenotes/notes/profiling-remove-getpid-from-memalloc-74f54043accdfc9e.yaml @@ -0,0 +1,5 @@ +--- +fixes: + - | + profiling: Removed a system call from the memory allocation profiler, used to detect forks, + which ran on every allocation and resulted in a significant slowdown.