From owner-freebsd-current@freebsd.org Sat Apr 3 00:13:14 2021 Return-Path: Delivered-To: freebsd-current@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 87C3D5B786D for ; Sat, 3 Apr 2021 00:13:14 +0000 (UTC) (envelope-from ota@j.email.ne.jp) Received: from mail03.asahi-net.or.jp (mail03.asahi-net.or.jp [202.224.55.15]) by mx1.freebsd.org (Postfix) with ESMTP id 4FBy7D4Zppz4bpy for ; Sat, 3 Apr 2021 00:13:12 +0000 (UTC) (envelope-from ota@j.email.ne.jp) Received: from vmware12.advok.com (cpe-184-152-96-96.nj.res.rr.com [184.152.96.96]) (Authenticated sender: NR2Y-OOT) by mail03.asahi-net.or.jp (Postfix) with ESMTPSA id 834CC6EBFB for ; Sat, 3 Apr 2021 09:13:09 +0900 (JST) Date: Fri, 2 Apr 2021 20:12:14 -0400 From: Yoshihiro Ota To: freebsd-current@freebsd.org Subject: systat -swap to display large swap space users Message-Id: <20210402201214.bdd588a10d430c393585e1e3@j.email.ne.jp> X-Mailer: Sylpheed 3.7.0 (GTK+ 2.24.32; i386-portbld-freebsd12.1) Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="Multipart=_Fri__2_Apr_2021_20_12_14_-0400_=uWnY=jy_qfrslZE" X-Rspamd-Queue-Id: 4FBy7D4Zppz4bpy X-Spamd-Bar: -- Authentication-Results: mx1.freebsd.org; dkim=none; dmarc=none; spf=pass (mx1.freebsd.org: domain of ota@j.email.ne.jp designates 202.224.55.15 as permitted sender) smtp.mailfrom=ota@j.email.ne.jp X-Spamd-Result: default: False [-2.80 / 15.00]; RCVD_VIA_SMTP_AUTH(0.00)[]; MV_CASE(0.50)[]; R_SPF_ALLOW(-0.20)[+ip4:202.224.55.0/24]; HAS_ATTACHMENT(0.00)[]; TO_DN_NONE(0.00)[]; NEURAL_HAM_SHORT(-1.00)[-1.000]; RCVD_NO_TLS_LAST(0.10)[]; RECEIVED_SPAMHAUS_PBL(0.00)[184.152.96.96:received]; MIME_TRACE(0.00)[0:+,1:+,2:+]; RBL_DBL_DONT_QUERY_IPS(0.00)[202.224.55.15:from]; FROM_EQ_ENVFROM(0.00)[]; R_DKIM_NA(0.00)[]; MID_RHS_MATCH_FROM(0.00)[]; ASN(0.00)[asn:4685, ipnet:202.224.32.0/19, country:JP]; ARC_NA(0.00)[]; NEURAL_HAM_MEDIUM(-1.00)[-1.000]; RCVD_IN_DNSWL_LOW(-0.10)[202.224.55.15:from]; FROM_HAS_DN(0.00)[]; TO_MATCH_ENVRCPT_ALL(0.00)[]; NEURAL_HAM_LONG(-1.00)[-1.000]; MIME_GOOD(-0.10)[multipart/mixed,text/plain,text/x-diff]; PREVIOUSLY_DELIVERED(0.00)[freebsd-current@freebsd.org]; DMARC_NA(0.00)[email.ne.jp]; RCPT_COUNT_ONE(0.00)[1]; SPAMHAUS_ZRD(0.00)[202.224.55.15:from:127.0.2.255]; RCVD_COUNT_TWO(0.00)[2]; MAILMAN_DEST(0.00)[freebsd-current] X-BeenThere: freebsd-current@freebsd.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Discussions about the use of FreeBSD-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 03 Apr 2021 00:13:14 -0000 This is a multi-part message in MIME format. --Multipart=_Fri__2_Apr_2021_20_12_14_-0400_=uWnY=jy_qfrslZE Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit 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 --Multipart=_Fri__2_Apr_2021_20_12_14_-0400_=uWnY=jy_qfrslZE Content-Type: text/x-diff; name="systat-proc-swap-main.diff" Content-Disposition: attachment; filename="systat-proc-swap-main.diff" Content-Transfer-Encoding: 7bit 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.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 +#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 +__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 @@ -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 +#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); --Multipart=_Fri__2_Apr_2021_20_12_14_-0400_=uWnY=jy_qfrslZE--