Commit b7952180 authored by Helge Deller's avatar Helge Deller Committed by Linus Torvalds

ipc/shm.c: add RSS and swap size information to /proc/sysvipc/shm

The kernel currently provides no functionality to analyze the RSS and swap
space usage of each individual sysvipc shared memory segment.

This patch adds this info for each existing shm segment by extending the
output of /proc/sysvipc/shm by two columns for RSS and swap.

Since shmctl(SHM_INFO) already provides a similiar calculation (it
currently sums up all RSS/swap info for all segments), I did split out a
static function which is now used by the /proc/sysvipc/shm output and
shmctl(SHM_INFO).

SAP products (esp.  the SAP Netweaver ABAP Kernel) uses lots of big shared
memory segments (we often have Linux systems with >= 16GB shm usage).
Sometimes we get customer reports about "slow" system responses and while
looking into their configurations we often find massive swapping activity
on the system.  With this patch it's now easy to see from the command line
if and which shm segments gets swapped out (and how much) and can more
easily give recommendations for system tuning.  Without the patch it's
currently not possible to do such shm analysis at all.

Also...

Add some spaces in front of the "size" field for 64bit kernels to get the
columns correct if you cat the contents of the file.  In
sysvipc_shm_proc_show() the kernel prints the size value in "SPEC_SIZE"
format, which is defined like this:

#if BITS_PER_LONG <= 32
#define SIZE_SPEC "%10lu"
#else
#define SIZE_SPEC "%21lu"
#endif

So, if the header is not adjusted, the columns are not correctly aligned.
I actually tested this on 32- and 64-bit and it seems correct now.
Signed-off-by: default avatarHelge Deller <deller@gmx.de>
Cc: Manfred Spraul <manfred@colorfullife.com>
Acked-by: default avatarHugh Dickins <hughd@google.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 98391cf4
...@@ -108,7 +108,11 @@ void __init shm_init (void) ...@@ -108,7 +108,11 @@ void __init shm_init (void)
{ {
shm_init_ns(&init_ipc_ns); shm_init_ns(&init_ipc_ns);
ipc_init_proc_interface("sysvipc/shm", ipc_init_proc_interface("sysvipc/shm",
" key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime\n", #if BITS_PER_LONG <= 32
" key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime rss swap\n",
#else
" key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime rss swap\n",
#endif
IPC_SHM_IDS, sysvipc_shm_proc_show); IPC_SHM_IDS, sysvipc_shm_proc_show);
} }
...@@ -543,6 +547,34 @@ static inline unsigned long copy_shminfo_to_user(void __user *buf, struct shminf ...@@ -543,6 +547,34 @@ static inline unsigned long copy_shminfo_to_user(void __user *buf, struct shminf
} }
} }
/*
* Calculate and add used RSS and swap pages of a shm.
* Called with shm_ids.rw_mutex held as a reader
*/
static void shm_add_rss_swap(struct shmid_kernel *shp,
unsigned long *rss_add, unsigned long *swp_add)
{
struct inode *inode;
inode = shp->shm_file->f_path.dentry->d_inode;
if (is_file_hugepages(shp->shm_file)) {
struct address_space *mapping = inode->i_mapping;
struct hstate *h = hstate_file(shp->shm_file);
*rss_add += pages_per_huge_page(h) * mapping->nrpages;
} else {
#ifdef CONFIG_SHMEM
struct shmem_inode_info *info = SHMEM_I(inode);
spin_lock(&info->lock);
*rss_add += inode->i_mapping->nrpages;
*swp_add += info->swapped;
spin_unlock(&info->lock);
#else
*rss_add += inode->i_mapping->nrpages;
#endif
}
}
/* /*
* Called with shm_ids.rw_mutex held as a reader * Called with shm_ids.rw_mutex held as a reader
*/ */
...@@ -560,30 +592,13 @@ static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss, ...@@ -560,30 +592,13 @@ static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss,
for (total = 0, next_id = 0; total < in_use; next_id++) { for (total = 0, next_id = 0; total < in_use; next_id++) {
struct kern_ipc_perm *ipc; struct kern_ipc_perm *ipc;
struct shmid_kernel *shp; struct shmid_kernel *shp;
struct inode *inode;
ipc = idr_find(&shm_ids(ns).ipcs_idr, next_id); ipc = idr_find(&shm_ids(ns).ipcs_idr, next_id);
if (ipc == NULL) if (ipc == NULL)
continue; continue;
shp = container_of(ipc, struct shmid_kernel, shm_perm); shp = container_of(ipc, struct shmid_kernel, shm_perm);
inode = shp->shm_file->f_path.dentry->d_inode; shm_add_rss_swap(shp, rss, swp);
if (is_file_hugepages(shp->shm_file)) {
struct address_space *mapping = inode->i_mapping;
struct hstate *h = hstate_file(shp->shm_file);
*rss += pages_per_huge_page(h) * mapping->nrpages;
} else {
#ifdef CONFIG_SHMEM
struct shmem_inode_info *info = SHMEM_I(inode);
spin_lock(&info->lock);
*rss += inode->i_mapping->nrpages;
*swp += info->swapped;
spin_unlock(&info->lock);
#else
*rss += inode->i_mapping->nrpages;
#endif
}
total++; total++;
} }
...@@ -1072,6 +1087,9 @@ SYSCALL_DEFINE1(shmdt, char __user *, shmaddr) ...@@ -1072,6 +1087,9 @@ SYSCALL_DEFINE1(shmdt, char __user *, shmaddr)
static int sysvipc_shm_proc_show(struct seq_file *s, void *it) static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
{ {
struct shmid_kernel *shp = it; struct shmid_kernel *shp = it;
unsigned long rss = 0, swp = 0;
shm_add_rss_swap(shp, &rss, &swp);
#if BITS_PER_LONG <= 32 #if BITS_PER_LONG <= 32
#define SIZE_SPEC "%10lu" #define SIZE_SPEC "%10lu"
...@@ -1081,7 +1099,8 @@ static int sysvipc_shm_proc_show(struct seq_file *s, void *it) ...@@ -1081,7 +1099,8 @@ static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
return seq_printf(s, return seq_printf(s,
"%10d %10d %4o " SIZE_SPEC " %5u %5u " "%10d %10d %4o " SIZE_SPEC " %5u %5u "
"%5lu %5u %5u %5u %5u %10lu %10lu %10lu\n", "%5lu %5u %5u %5u %5u %10lu %10lu %10lu "
SIZE_SPEC " " SIZE_SPEC "\n",
shp->shm_perm.key, shp->shm_perm.key,
shp->shm_perm.id, shp->shm_perm.id,
shp->shm_perm.mode, shp->shm_perm.mode,
...@@ -1095,6 +1114,8 @@ static int sysvipc_shm_proc_show(struct seq_file *s, void *it) ...@@ -1095,6 +1114,8 @@ static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
shp->shm_perm.cgid, shp->shm_perm.cgid,
shp->shm_atim, shp->shm_atim,
shp->shm_dtim, shp->shm_dtim,
shp->shm_ctim); shp->shm_ctim,
rss * PAGE_SIZE,
swp * PAGE_SIZE);
} }
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment