aboutsummaryrefslogtreecommitdiffstats
path: root/ipc
diff options
context:
space:
mode:
authorHelge Deller <deller@gmx.de>2010-10-27 18:34:16 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-10-27 21:03:13 -0400
commitb795218075a1e1183169abb66a90dcdcf30367f9 (patch)
tree2bed7b593dc8398d6c30815e4350577d5bd90474 /ipc
parent98391cf4dcf893e9e74e1c14189851dbc9c5ad0d (diff)
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: Helge Deller <deller@gmx.de> Cc: Manfred Spraul <manfred@colorfullife.com> Acked-by: Hugh Dickins <hughd@google.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'ipc')
-rw-r--r--ipc/shm.c63
1 files changed, 42 insertions, 21 deletions
diff --git a/ipc/shm.c b/ipc/shm.c
index 7bc46a9fe1f..fd658a1c2b8 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -108,7 +108,11 @@ void __init shm_init (void)
108{ 108{
109 shm_init_ns(&init_ipc_ns); 109 shm_init_ns(&init_ipc_ns);
110 ipc_init_proc_interface("sysvipc/shm", 110 ipc_init_proc_interface("sysvipc/shm",
111 " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime\n", 111#if BITS_PER_LONG <= 32
112 " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime rss swap\n",
113#else
114 " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime rss swap\n",
115#endif
112 IPC_SHM_IDS, sysvipc_shm_proc_show); 116 IPC_SHM_IDS, sysvipc_shm_proc_show);
113} 117}
114 118
@@ -544,6 +548,34 @@ static inline unsigned long copy_shminfo_to_user(void __user *buf, struct shminf
544} 548}
545 549
546/* 550/*
551 * Calculate and add used RSS and swap pages of a shm.
552 * Called with shm_ids.rw_mutex held as a reader
553 */
554static void shm_add_rss_swap(struct shmid_kernel *shp,
555 unsigned long *rss_add, unsigned long *swp_add)
556{
557 struct inode *inode;
558
559 inode = shp->shm_file->f_path.dentry->d_inode;
560
561 if (is_file_hugepages(shp->shm_file)) {
562 struct address_space *mapping = inode->i_mapping;
563 struct hstate *h = hstate_file(shp->shm_file);
564 *rss_add += pages_per_huge_page(h) * mapping->nrpages;
565 } else {
566#ifdef CONFIG_SHMEM
567 struct shmem_inode_info *info = SHMEM_I(inode);
568 spin_lock(&info->lock);
569 *rss_add += inode->i_mapping->nrpages;
570 *swp_add += info->swapped;
571 spin_unlock(&info->lock);
572#else
573 *rss_add += inode->i_mapping->nrpages;
574#endif
575 }
576}
577
578/*
547 * Called with shm_ids.rw_mutex held as a reader 579 * Called with shm_ids.rw_mutex held as a reader
548 */ 580 */
549static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss, 581static 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,
560 for (total = 0, next_id = 0; total < in_use; next_id++) { 592 for (total = 0, next_id = 0; total < in_use; next_id++) {
561 struct kern_ipc_perm *ipc; 593 struct kern_ipc_perm *ipc;
562 struct shmid_kernel *shp; 594 struct shmid_kernel *shp;
563 struct inode *inode;
564 595
565 ipc = idr_find(&shm_ids(ns).ipcs_idr, next_id); 596 ipc = idr_find(&shm_ids(ns).ipcs_idr, next_id);
566 if (ipc == NULL) 597 if (ipc == NULL)
567 continue; 598 continue;
568 shp = container_of(ipc, struct shmid_kernel, shm_perm); 599 shp = container_of(ipc, struct shmid_kernel, shm_perm);
569 600
570 inode = shp->shm_file->f_path.dentry->d_inode; 601 shm_add_rss_swap(shp, rss, swp);
571
572 if (is_file_hugepages(shp->shm_file)) {
573 struct address_space *mapping = inode->i_mapping;
574 struct hstate *h = hstate_file(shp->shm_file);
575 *rss += pages_per_huge_page(h) * mapping->nrpages;
576 } else {
577#ifdef CONFIG_SHMEM
578 struct shmem_inode_info *info = SHMEM_I(inode);
579 spin_lock(&info->lock);
580 *rss += inode->i_mapping->nrpages;
581 *swp += info->swapped;
582 spin_unlock(&info->lock);
583#else
584 *rss += inode->i_mapping->nrpages;
585#endif
586 }
587 602
588 total++; 603 total++;
589 } 604 }
@@ -1072,6 +1087,9 @@ SYSCALL_DEFINE1(shmdt, char __user *, shmaddr)
1072static int sysvipc_shm_proc_show(struct seq_file *s, void *it) 1087static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
1073{ 1088{
1074 struct shmid_kernel *shp = it; 1089 struct shmid_kernel *shp = it;
1090 unsigned long rss = 0, swp = 0;
1091
1092 shm_add_rss_swap(shp, &rss, &swp);
1075 1093
1076#if BITS_PER_LONG <= 32 1094#if BITS_PER_LONG <= 32
1077#define SIZE_SPEC "%10lu" 1095#define SIZE_SPEC "%10lu"
@@ -1081,7 +1099,8 @@ static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
1081 1099
1082 return seq_printf(s, 1100 return seq_printf(s,
1083 "%10d %10d %4o " SIZE_SPEC " %5u %5u " 1101 "%10d %10d %4o " SIZE_SPEC " %5u %5u "
1084 "%5lu %5u %5u %5u %5u %10lu %10lu %10lu\n", 1102 "%5lu %5u %5u %5u %5u %10lu %10lu %10lu "
1103 SIZE_SPEC " " SIZE_SPEC "\n",
1085 shp->shm_perm.key, 1104 shp->shm_perm.key,
1086 shp->shm_perm.id, 1105 shp->shm_perm.id,
1087 shp->shm_perm.mode, 1106 shp->shm_perm.mode,
@@ -1095,6 +1114,8 @@ static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
1095 shp->shm_perm.cgid, 1114 shp->shm_perm.cgid,
1096 shp->shm_atim, 1115 shp->shm_atim,
1097 shp->shm_dtim, 1116 shp->shm_dtim,
1098 shp->shm_ctim); 1117 shp->shm_ctim,
1118 rss * PAGE_SIZE,
1119 swp * PAGE_SIZE);
1099} 1120}
1100#endif 1121#endif