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.c b/usr.bin/systat/devs.c
index b293796c2c7..87d04f989ea 100644
--- a/usr.bin/systat/devs.c
+++ b/usr.bin/systat/devs.c
@@ -426,12 +426,6 @@ dsshow2(int diskcol, int diskrow, int dn, int lc, struct statinfo *now, struct s
 	putlongdouble(device_busy, diskrow + 4, lc, 5, 0, 0);
 }
 
-static void
-dsshow3(int diskcol, int diskrow, int dn, int lc, struct statinfo *now, struct statinfo *then)
-{
-	dsshow2(diskcol, diskrow, dn, lc, now, then);
-}
-
 void
 dsshow(int maxdrives, int diskcol, int diskrow, struct statinfo *now, struct statinfo *then)
 {
@@ -439,5 +433,5 @@ dsshow(int maxdrives, int diskcol, int diskrow, struct statinfo *now, struct sta
 
 	for (i = 0, lc = 0; i < num_devices && lc < maxdrives; i++)
 		if (dev_select[i].selected)
-			dsshow3(diskcol, diskrow, i, ++lc, now, then);
+			dsshow2(diskcol, diskrow, i, ++lc, now, then);
 }
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
@@ -2,7 +2,7 @@
  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
  *
  * Copyright (c) 1998 David E. O'Brien
- *               2015 Yoshihiro Ota
+ *               2015, 2021 Yoshihiro Ota
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -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/extern.h b/usr.bin/systat/extern.h
index 6e3117bece4..322065f7931 100644
--- a/usr.bin/systat/extern.h
+++ b/usr.bin/systat/extern.h
@@ -168,6 +168,7 @@ char	*sysctl_dynread(const char *, size_t *);
 void	 sysputpage(WINDOW* , int, int, int, uint64_t, int);
 void	 sysputspaces(WINDOW* , int, int, int);
 void	 sysputstrs(WINDOW* , int, int, int);
+void	 sysputXs(WINDOW* , int, int, int);
 void	 sysputuint64(WINDOW* , int, int, int, uint64_t, int);
 void	 sysputwuint64(WINDOW* , int, int, int, uint64_t, int);
 
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/pigs.c b/usr.bin/systat/pigs.c
index d9f3f8d4ad1..879f6548d86 100644
--- a/usr.bin/systat/pigs.c
+++ b/usr.bin/systat/pigs.c
@@ -56,13 +56,13 @@ __FBSDID("$FreeBSD$");
 #include "systat.h"
 #include "extern.h"
 
-int compar(const void *, const void *);
+static int compar(const void *, const void *);
 
 static int nproc;
 static struct p_times {
 	float pt_pctcpu;
 	struct kinfo_proc *pt_kp;
-} *pt;
+} *pt = NULL;
 
 static int    fscale;
 static double  lccpu;
@@ -90,7 +90,7 @@ showpigs(void)
 	const char *uname, *pname;
 	char pidname[30];
 
-	if (pt == NULL)
+	if (nproc == 0)
 		return;
 
 	qsort(pt, nproc, sizeof (struct p_times), compar);
@@ -146,23 +146,20 @@ fetchpigs(void)
 	float ftime;
 	float *pctp;
 	struct kinfo_proc *kpp;
-	static int lastnproc = 0;
+	static int maxnproc = 0;
 
 	if ((kpp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nproc)) == NULL) {
 		error("%s", kvm_geterr(kd));
-		if (pt)
-			free(pt);
+		nproc = 0;
 		return;
 	}
-	if (nproc > lastnproc) {
-		free(pt);
-		if ((pt =
-		    malloc(nproc * sizeof(struct p_times))) == NULL) {
+	if (nproc > maxnproc) {
+		if ((pt = realloc(pt, nproc * sizeof(*pt))) == NULL) {
 			error("Out of memory");
 			die(0);
 		}
+		maxnproc = nproc;
 	}
-	lastnproc = nproc;
 	/*
 	 * calculate %cpu for each proc
 	 */
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 fc44db7d7d4..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 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,23 +57,21 @@ 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 char *header;
-static long blocksize;
-static int dlen, odlen;
-static int hlen;
-static int ulen, oulen;
-static int pagesize;
+static int pathlen;
 
 WINDOW *
 openswap(void)
 {
-	return (subwin(stdscr, LINES-3-1, 0, MAINWIN_ROW, 0));
+
+	return (subwin(stdscr, LINES - 3 - 1, 0, MAINWIN_ROW, 0));
 }
 
 void
 closeswap(WINDOW *w)
 {
+
 	if (w == NULL)
 		return;
 	wclear(w);
@@ -92,29 +90,6 @@ closeswap(WINDOW *w)
 static struct kvm_swap kvmsw[NSWAP];
 static int kvnsw, okvnsw;
 
-static void calclens(void);
-
-#define CONVERT(v)	((int)((int64_t)(v) * pagesize / blocksize))
-
-static void
-calclens(void)
-{
-	int i, n;
-	int len;
-
-	dlen = sizeof("Disk");
-	for (i = 0; i < kvnsw; ++i) {
-		len = strlen(kvmsw[i].ksw_devname);
-		if (dlen < len)
-			dlen = len;
-	}
-
-	ulen = sizeof("Used");
-	for (n = CONVERT(kvmsw[kvnsw].ksw_used), len = 2; n /= 10; ++len);
-	if (ulen < len)
-		ulen = len;
-}
-
 int
 initswap(void)
 {
@@ -123,22 +98,14 @@ initswap(void)
 	if (once)
 		return (1);
 
-	header = getbsize(&hlen, &blocksize);
-	pagesize = getpagesize();
-
 	if ((kvnsw = kvm_getswapinfo(kd, kvmsw, NSWAP, 0)) < 0) {
 		error("systat: kvm_getswapinfo failed");
 		return (0);
 	}
-	okvnsw = kvnsw;
-
-	calclens();
-	odlen = dlen;
-	oulen = ulen;
-
-	once = 1;
-
+	pathlen = 80 - 50 /* % */ - 5 /* Used */ - 5 /* Size */ - 3 /* space */;
 	dsinit(12);
+	procinit();
+	once = 1;
 
 	return (1);
 }
@@ -146,16 +113,13 @@ initswap(void)
 void
 fetchswap(void)
 {
+
 	okvnsw = kvnsw;
 	if ((kvnsw = kvm_getswapinfo(kd, kvmsw, NSWAP, 0)) < 0) {
 		error("systat: kvm_getswapinfo failed");
 		return;
 	}
 
-	odlen = dlen;
-	oulen = ulen;
-	calclens();
-
 	struct devinfo *tmp_dinfo;
 
 	tmp_dinfo = last_dev.dinfo;
@@ -163,71 +127,61 @@ 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;
-
-	fetchswap();
 
 	werase(wnd);
 
-	mvwprintw(wnd, 0, 0, "%*s%*s%*s %s",
-	    -dlen, "Disk", hlen, header, ulen, "Used",
-	    "/0%  /10  /20  /30  /40  /50  /60  /70  /80  /90  /100");
-
-	for (i = 0; i <= kvnsw; ++i) {
-		if (i == kvnsw) {
-			if (kvnsw == 1)
-				break;
-			name = "Total";
-		} else
-			name = kvmsw[i].ksw_devname;
-		mvwprintw(wnd, i + 1, 0, "%*s", -dlen, name);
+	dslabel(12, 0, LINES - DISKHIGHT - 1);
+
+	if (kvnsw <= 0) {
+		mvwprintw(wnd, 0, 0, "(swap not configured)");
+		return;
 	}
-	dslabel(12, 0, 18);
+
+	mvwprintw(wnd, 0, 0, "%*s%5s %5s %s",
+	    -pathlen, "Device/Path", "Size", "Used",
+	    "|0%  /10  /20  /30  /40  / 60\\  70\\  80\\  90\\ 100|");
 }
 
 void
 showswap(void)
 {
-	int count;
-	int i;
+	const char *name;
+	int count, i;
 
-	if (kvnsw != okvnsw || dlen != odlen || ulen != oulen)
+	if (kvnsw != okvnsw)
 		labelswap();
 
-	for (i = 0; i <= kvnsw; ++i) {
-		if (i == kvnsw) {
-			if (kvnsw == 1)
-				break;
-		}
+	dsshow(12, 0, LINES - DISKHIGHT - 1, &cur_dev, &last_dev);
 
-		if (kvmsw[i].ksw_total == 0) {
-			mvwprintw(
-			    wnd,
-			    i + 1,
-			    dlen + hlen + ulen + 1,
-			    "(swap not configured)"
-			);
-			continue;
-		}
-
-		wmove(wnd, i + 1, dlen);
+	if (kvnsw <= 0)
+		return;
 
-		wprintw(wnd, "%*d", hlen, CONVERT(kvmsw[i].ksw_total));
-		wprintw(wnd, "%*d", ulen, CONVERT(kvmsw[i].ksw_used));
+	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);
 
-		count = 50.0 * kvmsw[i].ksw_used / kvmsw[i].ksw_total + 1;
+		sysputpage(wnd, i + 1, pathlen, 5, kvmsw[i].ksw_total, 0);
+		sysputpage(wnd, i + 1, pathlen + 5 + 1, 5, kvmsw[i].ksw_used,
+		    0);
 
-		waddch(wnd, ' ');
-		while (count--)
-			waddch(wnd, 'X');
+		if (kvmsw[i].ksw_used > 0) {
+			count = 50 * kvmsw[i].ksw_used / kvmsw[i].ksw_total;
+			sysputXs(wnd, i + 1, pathlen + 5 + 1 + 5 + 1, count);
+		}
 		wclrtoeol(wnd);
 	}
-	dsshow(12, 0, 18, &cur_dev, &last_dev);
+	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 31c9127a83b..64a9699e45e 100644
--- a/usr.bin/systat/sysput.c
+++ b/usr.bin/systat/sysput.c
@@ -1,5 +1,7 @@
 /*-
- * Copyright (c) 2019 Yoshihiro Ota
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2019, 2020 Yoshihiro Ota
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -40,20 +42,47 @@ __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)
 {
-	static char str40[] = "                                        ";
+	static char str60[] = "                    "
+	    "                                        ";
 
-	mvwaddstr(wd, row, col, str40 + sizeof(str40) - width - 1);
+	mvwaddstr(wd, row, col, str60 + sizeof(str60) - width - 1);
 }
 
 void
 sysputstrs(WINDOW *wd, int row, int col, int width)
 {
-	static char str40[] = "****************************************";
+	static char str60[] = "********************"
+	    "****************************************";
+
+	mvwaddstr(wnd, row, col, str60 + sizeof(str60) - width - 1);
+}
+
+void
+sysputXs(WINDOW *wd, int row, int col, int width)
+{
+	static char str60[] = "XXXXXXXXXXXXXXXXXXXX"
+	    "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
 
-	mvwaddstr(wnd, row, col, str40 + sizeof(str40) - width - 1);
+	mvwaddstr(wnd, row, col, str60 + sizeof(str60) - width - 1);
 }
 
 void
@@ -93,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;
 }
@@ -109,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);
 }
diff --git a/usr.bin/systat/systat.1 b/usr.bin/systat/systat.1
index d2eeb285481..bc57d89cf06 100644
--- a/usr.bin/systat/systat.1
+++ b/usr.bin/systat/systat.1
@@ -297,9 +297,21 @@ not display kilobytes per transaction).
 .El
 .It Ic swap
 Show information about swap space usage on all the
-swap areas compiled into the kernel.
-The first column is the device name of the partition.
-The next column is the total space available in the partition.
+swap areas compiled into the kernel and processes that are swapped out.
+The swap areas are displayed first with their name, sizes and
+percentage usage.
+Then, processes are listed in order of higher swap vm object counts.
+Pid, username, a part of command line, the total number of swap objects
+in bytes, the size of process, and per-process swap usage percentage and
+per-system swap space percentage.
+A default vm objecte is converted to a swap vm objects when paging
+out to swap space first time.  Even if such a swap object is paged-in,
+the object remains as a swap object.
+In other words, under some circumstances, the number of swap objects
+may be higher than actual swap space usage.
+One known case is when
+.Dl $ swapoff -a
+ is run.
 The
 .Ar Used
 column indicates the total blocks used so far;
diff --git a/usr.bin/systat/systat.h b/usr.bin/systat/systat.h
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);
