Download code/tt_bevfusion/host/malloc.py from changh95/bevfusion-p150: direct link, hf CLI and curl.
- Browser
- Download file 2.53 kB
-
https://huggingface.co/changh95/bevfusion-p150/resolve/main/code/tt_bevfusion/host/malloc.py
- Command line
-
hf download hf://changh95/bevfusion-p150/code/tt_bevfusion/host/malloc.py
-
curl -L -o malloc.py https://huggingface.co/changh95/bevfusion-p150/resolve/main/code/tt_bevfusion/host/malloc.py
2.53 kB
| # SPDX-License-Identifier: Apache-2.0 | |
| """OPT_PLAN H7 (``BEVFUSION_HOST_MALLOC``): keep glibc from returning freed per-frame memory to the kernel. | |
| A frame allocates and frees tens of MB of short-lived arrays (the rulebook maps, the voxelizer's per-point arrays, | |
| the decoded cloud). With glibc's defaults the freed top of the heap is trimmed (and large blocks are unmapped), so | |
| the next frame takes those pages again as minor page faults: 15-17 MB (3.8-4.3 k faults, ~9 ms) per PandaSet | |
| pre-processing call on this host (OPT_REPORT round 7). ``mallopt`` is process-wide, so this is applied once at model | |
| load; it only changes when memory goes back to the kernel (the resident size stays at the per-frame peak). | |
| - ``default``: glibc as is; | |
| - ``trim``: ``M_TRIM_THRESHOLD`` = 512 MiB (no top-of-heap trim below it) and ``M_MMAP_THRESHOLD`` = 32 MiB (glibc's | |
| maximum). Setting either one freezes glibc's dynamic mmap threshold; frozen at its 128 KiB start (the model loads | |
| this before its large arrays) every per-frame array would be a fresh mapping, which round 7 measured as slower | |
| than the default, so the threshold is set explicitly; | |
| - ``arena1``: ``trim`` + ``M_ARENA_MAX`` = 1 (worker threads allocate from the main heap too, so their frames reuse | |
| the same pages; the threads then share the arena lock). | |
| """ | |
| from __future__ import annotations | |
| import ctypes | |
| import ctypes.util | |
| from typing import Optional | |
| __all__ = ["MODES", "apply"] | |
| MODES = ("default", "trim", "arena1") | |
| M_TRIM_THRESHOLD = -1 | |
| M_ARENA_MAX = -8 | |
| M_MMAP_THRESHOLD = -3 | |
| MMAP_BYTES = 32 << 20 | |
| TRIM_BYTES = 512 << 20 | |
| _APPLIED: Optional[str] = None | |
| def apply(mode: str) -> Optional[str]: | |
| """Apply ``mode`` once per process (later calls with another mode are ignored); returns the applied mode or None | |
| (``default``, or not glibc).""" | |
| global _APPLIED | |
| if mode not in MODES: | |
| raise ValueError(f"HOST_MALLOC must be one of {MODES}") | |
| if mode == "default" or _APPLIED is not None: | |
| return _APPLIED | |
| try: | |
| libc = ctypes.CDLL(ctypes.util.find_library("c") or "libc.so.6") | |
| mallopt = libc.mallopt | |
| except (OSError, AttributeError): # not glibc (musl, macOS): nothing to tune | |
| return None | |
| mallopt.argtypes = [ctypes.c_int, ctypes.c_int] | |
| mallopt.restype = ctypes.c_int | |
| ok = mallopt(M_MMAP_THRESHOLD, MMAP_BYTES) == 1 and mallopt(M_TRIM_THRESHOLD, TRIM_BYTES) == 1 | |
| if ok and mode == "arena1": | |
| ok = mallopt(M_ARENA_MAX, 1) == 1 | |
| _APPLIED = mode if ok else None | |
| return _APPLIED | |