Set MMAP_THRESHOLD to a fixed value (128K)
glibc's malloc has a misguided heuristic to detect transient allocations that will just result in allocation sizes below 32 MiB never using mmap. That it turn means that those relatively big allocations are on the heap where cleanup and returning memory to the OS is harder to do and easier to be blocked by long living, small allocations at the top (end) of the heap. Observing the malloc size distribution in a file-level backup run: @size: [0] 14 | | [1] 25214 |@@@@@ | [2, 4) 9090 |@ | [4, 8) 12987 |@@ | [8, 16) 93453 |@@@@@@@@@@@@@@@@@@@@ | [16, 32) 30255 |@@@@@@ | [32, 64) 237445 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@| [64, 128) 32692 |@@@@@@@ | [128, 256) 22296 |@@@@ | [256, 512) 16177 |@@@ | [512, 1K) 5139 |@ | [1K, 2K) 3352 | | [2K, 4K) 214 | | [4K, 8K) 1568 | | [8K, 16K) 95 | | [16K, 32K) 3457 | | [32K, 64K) 3175 | | [64K, 128K) 161 | | [128K, 256K) 453 | | [256K, 512K) 93 | | [512K, 1M) 74 | | [1M, 2M) 774 | | [2M, 4M) 319 | | [4M, 8M) 700 | | [8M, 16M) 93 | | [16M, 32M) 18 | | We see that all allocations will be on the heap, and that while most allocations are small, the relatively few big ones will still make up most of the RSS and if blocked from being released back to the OS result in much higher peak and average usage for the program than actually required. Avoiding the "dynamic" mmap-threshold increasement algorithm and fixing it at the original default of 128 KiB reduces RSS size by factor 10-20 when running backups. As with memory mappings other mappings or the heap can never block freeing the memory fully back to the OS. But, the drawback of using mmap is more wasted space for unaligned or small allocation sizes, and the fact that the kernel allegedly zeros out the data before giving it to user space. The former doesn't really matter for us when using it only for allocations bigger than 128 KiB, and the latter is a trade-off, using 10 to 20 times less memory brings its own performance improvement possibilities for the whole system after all ;-) Signed-off-by: Dietmar Maurer <dietmar@proxmox.com> [ Thomas: added to comment & commit message + extra-empty-line fixes ] Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
This commit is contained in:
parent
3af17d8919
commit
d91a0f9fc9
|
@ -8,3 +8,22 @@ pub mod sha;
|
|||
pub mod ticket;
|
||||
|
||||
pub mod async_lru_cache;
|
||||
|
||||
/// Set MMAP_THRESHOLD to a fixed value (128 KiB)
|
||||
///
|
||||
/// This avoids the "dynamic" mmap-treshold logic from glibc's malloc, which seems misguided and
|
||||
/// effectively avoids using mmap for all allocations smaller than 32 MiB. Which, in combination
|
||||
/// with the allocation pattern from our/tokio's complex async machinery, resulted in very large
|
||||
/// RSS sizes due to defragmentation and long-living (smaller) allocation on top of the heap
|
||||
/// avoiding that the (big) now free'd allocations below couldn't get given back to the OS. This is
|
||||
/// not an issue with mmap'd memeory chunks, those can be given back at any time.
|
||||
///
|
||||
/// Lowering effective MMAP treshold to 128 KiB allows freeing up memory to the OS better and with
|
||||
/// lower latency, which reduces the peak *and* average RSS size by an order of magnitude when
|
||||
/// running backup jobs. We measured a reduction by a factor of 10-20 in experiments and see much
|
||||
/// less erratic behavior in the overall's runtime RSS size.
|
||||
pub fn setup_libc_malloc_opts() {
|
||||
unsafe {
|
||||
libc::mallopt(libc::M_MMAP_THRESHOLD, 4096*32);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1464,6 +1464,7 @@ impl ReadAt for BufferedDynamicReadAt {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
pbs_tools::setup_libc_malloc_opts();
|
||||
|
||||
let backup_cmd_def = CliCommand::new(&API_METHOD_CREATE_BACKUP)
|
||||
.arg_param(&["backupspec"])
|
||||
|
|
|
@ -38,6 +38,8 @@ lazy_static! {
|
|||
|
||||
/// This is expected to be run by 'proxmox-file-restore' within a mini-VM
|
||||
fn main() -> Result<(), Error> {
|
||||
pbs_tools::setup_libc_malloc_opts();
|
||||
|
||||
if !Path::new(VM_DETECT_FILE).exists() {
|
||||
bail!(
|
||||
"This binary is not supposed to be run manually, use 'proxmox-file-restore' instead."
|
||||
|
|
|
@ -19,6 +19,8 @@ use proxmox_backup::auth_helpers::*;
|
|||
use proxmox_backup::config;
|
||||
|
||||
fn main() {
|
||||
pbs_tools::setup_libc_malloc_opts();
|
||||
|
||||
proxmox_backup::tools::setup_safe_path_env();
|
||||
|
||||
if let Err(err) = proxmox_async::runtime::main(run()) {
|
||||
|
|
|
@ -73,6 +73,8 @@ use proxmox_backup::server::do_verification_job;
|
|||
use proxmox_backup::server::do_prune_job;
|
||||
|
||||
fn main() -> Result<(), Error> {
|
||||
pbs_tools::setup_libc_malloc_opts();
|
||||
|
||||
proxmox_backup::tools::setup_safe_path_env();
|
||||
|
||||
let backup_uid = pbs_config::backup_user()?.uid;
|
||||
|
|
Loading…
Reference in New Issue