/*- * Copyright (c) 2010 Andrey Zonov * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Defined as PID_MAX in but visable only for kernel */ #define MAX_PID 99999 /* SWAP_META_PAGES defined in sys/vm/swap_pager.c */ #ifndef MAX_PAGEOUT_CLUSTER #define MAX_PAGEOUT_CLUSTER 16 #endif #if !defined(SWB_NPAGES) #define SWB_NPAGES MAX_PAGEOUT_CLUSTER #endif #define SWAP_META_PAGES (SWB_NPAGES * 2) int fd; long vmspace_swap_count_mmap(struct vmspace *vmspace); int main(int argc, char **argv) { int i, j; int pids, op, cnt; long swapages, swap; char swapsize[] = "Kb"; pid_t mypid, pid; static kvm_t *kd; struct kinfo_proc *kip; mypid = getpid(); /* Open /dev/kmem for mmap() kernel memory */ fd = open(_PATH_KMEM, O_RDONLY, 0); if (fd == -1) err(1, "open(%s)", _PATH_KMEM); kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, NULL); if (kd == NULL) err(1, "kvm_open(%s)", _PATH_DEVNULL); /* Show all processes */ if (argc == 1) { pids = 1; pid = 0; op = KERN_PROC_PROC; /* Show only requested processes */ } else { pids = argc - 1; pid = 0; op = KERN_PROC_PID; } for (i = 0; i < pids; i++) { if (argc > 1) { pid = (int)strtol(argv[i + 1], (char **)NULL, 10); /* Result of strtol() does not seem as valid pid */ if (pid <= 0 || pid > MAX_PID) continue; } /* Get info for process or all processes */ kip = kvm_getprocs(kd, op, pid, &cnt); if (kip == NULL || cnt == 0) { fprintf(stderr, "Cannot get info for process with pid: %d (%s)\n", pid, strerror(errno)); continue; } for (j = 0; j < cnt; j++, (kip++)) { /* Skip this process and system processes */ if (mypid == kip->ki_pid || kip->ki_flag & P_SYSTEM) continue; swapages = vmspace_swap_count_mmap(kip->ki_vmspace); /* There is not process in swap */ if (swapages == 0) continue; swap = swapages * PAGE_SIZE / (1<<10); strncpy(swapsize, "Kb", 2); /* Show swap in "Mb" if size more than 10^5 Kb */ if (swap >= pow(10, 5)) { swap = swapages * PAGE_SIZE / (1<<20); strncpy(swapsize, "Mb", 2); /* Show swap in "Gb" if size more or equal 10^8 Kb */ } else if (swap >= pow(10, 8)) { swap = swapages * PAGE_SIZE / (1<<30); strncpy(swapsize, "Gb", 2); } printf("pid: %5d; comm: %12.12s; swap: %5ld %s" "\n", kip->ki_pid, kip->ki_comm, swap, swapsize); } } kvm_close(kd); close(fd); exit(0); } /* * Adopted version of sys/vm/swap_pager.c:vmspace_swap_count() for userspace. */ long vmspace_swap_count_mmap(struct vmspace *vmspace) { int rc; off_t off; long count = 0; vm_map_t m_map; vm_map_entry_t cur; vm_map_t map = &vmspace->vm_map; off = (off_t)((uintptr_t)map); m_map = mmap(0, sizeof(struct vm_map), PROT_READ, 0, fd, off); if (m_map == MAP_FAILED) err(1, "mmap()"); cur = m_map->header.next; while (cur != &map->header) { vm_map_entry_t m_cur; vm_object_t object; off = (off_t)((uintptr_t)cur); m_cur = mmap(0, sizeof(struct vm_map_entry), PROT_READ, 0, fd, off); if (m_cur == MAP_FAILED) err(1, "mmap()"); if ((m_cur->eflags & MAP_ENTRY_IS_SUB_MAP) == 0 && (object = m_cur->object.vm_object) != NULL) { vm_object_t m_object; off = (off_t)((uintptr_t)object); m_object = mmap(0, sizeof(struct vm_object), PROT_READ, 0, fd, off); if (m_object == MAP_FAILED) err(1, "mmap()"); if (m_object->type == OBJT_SWAP && m_object->un_pager.swp.swp_bcount != 0) { vm_offset_t n = (m_cur->end - m_cur->start) / PAGE_SIZE; count += m_object->un_pager.swp.swp_bcount * SWAP_META_PAGES * n / m_object->size + 1; } rc = munmap(m_object, sizeof(struct vm_object)); if (rc == -1) err(1, "munmap()"); } cur = m_cur->next; rc = munmap(m_cur, sizeof(struct vm_map_entry)); if (rc == -1) err(1, "munmap()"); } rc = munmap(m_map, sizeof(struct vm_map)); if (rc == -1) err(1, "munmap()"); return (count); }