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 diff --git a/usr.bin/systat/devs.c b/usr.bin/systat/devs.c index ecbebc0fcea..87d04f989ea 100644 --- a/usr.bin/systat/devs.c +++ b/usr.bin/systat/devs.c @@ -426,13 +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) { @@ -440,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 +#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 322065f7931..dfdbff23d43 100644 --- a/usr.bin/systat/extern.h +++ b/usr.bin/systat/extern.h @@ -71,17 +71,6 @@ extern struct nlist namelist[]; int checkhost(struct in_conninfo *); int checkport(struct in_conninfo *); -void closeicmp(WINDOW *); -void closeicmp6(WINDOW *); -void closeifstat(WINDOW *); -void closeiostat(WINDOW *); -void closeip(WINDOW *); -void closeip6(WINDOW *); -void closekre(WINDOW *); -void closenetstat(WINDOW *); -void closepigs(WINDOW *); -void closeswap(WINDOW *); -void closetcp(WINDOW *); int cmdifstat(const char *, const char *); int cmdiostat(const char *, const char *); int cmdkre(const char *, const char *); @@ -93,74 +82,23 @@ void display(void); int dkinit(void); int dkcmd(char *, char *); void error(const char *fmt, ...) __printflike(1, 2); -void fetchicmp(void); -void fetchicmp6(void); void fetchifstat(void); -void fetchip(void); -void fetchip6(void); -void fetchiostat(void); -void fetchkre(void); -void fetchnetstat(void); -void fetchpigs(void); -void fetchswap(void); -void fetchtcp(void); void getsysctl(const char *, void *, size_t); int ifcmd(const char *cmd, const char *args); -int initicmp(void); -int initicmp6(void); -int initifstat(void); -int initip(void); -int initip6(void); -int initiostat(void); -int initkre(void); -int initnetstat(void); -int initpigs(void); -int initswap(void); -int inittcp(void); int keyboard(void); int kvm_ckread(void *, void *, int); -void labelicmp(void); -void labelicmp6(void); -void labelifstat(void); -void labelip(void); -void labelip6(void); -void labeliostat(void); -void labelkre(void); -void labelnetstat(void); -void labelpigs(void); void labels(void); -void labelswap(void); -void labeltcp(void); void load(void); int netcmd(const char *, const char *); void nlisterr(struct nlist []); -WINDOW *openicmp(void); -WINDOW *openicmp6(void); -WINDOW *openifstat(void); -WINDOW *openip(void); -WINDOW *openip6(void); -WINDOW *openiostat(void); -WINDOW *openkre(void); -WINDOW *opennetstat(void); -WINDOW *openpigs(void); -WINDOW *openswap(void); -WINDOW *opentcp(void); int prefix(const char *, const char *); void reseticmp(void); void reseticmp6(void); void resetip(void); void resetip6(void); void resettcp(void); -void showicmp(void); -void showicmp6(void); -void showifstat(void); -void showip(void); -void showip6(void); -void showiostat(void); -void showkre(void); -void shownetstat(void); -void showpigs(void); -void showswap(void); +void resetsctp(void); +void resetzarc(void); void showtcp(void); void status(void); void suspend(int); @@ -178,8 +116,18 @@ void sysputwuint64(WINDOW* , int, int, int, uint64_t, int); int init ## name(void); \ void label ## name(void); \ WINDOW *open ## name(void); \ - void reset ## name(void); \ void show ## name(void) -SYSTAT_CMD( zarc ); +SYSTAT_CMD( kre ); +SYSTAT_CMD( icmp ); +SYSTAT_CMD( icmp6 ); +SYSTAT_CMD( ifstat ); +SYSTAT_CMD( iostat ); +SYSTAT_CMD( ip ); +SYSTAT_CMD( ip6 ); +SYSTAT_CMD( netstat ); +SYSTAT_CMD( pigs ); SYSTAT_CMD( sctp ); +SYSTAT_CMD( swap ); +SYSTAT_CMD( tcp ); +SYSTAT_CMD( zarc ); 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 0bec6aceaaa..879f6548d86 100644 --- a/usr.bin/systat/pigs.c +++ b/usr.bin/systat/pigs.c @@ -56,7 +56,7 @@ __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 { 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#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 + +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 @@ -1,4 +1,6 @@ /*- + * SPDX-License-Identifier: BSD-3-Clause + * * Copyright (c) 2019, 2020 Yoshihiro Ota * * Redistribution and use in source and binary forms, with or without @@ -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); } 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 +#include 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);