Date: Fri, 2 Apr 2021 20:12:14 -0400 From: Yoshihiro Ota <ota@j.email.ne.jp> To: freebsd-current@freebsd.org Subject: systat -swap to display large swap space users Message-ID: <20210402201214.bdd588a10d430c393585e1e3@j.email.ne.jp>
next in thread | raw e-mail | index | archive | help
[-- Attachment #1 --]
Hi,
We do not seem to have a nice way to see current swap space usage per process.
I updated systat to use libprocstat to obtain such infomation and display
along with swap devise/file stats.
I think patch works for 14-CURRENT and 13-STABLE/13.0-*.
12-STABLE needs some changes from main.
The new screen looks like below with 'systat -swap':
/0 /1 /2 /3 /4 /5 /6 /7 /8 /9 /10
Load Average |
Device/Path Size Used |0% /10 /20 /30 /40 / 60\ 70\ 80\ 90\ 100|
ada0s1b 2048M 2034M XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
zvol/sys/tempora 1024M 1015M XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
zvol/sys/swap 1024M 1014M XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Total 4096M 4063M XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Pid Username Command Swap/Total Per-Process Per-System
24153 hiro seamonkey 98M / 1G 7% 2%
23677 hiro xfce4-pane 28M / 81M 34% XXX 0%
23629 hiro xfce4-sess 25M / 118M 21% XX 0%
23681 hiro xfdesktop 20M / 58M 34% XXX 0%
23678 hiro thunar 15M / 43M 36% XXX 0%
23658 hiro at-spi-bus 14M / 23M 63% XXXXXX 0%
23660 hiro gvfsd 12M / 21M 56% XXXXX 0%
Disks ada0 ada1 ada2 cd0 pass0 pass1 pass2 pass3
KB/t 8.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
tps 0 0 0 0 1 0 0 0
MB/s 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
%busy 0 0 0 0 0 0 0 0
Hiro
[-- Attachment #2 --]
diff --git a/usr.bin/systat/Makefile b/usr.bin/systat/Makefile
index ca3f7ed72ce..bfbe1336d29 100644
--- a/usr.bin/systat/Makefile
+++ b/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 @@ CFLAGS+= -DINET6
WARNS?= 1
-LIBADD= ncursesw m devstat kvm util
+LIBADD= ncursesw m devstat kvm util procstat
.include <bsd.prog.mk>
diff --git a/usr.bin/systat/devs.h b/usr.bin/systat/devs.h
index cbedd844290..79a44a6c3f5 100644
--- a/usr.bin/systat/devs.h
+++ b/usr.bin/systat/devs.h
@@ -34,6 +34,8 @@
#include <devstat.h>
+#define DISKHIGHT 5
+
int dsinit(int);
void dsgetinfo(struct statinfo *);
int dscmd(const char *, const char *, int, struct statinfo *);
diff --git a/usr.bin/systat/main.c b/usr.bin/systat/main.c
index b5a19d381ad..b84351379f4 100644
--- a/usr.bin/systat/main.c
+++ b/usr.bin/systat/main.c
@@ -135,6 +135,21 @@ parse_cmd_args (int argc, char **argv)
}
+static void
+resize(int signo __unused)
+{
+
+ endwin();
+ refresh();
+ clear();
+
+ CMDLINE = LINES - 1;
+ labels();
+ display();
+ status();
+}
+
+
int
main(int argc, char **argv)
{
@@ -191,6 +206,7 @@ main(int argc, char **argv)
signal(SIGINT, die);
signal(SIGQUIT, die);
signal(SIGTERM, die);
+ signal(SIGWINCH, resize);
/*
* Initialize display. Load average appears in a one line
diff --git a/usr.bin/systat/proc.c b/usr.bin/systat/proc.c
new file mode 100644
index 00000000000..0def660d2dc
--- /dev/null
+++ b/usr.bin/systat/proc.c
@@ -0,0 +1,192 @@
+/*-
+ * 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 <libprocstat.h>
+
+#include <curses.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "subs.h"
+#include "systat.h"
+#include "extern.h"
+
+static int compar(const void *, const void *);
+
+static unsigned int nproc;
+
+static struct procstat *prstat = NULL;
+static struct proc_usage {
+ pid_t pid;
+ uid_t uid;
+ char command[COMMLEN+1];
+ uint64_t total;
+ uint64_t swap;
+} *pu = NULL, pzero;
+
+
+void
+closeproc(WINDOW *w)
+{
+ 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, j, y, offset;
+ int rate;
+ const char *uname, *pname;
+ char buf[30];
+
+ if (nproc > 1)
+ qsort(pu, nproc, sizeof (struct proc_usage), compar);
+ y = col + 1 /* HEADING */;
+ offset = 0;
+ for (i = 0; i < hight; i++, y++) {
+ wmove(wnd, y, 0);
+ wclrtoeol(wnd);
+ if (i >= nproc)
+ continue;
+
+ uname = user_from_uid(pu[i].uid, 0);
+ snprintf(buf, sizeof(buf), "%6d %-10s %-10.10s", pu[i].pid,
+ uname, pu[i].command);
+ offset = 6 + 1 + 10 + 1 + 10 + 1;
+ mvwaddstr(wnd, y, 0, buf);
+ sysputuint64(wnd, y, offset, 4, pu[i].swap, 0);
+ offset += 4;
+ mvwaddstr(wnd, y, offset, " / ");
+ offset += 3;
+ sysputuint64(wnd, y, offset, 4, pu[i].total, 0);
+ offset += 4;
+
+ rate = (pu[i].total > 1 ? 100 * pu[i].swap / pu[i].total : 0);
+ snprintf(buf, sizeof(buf), "%3d%%", rate);
+ mvwaddstr(wnd, y, offset, buf);
+ sysputXs(wnd, y, offset + 5, rate / 10);
+
+ rate = 100 * byte_to_page(pu[i].swap) / totalswappages;
+ snprintf(buf, sizeof(buf), "%3d%%", rate);
+ mvwaddstr(wnd, y, offset + 16, buf);
+ sysputXs(wnd, y, offset + 21, rate / 10);
+ }
+}
+
+int
+procinit(void)
+{
+
+ if (prstat != NULL)
+ return(1);
+ prstat = procstat_open_sysctl();
+ return (prstat == NULL);
+}
+
+void
+procgetinfo(void)
+{
+ static unsigned int maxnproc = 0;
+ int i, j, k;
+ unsigned int cnt;
+ struct kinfo_proc *kipp;
+ struct kinfo_vmentry *freep, *kve;
+
+ kipp = procstat_getprocs(prstat, KERN_PROC_PROC, 0, &nproc);
+ if (kipp == NULL) {
+ error("procstat_getprocs()");
+ return;
+ }
+
+ if (nproc > maxnproc) {
+ maxnproc = nproc;
+ if ((pu = realloc(pu, maxnproc * sizeof(*pu))) == NULL) {
+ error("Out of memory");
+ die(0);
+ }
+ }
+ for (i = 0, k = 0; i < nproc; i++) {
+ freep = procstat_getvmmap(prstat, &kipp[i], &cnt);
+ if (freep == NULL) {
+ continue;
+ }
+ pu[k].swap = 0;
+ for (j = 0; j < cnt; j++) {
+ kve = &freep[j];
+ if (kve->kve_type == KVME_TYPE_SWAP) {
+ pu[k].swap += kve->kve_end - kve->kve_start;
+ pu[k].swap -= page_to_byte(kve->kve_resident);
+ }
+ }
+ if (pu[k].swap != 0) {
+ strcpy(pu[k].command, kipp[i].ki_comm);
+ pu[k].pid = kipp[i].ki_pid;
+ pu[k].uid = kipp[i].ki_uid;
+ pu[k].total = kipp[i].ki_size;
+ k++;
+ }
+ free(freep);
+ }
+ procstat_freeprocs(prstat, kipp);
+ nproc = k;
+}
+
+void
+proclabel(int col)
+{
+
+ wmove(wnd, col, 0);
+ wclrtoeol(wnd);
+ mvwaddstr(wnd, col, 0,
+ "Pid Username Command Swap/Total "
+ "Per-Process Per-System");
+}
+
+int
+compar(const void *a, const void *b)
+{
+
+ return (((const struct proc_usage *) a)->swap >
+ ((const struct proc_usage *) b)->swap) ? -1: 1;
+}
diff --git a/usr.bin/systat/subs.h b/usr.bin/systat/subs.h
new file mode 100644
index 00000000000..e4184be8dae
--- /dev/null
+++ b/usr.bin/systat/subs.h
@@ -0,0 +1,42 @@
+/*-
+ * 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$
+ */
+
+#ifndef SUBS_H
+#define SUBS_H
+
+#include <sys/stdint.h>
+
+int procinit(void);
+void procgetinfo(void);
+
+void proclabel(int col);
+void procshow(int col, int hight, uint64_t totalswappages);
+
+#endif
diff --git a/usr.bin/systat/swap.c b/usr.bin/systat/swap.c
index 29b04df0157..44a321a5705 100644
--- a/usr.bin/systat/swap.c
+++ b/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
@@ -57,6 +57,7 @@ static const char sccsid[] = "@(#)swap.c 8.3 (Berkeley) 4/29/95";
#include "systat.h"
#include "extern.h"
#include "devs.h"
+#include "subs.h"
static int pathlen;
@@ -103,6 +104,7 @@ initswap(void)
}
pathlen = 80 - 50 /* % */ - 5 /* Used */ - 5 /* Size */ - 3 /* space */;
dsinit(12);
+ procinit();
once = 1;
return (1);
@@ -125,18 +127,17 @@ fetchswap(void)
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);
- dslabel(12, 0, 18);
+ dslabel(12, 0, LINES - DISKHIGHT - 1);
if (kvnsw <= 0) {
mvwprintw(wnd, 0, 0, "(swap not configured)");
@@ -146,28 +147,26 @@ labelswap(void)
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();
- dsshow(12, 0, 18, &cur_dev, &last_dev);
+ dsshow(12, 0, LINES - DISKHIGHT - 1, &cur_dev, &last_dev);
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 +177,11 @@ showswap(void)
}
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);
}
diff --git a/usr.bin/systat/sysput.c b/usr.bin/systat/sysput.c
index 10401cee772..64a9699e45e 100644
--- a/usr.bin/systat/sysput.c
+++ b/usr.bin/systat/sysput.c
@@ -40,6 +42,22 @@ __FBSDID("$FreeBSD$");
#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 +122,16 @@ sysputwuint64(WINDOW *wd, int row, int col, int width, uint64_t val, int flags)
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 +139,6 @@ calc_page_shift()
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 92233e05817..661e3f2043b 100644
--- a/usr.bin/systat/systat.h
+++ b/usr.bin/systat/systat.h
@@ -33,6 +33,7 @@
*/
#include <curses.h>
+#include <sys/stdint.h>
struct cmdtab {
const char *c_name; /* command name */
@@ -69,6 +70,9 @@ extern int use_kvm;
#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);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20210402201214.bdd588a10d430c393585e1e3>
