minimizing buffer size (i.e. page cache) for bulk copy/rsync -- Re: Swappiness in Buster
Anyone here able to answer this annoying buffer issue on bulk copies? ----- Forwarded message from Zenaan Harkness <zenaan@freedbms.net> ----- From: Zenaan Harkness <zenaan@freedbms.net> To: debian-user@lists.debian.org Date: Wed, 8 Jul 2020 17:52:06 +1000 Subject: minimizing buffer size (i.e. page cache) for bulk copy/rsync -- Re: Swappiness in Buster On Wed, Jul 08, 2020 at 08:26:18AM +0200, Martin Reissner wrote:
For the sake of completeness, I seem to have solved it after some more research and it turned out to be systemd, as following bug that was reported for Centos7 seems to be applying to Debian Buster as well:
https://github.com/systemd/systemd/issues/9276
Luckily the workaround mentioned in:
https://github.com/systemd/systemd/issues/9276#issuecomment-442514543
applies here as well and by setting this to the desired swappiness value and rebooting the system so far it seems to work as before and swapping out is only done if it can't be avoided.
Your thread brings to mind an "$AGE_OF_LINUX_KERNEL + 1 year" years old Linux kernel bona fydee, bulk copy bug bear: Doing a bulk copy e.g. using cp or rsync, to copy GiBs far greater than available RAM from one disk to another, results in ... <sinister musak please> Total Annihilation of Desktop Latency <sinister laugh> This happens to this day even on the latest Linux kernels on Sid such as 5.7.0-1-amd64 to pick an entirely random example... and has been literally bugging me since the beginnings of my Debian journey ~20 years ago. Note that in this extremely humble user's experience, even ionice --class Idle ... is not even able to quell the Memory Beast's all consuming hunger games for all possible RAM and then some, in it's insatiable appetite for all the page cache in... <more sinister musak please> The Entire Universe <sinister laugh> What needs to happen ™©® What is needed is an option somewhere, strictly abided by, where "For the following command" only say 1MiB of buffer and Page Cache, in TOTAL, is able to be used by that command ever, until its completion. In this way my 16GiBs of RAM will __finally__ be left to its rightful owners Firefox, mutt, and my XOrg's cursor, since to me as an extremely humble desktop user, these are the only things in the world that I ever care about, and I esPECIALLY want to NOT care that a 1,700 GiB movie disk backup takes an extra 5 or 10 % longer than the NINE hours it already takes across its USB 2 connection! Seriously, is there a way to stop bulk copies from eternally flushing my $Desktop's cached pages down the drain minute after blessful minute, hour after gratitude filled hour? The heavens will truly be pleased .. ----- End forwarded message -----
‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐ On Wednesday, July 8, 2020 7:53 AM, Zenaan Harkness <zen@freedbms.net> wrote:
Anyone here able to answer this annoying buffer issue on bulk copies?
[ paraphrasing: page cache gets swamped by bulk copy, driving interactive desktop applications to heavy latency... ] use an LD_PRELOAD hack to force mlock() on the apps you want to keep interactive: https://stackoverflow.com/questions/37818335/mlock-a-program-from-a-wrapper --- If you have the sources for the program, add a command-line option so that the program calls mlockall(MCL_CURRENT | MCL_FUTURE) at some point. That locks it in memory. If you want to control the address spaces the kernel loads the program into, you need to delve into kernel internals. Most likely, there is no reason to do so; only people with really funky hardware would. If you don't have the sources, or don't want to recompile the program, then you can create a dynamic library that executes the command, and inject it into the process via LD_PRELOAD. Save the following as lockall.c: #include <stdlib.h> #include <unistd.h> #include <sys/mman.h> #include <string.h> #include <errno.h> static void wrerr(const char *p) { if (p) { const char *q = p + strlen(p); ssize_t n; while (p < q) { n = write(STDERR_FILENO, p, (size_t)(q - p)); if (n > 0) p += n; else if (n != -1 || errno != EINTR) return; } } } static void init(void) __attribute__((constructor)); static void init(void) { int saved_errno = errno; if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) { const char *errmsg = strerror(errno); wrerr("Cannot lock all memory: "); wrerr(errmsg); wrerr(".\n"); exit(127); } else wrerr("All memory locked.\n"); errno = saved_errno; } Compile it to a dynamic library liblockall.so using gcc -Wall -O2 -fPIC -shared lockall.c -Wl,-soname,liblockall.so -o liblockall.so Install the library somewhere typical, for example sudo install -o 0 -g 0 -m 0664 liblockall.so /usr/lib/ so you can run any binary, and lock it into memory, using LD_PRELOAD=liblockall.so binary arguments.. If you install the library somewhere else (not listed in /etc/ld.so.conf), you'll need to specify path to the library, like LD_PRELOAD=/usr/lib/liblockall.so binary arguments.. Typically, you'll see the message Cannot lock all memory: Cannot allocate memory. printed by the interposed library, when running commands as a normal user. (The superuser, or root, typically has no such limit.) This is because for obvious reasons, most Linux distributions limit the amount of memory an unprivileged user can lock into memory; this is the RLIMIT_MEMLOCK resource limit. Run ulimit -l to see the per-process resource limits currently set (for the current user, obviously). I suggest you set a suitable limit of how much memory the process can run, running e.g. ulimit -l 16384 bash-built-in before executing the (to set the limit to 16384*1024 bytes, or 16 MiB), if running as superuser (root). If the process leaks memory, instead of crashing your machine (because it locked all available memory), the process will die (from SIGSEGV) if it exceeds the limit. That is, you'd start your process using ulimit -l 16384 LD_PRELOAD=/usr/lib/liblockall.so binary arguments.. if using Bash or dash shell. If running as a dedicated user, most distributions use the pam_limits.so PAM module to set the resource limits "automatically". The limits are listed either in the /etc/security/limits.conf file, or in a file in the /etc/security/limits.d/ subdirectory, using this format; the memlock item specifies the amount of memory each process can lock, in units of 1024 bytes. So, if your service runs as user mydev, and you wish to allow the user to lock up to 16 megabytes = 16384*1024 bytes per process, then add line mydev - memlock 16384 into /etc/security/limits.conf or /etc/security/limits.d/mydev.conf, whichever your Linux distribution prefers/suggests. Prior to PAM, shadow-utils were used to control the resource limits. The memlock resource limit is specified in units of 1024 bytes; a limit of 16 megabytes would be set using M16384. So, if using shadow-utils instead of PAM, adding line mydev M16384 (followed by whatever the other limits you wish to specify) to /etc/limits should do the trick. ---end-cut--- best regards,
participants (2)
-
coderman
-
Zenaan Harkness