1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-07-28 00:21:52 +03:00

linux/getsysstats.c: use sysinfo() instead of parsing /proc/meminfo

Profiling git's test suite, Linus noted [1] that a disproportionately
large amount of time was spent reading /proc/meminfo. This is done by
the glibc functions get_phys_pages and get_avphys_pages, but they only
need the MemTotal and MemFree fields, respectively. That same
information can be obtained with a single syscall, sysinfo, instead of
six: open, fstat, mmap, read, close, munmap. While sysinfo also
provides more than necessary, it does a lot less work than what the
kernel needs to do to provide the entire /proc/meminfo. Both strace -T
and in-app microbenchmarks shows that the sysinfo() approach is
roughly an order of magnitude faster.

sysinfo() is much older than what glibc currently requires, so I don't
think there's any reason to keep the old parsing code. Moreover, this
makes get_[av]phys_pages work even in the absence of /proc.

Linus noted that something as simple as 'bash -c "echo"' would trigger
the reading of /proc/meminfo, but gdb says that many more applications
than just bash are affected:

Starting program: /bin/bash "-c" "echo"

Breakpoint 1, __get_phys_pages () at ../sysdeps/unix/sysv/linux/getsysstats.c:283
283     ../sysdeps/unix/sysv/linux/getsysstats.c: No such file or directory.
(gdb) bt

So it seems that any application that uses qsort on a moderately sized
array will incur this cost (once), which is obviously proportionately
more expensive for lots of short-lived processes (such as the git test
suite).

[1] http://thread.gmane.org/gmane.linux.kernel/2019285

Signed-off-by: Rasmus Villemoes <rv@rasmusvillemoes.dk>

	* sysdeps/unix/sysv/linux/getsysstats.c (__get_phys_pages):
	Use sysinfo system call instead of parsing /proc/meminfo.
	* sysdeps/unix/sysv/linux/getsysstats.c (__get_avphys_pages):
	Likewise.
This commit is contained in:
Rasmus Villemoes
2015-08-18 11:55:34 +02:00
committed by Mike Frysinger
parent b482d0364e
commit 0ce657c576
4 changed files with 64 additions and 59 deletions

View File

@ -278,81 +278,53 @@ __get_nprocs_conf (void)
}
weak_alias (__get_nprocs_conf, get_nprocs_conf)
/* General function to get information about memory status from proc
filesystem. */
/* Compute (num*mem_unit)/pagesize, but avoid overflowing long int.
In practice, mem_unit is never bigger than the page size, so after
the first loop it is 1. [In the kernel, it is initialized to
PAGE_SIZE in mm/page_alloc.c:si_meminfo(), and then in
kernel.sys.c:do_sysinfo() it is set to 1 if unsigned long can
represent all the sizes measured in bytes]. */
static long int
internal_function
phys_pages_info (const char *format)
sysinfo_mempages (unsigned long int num, unsigned int mem_unit)
{
char buffer[8192];
long int result = -1;
unsigned long int ps = __getpagesize ();
/* If we haven't found an appropriate entry return 1. */
FILE *fp = fopen ("/proc/meminfo", "rce");
if (fp != NULL)
while (mem_unit > 1 && ps > 1)
{
/* No threads use this stream. */
__fsetlocking (fp, FSETLOCKING_BYCALLER);
result = 0;
/* Read all lines and count the lines starting with the
string "processor". We don't have to fear extremely long
lines since the kernel will not generate them. 8192
bytes are really enough. */
while (__fgets_unlocked (buffer, sizeof buffer, fp) != NULL)
if (sscanf (buffer, format, &result) == 1)
{
result /= (__getpagesize () / 1024);
break;
}
fclose (fp);
mem_unit >>= 1;
ps >>= 1;
}
if (result == -1)
/* We cannot get the needed value: signal an error. */
__set_errno (ENOSYS);
return result;
num *= mem_unit;
while (ps > 1)
{
ps >>= 1;
num >>= 1;
}
return num;
}
/* Return the number of pages of physical memory in the system. There
is currently (as of version 2.0.21) no system call to determine the
number. It is planned for the 2.1.x series to add this, though.
One possibility to implement it for systems using Linux 2.0 is to
examine the pseudo file /proc/cpuinfo. Here we have one entry for
each processor.
But not all systems have support for the /proc filesystem. If it
is not available we return -1 as an error signal. */
/* Return the number of pages of total/available physical memory in
the system. This used to be done by parsing /proc/meminfo, but
that's unnecessarily expensive (and /proc is not always available).
The sysinfo syscall provides the same information, and has been
available at least since kernel 2.3.48. */
long int
__get_phys_pages (void)
{
/* XXX Here will come a test for the new system call. */
struct sysinfo info;
return phys_pages_info ("MemTotal: %ld kB");
__sysinfo (&info);
return sysinfo_mempages (info.totalram, info.mem_unit);
}
weak_alias (__get_phys_pages, get_phys_pages)
/* Return the number of available pages of physical memory in the
system. There is currently (as of version 2.0.21) no system call
to determine the number. It is planned for the 2.1.x series to add
this, though.
One possibility to implement it for systems using Linux 2.0 is to
examine the pseudo file /proc/cpuinfo. Here we have one entry for
each processor.
But not all systems have support for the /proc filesystem. If it
is not available we return -1 as an error signal. */
long int
__get_avphys_pages (void)
{
/* XXX Here will come a test for the new system call. */
struct sysinfo info;
return phys_pages_info ("MemFree: %ld kB");
__sysinfo (&info);
return sysinfo_mempages (info.freeram, info.mem_unit);
}
weak_alias (__get_avphys_pages, get_avphys_pages)