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 Index: usr.bin/systat/devs.h =================================================================== --- usr.bin/systat/devs.h +++ /dev/null @@ -1,46 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 1998 David E. O'Brien - * 2015 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 DEVS_H -#define DEVS_H - -#include - -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; - -#endif Index: usr.bin/systat/devs.c =================================================================== --- usr.bin/systat/devs.c +++ usr.bin/systat/devs.c @@ -76,7 +76,6 @@ #include "systat.h" #include "extern.h" -#include "devs.h" typedef enum { DS_MATCHTYPE_NONE, @@ -426,12 +425,6 @@ 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 +432,5 @@ 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); } Index: usr.bin/systat/iostat.c =================================================================== --- usr.bin/systat/iostat.c +++ usr.bin/systat/iostat.c @@ -68,7 +68,6 @@ #include #include -#include #include #include #include @@ -77,7 +76,6 @@ #include "systat.h" #include "extern.h" -#include "devs.h" static int linesperregion; static double etime; Index: usr.bin/systat/main.c =================================================================== --- usr.bin/systat/main.c +++ usr.bin/systat/main.c @@ -135,6 +135,21 @@ } +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 @@ signal(SIGINT, die); signal(SIGQUIT, die); signal(SIGTERM, die); + signal(SIGWINCH, resize); /* * Initialize display. Load average appears in a one line Index: usr.bin/systat/proc.c =================================================================== --- /dev/null +++ usr.bin/systat/proc.c @@ -0,0 +1,191 @@ +/*- + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#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; +} 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 @@ -56,7 +56,6 @@ #include "systat.h" #include "extern.h" -#include "devs.h" static int pathlen; @@ -103,6 +102,7 @@ } pathlen = 80 - 50 /* % */ - 5 /* Used */ - 5 /* Size */ - 3 /* space */; dsinit(12); + procinit(); once = 1; return (1); @@ -125,18 +125,17 @@ 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 +145,26 @@ 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 +175,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 +#include +#include 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; Index: usr.bin/systat/systat.1 =================================================================== --- usr.bin/systat/systat.1 +++ usr.bin/systat/systat.1 @@ -279,9 +279,21 @@ .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; Index: usr.bin/systat/vmstat.c =================================================================== --- usr.bin/systat/vmstat.c +++ usr.bin/systat/vmstat.c @@ -68,7 +68,6 @@ #include #include "systat.h" #include "extern.h" -#include "devs.h" static struct Info { long time[CPUSTATES]; Index: usr.bin/systat/zarc.c =================================================================== --- usr.bin/systat/zarc.c +++ usr.bin/systat/zarc.c @@ -39,7 +39,6 @@ #include "systat.h" #include "extern.h" -#include "devs.h" struct zfield { uint64_t arcstats;