xz: Read MemAvailable from /proc/meminfo on Linux.

This uses 75 % of MemAvailable as the default soft memory usage limit
for -T0. It can be checked with --info-memory.

The use of MemAvailable was first suggested by
Sebastian Andrzej Siewior in 2021. This is a different
implementation, including the 75 % part.
This commit is contained in:
Lasse Collin 2024-02-28 19:55:48 +02:00
parent a94b42362c
commit b38da4a8bf
1 changed files with 54 additions and 4 deletions

View File

@ -307,19 +307,69 @@ hardware_memlimit_show(void)
} }
#ifdef __linux__
static uint64_t
get_available_ram(void)
{
FILE *f = fopen("/proc/meminfo", "r");
if (f == NULL)
return 0;
// The information is near the very beginning of the file.
char buf[256];
// Read one byte less than sizeof(buf) to leave room for '\0'.
const size_t size = fread(buf, 1, sizeof(buf) - 1, f);
(void)fclose(f);
buf[size] = '\0';
const char needle[] = "\nMemAvailable:";
char *str = strstr(buf, needle);
if (str == NULL)
return 0;
// Skip the needle.
str += sizeof(needle) - 1;
// Skip spaces.
while (*str == ' ')
++str;
// Here it seems safe enough to assume that there won't be
// an integer overflow or at least it won't cause big trouble.
uint64_t ret = 0;
while (*str >= '0' && *str <= '9')
ret = ret * 10 + (uint64_t)(*str++ - '0');
// The value should end with " kB" so check for the space.
if (*str != ' ')
return 0;
return 1024 * ret;
}
#endif
extern void extern void
hardware_init(void) hardware_init(void)
{ {
uint64_t available_ram = 0;
#ifdef __linux__
available_ram = get_available_ram();
#endif
// Get the amount of RAM. If we cannot determine it, // Get the amount of RAM. If we cannot determine it,
// use the assumption defined by the configure script. // use the assumption defined by the configure script.
total_ram = lzma_physmem(); total_ram = lzma_physmem();
if (total_ram == 0) if (total_ram == 0)
total_ram = (uint64_t)(ASSUME_RAM) * 1024 * 1024; total_ram = (uint64_t)(ASSUME_RAM) * 1024 * 1024;
// FIXME? There may be better methods to determine the default value. // Use 75 % of currently-available RAM or 25 % of total RAM
// One Linux-specific suggestion is to use MemAvailable from // as the default value.
// /proc/meminfo as the starting point. memlimit_mt_default = available_ram != 0
memlimit_mt_default = total_ram / 4; ? available_ram - available_ram / 4
: total_ram / 4;
#if SIZE_MAX == UINT32_MAX #if SIZE_MAX == UINT32_MAX
// A too high value may cause 32-bit xz to run out of address space. // A too high value may cause 32-bit xz to run out of address space.