Add dynamic untracked memory limits for more precise memory tracking#101251
Add dynamic untracked memory limits for more precise memory tracking#101251azat wants to merge 4 commits into
Conversation
9d23adc to
f1f1f1b
Compare
|
The Stress test (arm_msan) failure is fixed by #101239, which should be merged first. After it is merged, please update the branch to include the fix. |
|
The MSan stress test failure (MemorySanitizer: use-of-uninitialized-value, STID 4179-5154 or 4148-3044) is a known pre-existing issue unrelated to this PR. Fix: #102158 |
|
The |
|
@serxa PTAL |
|
Here is also a way for |
8ad391b to
b5433a6
Compare
|
I've looked at performance regressions:
So I think this is acceptable, I'm going to add profile event (hope it will not slows down even more) Note: I've tried to add metrics for all allocations, and it slows down - #85545, hence only when MemoryTracker is called |
b5433a6 to
aa50660
Compare
7efdb6c to
10b62fe
Compare
The current memory tracker has an error of up to `untracked_memory_limit = 4MB` per thread. Consider a ClickHouse server running with 8GB RAM and a standard `max_server_memory_usage_to_ram_ratio = 0.9` server setting. If there are 1000 threads (and every thread has 800KB on average) OOM can happen before any query is stopped with `MEMORY_LIMIT_EXCEEDED`. We need total untracked memory to be proportional to current memory usage regardless of the number of threads. To make it fit into 10% RAM we want an error to be less than e.g. 6%. To achieve it we need `untracked_memory_limit` to be updated dynamically and be proportional to current thread memory usage for threads with small memory footprint: `untracked_memory_limit = clamp(already_tracked / 16, 4KB, 4MB)` Resubmit of: ClickHouse#64423 Co-authored-by: Azat Khuzhin <a3at.mail@gmail.com>
10b62fe to
1e19934
Compare
| if (current_thread->untracked_memory < -current_thread->untracked_memory_limit) | ||
| /// Use `max_untracked_memory` (not `untracked_memory_limit`) to create hysteresis and avoid track/untrack cycles | ||
| if (current_thread->untracked_memory < -current_thread->max_untracked_memory) | ||
| { |
There was a problem hiding this comment.
Using max_untracked_memory as the flush threshold for deallocations can permanently overcount memory after short-lived spikes.
Concrete trace:
min_untracked_memory = 4KiB,max_untracked_memory = 4MiB.- Allocate
1MiB-> allocation flushes (because current limit is small), somemory_trackerincreases by1MiB. - Free
1MiB->untracked_memory = -1MiB, but this branch does not flush because-1MiB > -max_untracked_memory. - Next alloc/free cycles of
1MiBkeepuntracked_memoryoscillating between0and-1MiB, so the previously tracked1MiBis never released to parent trackers.
This means query/global trackers can stay overestimated by up to ~max_untracked_memory per thread for a long time, which can trigger premature MEMORY_LIMIT_EXCEEDED under concurrency. I think the deallocation flush condition should stay tied to the current dynamic limit (or another dynamic lower bound), not a fixed max_untracked_memory.
There was a problem hiding this comment.
I think initially different bounds for alloc/dealloc were introduced to avoid too many tracker invocations in corner cases, but now it seems to be unavoidable when I think about it
There was a problem hiding this comment.
I also thought about this for awhile and decided to try this option, plus, I don't see too much benefits - https://pastila.nl/?009ef774/015773a63df85587f4c9889ec3f9186f#0Ruws2sMXI1d4WKqcrjt0A==GCM
And also maybe we can speedup MemoryTracker - #103464
| @@ -0,0 +1,3 @@ | |||
| profiles: | |||
| default: | |||
| min_untracked_memory: 4Mi | |||
There was a problem hiding this comment.
All updated tests in this PR pin min_untracked_memory back to 4Mi, so the new default dynamic behavior (4KiB lower bound) is not covered.
Could we add at least one test that keeps defaults and verifies the new path (reduced untracked error / earlier memory-limit reaction) to protect against regressions?
LLVM Coverage Report
Changed lines: 100.00% (62/62) · Uncovered code |
|
Take a look at this code: https://github.com/ClickHouse/vskipin-experiments/blob/master/src/util/memory-tracker.h |
|
Here is an alternative - #106055 |
|
Alternative has been merged and it looks better |

Changelog category (leave one):
Changelog entry (a user-readable short description of the changes that goes into CHANGELOG.md):
Add dynamic untracked memory limits for more precise memory tracking
Original comment from @serxa:
The current memory tracker has an error of up to
untracked_memory_limit = 4MBper thread. Consider a ClickHouse server running with 8GB RAM and a standardmax_server_memory_usage_to_ram_ratio = 0.9server setting. If there are 1000 threads (and every thread has 800KB on average) OOM can happen before any query is stopped withMEMORY_LIMIT_EXCEEDED.We need total untracked memory to be proportional to current memory usage regardless of the number of threads. To make it fit into 10% RAM we want an error to be less than e.g. 6%. To achieve it we need
untracked_memory_limitto be updated dynamically and be proportional to current thread memory usage for threads with small memory footprint:untracked_memory_limit = clamp(already_tracked / 16, 4KB, 4MB)Resubmit of: #64423 (by @serxa)
Note: marked as
Performance Improvementfor run perf tests and memory accounting can be also "performance imporvement"