Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F151946530
D29754.id88635.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
13 KB
Referenced Files
None
Subscribers
None
D29754.id88635.diff
View Options
Index: usr.bin/systat/Makefile
===================================================================
--- usr.bin/systat/Makefile
+++ usr.bin/systat/Makefile
@@ -5,7 +5,7 @@
PROG= systat
SRCS= cmds.c cmdtab.c devs.c fetch.c iostat.c keyboard.c main.c sysput.c \
- netcmds.c netstat.c pigs.c swap.c icmp.c \
+ netcmds.c netstat.c pigs.c proc.c swap.c icmp.c \
mode.c ip.c sctp.c tcp.c zarc.c \
vmstat.c convtbl.c ifcmds.c ifstat.c
@@ -16,6 +16,6 @@
WARNS?= 1
-LIBADD= ncursesw m devstat kvm util
+LIBADD= ncursesw m devstat kvm util procstat
.include <bsd.prog.mk>
Index: usr.bin/systat/proc.c
===================================================================
--- /dev/null
+++ usr.bin/systat/proc.c
@@ -0,0 +1,315 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2021 Yoshihiro Ota
+ * 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+
+#include <curses.h>
+#include <libprocstat.h>
+#include <libutil.h>
+#include <pwd.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "systat.h"
+#include "extern.h"
+
+/*
+ * vm objects of swappable types
+ */
+static struct swapvm {
+ uint64_t kvo_me;
+ uint32_t swapped; /* in pages */
+ uint64_t next;
+ pid_t pid; /* to avoid double counting */
+} *swobj = NULL;
+static int nswobj = 0;
+
+static struct procstat *prstat = NULL;
+/*
+ *procstat_getvmmap() is an expensive call and the number of processes running
+ * may also be high. So, maintain an array of pointers for ease of expanding
+ * an array and also swapping pointers are faster than struct.
+ */
+static struct proc_usage {
+ pid_t pid;
+ uid_t uid;
+ char command[COMMLEN+1];
+ uint64_t total;
+ uint32_t pages;
+} **pu = NULL;
+static unsigned int nproc;
+static int proc_compar(const void *, const void *);
+
+static void
+display_proc_line(int idx, int y, uint64_t totalswappages)
+{
+ int offset = 0, rate;
+ const char *uname, *pname;
+ char buf[30];
+ uint64_t swapbytes;
+
+ wmove(wnd, y, 0);
+ wclrtoeol(wnd);
+ if (idx >= nproc)
+ return;
+
+ uname = user_from_uid(pu[idx]->uid, 0);
+ swapbytes = page_to_byte(pu[idx]->pages);
+
+ snprintf(buf, sizeof(buf), "%6d %-10s %-10.10s", pu[idx]->pid, uname,
+ pu[idx]->command);
+ offset = 6 + 1 + 10 + 1 + 10 + 1;
+ mvwaddstr(wnd, y, 0, buf);
+ sysputuint64(wnd, y, offset, 4, swapbytes, 0);
+ offset += 4;
+ mvwaddstr(wnd, y, offset, " / ");
+ offset += 3;
+ sysputuint64(wnd, y, offset, 4, pu[idx]->total, 0);
+ offset += 4;
+
+ rate = pu[idx]->total > 1 ? 100 * swapbytes / pu[idx]->total : 0;
+ snprintf(buf, sizeof(buf), "%3d%%", rate);
+ mvwaddstr(wnd, y, offset, buf);
+ if (rate > 100) /* avoid running over the screen */
+ rate = 100;
+ sysputXs(wnd, y, offset + 5, rate / 10);
+
+ rate = 100 * pu[idx]->pages / totalswappages;
+ snprintf(buf, sizeof(buf), "%3d%%", rate);
+ mvwaddstr(wnd, y, offset + 16, buf);
+ if (rate > 100) /* avoid running over the screen */
+ rate = 100;
+ sysputXs(wnd, y, offset + 21, rate / 10);
+}
+
+static int
+swobj_search(const void *a, const void *b)
+{
+ const uint64_t *aa = a;
+ const struct swapvm *bb = b;
+
+ if (*aa == bb->kvo_me)
+ return(0);
+ return (*aa > bb->kvo_me) ? -1: 1;
+}
+
+static int
+swobj_sort(const void *a, const void *b)
+{
+
+ return (((const struct swapvm *) a)->kvo_me >
+ ((const struct swapvm *) b)->kvo_me) ? -1: 1;
+}
+
+static bool
+get_swap_vmobjects(void)
+{
+ static int maxnobj;
+ int cnt, i, next_i, last_nswobj;
+ struct kinfo_vmobject *kvo;
+
+ next_i = nswobj = 0;
+ kvo = kinfo_getvmobject(&cnt);
+ if (kvo == NULL) {
+ error("kinfo_getvmobject()");
+ return (false);
+ }
+ do {
+ for (i = next_i; i < cnt; i++) {
+ if (kvo[i].kvo_type != KVME_TYPE_DEFAULT &&
+ kvo[i].kvo_type != KVME_TYPE_SWAP)
+ continue;
+ if (nswobj < maxnobj) {
+ swobj[nswobj].kvo_me = kvo[i].kvo_me;
+ swobj[nswobj].swapped = kvo[i].kvo_swapped;
+ swobj[nswobj].next = kvo[i].kvo_backing_obj;
+ swobj[nswobj].pid = 0;
+ next_i = i + 1;
+ }
+ nswobj++;
+ }
+ if (nswobj <= maxnobj)
+ break;
+ /* allocate memory and fill skipped elements */
+ last_nswobj = maxnobj;
+ maxnobj = nswobj;
+ nswobj = last_nswobj;
+ /* allocate more memory and fill missed ones */
+ if ((swobj = realloc(swobj, maxnobj * sizeof(*swobj))) ==
+ NULL) {
+ error("Out of memory");
+ die(0);
+ }
+ } while (i <= cnt); /* extra safety guard */
+ free(kvo);
+ if (nswobj > 1)
+ qsort(swobj, nswobj, sizeof(swobj[0]), swobj_sort);
+ return (nswobj > 0);
+}
+
+/* This returns the number of pages a process uses. */
+static uint32_t per_proc_swap_usage(struct kinfo_proc *kipp)
+{
+ int i, cnt;
+ uint32_t pages = 0;
+ uint64_t vmobj;
+ struct kinfo_vmentry *freep, *kve;
+ struct swapvm *vm;
+
+ freep = procstat_getvmmap(prstat, kipp, &cnt);
+ if (freep == NULL)
+ return (pages);
+
+ for (i = 0; i < cnt; i++) {
+ kve = &freep[i];
+ if (kve->kve_type == KVME_TYPE_DEFAULT ||
+ kve->kve_type == KVME_TYPE_SWAP) {
+ vmobj = kve->kve_obj;
+ do {
+ vm = bsearch(&vmobj, swobj, nswobj,
+ sizeof(swobj[0]), swobj_search);
+ if (vm != NULL && vm->pid != kipp->ki_pid) {
+ pages += vm->swapped;
+ vmobj = vm->next;
+ vm->pid = kipp->ki_pid;
+ } else
+ break;
+ } while (vmobj != 0);
+ }
+ }
+ free(freep);
+ return pages;
+}
+
+void
+closeproc(WINDOW *w)
+{
+
+ if (prstat != NULL)
+ procstat_close(prstat);
+ prstat = NULL;
+ if (w == NULL)
+ return;
+ wclear(w);
+ wrefresh(w);
+ delwin(w);
+}
+
+void
+procshow(int col, int hight, uint64_t totalswappages)
+{
+ int i, y;
+
+ for (i = 0, y = col + 1 /* HEADING */; i < hight; i++, y++)
+ display_proc_line(i, y, totalswappages);
+}
+
+int
+procinit(void)
+{
+
+ if (prstat != NULL)
+ return(1);
+ prstat = procstat_open_sysctl();
+ return (prstat == NULL);
+}
+
+void
+procgetinfo(void)
+{
+ static unsigned int maxnproc = 0;
+ int cnt, i;
+ uint32_t pages;
+ struct kinfo_proc *kipp;
+
+ nproc = 0;
+ if ( ! get_swap_vmobjects() ) /* call failed or nothing is paged-out */
+ return;
+
+ kipp = procstat_getprocs(prstat, KERN_PROC_PROC, 0, &cnt);
+ if (kipp == NULL) {
+ error("procstat_getprocs()");
+ return;
+ }
+ if (maxnproc < cnt) {
+ if ((pu = realloc(pu, cnt * sizeof(*pu))) == NULL) {
+ error("Out of memory");
+ die(0);
+ }
+ memset(&pu[maxnproc], 0, (cnt - maxnproc) * sizeof(pu[0]));
+ maxnproc = cnt;
+ }
+
+ for (i = 0; i < cnt; i++) {
+ pages = per_proc_swap_usage(&kipp[i]);
+ if (pages == 0)
+ continue;
+ if (pu[nproc] == NULL &&
+ ((pu[nproc] = malloc(sizeof(**pu))) == NULL)) {
+ error("Out of memory");
+ die(0);
+ }
+ strlcpy(pu[nproc]->command, kipp[i].ki_comm,
+ sizeof(pu[nproc]->command));
+ pu[nproc]->pid = kipp[i].ki_pid;
+ pu[nproc]->uid = kipp[i].ki_uid;
+ pu[nproc]->pages = pages;
+ pu[nproc]->total = kipp[i].ki_size;
+ nproc++;
+ }
+ if (nproc > 1)
+ qsort(pu, nproc, sizeof(*pu), proc_compar);
+}
+
+void
+proclabel(int col)
+{
+
+ wmove(wnd, col, 0);
+ wclrtoeol(wnd);
+ mvwaddstr(wnd, col, 0,
+ "Pid Username Command Swap/Total "
+ "Per-Process Per-System");
+}
+
+int
+proc_compar(const void *a, const void *b)
+{
+ const struct proc_usage *aa = *((const struct proc_usage **) a);
+ const struct proc_usage *bb = *((const struct proc_usage **) b);
+
+ return (aa->pages > bb->pages) ? -1: 1;
+}
Index: usr.bin/systat/swap.c
===================================================================
--- usr.bin/systat/swap.c
+++ usr.bin/systat/swap.c
@@ -3,7 +3,7 @@
*
* Copyright (c) 1980, 1992, 1993
* The Regents of the University of California. All rights reserved.
- * Copyright (c) 2017, 2020 Yoshihiro Ota
+ * Copyright (c) 2017, 2020, 2021 Yoshihiro Ota
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -103,6 +103,7 @@
}
pathlen = 80 - 50 /* % */ - 5 /* Used */ - 5 /* Size */ - 3 /* space */;
dsinit(12);
+ procinit();
once = 1;
return (1);
@@ -125,14 +126,13 @@
cur_dev.dinfo = tmp_dinfo;
last_dev.snap_time = cur_dev.snap_time;
- dsgetinfo( &cur_dev );
+ dsgetinfo(&cur_dev);
+ procgetinfo();
}
void
labelswap(void)
{
- const char *name;
- int i;
werase(wnd);
@@ -146,18 +146,13 @@
mvwprintw(wnd, 0, 0, "%*s%5s %5s %s",
-pathlen, "Device/Path", "Size", "Used",
"|0% /10 /20 /30 /40 / 60\\ 70\\ 80\\ 90\\ 100|");
-
- for (i = 0; i <= kvnsw; ++i) {
- name = i == kvnsw ? "Total" : kvmsw[i].ksw_devname;
- mvwprintw(wnd, 1 + i, 0, "%-*.*s", pathlen, pathlen - 1, name);
- }
}
void
showswap(void)
{
- int count;
- int i;
+ const char *name;
+ int count, i;
if (kvnsw != okvnsw)
labelswap();
@@ -167,7 +162,10 @@
if (kvnsw <= 0)
return;
- for (i = 0; i <= kvnsw; ++i) {
+ for (i = (kvnsw == 1 ? 0 : kvnsw); i >= 0; i--) {
+ name = i == kvnsw ? "Total" : kvmsw[i].ksw_devname;
+ mvwprintw(wnd, 1 + i, 0, "%-*.*s", pathlen, pathlen - 1, name);
+
sysputpage(wnd, i + 1, pathlen, 5, kvmsw[i].ksw_total, 0);
sysputpage(wnd, i + 1, pathlen + 5 + 1, 5, kvmsw[i].ksw_used,
0);
@@ -178,4 +176,11 @@
}
wclrtoeol(wnd);
}
+ if (kvnsw == 1)
+ count = 2;
+ else
+ count = 3;
+ proclabel(kvnsw + count);
+ procshow(kvnsw + count, LINES - 5 - (kvnsw + 3) - (DISKHIGHT + 1),
+ kvmsw[kvnsw].ksw_total);
}
Index: usr.bin/systat/sysput.c
===================================================================
--- usr.bin/systat/sysput.c
+++ usr.bin/systat/sysput.c
@@ -40,6 +40,22 @@
#include "systat.h"
#include "extern.h"
+static int page_shift();
+
+uint64_t
+byte_to_page(uint64_t size)
+{
+
+ return (size >> page_shift());
+}
+
+uint64_t
+page_to_byte(uint64_t size)
+{
+
+ return (size << page_shift());
+}
+
void
sysputspaces(WINDOW *wd, int row, int col, int width)
{
@@ -104,15 +120,16 @@
sysputuint64(wd, row, col, width, val, flags);
}
-static int
-calc_page_shift()
+int
+page_shift()
{
u_int page_size;
- int shifts;
+ static int shifts = 0;
- shifts = 0;
+ if (shifts != 0)
+ return (shifts);
GETSYSCTL("vm.stats.vm.v_page_size", page_size);
- for(; page_size > 1; page_size >>= 1)
+ for (; page_size > 1; page_size >>= 1)
shifts++;
return shifts;
}
@@ -120,10 +137,6 @@
void
sysputpage(WINDOW *wd, int row, int col, int width, uint64_t pages, int flags)
{
- static int shifts = 0;
- if (shifts == 0)
- shifts = calc_page_shift();
- pages <<= shifts;
- sysputuint64(wd, row, col, width, pages, flags);
+ sysputuint64(wd, row, col, width, page_to_byte(pages), flags);
}
Index: usr.bin/systat/systat.h
===================================================================
--- usr.bin/systat/systat.h
+++ usr.bin/systat/systat.h
@@ -3,6 +3,8 @@
*
* Copyright (c) 1980, 1989, 1992, 1993
* The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1998 David E. O'Brien
+ * 2015, 2021 Yoshihiro Ota
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -33,6 +35,8 @@
*/
#include <curses.h>
+#include <devstat.h>
+#include <sys/stdint.h>
struct cmdtab {
const char *c_name; /* command name */
@@ -69,6 +73,32 @@
#define NPTR(indx) (void *)NVAL((indx))
#define NREAD(indx, buf, len) kvm_ckread(NPTR((indx)), (buf), (len))
+extern uint64_t byte_to_page(uint64_t size);
+extern uint64_t page_to_byte(uint64_t size);
+
extern void putint(int, int, int, int);
extern void putfloat(double, int, int, int, int, int);
extern void putlongdouble(long double, int, int, int, int, int);
+
+
+/*** reuseable components ***/
+
+/** libproc stat based sub components - currently support swap usage via vm **/
+int procinit(void);
+void procgetinfo(void);
+void proclabel(int col);
+void procshow(int col, int hight, uint64_t totalswappages);
+
+
+/** devstat based sub components - currently support disk activities **/
+
+#define DISKHIGHT 5
+
+int dsinit(int);
+void dsgetinfo(struct statinfo *);
+int dscmd(const char *, const char *, int, struct statinfo *);
+
+void dslabel(int, int, int);
+void dsshow(int, int, int, struct statinfo *, struct statinfo *);
+
+extern struct statinfo cur_dev, last_dev, run_dev;
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Apr 12, 4:51 PM (2 h, 48 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31359692
Default Alt Text
D29754.id88635.diff (13 KB)
Attached To
Mode
D29754: Augment systat(1) -swap to display large swap space processes
Attached
Detach File
Event Timeline
Log In to Comment