Add host memory limits - #1193
Conversation
- Track pageable-host allocations through the generalized resource adaptor. - Add an absolute, unbounded-by-default host memory limit. - Reconcile pageable and pinned-host budgets and reject invalid pinned limits. - Extend statistics, Python bindings, documentation, and tests. Signed-off-by: niranda perera <niranda.perera@gmail.com>
f0bf4cb to
e1566bd
Compare
| * The limit must be an absolute byte count. Disabled values produce an | ||
| * unbounded pageable-host budget. This limit is independent of | ||
| * `pinned_max_pool_size`. When both limits are bounded, | ||
| * `BufferResource::from_options()` rejects configurations where their sum | ||
| * exceeds the summed host memory of the nodes in the calling thread's memory | ||
| * policy. The pinned maximum is also constrained by the host memory of its | ||
| * NUMA node. |
There was a problem hiding this comment.
So now users have two limits they have to independently set not to cause a host OOM? If so, I don't think this is a good UX, it will be difficult for users to ensure they're both within safe limits.
Also, while the sum of the two is in theory correct, in practice this is an unfeasible limit, since OS alone takes non-negligible amounts of memory. I don't know what would be a safe value, but perhaps looking at the amount of free memory when the process is starting minus some percentage is more reasonable.
There was a problem hiding this comment.
I see your point.
One issue I had was, what should be the max limit for HOST memory?
In multi GPU nodes, I think its correct to limit PINNED to host_memory_per_gpu because a pool can only be assigned to a single numa ID. But HOST can span across numa nodes.
But since we are running with rrun (or with apply_bindings), I think the processes will have MPOL_BIND set to proper numa nodes.
So, in that case, HOST + PINNED < get_numa_node_host_memory(get_current_numa_node()) IINM.
Getting free memory is a reasonable idea. let me look at that
| if (host_limit != unbounded && pinned_limit != unbounded) { | ||
| auto const numa_host = safe_cast<std::int64_t>( | ||
| get_numa_node_host_memory(pinned_pool_properties->numa_id) | ||
| ); | ||
| RAPIDSMPF_EXPECTS( | ||
| pinned_limit <= numa_host, | ||
| "pinned_max_pool_size exceeds NUMA node host memory", | ||
| std::invalid_argument | ||
| ); |
There was a problem hiding this comment.
Could we move the pinned_limit <= numa_host validation outside this combined bounded-host/bounded-pinned condition, and mirror that change in the Python from_options() path? As written, pinned_max_pool_size can be set above its NUMA node’s host memory whenever spill_host_limit is left at its default "disabled". That contradicts the new configuration documentation and accepts an incompatible pool configuration, only the combined pageable+pinned budget check needs both limits to be bounded. Please add also coverage for a bounded oversized pinned limit with spill_host_limit=disabled.
There was a problem hiding this comment.
@pentschev I am not sure if I understood you correctly. spill_host_limit=="disabled" implies that host memory is unbounded. if pinned_pool_max_size is not set, but spill_host_limit is set, we cant reliably ensure host_limit <= total_host - pinned_limit during BR creation.
| - **Description**: Soft upper limit on pageable host memory configured for | ||
| RapidsMPF, independent of `pinned_max_pool_size`. When both limits are | ||
| bounded, their sum cannot exceed the summed host memory of the nodes in the | ||
| calling thread's memory policy; the pinned maximum also cannot exceed its | ||
| NUMA node's host memory. This is a coarse validation because other processes | ||
| and allocations may consume the same host memory. It accepts absolute byte | ||
| counts (for example, `"10GiB"` or `"512MB"`). Percentages are not supported | ||
| because the appropriate host-memory share depends on the job's process and | ||
| NUMA topology. |
There was a problem hiding this comment.
This looks closer to proper docstrings than that from host_limit_from_options. However, those same issues are still relevant, perhaps taking into account the free memory is more realistic. I also don't understand how depending on job's processes/NUMA topology voids the potential for using percentages.
| # means pinned host memory is disabled. | ||
| cdef optional[cpp_PinnedPoolProperties] props = \ | ||
| pinned_pool_properties_from_options(options._handle) | ||
| unbounded = 2**63 - 1 |
There was a problem hiding this comment.
from libc.stdint cimport INT64_MAX, int64_t
...
cdef int64_t unbounded = INT64_MAXSigned-off-by: niranda perera <niranda.perera@gmail.com>
Signed-off-by: niranda perera <niranda.perera@gmail.com>
|
@pentschev I thought the I think we can not reliably use a % of available/ free memory. It may give use an earlier signal before an OOM, but
So, I decided to leave |
Pageable-host allocations were not tracked, and pinned-pool limits were not reflected in reservation accounting, allowing reservations beyond the configured pool maximum. This adds the host-memory accounting and limit handling needed for disk-spill decisions.
spill_host_limit, unbounded by default, and derive the pageable-host budget after accounting for bounded pinned memory.pinned_max_pool_sizeinto reservation limits, supportingdisabledas unbounded, and rejecting zero or incompatible limits.This is related to #1170. IMO it would be a nice to have change in general.
Option Defaults
pinned_memorypinned_initial_pool_sizepinned_max_pool_sizespill_host_limitEffect on PINNED_HOST and HOST
Following table shows the effect on memory limits based on different option settings.
pinned_memorypinned_max_pool_sizespill_host_limitPINNED_HOSTlimitHOSTlimit00pinned_max <= numa_hostpinned_max <= numa_host, thenspill_host_limit <= total_numa_host - pinned_maxnuma_host= host memory of current numa nodetotal_numa_host= host memory of current numa nodes (governed by numa policy setting)pinned_max_pool_sizeis set, it should be greater-than zeroIndicative values
Ideally,
pinned_max_pool_size + spill_host_limit <= 80% host_mem_per_gpu