mirror of
https://github.com/hanzoai/datastore.git
synced 2026-09-26 13:55:07 +00:00
Fix jemalloc background thread busy-spin on macOS (clock mismatch)
On macOS, `nstime_get` used `mach_absolute_time` (a monotonic uptime clock) because `JEMALLOC_HAVE_MACH_ABSOLUTE_TIME` was defined in the Darwin config headers, while the background thread's condition variable is created with the default clock (`CLOCK_REALTIME`): macOS has no `pthread_condattr_setclock`, and jemalloc only attempts to bind the condvar to a monotonic clock when `JEMALLOC_HAVE_CLOCK_MONOTONIC[_COARSE]` is defined (it is not, on Darwin). `background_thread_sleep` builds the `pthread_cond_timedwait` deadline from the `nstime` (uptime) clock and passes it to a `CLOCK_REALTIME` wait. The uptime value is decades behind the realtime epoch, so the deadline is always in the past and the wait returns `ETIMEDOUT` immediately - the background thread busy-spins a CPU core during the whole decay window instead of sleeping for `dirty_decay_ms`. This would replace the old `madvise` storm with a hot background-thread loop on exactly the allocation-churning workload that enabling `background_thread:true` was meant to speed up. Fix: undef `JEMALLOC_HAVE_MACH_ABSOLUTE_TIME` in the Darwin headers so `nstime_get` falls back to `gettimeofday` (`CLOCK_REALTIME`) - the same clock the condvar waits on - so the timed-wait deadline is honoured. This is the canonical clock for `pthread_cond_timedwait` on macOS. Linux and FreeBSD are unaffected (they use their own config headers). This is a prerequisite for `JEMALLOC_BACKGROUND_THREAD` to work correctly on macOS, enabled in the previous commits of this branch. See https://github.com/ClickHouse/ClickHouse/issues/108429 Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
d660d0cfcc
commit
3b3c99a08d
@@ -59,6 +59,12 @@ else()
|
||||
# JEMALLOC_BACKGROUND_THREAD and switching malloc_mutex_t to pthread_mutex_t (undef
|
||||
# JEMALLOC_OS_UNFAIR_LOCK), as on Linux and FreeBSD.
|
||||
#
|
||||
# In the same Darwin headers we also undef JEMALLOC_HAVE_MACH_ABSOLUTE_TIME so that nstime_get() uses
|
||||
# gettimeofday() (CLOCK_REALTIME). macOS cannot bind a pthread condition variable to a monotonic clock
|
||||
# (no pthread_condattr_setclock), so the background thread waits on CLOCK_REALTIME; nstime must use the
|
||||
# same clock, otherwise the pthread_cond_timedwait() deadline is always in the past and the thread
|
||||
# busy-spins instead of sleeping for dirty_decay_ms.
|
||||
#
|
||||
# Previously dirty_decay_ms was set to 0 here (immediate purging) to bound RSS, under the assumption
|
||||
# that background_thread was unavailable. That assumption was wrong, and immediate purging is very
|
||||
# expensive for allocation-churning workloads (e.g. recursive CTEs): every free issues a madvise()
|
||||
|
||||
+17
-1
@@ -112,8 +112,24 @@
|
||||
|
||||
/*
|
||||
* Defined if mach_absolute_time() is available.
|
||||
*
|
||||
* ClickHouse: intentionally left undefined so that nstime_get() falls back to
|
||||
* gettimeofday() (CLOCK_REALTIME). With this defined, nstime_get() uses
|
||||
* mach_absolute_time(), a monotonic uptime clock. But the background thread's
|
||||
* condition variable is created with the default clock (CLOCK_REALTIME): macOS
|
||||
* provides no pthread_condattr_setclock to bind it to a monotonic clock, and
|
||||
* jemalloc only attempts that when JEMALLOC_HAVE_CLOCK_MONOTONIC[_COARSE] is
|
||||
* defined, which it is not here. background_thread_sleep() builds the
|
||||
* pthread_cond_timedwait() deadline from the nstime (uptime) clock and passes
|
||||
* it to a CLOCK_REALTIME wait; the uptime value is decades behind the realtime
|
||||
* epoch, so the deadline is always in the past and the wait returns ETIMEDOUT
|
||||
* immediately - the background thread busy-spins a CPU core instead of sleeping
|
||||
* for dirty_decay_ms. Falling back to gettimeofday() makes nstime_get() use the
|
||||
* same clock the condvar waits on (CLOCK_REALTIME), so the deadline is honoured.
|
||||
* This is a prerequisite for JEMALLOC_BACKGROUND_THREAD to work correctly on
|
||||
* macOS. See https://github.com/ClickHouse/ClickHouse/issues/108429
|
||||
*/
|
||||
#define JEMALLOC_HAVE_MACH_ABSOLUTE_TIME
|
||||
/* #undef JEMALLOC_HAVE_MACH_ABSOLUTE_TIME */
|
||||
|
||||
/*
|
||||
* Defined if clock_gettime(CLOCK_REALTIME, ...) is available.
|
||||
|
||||
+17
-1
@@ -112,8 +112,24 @@
|
||||
|
||||
/*
|
||||
* Defined if mach_absolute_time() is available.
|
||||
*
|
||||
* ClickHouse: intentionally left undefined so that nstime_get() falls back to
|
||||
* gettimeofday() (CLOCK_REALTIME). With this defined, nstime_get() uses
|
||||
* mach_absolute_time(), a monotonic uptime clock. But the background thread's
|
||||
* condition variable is created with the default clock (CLOCK_REALTIME): macOS
|
||||
* provides no pthread_condattr_setclock to bind it to a monotonic clock, and
|
||||
* jemalloc only attempts that when JEMALLOC_HAVE_CLOCK_MONOTONIC[_COARSE] is
|
||||
* defined, which it is not here. background_thread_sleep() builds the
|
||||
* pthread_cond_timedwait() deadline from the nstime (uptime) clock and passes
|
||||
* it to a CLOCK_REALTIME wait; the uptime value is decades behind the realtime
|
||||
* epoch, so the deadline is always in the past and the wait returns ETIMEDOUT
|
||||
* immediately - the background thread busy-spins a CPU core instead of sleeping
|
||||
* for dirty_decay_ms. Falling back to gettimeofday() makes nstime_get() use the
|
||||
* same clock the condvar waits on (CLOCK_REALTIME), so the deadline is honoured.
|
||||
* This is a prerequisite for JEMALLOC_BACKGROUND_THREAD to work correctly on
|
||||
* macOS. See https://github.com/ClickHouse/ClickHouse/issues/108429
|
||||
*/
|
||||
#define JEMALLOC_HAVE_MACH_ABSOLUTE_TIME
|
||||
/* #undef JEMALLOC_HAVE_MACH_ABSOLUTE_TIME */
|
||||
|
||||
/*
|
||||
* Defined if clock_gettime(CLOCK_REALTIME, ...) is available.
|
||||
|
||||
Reference in New Issue
Block a user