Index: user/alc/PQ_LAUNDRY/usr.bin/systat/systat.1 =================================================================== --- user/alc/PQ_LAUNDRY/usr.bin/systat/systat.1 (revision 290832) +++ user/alc/PQ_LAUNDRY/usr.bin/systat/systat.1 (revision 290833) @@ -1,683 +1,683 @@ .\" Copyright (c) 1985, 1990, 1993 .\" The Regents of the University of California. 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. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. .\" .\" @(#)systat.1 8.2 (Berkeley) 12/30/93 .\" $FreeBSD$ .\" -.Dd October 24, 2015 +.Dd November 14, 2015 .Dt SYSTAT 1 .Os .Sh NAME .Nm systat .Nd display system statistics .Sh SYNOPSIS .Nm .Op Fl display .Op Ar display-commands .Op Ar refresh-interval .Sh DESCRIPTION The .Nm utility displays various system statistics in a screen oriented fashion using the curses screen display library, .Xr ncurses 3 . .Pp While .Nm is running the screen is usually divided into two windows (an exception is the vmstat display which uses the entire screen). The upper window depicts the current system load average. The information displayed in the lower window may vary, depending on user commands. The last line on the screen is reserved for user input and error messages. .Pp By default .Nm displays the processes getting the largest percentage of the processor in the lower window. Other displays show swap space usage, disk .Tn I/O statistics (a la .Xr iostat 8 ) , virtual memory statistics (a la .Xr vmstat 8 ) , .Tn TCP/IP statistics, and network connections (a la .Xr netstat 1 ) . .Pp Input is interpreted at two different levels. A ``global'' command interpreter processes all keyboard input. If this command interpreter fails to recognize a command, the input line is passed to a per-display command interpreter. This allows each display to have certain display-specific commands. .Pp Command line options: .Bl -tag -width "refresh_interval" .It Fl Ns Ar display The .Fl flag expects .Ar display to be one of: .Ic icmp , .Ic icmp6 , .Ic ifstat , .Ic iostat , .Ic ip , .Ic ip6 , .Ic netstat , .Ic pigs , .Ic sctp , .Ic swap , .Ic tcp , .Ic vmstat , or .Ic zarc , These displays can also be requested interactively (without the .Dq Fl ) and are described in full detail below. .It Ar refresh-interval The .Ar refresh-value specifies the screen refresh time interval in seconds. Time interval can be fractional. .It Ar display-commands A list of commands specific for this display. These commands can also be entered interactively and are described for each display separately below. If the command of the display requires an argument or arguments, it is possible to specify them as separate command line argument. To finish display commands it is possible to use double dash at the end of the list. For example: .Pp .Dl Nm Fl ifstat Fl match Ar bge0,em1 Fl pps .Pp This will display statistics of packets per second for network interfaces named as bge0 and em1. .Pp .Dl Nm Fl iostat Fl numeric Fl - Ar 2.1 .Pp This will display all IO statistics in a numeric format and the information will be refreshed each 2.1 seconds. .El .Pp Certain characters cause immediate action by .Nm . These are .Bl -tag -width Fl .It Ic \&^L Refresh the screen. .It Ic \&^G Print the name of the current ``display'' being shown in the lower window and the refresh interval. .It Ic \&: Move the cursor to the command line and interpret the input line typed as a command. While entering a command the current character erase, word erase, and line kill characters may be used. .El .Pp The following commands are interpreted by the ``global'' command interpreter. .Bl -tag -width Fl .It Ic help Print the names of the available displays on the command line. .It Ic load Print the load average over the past 1, 5, and 15 minutes on the command line. .It Ic stop Stop refreshing the screen. .It Xo .Op Ic start .Op Ar number .Xc Start (continue) refreshing the screen. If a second, numeric, argument is provided it is interpreted as a refresh interval (in seconds). Supplying only a number will set the refresh interval to this value. .It Ic quit Exit .Nm . (This may be abbreviated to .Ic q . ) .El .Pp The available displays are: .Bl -tag -width Ic .It Ic pigs Display, in the lower window, those processes resident in main memory and getting the largest portion of the processor (the default display). When less than 100% of the processor is scheduled to user processes, the remaining time is accounted to the ``idle'' process. .It Ic icmp Display, in the lower window, statistics about messages received and transmitted by the Internet Control Message Protocol .Pq Dq Tn ICMP . The left half of the screen displays information about received packets, and the right half displays information regarding transmitted packets. .Pp The .Ic icmp display understands two commands: .Ic mode and .Ic reset . The .Ic mode command is used to select one of four display modes, given as its argument: .Bl -tag -width absoluteXX -compact .It Ic rate : show the rate of change of each value in packets (the default) per second .It Ic delta : show the rate of change of each value in packets per refresh interval .It Ic since : show the total change of each value since the display was last reset .It Ic absolute : show the absolute value of each statistic .El .Pp The .Ic reset command resets the baseline for .Ic since mode. The .Ic mode command with no argument will display the current mode in the command line. .It Ic icmp6 This display is like the .Ic icmp display, but displays statistics for IPv6 ICMP. .It Ic ip Otherwise identical to the .Ic icmp display, except that it displays .Tn IP and .Tn UDP statistics. .It Ic ip6 Like the .Ic ip display, except that it displays .Tn IPv6 statistics. It does not display .Tn UDP statistics. .It Ic sctp Like .Ic icmp , but with .Tn SCTP statistics. .It Ic tcp Like .Ic icmp , but with .Tn TCP statistics. .It Ic iostat Display, in the lower window, statistics about processor use and disk throughput. Statistics on processor use appear as bar graphs of the amount of time executing in user mode (``user''), in user mode running low priority processes (``nice''), in system mode (``system''), in interrupt mode (``interrupt''), and idle (``idle''). Statistics on disk throughput show, for each drive, megabytes per second, average number of disk transactions per second, and average kilobytes of data per transaction. This information may be displayed as bar graphs or as rows of numbers which scroll downward. Bar graphs are shown by default. .Pp The following commands are specific to the .Ic iostat display; the minimum unambiguous prefix may be supplied. .Pp .Bl -tag -width Fl -compact .It Cm numbers Show the disk .Tn I/O statistics in numeric form. Values are displayed in numeric columns which scroll downward. .It Cm bars Show the disk .Tn I/O statistics in bar graph form (default). .It Cm kbpt Toggle the display of kilobytes per transaction. (the default is to 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. The .Ar Used column indicates the total blocks used so far; the graph shows the percentage of space in use on each partition. If there are more than one swap partition in use, a total line is also shown. Areas known to the kernel, but not in use are shown as not available. .It Ic vmstat Take over the entire display and show a (rather crowded) compendium of statistics related to virtual memory usage, process scheduling, device interrupts, system name translation caching, disk .Tn I/O etc. .Pp The upper left quadrant of the screen shows the number of users logged in and the load average over the last one, five, and fifteen minute intervals. Below this line are statistics on memory utilization. The first row of the table reports memory usage only among active processes, that is processes that have run in the previous twenty seconds. The second row reports on memory usage of all processes. The first column reports on the number of kilobytes in physical pages claimed by processes. The second column reports the number of kilobytes in physical pages that are devoted to read only text pages. The third and fourth columns report the same two figures for virtual pages, that is the number of kilobytes in pages that would be needed if all processes had all of their pages. Finally the last column shows the number of kilobytes in physical pages on the free list. .Pp Below the memory display is a list of the average number of processes (over the last refresh interval) that are runnable (`r'), in page wait (`p'), in disk wait other than paging (`d'), sleeping (`s'), and swapped out but desiring to run (`w'). The row also shows the average number of context switches (`Csw'), traps (`Trp'; includes page faults), system calls (`Sys'), interrupts (`Int'), network software interrupts (`Sof'), and page faults (`Flt'). .Pp Below the process queue length listing is a numerical listing and a bar graph showing the amount of system (shown as `='), interrupt (shown as `+'), user (shown as `>'), nice (shown as `-'), and idle time (shown as ` '). .Pp Below the process display are statistics on name translations. It lists the number of names translated in the previous interval, the number and percentage of the translations that were handled by the system wide name translation cache, and the number and percentage of the translations that were handled by the per process name translation cache. .Pp To the right of the name translations display are lines showing the number of dirty buffers in the buffer cache (`dtbuf'), desired maximum size of vnode cache (`desvn'), number of vnodes actually allocated (`numvn'), and number of allocated vnodes that are free (`frevn'). .Pp At the bottom left is the disk usage display. It reports the number of kilobytes per transaction, transactions per second, megabytes per second and the percentage of the time the disk was busy averaged over the refresh period of the display (by default, five seconds). The system keeps statistics on most every storage device. In general, up to seven devices are displayed. The devices displayed by default are the first devices in the kernel's device list. See .Xr devstat 3 and .Xr devstat 9 for details on the devstat system. .Pp Under the date in the upper right hand quadrant are statistics on paging and swapping activity. The first two columns report the average number of pages brought in and out per second over the last refresh interval due to page faults and the paging daemon. The third and fourth columns report the average number of pages brought in and out per second over the last refresh interval due to swap requests initiated by the scheduler. The first row of the display shows the average number of disk transfers per second over the last refresh interval; the second row of the display shows the average number of pages transferred per second over the last refresh interval. .Pp Below the paging statistics is a column of lines regarding the virtual memory system. The first few lines describe, in units (except as noted below) of pages per second averaged over the sampling interval, pages copied on write (`cow'), pages zero filled on demand (`zfod'), pages optimally zero filled on demand (`ozfod'), the ratio of the (average) ozfod / zfod as a percentage (`%ozfod'), pages freed by the page daemon (`daefr'), pages freed by exiting processes (`prcfr'), total pages freed (`totfr'), pages reactivated from the free list (`react'), the average number of times per second that the page daemon was awakened (`pdwak'), pages analyzed by the page daemon (`pdpgs'), and in-transit blocking page faults (`intrn'). Note that the units are special for `%ozfod' and `pdwak'. The next few lines describe, as amounts of memory in kilobytes, pages wired down (`wire'), active pages (`act'), inactive pages (`inact'), -pages on the cache queue (`cache'), +pages in the laundry queue (`laund'), and free pages (`free'). Note that the values displayed are the current transient ones; they are not averages. .Pp At the bottom of this column is a line showing the amount of virtual memory, in kilobytes, mapped into the buffer cache (`buf'). This statistic is not useful. It exists only as a placeholder for the corresponding useful statistic (the amount of real memory used to cache disks). The most important component of the latter (the amount of real memory used by the vm system to cache disks) is not available, but can be guessed from the `inact' amount under some system loads. .Pp Running down the right hand side of the display is a breakdown of the interrupts being handled by the system. At the top of the list is the total interrupts per second over the time interval. The rest of the column breaks down the total on a device by device basis. Only devices that have interrupted at least once since boot time are shown. .Pp The following commands are specific to the .Ic vmstat display; the minimum unambiguous prefix may be supplied. .Pp .Bl -tag -width Ar -compact .It Cm boot Display cumulative statistics since the system was booted. .It Cm run Display statistics as a running total from the point this command is given. .It Cm time Display statistics averaged over the refresh interval (the default). .It Cm zero Reset running statistics to zero. .El .It Ic zarc display arc cache usage and hit/miss statistics. .It Ic netstat Display, in the lower window, network connections. By default, network servers awaiting requests are not displayed. Each address is displayed in the format ``host.port'', with each shown symbolically, when possible. It is possible to have addresses displayed numerically, limit the display to a set of ports, hosts, and/or protocols (the minimum unambiguous prefix may be supplied): .Pp .Bl -tag -width Ar -compact .It Cm all Toggle the displaying of server processes awaiting requests (this is the equivalent of the .Fl a flag to .Xr netstat 1 ) . .It Cm numbers Display network addresses numerically. .It Cm names Display network addresses symbolically. .It Cm proto Ar protocol Display only network connections using the indicated .Ar protocol . Supported protocols are ``tcp'', ``udp'', and ``all''. .It Cm ignore Op Ar items Do not display information about connections associated with the specified hosts or ports. Hosts and ports may be specified by name (``vangogh'', ``ftp''), or numerically. Host addresses use the Internet dot notation (``128.32.0.9''). Multiple items may be specified with a single command by separating them with spaces. .It Cm display Op Ar items Display information about the connections associated with the specified hosts or ports. As for .Ar ignore , .Op Ar items may be names or numbers. .It Cm show Op Ar ports\&|hosts Show, on the command line, the currently selected protocols, hosts, and ports. Hosts and ports which are being ignored are prefixed with a `!'. If .Ar ports or .Ar hosts is supplied as an argument to .Cm show , then only the requested information will be displayed. .It Cm reset Reset the port, host, and protocol matching mechanisms to the default (any protocol, port, or host). .El .It Ic ifstat Display the network traffic going through active interfaces on the system. Idle interfaces will not be displayed until they receive some traffic. .Pp For each interface being displayed, the current, peak and total statistics are displayed for incoming and outgoing traffic. By default, the .Ic ifstat display will automatically scale the units being used so that they are in a human-readable format. The scaling units used for the current and peak traffic columns can be altered by the .Ic scale command. .Bl -tag -width ".Cm scale Op Ar units" .It Cm scale Op Ar units Modify the scale used to display the current and peak traffic over all interfaces. The following units are recognised: kbit, kbyte, mbit, mbyte, gbit, gbyte and auto. .It Cm pps Show statistics in packets per second instead of bytes/bits per second. A subsequent call of .Ic pps switches this mode off. .It Cm match Op Ar patterns Display only interfaces that match pattern provided as an argument. Patterns should be in shell syntax separated by whitespaces or commas. If this command is called without arguments then all interfaces are displayed. For example: .Pp .Dl match em0, bge1 .Pp This will display em0 and bge1 interfaces. .Pp .Dl match em*, bge*, lo0 .Pp This will display all .Ic em interfaces, all .Ic bge interfaces and the loopback interface. .El .El .Pp Commands to switch between displays may be abbreviated to the minimum unambiguous prefix; for example, ``io'' for ``iostat''. Certain information may be discarded when the screen size is insufficient for display. For example, on a machine with 10 drives the .Ic iostat bar graph displays only 3 drives on a 24 line terminal. When a bar graph would overflow the allotted screen space it is truncated and the actual value is printed ``over top'' of the bar. .Pp The following commands are common to each display which shows information about disk drives. These commands are used to select a set of drives to report on, should your system have more drives configured than can normally be displayed on the screen. .Pp .Bl -tag -width Ar -compact .It Cm ignore Op Ar drives Do not display information about the drives indicated. Multiple drives may be specified, separated by spaces. .It Cm display Op Ar drives Display information about the drives indicated. Multiple drives may be specified, separated by spaces. .It Cm only Op Ar drives Display only the specified drives. Multiple drives may be specified, separated by spaces. .It Cm drives Display a list of available devices. .It Cm match Xo .Ar type , Ns Ar if , Ns Ar pass .Op | Ar ... .Xc Display devices matching the given pattern. The basic matching expressions are the same as those used in .Xr iostat 8 with one difference. Instead of specifying multiple .Fl t arguments which are then ORed together, the user instead specifies multiple matching expressions joined by the pipe .Pq Ql \&| character. The comma separated arguments within each matching expression are ANDed together, and then the pipe separated matching expressions are ORed together. Any device matching the combined expression will be displayed, if there is room to display it. For example: .Pp .Dl match da,scsi | cd,ide .Pp This will display all SCSI Direct Access devices and all IDE CDROM devices. .Pp .Dl match da | sa | cd,pass .Pp This will display all Direct Access devices, all Sequential Access devices, and all passthrough devices that provide access to CDROM drives. .El .Sh FILES .Bl -tag -width /boot/kernel/kernel -compact .It Pa /boot/kernel/kernel For the namelist. .It Pa /dev/kmem For information in main memory. .It Pa /etc/hosts For host names. .It Pa /etc/networks For network names. .It Pa /etc/services For port names. .El .Sh SEE ALSO .Xr netstat 1 , .Xr kvm 3 , .Xr icmp 4 , .Xr icmp6 4 , .Xr ip 4 , .Xr ip6 4 , .Xr tcp 4 , .Xr udp 4 , .Xr gstat 8 , .Xr iostat 8 , .Xr vmstat 8 .Sh HISTORY The .Nm program appeared in .Bx 4.3 . The .Ic icmp , .Ic ip , and .Ic tcp displays appeared in .Fx 3.0 ; the notion of having different display modes for the .Tn ICMP , .Tn IP , .Tn TCP , and .Tn UDP statistics was stolen from the .Fl C option to .Xr netstat 1 in Silicon Graphics' .Tn IRIX system. .Sh BUGS Certain displays presume a minimum of 80 characters per line. The .Ic vmstat display looks out of place because it is (it was added in as a separate display rather than created as a new program). Index: user/alc/PQ_LAUNDRY/usr.bin/systat/vmstat.c =================================================================== --- user/alc/PQ_LAUNDRY/usr.bin/systat/vmstat.c (revision 290832) +++ user/alc/PQ_LAUNDRY/usr.bin/systat/vmstat.c (revision 290833) @@ -1,884 +1,884 @@ /*- * Copyright (c) 1983, 1989, 1992, 1993 * The Regents of the University of California. 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. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. */ #include __FBSDID("$FreeBSD$"); #ifdef lint static const char sccsid[] = "@(#)vmstat.c 8.2 (Berkeley) 1/12/94"; #endif /* * Cursed vmstat -- from Robert Elz. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "systat.h" #include "extern.h" #include "devs.h" static struct Info { long time[CPUSTATES]; u_int v_swtch; /* context switches */ u_int v_trap; /* calls to trap */ u_int v_syscall; /* calls to syscall() */ u_int v_intr; /* device interrupts */ u_int v_soft; /* software interrupts */ /* * Virtual memory activity. */ u_int v_vm_faults; /* number of address memory faults */ u_int v_io_faults; /* page faults requiring I/O */ u_int v_cow_faults; /* number of copy-on-writes */ u_int v_zfod; /* pages zero filled on demand */ u_int v_ozfod; /* optimized zero fill pages */ u_int v_swapin; /* swap pager pageins */ u_int v_swapout; /* swap pager pageouts */ u_int v_swappgsin; /* swap pager pages paged in */ u_int v_swappgsout; /* swap pager pages paged out */ u_int v_vnodein; /* vnode pager pageins */ u_int v_vnodeout; /* vnode pager pageouts */ u_int v_vnodepgsin; /* vnode_pager pages paged in */ u_int v_vnodepgsout; /* vnode pager pages paged out */ u_int v_intrans; /* intransit blocking page faults */ u_int v_reactivated; /* number of pages reactivated from free list */ u_int v_pdwakeups; /* number of times daemon has awaken from sleep */ u_int v_pdpages; /* number of pages analyzed by daemon */ u_int v_dfree; /* pages freed by daemon */ u_int v_pfree; /* pages freed by exiting processes */ u_int v_tfree; /* total pages freed */ /* * Distribution of page usages. */ u_int v_page_size; /* page size in bytes */ u_int v_free_count; /* number of pages free */ u_int v_wire_count; /* number of pages wired down */ u_int v_active_count; /* number of pages active */ u_int v_inactive_count; /* number of pages inactive */ - u_int v_cache_count; /* number of pages on buffer cache queue */ + u_int v_laundry_count; /* number of pages in laundry queue */ struct vmtotal Total; struct nchstats nchstats; long nchcount; long *intrcnt; long bufspace; int desiredvnodes; long numvnodes; long freevnodes; int numdirtybuffers; } s, s1, s2, z; struct statinfo cur, last, run; #define total s.Total #define nchtotal s.nchstats #define oldnchtotal s1.nchstats static enum state { BOOT, TIME, RUN } state = TIME; static void allocinfo(struct Info *); static void copyinfo(struct Info *, struct Info *); static float cputime(int); static void dinfo(int, int, struct statinfo *, struct statinfo *); static void getinfo(struct Info *); static void putint(int, int, int, int); static void putfloat(double, int, int, int, int, int); static void putlongdouble(long double, int, int, int, int, int); static int ucount(void); static int ncpu; static char buf[26]; static time_t t; static double etime; static int nintr; static long *intrloc; static char **intrname; static int nextintsrow; WINDOW * openkre(void) { return (stdscr); } void closekre(WINDOW *w) { if (w == NULL) return; wclear(w); wrefresh(w); } /* * These constants define where the major pieces are laid out */ #define STATROW 0 /* uses 1 row and 67 cols */ #define STATCOL 0 #define MEMROW 2 /* uses 4 rows and 45 cols */ #define MEMCOL 0 #define PAGEROW 2 /* uses 4 rows and 30 cols */ #define PAGECOL 47 #define INTSROW 6 /* uses all rows to bottom and 16 cols */ #define INTSCOL 64 #define PROCSROW 6 /* uses 3 rows and 19 cols */ #define PROCSCOL 0 #define GENSTATROW 7 /* uses 2 rows and 29 cols */ #define GENSTATCOL 21 #define VMSTATROW 7 /* uses 17 rows and 12-14 cols */ #define VMSTATCOL 49 /* actually 50-51 for some fields */ #define GRAPHROW 10 /* uses 3 rows and 49-51 cols */ #define GRAPHCOL 0 #define VNSTATROW 13 /* uses 4 rows and 13 columns */ #define VNSTATCOL 35 #define NAMEIROW 14 /* uses 3 rows and 32 cols */ #define NAMEICOL 0 #define DISKROW 18 /* uses 5 rows and 47 cols (for 7 drives) */ #define DISKCOL 0 #define DRIVESPACE 7 /* max # for space */ #define MAXDRIVES DRIVESPACE /* max # to display */ int initkre(void) { char *cp, *cp1, *cp2, *intrnamebuf, *nextcp; int i; size_t sz; if ((num_devices = devstat_getnumdevs(NULL)) < 0) { warnx("%s", devstat_errbuf); return(0); } cur.dinfo = calloc(1, sizeof(struct devinfo)); last.dinfo = calloc(1, sizeof(struct devinfo)); run.dinfo = calloc(1, sizeof(struct devinfo)); if (dsinit(MAXDRIVES, &cur, &last, &run) != 1) return(0); if (nintr == 0) { if (sysctlbyname("hw.intrcnt", NULL, &sz, NULL, 0) == -1) { error("sysctl(hw.intrcnt...) failed: %s", strerror(errno)); return (0); } nintr = sz / sizeof(u_long); intrloc = calloc(nintr, sizeof (long)); intrname = calloc(nintr, sizeof (char *)); intrnamebuf = sysctl_dynread("hw.intrnames", NULL); if (intrnamebuf == NULL || intrname == NULL || intrloc == NULL) { error("Out of memory"); if (intrnamebuf) free(intrnamebuf); if (intrname) free(intrname); if (intrloc) free(intrloc); nintr = 0; return(0); } for (cp = intrnamebuf, i = 0; i < nintr; i++) { nextcp = cp + strlen(cp) + 1; /* Discard trailing spaces. */ for (cp1 = nextcp - 1; cp1 > cp && *(cp1 - 1) == ' '; ) *--cp1 = '\0'; /* Convert "irqN: name" to "name irqN". */ if (strncmp(cp, "irq", 3) == 0) { cp1 = cp + 3; while (isdigit((u_char)*cp1)) cp1++; if (cp1 != cp && *cp1 == ':' && *(cp1 + 1) == ' ') { sz = strlen(cp); *cp1 = '\0'; cp1 = cp1 + 2; cp2 = strdup(cp); bcopy(cp1, cp, sz - (cp1 - cp) + 1); if (sz <= 10 + 4) { strcat(cp, " "); strcat(cp, cp2 + 3); } free(cp2); } } /* * Convert "name irqN" to "name N" if the former is * longer than the field width. */ if ((cp1 = strstr(cp, "irq")) != NULL && strlen(cp) > 10) bcopy(cp1 + 3, cp1, strlen(cp1 + 3) + 1); intrname[i] = cp; cp = nextcp; } nextintsrow = INTSROW + 2; allocinfo(&s); allocinfo(&s1); allocinfo(&s2); allocinfo(&z); } getinfo(&s2); copyinfo(&s2, &s1); return(1); } void fetchkre(void) { time_t now; struct tm *tp; static int d_first = -1; if (d_first < 0) d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); time(&now); tp = localtime(&now); (void) strftime(buf, sizeof(buf), d_first ? "%e %b %R" : "%b %e %R", tp); getinfo(&s); } void labelkre(void) { int i, j; clear(); mvprintw(STATROW, STATCOL + 6, "users Load"); mvprintw(MEMROW, MEMCOL, "Mem:KB REAL VIRTUAL"); mvprintw(MEMROW + 1, MEMCOL, " Tot Share Tot Share"); mvprintw(MEMROW + 2, MEMCOL, "Act"); mvprintw(MEMROW + 3, MEMCOL, "All"); mvprintw(MEMROW + 1, MEMCOL + 41, "Free"); mvprintw(PAGEROW, PAGECOL, " VN PAGER SWAP PAGER"); mvprintw(PAGEROW + 1, PAGECOL, " in out in out"); mvprintw(PAGEROW + 2, PAGECOL, "count"); mvprintw(PAGEROW + 3, PAGECOL, "pages"); mvprintw(INTSROW, INTSCOL + 1, "Interrupts"); mvprintw(INTSROW + 1, INTSCOL + 6, "total"); mvprintw(VMSTATROW, VMSTATCOL + 9, "ioflt"); mvprintw(VMSTATROW + 1, VMSTATCOL + 9, "cow"); mvprintw(VMSTATROW + 2, VMSTATCOL + 9, "zfod"); mvprintw(VMSTATROW + 3, VMSTATCOL + 9, "ozfod"); mvprintw(VMSTATROW + 4, VMSTATCOL + 9 - 1, "%%ozfod"); mvprintw(VMSTATROW + 5, VMSTATCOL + 9, "daefr"); mvprintw(VMSTATROW + 6, VMSTATCOL + 9, "prcfr"); mvprintw(VMSTATROW + 7, VMSTATCOL + 9, "totfr"); mvprintw(VMSTATROW + 8, VMSTATCOL + 9, "react"); mvprintw(VMSTATROW + 9, VMSTATCOL + 9, "pdwak"); mvprintw(VMSTATROW + 10, VMSTATCOL + 9, "pdpgs"); mvprintw(VMSTATROW + 11, VMSTATCOL + 9, "intrn"); mvprintw(VMSTATROW + 12, VMSTATCOL + 9, "wire"); mvprintw(VMSTATROW + 13, VMSTATCOL + 9, "act"); mvprintw(VMSTATROW + 14, VMSTATCOL + 9, "inact"); - mvprintw(VMSTATROW + 15, VMSTATCOL + 9, "cache"); + mvprintw(VMSTATROW + 15, VMSTATCOL + 9, "laund"); mvprintw(VMSTATROW + 16, VMSTATCOL + 9, "free"); if (LINES - 1 > VMSTATROW + 17) mvprintw(VMSTATROW + 17, VMSTATCOL + 9, "buf"); mvprintw(GENSTATROW, GENSTATCOL, " Csw Trp Sys Int Sof Flt"); mvprintw(GRAPHROW, GRAPHCOL, " . %%Sys . %%Intr . %%User . %%Nice . %%Idle"); mvprintw(PROCSROW, PROCSCOL, "Proc:"); mvprintw(PROCSROW + 1, PROCSCOL, " r p d s w"); mvprintw(GRAPHROW + 1, GRAPHCOL, "| | | | | | | | | | |"); mvprintw(VNSTATROW, VNSTATCOL + 8, "dtbuf"); mvprintw(VNSTATROW + 1, VNSTATCOL + 8, "desvn"); mvprintw(VNSTATROW + 2, VNSTATCOL + 8, "numvn"); mvprintw(VNSTATROW + 3, VNSTATCOL + 8, "frevn"); mvprintw(NAMEIROW, NAMEICOL, "Namei Name-cache Dir-cache"); mvprintw(NAMEIROW + 1, NAMEICOL, " Calls hits %% hits %%"); mvprintw(DISKROW, DISKCOL, "Disks"); mvprintw(DISKROW + 1, DISKCOL, "KB/t"); mvprintw(DISKROW + 2, DISKCOL, "tps"); mvprintw(DISKROW + 3, DISKCOL, "MB/s"); mvprintw(DISKROW + 4, DISKCOL, "%%busy"); /* * For now, we don't support a fourth disk statistic. So there's * no point in providing a label for it. If someone can think of a * fourth useful disk statistic, there is room to add it. */ /* mvprintw(DISKROW + 4, DISKCOL, " msps"); */ j = 0; for (i = 0; i < num_devices && j < MAXDRIVES; i++) if (dev_select[i].selected) { char tmpstr[80]; sprintf(tmpstr, "%s%d", dev_select[i].device_name, dev_select[i].unit_number); mvprintw(DISKROW, DISKCOL + 5 + 6 * j, " %5.5s", tmpstr); j++; } for (i = 0; i < nintr; i++) { if (intrloc[i] == 0) continue; mvprintw(intrloc[i], INTSCOL + 6, "%-10.10s", intrname[i]); } } #define X(fld) {t=s.fld[i]; s.fld[i]-=s1.fld[i]; if(state==TIME) s1.fld[i]=t;} #define Q(fld) {t=cur.fld[i]; cur.fld[i]-=last.fld[i]; if(state==TIME) last.fld[i]=t;} #define Y(fld) {t = s.fld; s.fld -= s1.fld; if(state == TIME) s1.fld = t;} #define Z(fld) {t = s.nchstats.fld; s.nchstats.fld -= s1.nchstats.fld; \ if(state == TIME) s1.nchstats.fld = t;} #define PUTRATE(fld, l, c, w) \ do { \ Y(fld); \ putint((int)((float)s.fld/etime + 0.5), l, c, w); \ } while (0) #define MAXFAIL 5 static char cpuchar[CPUSTATES] = { '=' , '+', '>', '-', ' ' }; static char cpuorder[CPUSTATES] = { CP_SYS, CP_INTR, CP_USER, CP_NICE, CP_IDLE }; void showkre(void) { float f1, f2; int psiz, inttotal; int i, l, lc; static int failcnt = 0; etime = 0; for(i = 0; i < CPUSTATES; i++) { X(time); Q(cp_time); etime += s.time[i]; } if (etime < 5.0) { /* < 5 ticks - ignore this trash */ if (failcnt++ >= MAXFAIL) { clear(); mvprintw(2, 10, "The alternate system clock has died!"); mvprintw(3, 10, "Reverting to ``pigs'' display."); move(CMDLINE, 0); refresh(); failcnt = 0; sleep(5); command("pigs"); } return; } failcnt = 0; etime /= hertz; etime /= ncpu; inttotal = 0; for (i = 0; i < nintr; i++) { if (s.intrcnt[i] == 0) continue; X(intrcnt); l = (int)((float)s.intrcnt[i]/etime + 0.5); inttotal += l; if (intrloc[i] == 0) { if (nextintsrow == LINES) continue; intrloc[i] = nextintsrow++; mvprintw(intrloc[i], INTSCOL + 6, "%-10.10s", intrname[i]); } putint(l, intrloc[i], INTSCOL, 5); } putint(inttotal, INTSROW + 1, INTSCOL, 5); Z(ncs_goodhits); Z(ncs_badhits); Z(ncs_miss); Z(ncs_long); Z(ncs_pass2); Z(ncs_2passes); Z(ncs_neghits); s.nchcount = nchtotal.ncs_goodhits + nchtotal.ncs_badhits + nchtotal.ncs_miss + nchtotal.ncs_long + nchtotal.ncs_neghits; if (state == TIME) s1.nchcount = s.nchcount; psiz = 0; f2 = 0.0; for (lc = 0; lc < CPUSTATES; lc++) { i = cpuorder[lc]; f1 = cputime(i); f2 += f1; l = (int) ((f2 + 1.0) / 2.0) - psiz; putfloat(f1, GRAPHROW, GRAPHCOL + 10 * lc, 4, 1, 0); move(GRAPHROW + 2, psiz); psiz += l; while (l-- > 0) addch(cpuchar[lc]); } putint(ucount(), STATROW, STATCOL, 5); putfloat(avenrun[0], STATROW, STATCOL + 20, 5, 2, 0); putfloat(avenrun[1], STATROW, STATCOL + 26, 5, 2, 0); putfloat(avenrun[2], STATROW, STATCOL + 32, 5, 2, 0); mvaddstr(STATROW, STATCOL + 55, buf); #define pgtokb(pg) ((pg) * (s.v_page_size / 1024)) putint(pgtokb(total.t_arm), MEMROW + 2, MEMCOL + 4, 7); putint(pgtokb(total.t_armshr), MEMROW + 2, MEMCOL + 12, 7); putint(pgtokb(total.t_avm), MEMROW + 2, MEMCOL + 20, 8); putint(pgtokb(total.t_avmshr), MEMROW + 2, MEMCOL + 29, 8); putint(pgtokb(total.t_rm), MEMROW + 3, MEMCOL + 4, 7); putint(pgtokb(total.t_rmshr), MEMROW + 3, MEMCOL + 12, 7); putint(pgtokb(total.t_vm), MEMROW + 3, MEMCOL + 20, 8); putint(pgtokb(total.t_vmshr), MEMROW + 3, MEMCOL + 29, 8); putint(pgtokb(total.t_free), MEMROW + 2, MEMCOL + 38, 7); putint(total.t_rq - 1, PROCSROW + 2, PROCSCOL, 3); putint(total.t_pw, PROCSROW + 2, PROCSCOL + 4, 3); putint(total.t_dw, PROCSROW + 2, PROCSCOL + 8, 3); putint(total.t_sl, PROCSROW + 2, PROCSCOL + 12, 3); putint(total.t_sw, PROCSROW + 2, PROCSCOL + 16, 3); PUTRATE(v_io_faults, VMSTATROW, VMSTATCOL + 2, 8 - 2); PUTRATE(v_cow_faults, VMSTATROW + 1, VMSTATCOL + 2, 8 - 2); PUTRATE(v_zfod, VMSTATROW + 2, VMSTATCOL + 2, 8 - 2); PUTRATE(v_ozfod, VMSTATROW + 3, VMSTATCOL, 8); putint(s.v_zfod != 0 ? (int)(s.v_ozfod * 100.0 / s.v_zfod) : 0, VMSTATROW + 4, VMSTATCOL + 1, 8 - 1); PUTRATE(v_dfree, VMSTATROW + 5, VMSTATCOL + 2, 8 - 2); PUTRATE(v_pfree, VMSTATROW + 6, VMSTATCOL + 2, 8 - 2); PUTRATE(v_tfree, VMSTATROW + 7, VMSTATCOL, 8); PUTRATE(v_reactivated, VMSTATROW + 8, VMSTATCOL, 8); PUTRATE(v_pdwakeups, VMSTATROW + 9, VMSTATCOL, 8); PUTRATE(v_pdpages, VMSTATROW + 10, VMSTATCOL, 8); PUTRATE(v_intrans, VMSTATROW + 11, VMSTATCOL, 8); putint(pgtokb(s.v_wire_count), VMSTATROW + 12, VMSTATCOL, 8); putint(pgtokb(s.v_active_count), VMSTATROW + 13, VMSTATCOL, 8); putint(pgtokb(s.v_inactive_count), VMSTATROW + 14, VMSTATCOL, 8); - putint(pgtokb(s.v_cache_count), VMSTATROW + 15, VMSTATCOL, 8); + putint(pgtokb(s.v_laundry_count), VMSTATROW + 15, VMSTATCOL, 8); putint(pgtokb(s.v_free_count), VMSTATROW + 16, VMSTATCOL, 8); if (LINES - 1 > VMSTATROW + 17) putint(s.bufspace / 1024, VMSTATROW + 17, VMSTATCOL, 8); PUTRATE(v_vnodein, PAGEROW + 2, PAGECOL + 6, 5); PUTRATE(v_vnodeout, PAGEROW + 2, PAGECOL + 12, 5); PUTRATE(v_swapin, PAGEROW + 2, PAGECOL + 19, 5); PUTRATE(v_swapout, PAGEROW + 2, PAGECOL + 25, 5); PUTRATE(v_vnodepgsin, PAGEROW + 3, PAGECOL + 6, 5); PUTRATE(v_vnodepgsout, PAGEROW + 3, PAGECOL + 12, 5); PUTRATE(v_swappgsin, PAGEROW + 3, PAGECOL + 19, 5); PUTRATE(v_swappgsout, PAGEROW + 3, PAGECOL + 25, 5); PUTRATE(v_swtch, GENSTATROW + 1, GENSTATCOL, 4); PUTRATE(v_trap, GENSTATROW + 1, GENSTATCOL + 5, 4); PUTRATE(v_syscall, GENSTATROW + 1, GENSTATCOL + 10, 4); PUTRATE(v_intr, GENSTATROW + 1, GENSTATCOL + 15, 4); PUTRATE(v_soft, GENSTATROW + 1, GENSTATCOL + 20, 4); PUTRATE(v_vm_faults, GENSTATROW + 1, GENSTATCOL + 25, 4); for (i = 0, lc = 0; i < num_devices && lc < MAXDRIVES; i++) if (dev_select[i].selected) { switch(state) { case TIME: dinfo(i, ++lc, &cur, &last); break; case RUN: dinfo(i, ++lc, &cur, &run); break; case BOOT: dinfo(i, ++lc, &cur, NULL); break; } } putint(s.numdirtybuffers, VNSTATROW, VNSTATCOL, 7); putint(s.desiredvnodes, VNSTATROW + 1, VNSTATCOL, 7); putint(s.numvnodes, VNSTATROW + 2, VNSTATCOL, 7); putint(s.freevnodes, VNSTATROW + 3, VNSTATCOL, 7); putint(s.nchcount, NAMEIROW + 2, NAMEICOL, 8); putint((nchtotal.ncs_goodhits + nchtotal.ncs_neghits), NAMEIROW + 2, NAMEICOL + 9, 7); #define nz(x) ((x) ? (x) : 1) putfloat((nchtotal.ncs_goodhits+nchtotal.ncs_neghits) * 100.0 / nz(s.nchcount), NAMEIROW + 2, NAMEICOL + 17, 3, 0, 1); putint(nchtotal.ncs_pass2, NAMEIROW + 2, NAMEICOL + 21, 7); putfloat(nchtotal.ncs_pass2 * 100.0 / nz(s.nchcount), NAMEIROW + 2, NAMEICOL + 29, 3, 0, 1); #undef nz } int cmdkre(const char *cmd, const char *args) { int retval; if (prefix(cmd, "run")) { retval = 1; copyinfo(&s2, &s1); switch (devstat_getdevs(NULL, &run)) { case -1: errx(1, "%s", devstat_errbuf); break; case 1: num_devices = run.dinfo->numdevs; generation = run.dinfo->generation; retval = dscmd("refresh", NULL, MAXDRIVES, &cur); if (retval == 2) labelkre(); break; default: break; } state = RUN; return (retval); } if (prefix(cmd, "boot")) { state = BOOT; copyinfo(&z, &s1); return (1); } if (prefix(cmd, "time")) { state = TIME; return (1); } if (prefix(cmd, "zero")) { retval = 1; if (state == RUN) { getinfo(&s1); switch (devstat_getdevs(NULL, &run)) { case -1: errx(1, "%s", devstat_errbuf); break; case 1: num_devices = run.dinfo->numdevs; generation = run.dinfo->generation; retval = dscmd("refresh",NULL, MAXDRIVES, &cur); if (retval == 2) labelkre(); break; default: break; } } return (retval); } retval = dscmd(cmd, args, MAXDRIVES, &cur); if (retval == 2) labelkre(); return(retval); } /* calculate number of users on the system */ static int ucount(void) { int nusers = 0; struct utmpx *ut; setutxent(); while ((ut = getutxent()) != NULL) if (ut->ut_type == USER_PROCESS) nusers++; endutxent(); return (nusers); } static float cputime(int indx) { double lt; int i; lt = 0; for (i = 0; i < CPUSTATES; i++) lt += s.time[i]; if (lt == 0.0) lt = 1.0; return (s.time[indx] * 100.0 / lt); } static void putint(int n, int l, int lc, int w) { int snr; char b[128]; move(l, lc); #ifdef DEBUG while (w-- > 0) addch('*'); return; #endif if (n == 0) { while (w-- > 0) addch(' '); return; } snr = snprintf(b, sizeof(b), "%*d", w, n); if (snr != w) snr = snprintf(b, sizeof(b), "%*dk", w - 1, n / 1000); if (snr != w) snr = snprintf(b, sizeof(b), "%*dM", w - 1, n / 1000000); if (snr != w) { while (w-- > 0) addch('*'); return; } addstr(b); } static void putfloat(double f, int l, int lc, int w, int d, int nz) { int snr; char b[128]; move(l, lc); #ifdef DEBUG while (--w >= 0) addch('*'); return; #endif if (nz && f == 0.0) { while (--w >= 0) addch(' '); return; } snr = snprintf(b, sizeof(b), "%*.*f", w, d, f); if (snr != w) snr = snprintf(b, sizeof(b), "%*.0f", w, f); if (snr != w) snr = snprintf(b, sizeof(b), "%*.0fk", w - 1, f / 1000); if (snr != w) snr = snprintf(b, sizeof(b), "%*.0fM", w - 1, f / 1000000); if (snr != w) { while (--w >= 0) addch('*'); return; } addstr(b); } static void putlongdouble(long double f, int l, int lc, int w, int d, int nz) { int snr; char b[128]; move(l, lc); #ifdef DEBUG while (--w >= 0) addch('*'); return; #endif if (nz && f == 0.0) { while (--w >= 0) addch(' '); return; } snr = snprintf(b, sizeof(b), "%*.*Lf", w, d, f); if (snr != w) snr = snprintf(b, sizeof(b), "%*.0Lf", w, f); if (snr != w) snr = snprintf(b, sizeof(b), "%*.0Lfk", w - 1, f / 1000); if (snr != w) snr = snprintf(b, sizeof(b), "%*.0LfM", w - 1, f / 1000000); if (snr != w) { while (--w >= 0) addch('*'); return; } addstr(b); } static void getinfo(struct Info *ls) { struct devinfo *tmp_dinfo; size_t size; int mib[2]; GETSYSCTL("kern.cp_time", ls->time); GETSYSCTL("kern.cp_time", cur.cp_time); GETSYSCTL("vm.stats.sys.v_swtch", ls->v_swtch); GETSYSCTL("vm.stats.sys.v_trap", ls->v_trap); GETSYSCTL("vm.stats.sys.v_syscall", ls->v_syscall); GETSYSCTL("vm.stats.sys.v_intr", ls->v_intr); GETSYSCTL("vm.stats.sys.v_soft", ls->v_soft); GETSYSCTL("vm.stats.vm.v_vm_faults", ls->v_vm_faults); GETSYSCTL("vm.stats.vm.v_io_faults", ls->v_io_faults); GETSYSCTL("vm.stats.vm.v_cow_faults", ls->v_cow_faults); GETSYSCTL("vm.stats.vm.v_zfod", ls->v_zfod); GETSYSCTL("vm.stats.vm.v_ozfod", ls->v_ozfod); GETSYSCTL("vm.stats.vm.v_swapin", ls->v_swapin); GETSYSCTL("vm.stats.vm.v_swapout", ls->v_swapout); GETSYSCTL("vm.stats.vm.v_swappgsin", ls->v_swappgsin); GETSYSCTL("vm.stats.vm.v_swappgsout", ls->v_swappgsout); GETSYSCTL("vm.stats.vm.v_vnodein", ls->v_vnodein); GETSYSCTL("vm.stats.vm.v_vnodeout", ls->v_vnodeout); GETSYSCTL("vm.stats.vm.v_vnodepgsin", ls->v_vnodepgsin); GETSYSCTL("vm.stats.vm.v_vnodepgsout", ls->v_vnodepgsout); GETSYSCTL("vm.stats.vm.v_intrans", ls->v_intrans); GETSYSCTL("vm.stats.vm.v_reactivated", ls->v_reactivated); GETSYSCTL("vm.stats.vm.v_pdwakeups", ls->v_pdwakeups); GETSYSCTL("vm.stats.vm.v_pdpages", ls->v_pdpages); GETSYSCTL("vm.stats.vm.v_dfree", ls->v_dfree); GETSYSCTL("vm.stats.vm.v_pfree", ls->v_pfree); GETSYSCTL("vm.stats.vm.v_tfree", ls->v_tfree); GETSYSCTL("vm.stats.vm.v_page_size", ls->v_page_size); GETSYSCTL("vm.stats.vm.v_free_count", ls->v_free_count); GETSYSCTL("vm.stats.vm.v_wire_count", ls->v_wire_count); GETSYSCTL("vm.stats.vm.v_active_count", ls->v_active_count); GETSYSCTL("vm.stats.vm.v_inactive_count", ls->v_inactive_count); - GETSYSCTL("vm.stats.vm.v_cache_count", ls->v_cache_count); + GETSYSCTL("vm.stats.vm.v_laundry_count", ls->v_laundry_count); GETSYSCTL("vfs.bufspace", ls->bufspace); GETSYSCTL("kern.maxvnodes", ls->desiredvnodes); GETSYSCTL("vfs.numvnodes", ls->numvnodes); GETSYSCTL("vfs.freevnodes", ls->freevnodes); GETSYSCTL("vfs.cache.nchstats", ls->nchstats); GETSYSCTL("vfs.numdirtybuffers", ls->numdirtybuffers); getsysctl("hw.intrcnt", ls->intrcnt, nintr * sizeof(u_long)); size = sizeof(ls->Total); mib[0] = CTL_VM; mib[1] = VM_TOTAL; if (sysctl(mib, 2, &ls->Total, &size, NULL, 0) < 0) { error("Can't get kernel info: %s\n", strerror(errno)); bzero(&ls->Total, sizeof(ls->Total)); } size = sizeof(ncpu); if (sysctlbyname("hw.ncpu", &ncpu, &size, NULL, 0) < 0 || size != sizeof(ncpu)) ncpu = 1; tmp_dinfo = last.dinfo; last.dinfo = cur.dinfo; cur.dinfo = tmp_dinfo; last.snap_time = cur.snap_time; switch (devstat_getdevs(NULL, &cur)) { case -1: errx(1, "%s", devstat_errbuf); break; case 1: num_devices = cur.dinfo->numdevs; generation = cur.dinfo->generation; cmdkre("refresh", NULL); break; default: break; } } static void allocinfo(struct Info *ls) { ls->intrcnt = (long *) calloc(nintr, sizeof(long)); if (ls->intrcnt == NULL) errx(2, "out of memory"); } static void copyinfo(struct Info *from, struct Info *to) { long *intrcnt; /* * time, wds, seek, and xfer are malloc'd so we have to * save the pointers before the structure copy and then * copy by hand. */ intrcnt = to->intrcnt; *to = *from; bcopy(from->intrcnt, to->intrcnt = intrcnt, nintr * sizeof (int)); } static void dinfo(int dn, int lc, struct statinfo *now, struct statinfo *then) { long double transfers_per_second; long double kb_per_transfer, mb_per_second; long double elapsed_time, device_busy; int di; di = dev_select[dn].position; if (then != NULL) { /* Calculate relative to previous sample */ elapsed_time = now->snap_time - then->snap_time; } else { /* Calculate relative to device creation */ elapsed_time = now->snap_time - devstat_compute_etime( &now->dinfo->devices[di].creation_time, NULL); } if (devstat_compute_statistics(&now->dinfo->devices[di], then ? &then->dinfo->devices[di] : NULL, elapsed_time, DSM_KB_PER_TRANSFER, &kb_per_transfer, DSM_TRANSFERS_PER_SECOND, &transfers_per_second, DSM_MB_PER_SECOND, &mb_per_second, DSM_BUSY_PCT, &device_busy, DSM_NONE) != 0) errx(1, "%s", devstat_errbuf); lc = DISKCOL + lc * 6; putlongdouble(kb_per_transfer, DISKROW + 1, lc, 5, 2, 0); putlongdouble(transfers_per_second, DISKROW + 2, lc, 5, 0, 0); putlongdouble(mb_per_second, DISKROW + 3, lc, 5, 2, 0); putlongdouble(device_busy, DISKROW + 4, lc, 5, 0, 0); } Index: user/alc/PQ_LAUNDRY/usr.bin/top/machine.c =================================================================== --- user/alc/PQ_LAUNDRY/usr.bin/top/machine.c (revision 290832) +++ user/alc/PQ_LAUNDRY/usr.bin/top/machine.c (revision 290833) @@ -1,1602 +1,1602 @@ /* * top - a top users display for Unix * * SYNOPSIS: For FreeBSD-2.x and later * * DESCRIPTION: * Originally written for BSD4.4 system by Christos Zoulas. * Ported to FreeBSD 2.x by Steven Wallace && Wolfram Schneider * Order support hacked in from top-3.5beta6/machine/m_aix41.c * by Monte Mitzelfelt (for latest top see http://www.groupsys.com/topinfo/) * * This is the machine-dependent module for FreeBSD 2.2 * Works for: * FreeBSD 2.2.x, 3.x, 4.x, and probably FreeBSD 2.1.x * * LIBS: -lkvm * * AUTHOR: Christos Zoulas * Steven Wallace * Wolfram Schneider * Thomas Moestl * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "top.h" #include "machine.h" #include "screen.h" #include "utils.h" #include "layout.h" #define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof(var)) #define SMPUNAMELEN 13 #define UPUNAMELEN 15 extern struct process_select ps; extern char* printable(char *); static int smpmode; enum displaymodes displaymode; #ifdef TOP_USERNAME_LEN static int namelength = TOP_USERNAME_LEN; #else static int namelength = 8; #endif /* TOP_JID_LEN based on max of 999999 */ #define TOP_JID_LEN 7 static int jidlength; static int cmdlengthdelta; /* Prototypes for top internals */ void quit(int); /* get_process_info passes back a handle. This is what it looks like: */ struct handle { struct kinfo_proc **next_proc; /* points to next valid proc pointer */ int remaining; /* number of pointers remaining */ }; /* declarations for load_avg */ #include "loadavg.h" /* define what weighted cpu is. */ #define weighted_cpu(pct, pp) ((pp)->ki_swtime == 0 ? 0.0 : \ ((pct) / (1.0 - exp((pp)->ki_swtime * logcpu)))) /* what we consider to be process size: */ #define PROCSIZE(pp) ((pp)->ki_size / 1024) #define RU(pp) (&(pp)->ki_rusage) #define RUTOT(pp) \ (RU(pp)->ru_inblock + RU(pp)->ru_oublock + RU(pp)->ru_majflt) #define PCTCPU(pp) (pcpu[pp - pbase]) /* definitions for indices in the nlist array */ /* * These definitions control the format of the per-process area */ static char io_header[] = " PID%*s %-*.*s VCSW IVCSW READ WRITE FAULT TOTAL PERCENT COMMAND"; #define io_Proc_format \ "%5d%*s %-*.*s %6ld %6ld %6ld %6ld %6ld %6ld %6.2f%% %.*s" static char smp_header_thr[] = " PID%*s %-*.*s THR PRI NICE SIZE RES STATE C TIME %7s COMMAND"; static char smp_header[] = " PID%*s %-*.*s " "PRI NICE SIZE RES STATE C TIME %7s COMMAND"; #define smp_Proc_format \ "%5d%*s %-*.*s %s%3d %4s%7s %6s %-6.6s %2d%7s %6.2f%% %.*s" static char up_header_thr[] = " PID%*s %-*.*s THR PRI NICE SIZE RES STATE TIME %7s COMMAND"; static char up_header[] = " PID%*s %-*.*s " "PRI NICE SIZE RES STATE TIME %7s COMMAND"; #define up_Proc_format \ "%5d%*s %-*.*s %s%3d %4s%7s %6s %-6.6s%.0d%7s %6.2f%% %.*s" /* process state names for the "STATE" column of the display */ /* the extra nulls in the string "run" are for adding a slash and the processor number when needed */ char *state_abbrev[] = { "", "START", "RUN\0\0\0", "SLEEP", "STOP", "ZOMB", "WAIT", "LOCK" }; static kvm_t *kd; /* values that we stash away in _init and use in later routines */ static double logcpu; /* these are retrieved from the kernel in _init */ static load_avg ccpu; /* these are used in the get_ functions */ static int lastpid; /* these are for calculating cpu state percentages */ static long cp_time[CPUSTATES]; static long cp_old[CPUSTATES]; static long cp_diff[CPUSTATES]; /* these are for detailing the process states */ int process_states[8]; char *procstatenames[] = { "", " starting, ", " running, ", " sleeping, ", " stopped, ", " zombie, ", " waiting, ", " lock, ", NULL }; /* these are for detailing the cpu states */ int cpu_states[CPUSTATES]; char *cpustatenames[] = { "user", "nice", "system", "interrupt", "idle", NULL }; /* these are for detailing the memory statistics */ int memory_stats[7]; char *memorynames[] = { - "K Active, ", "K Inact, ", "K Wired, ", "K Cache, ", "K Buf, ", + "K Active, ", "K Inact, ", "K Laundry, ", "K Wired, ", "K Buf, ", "K Free", NULL }; int arc_stats[7]; char *arcnames[] = { "K Total, ", "K MFU, ", "K MRU, ", "K Anon, ", "K Header, ", "K Other", NULL }; int swap_stats[7]; char *swapnames[] = { "K Total, ", "K Used, ", "K Free, ", "% Inuse, ", "K In, ", "K Out", NULL }; /* these are for keeping track of the proc array */ static int nproc; static int onproc = -1; static int pref_len; static struct kinfo_proc *pbase; static struct kinfo_proc **pref; static struct kinfo_proc *previous_procs; static struct kinfo_proc **previous_pref; static int previous_proc_count = 0; static int previous_proc_count_max = 0; static int previous_thread; /* data used for recalculating pctcpu */ static double *pcpu; static struct timespec proc_uptime; static struct timeval proc_wall_time; static struct timeval previous_wall_time; static uint64_t previous_interval = 0; /* total number of io operations */ static long total_inblock; static long total_oublock; static long total_majflt; /* these are for getting the memory statistics */ static int arc_enabled; static int pageshift; /* log base 2 of the pagesize */ /* define pagetok in terms of pageshift */ #define pagetok(size) ((size) << pageshift) /* useful externals */ long percentages(); #ifdef ORDER /* * Sorting orders. The first element is the default. */ char *ordernames[] = { "cpu", "size", "res", "time", "pri", "threads", "total", "read", "write", "fault", "vcsw", "ivcsw", "jid", "pid", NULL }; #endif /* Per-cpu time states */ static int maxcpu; static int maxid; static int ncpus; static u_long cpumask; static long *times; static long *pcpu_cp_time; static long *pcpu_cp_old; static long *pcpu_cp_diff; static int *pcpu_cpu_states; static int compare_jid(const void *a, const void *b); static int compare_pid(const void *a, const void *b); static int compare_tid(const void *a, const void *b); static const char *format_nice(const struct kinfo_proc *pp); static void getsysctl(const char *name, void *ptr, size_t len); static int swapmode(int *retavail, int *retfree); static void update_layout(void); void toggle_pcpustats(void) { if (ncpus == 1) return; update_layout(); } /* Adjust display based on ncpus and the ARC state. */ static void update_layout(void) { y_mem = 3; y_arc = 4; y_swap = 4 + arc_enabled; y_idlecursor = 5 + arc_enabled; y_message = 5 + arc_enabled; y_header = 6 + arc_enabled; y_procs = 7 + arc_enabled; Header_lines = 7 + arc_enabled; if (pcpu_stats) { y_mem += ncpus - 1; y_arc += ncpus - 1; y_swap += ncpus - 1; y_idlecursor += ncpus - 1; y_message += ncpus - 1; y_header += ncpus - 1; y_procs += ncpus - 1; Header_lines += ncpus - 1; } } int machine_init(struct statics *statics, char do_unames) { int i, j, empty, pagesize; uint64_t arc_size; size_t size; struct passwd *pw; size = sizeof(smpmode); if ((sysctlbyname("machdep.smp_active", &smpmode, &size, NULL, 0) != 0 && sysctlbyname("kern.smp.active", &smpmode, &size, NULL, 0) != 0) || size != sizeof(smpmode)) smpmode = 0; size = sizeof(arc_size); if (sysctlbyname("kstat.zfs.misc.arcstats.size", &arc_size, &size, NULL, 0) == 0 && arc_size != 0) arc_enabled = 1; if (do_unames) { while ((pw = getpwent()) != NULL) { if (strlen(pw->pw_name) > namelength) namelength = strlen(pw->pw_name); } } if (smpmode && namelength > SMPUNAMELEN) namelength = SMPUNAMELEN; else if (namelength > UPUNAMELEN) namelength = UPUNAMELEN; kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open"); if (kd == NULL) return (-1); GETSYSCTL("kern.ccpu", ccpu); /* this is used in calculating WCPU -- calculate it ahead of time */ logcpu = log(loaddouble(ccpu)); pbase = NULL; pref = NULL; pcpu = NULL; nproc = 0; onproc = -1; /* get the page size and calculate pageshift from it */ pagesize = getpagesize(); pageshift = 0; while (pagesize > 1) { pageshift++; pagesize >>= 1; } /* we only need the amount of log(2)1024 for our conversion */ pageshift -= LOG1024; /* fill in the statics information */ statics->procstate_names = procstatenames; statics->cpustate_names = cpustatenames; statics->memory_names = memorynames; if (arc_enabled) statics->arc_names = arcnames; else statics->arc_names = NULL; statics->swap_names = swapnames; #ifdef ORDER statics->order_names = ordernames; #endif /* Allocate state for per-CPU stats. */ cpumask = 0; ncpus = 0; GETSYSCTL("kern.smp.maxcpus", maxcpu); size = sizeof(long) * maxcpu * CPUSTATES; times = malloc(size); if (times == NULL) err(1, "malloc %zu bytes", size); if (sysctlbyname("kern.cp_times", times, &size, NULL, 0) == -1) err(1, "sysctlbyname kern.cp_times"); pcpu_cp_time = calloc(1, size); maxid = (size / CPUSTATES / sizeof(long)) - 1; for (i = 0; i <= maxid; i++) { empty = 1; for (j = 0; empty && j < CPUSTATES; j++) { if (times[i * CPUSTATES + j] != 0) empty = 0; } if (!empty) { cpumask |= (1ul << i); ncpus++; } } size = sizeof(long) * ncpus * CPUSTATES; pcpu_cp_old = calloc(1, size); pcpu_cp_diff = calloc(1, size); pcpu_cpu_states = calloc(1, size); statics->ncpus = ncpus; update_layout(); /* all done! */ return (0); } char * format_header(char *uname_field) { static char Header[128]; const char *prehead; if (ps.jail) jidlength = TOP_JID_LEN + 1; /* +1 for extra left space. */ else jidlength = 0; switch (displaymode) { case DISP_CPU: /* * The logic of picking the right header format seems reverse * here because we only want to display a THR column when * "thread mode" is off (and threads are not listed as * separate lines). */ prehead = smpmode ? (ps.thread ? smp_header : smp_header_thr) : (ps.thread ? up_header : up_header_thr); snprintf(Header, sizeof(Header), prehead, jidlength, ps.jail ? " JID" : "", namelength, namelength, uname_field, ps.wcpu ? "WCPU" : "CPU"); break; case DISP_IO: prehead = io_header; snprintf(Header, sizeof(Header), prehead, jidlength, ps.jail ? " JID" : "", namelength, namelength, uname_field); break; } cmdlengthdelta = strlen(Header) - 7; return (Header); } static int swappgsin = -1; static int swappgsout = -1; extern struct timeval timeout; void get_system_info(struct system_info *si) { long total; struct loadavg sysload; int mib[2]; struct timeval boottime; uint64_t arc_stat, arc_stat2; int i, j; size_t size; /* get the CPU stats */ size = (maxid + 1) * CPUSTATES * sizeof(long); if (sysctlbyname("kern.cp_times", pcpu_cp_time, &size, NULL, 0) == -1) err(1, "sysctlbyname kern.cp_times"); GETSYSCTL("kern.cp_time", cp_time); GETSYSCTL("vm.loadavg", sysload); GETSYSCTL("kern.lastpid", lastpid); /* convert load averages to doubles */ for (i = 0; i < 3; i++) si->load_avg[i] = (double)sysload.ldavg[i] / sysload.fscale; /* convert cp_time counts to percentages */ for (i = j = 0; i <= maxid; i++) { if ((cpumask & (1ul << i)) == 0) continue; percentages(CPUSTATES, &pcpu_cpu_states[j * CPUSTATES], &pcpu_cp_time[j * CPUSTATES], &pcpu_cp_old[j * CPUSTATES], &pcpu_cp_diff[j * CPUSTATES]); j++; } percentages(CPUSTATES, cpu_states, cp_time, cp_old, cp_diff); /* sum memory & swap statistics */ { static unsigned int swap_delay = 0; static int swapavail = 0; static int swapfree = 0; static long bufspace = 0; static int nspgsin, nspgsout; GETSYSCTL("vfs.bufspace", bufspace); GETSYSCTL("vm.stats.vm.v_active_count", memory_stats[0]); GETSYSCTL("vm.stats.vm.v_inactive_count", memory_stats[1]); - GETSYSCTL("vm.stats.vm.v_wire_count", memory_stats[2]); - GETSYSCTL("vm.stats.vm.v_cache_count", memory_stats[3]); + GETSYSCTL("vm.stats.vm.v_laundry_count", memory_stats[2]); + GETSYSCTL("vm.stats.vm.v_wire_count", memory_stats[3]); GETSYSCTL("vm.stats.vm.v_free_count", memory_stats[5]); GETSYSCTL("vm.stats.vm.v_swappgsin", nspgsin); GETSYSCTL("vm.stats.vm.v_swappgsout", nspgsout); /* convert memory stats to Kbytes */ memory_stats[0] = pagetok(memory_stats[0]); memory_stats[1] = pagetok(memory_stats[1]); memory_stats[2] = pagetok(memory_stats[2]); memory_stats[3] = pagetok(memory_stats[3]); memory_stats[4] = bufspace / 1024; memory_stats[5] = pagetok(memory_stats[5]); memory_stats[6] = -1; /* first interval */ if (swappgsin < 0) { swap_stats[4] = 0; swap_stats[5] = 0; } /* compute differences between old and new swap statistic */ else { swap_stats[4] = pagetok(((nspgsin - swappgsin))); swap_stats[5] = pagetok(((nspgsout - swappgsout))); } swappgsin = nspgsin; swappgsout = nspgsout; /* call CPU heavy swapmode() only for changes */ if (swap_stats[4] > 0 || swap_stats[5] > 0 || swap_delay == 0) { swap_stats[3] = swapmode(&swapavail, &swapfree); swap_stats[0] = swapavail; swap_stats[1] = swapavail - swapfree; swap_stats[2] = swapfree; } swap_delay = 1; swap_stats[6] = -1; } if (arc_enabled) { GETSYSCTL("kstat.zfs.misc.arcstats.size", arc_stat); arc_stats[0] = arc_stat >> 10; GETSYSCTL("vfs.zfs.mfu_size", arc_stat); arc_stats[1] = arc_stat >> 10; GETSYSCTL("vfs.zfs.mru_size", arc_stat); arc_stats[2] = arc_stat >> 10; GETSYSCTL("vfs.zfs.anon_size", arc_stat); arc_stats[3] = arc_stat >> 10; GETSYSCTL("kstat.zfs.misc.arcstats.hdr_size", arc_stat); GETSYSCTL("kstat.zfs.misc.arcstats.l2_hdr_size", arc_stat2); arc_stats[4] = arc_stat + arc_stat2 >> 10; GETSYSCTL("kstat.zfs.misc.arcstats.other_size", arc_stat); arc_stats[5] = arc_stat >> 10; si->arc = arc_stats; } /* set arrays and strings */ if (pcpu_stats) { si->cpustates = pcpu_cpu_states; si->ncpus = ncpus; } else { si->cpustates = cpu_states; si->ncpus = 1; } si->memory = memory_stats; si->swap = swap_stats; if (lastpid > 0) { si->last_pid = lastpid; } else { si->last_pid = -1; } /* * Print how long system has been up. * (Found by looking getting "boottime" from the kernel) */ mib[0] = CTL_KERN; mib[1] = KERN_BOOTTIME; size = sizeof(boottime); if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 && boottime.tv_sec != 0) { si->boottime = boottime; } else { si->boottime.tv_sec = -1; } } #define NOPROC ((void *)-1) /* * We need to compare data from the old process entry with the new * process entry. * To facilitate doing this quickly we stash a pointer in the kinfo_proc * structure to cache the mapping. We also use a negative cache pointer * of NOPROC to avoid duplicate lookups. * XXX: this could be done when the actual processes are fetched, we do * it here out of laziness. */ const struct kinfo_proc * get_old_proc(struct kinfo_proc *pp) { struct kinfo_proc **oldpp, *oldp; /* * If this is the first fetch of the kinfo_procs then we don't have * any previous entries. */ if (previous_proc_count == 0) return (NULL); /* negative cache? */ if (pp->ki_udata == NOPROC) return (NULL); /* cached? */ if (pp->ki_udata != NULL) return (pp->ki_udata); /* * Not cached, * 1) look up based on pid. * 2) compare process start. * If we fail here, then setup a negative cache entry, otherwise * cache it. */ oldpp = bsearch(&pp, previous_pref, previous_proc_count, sizeof(*previous_pref), ps.thread ? compare_tid : compare_pid); if (oldpp == NULL) { pp->ki_udata = NOPROC; return (NULL); } oldp = *oldpp; if (bcmp(&oldp->ki_start, &pp->ki_start, sizeof(pp->ki_start)) != 0) { pp->ki_udata = NOPROC; return (NULL); } pp->ki_udata = oldp; return (oldp); } /* * Return the total amount of IO done in blocks in/out and faults. * store the values individually in the pointers passed in. */ long get_io_stats(struct kinfo_proc *pp, long *inp, long *oup, long *flp, long *vcsw, long *ivcsw) { const struct kinfo_proc *oldp; static struct kinfo_proc dummy; long ret; oldp = get_old_proc(pp); if (oldp == NULL) { bzero(&dummy, sizeof(dummy)); oldp = &dummy; } *inp = RU(pp)->ru_inblock - RU(oldp)->ru_inblock; *oup = RU(pp)->ru_oublock - RU(oldp)->ru_oublock; *flp = RU(pp)->ru_majflt - RU(oldp)->ru_majflt; *vcsw = RU(pp)->ru_nvcsw - RU(oldp)->ru_nvcsw; *ivcsw = RU(pp)->ru_nivcsw - RU(oldp)->ru_nivcsw; ret = (RU(pp)->ru_inblock - RU(oldp)->ru_inblock) + (RU(pp)->ru_oublock - RU(oldp)->ru_oublock) + (RU(pp)->ru_majflt - RU(oldp)->ru_majflt); return (ret); } /* * If there was a previous update, use the delta in ki_runtime over * the previous interval to calculate pctcpu. Otherwise, fall back * to using the kernel's ki_pctcpu. */ static double proc_calc_pctcpu(struct kinfo_proc *pp) { const struct kinfo_proc *oldp; if (previous_interval != 0) { oldp = get_old_proc(pp); if (oldp != NULL) return ((double)(pp->ki_runtime - oldp->ki_runtime) / previous_interval); /* * If this process/thread was created during the previous * interval, charge it's total runtime to the previous * interval. */ else if (pp->ki_start.tv_sec > previous_wall_time.tv_sec || (pp->ki_start.tv_sec == previous_wall_time.tv_sec && pp->ki_start.tv_usec >= previous_wall_time.tv_usec)) return ((double)pp->ki_runtime / previous_interval); } return (pctdouble(pp->ki_pctcpu)); } /* * Return true if this process has used any CPU time since the * previous update. */ static int proc_used_cpu(struct kinfo_proc *pp) { const struct kinfo_proc *oldp; oldp = get_old_proc(pp); if (oldp == NULL) return (PCTCPU(pp) != 0); return (pp->ki_runtime != oldp->ki_runtime || RU(pp)->ru_nvcsw != RU(oldp)->ru_nvcsw || RU(pp)->ru_nivcsw != RU(oldp)->ru_nivcsw); } /* * Return the total number of block in/out and faults by a process. */ long get_io_total(struct kinfo_proc *pp) { long dummy; return (get_io_stats(pp, &dummy, &dummy, &dummy, &dummy, &dummy)); } static struct handle handle; caddr_t get_process_info(struct system_info *si, struct process_select *sel, int (*compare)(const void *, const void *)) { int i; int total_procs; long p_io; long p_inblock, p_oublock, p_majflt, p_vcsw, p_ivcsw; long nsec; int active_procs; struct kinfo_proc **prefp; struct kinfo_proc *pp; struct timespec previous_proc_uptime; /* these are copied out of sel for speed */ int show_idle; int show_jid; int show_self; int show_system; int show_uid; int show_command; int show_kidle; /* * If thread state was toggled, don't cache the previous processes. */ if (previous_thread != sel->thread) nproc = 0; previous_thread = sel->thread; /* * Save the previous process info. */ if (previous_proc_count_max < nproc) { free(previous_procs); previous_procs = malloc(nproc * sizeof(*previous_procs)); free(previous_pref); previous_pref = malloc(nproc * sizeof(*previous_pref)); if (previous_procs == NULL || previous_pref == NULL) { (void) fprintf(stderr, "top: Out of memory.\n"); quit(23); } previous_proc_count_max = nproc; } if (nproc) { for (i = 0; i < nproc; i++) previous_pref[i] = &previous_procs[i]; bcopy(pbase, previous_procs, nproc * sizeof(*previous_procs)); qsort(previous_pref, nproc, sizeof(*previous_pref), ps.thread ? compare_tid : compare_pid); } previous_proc_count = nproc; previous_proc_uptime = proc_uptime; previous_wall_time = proc_wall_time; previous_interval = 0; pbase = kvm_getprocs(kd, sel->thread ? KERN_PROC_ALL : KERN_PROC_PROC, 0, &nproc); (void)gettimeofday(&proc_wall_time, NULL); if (clock_gettime(CLOCK_UPTIME, &proc_uptime) != 0) memset(&proc_uptime, 0, sizeof(proc_uptime)); else if (previous_proc_uptime.tv_sec != 0 && previous_proc_uptime.tv_nsec != 0) { previous_interval = (proc_uptime.tv_sec - previous_proc_uptime.tv_sec) * 1000000; nsec = proc_uptime.tv_nsec - previous_proc_uptime.tv_nsec; if (nsec < 0) { previous_interval -= 1000000; nsec += 1000000000; } previous_interval += nsec / 1000; } if (nproc > onproc) { pref = realloc(pref, sizeof(*pref) * nproc); pcpu = realloc(pcpu, sizeof(*pcpu) * nproc); onproc = nproc; } if (pref == NULL || pbase == NULL || pcpu == NULL) { (void) fprintf(stderr, "top: Out of memory.\n"); quit(23); } /* get a pointer to the states summary array */ si->procstates = process_states; /* set up flags which define what we are going to select */ show_idle = sel->idle; show_jid = sel->jid != -1; show_self = sel->self == -1; show_system = sel->system; show_uid = sel->uid != -1; show_command = sel->command != NULL; show_kidle = sel->kidle; /* count up process states and get pointers to interesting procs */ total_procs = 0; active_procs = 0; total_inblock = 0; total_oublock = 0; total_majflt = 0; memset((char *)process_states, 0, sizeof(process_states)); prefp = pref; for (pp = pbase, i = 0; i < nproc; pp++, i++) { if (pp->ki_stat == 0) /* not in use */ continue; if (!show_self && pp->ki_pid == sel->self) /* skip self */ continue; if (!show_system && (pp->ki_flag & P_SYSTEM)) /* skip system process */ continue; p_io = get_io_stats(pp, &p_inblock, &p_oublock, &p_majflt, &p_vcsw, &p_ivcsw); total_inblock += p_inblock; total_oublock += p_oublock; total_majflt += p_majflt; total_procs++; process_states[pp->ki_stat]++; if (pp->ki_stat == SZOMB) /* skip zombies */ continue; if (!show_kidle && pp->ki_tdflags & TDF_IDLETD) /* skip kernel idle process */ continue; PCTCPU(pp) = proc_calc_pctcpu(pp); if (sel->thread && PCTCPU(pp) > 1.0) PCTCPU(pp) = 1.0; if (displaymode == DISP_CPU && !show_idle && (!proc_used_cpu(pp) || pp->ki_stat == SSTOP || pp->ki_stat == SIDL)) /* skip idle or non-running processes */ continue; if (displaymode == DISP_IO && !show_idle && p_io == 0) /* skip processes that aren't doing I/O */ continue; if (show_jid && pp->ki_jid != sel->jid) /* skip proc. that don't belong to the selected JID */ continue; if (show_uid && pp->ki_ruid != (uid_t)sel->uid) /* skip proc. that don't belong to the selected UID */ continue; *prefp++ = pp; active_procs++; } /* if requested, sort the "interesting" processes */ if (compare != NULL) qsort(pref, active_procs, sizeof(*pref), compare); /* remember active and total counts */ si->p_total = total_procs; si->p_active = pref_len = active_procs; /* pass back a handle */ handle.next_proc = pref; handle.remaining = active_procs; return ((caddr_t)&handle); } static char fmt[512]; /* static area where result is built */ char * format_next_process(caddr_t handle, char *(*get_userid)(int), int flags) { struct kinfo_proc *pp; const struct kinfo_proc *oldp; long cputime; double pct; struct handle *hp; char status[16]; int cpu, state; struct rusage ru, *rup; long p_tot, s_tot; char *proc_fmt, thr_buf[6], jid_buf[TOP_JID_LEN + 1]; char *cmdbuf = NULL; char **args; const int cmdlen = 128; /* find and remember the next proc structure */ hp = (struct handle *)handle; pp = *(hp->next_proc++); hp->remaining--; /* get the process's command name */ if ((pp->ki_flag & P_INMEM) == 0) { /* * Print swapped processes as */ size_t len; len = strlen(pp->ki_comm); if (len > sizeof(pp->ki_comm) - 3) len = sizeof(pp->ki_comm) - 3; memmove(pp->ki_comm + 1, pp->ki_comm, len); pp->ki_comm[0] = '<'; pp->ki_comm[len + 1] = '>'; pp->ki_comm[len + 2] = '\0'; } /* * Convert the process's runtime from microseconds to seconds. This * time includes the interrupt time although that is not wanted here. * ps(1) is similarly sloppy. */ cputime = (pp->ki_runtime + 500000) / 1000000; /* calculate the base for cpu percentages */ pct = PCTCPU(pp); /* generate "STATE" field */ switch (state = pp->ki_stat) { case SRUN: if (smpmode && pp->ki_oncpu != NOCPU) sprintf(status, "CPU%d", pp->ki_oncpu); else strcpy(status, "RUN"); break; case SLOCK: if (pp->ki_kiflag & KI_LOCKBLOCK) { sprintf(status, "*%.6s", pp->ki_lockname); break; } /* fall through */ case SSLEEP: if (pp->ki_wmesg != NULL) { sprintf(status, "%.6s", pp->ki_wmesg); break; } /* FALLTHROUGH */ default: if (state >= 0 && state < sizeof(state_abbrev) / sizeof(*state_abbrev)) sprintf(status, "%.6s", state_abbrev[state]); else sprintf(status, "?%5d", state); break; } cmdbuf = (char *)malloc(cmdlen + 1); if (cmdbuf == NULL) { warn("malloc(%d)", cmdlen + 1); return NULL; } if (!(flags & FMT_SHOWARGS)) { if (ps.thread && pp->ki_flag & P_HADTHREADS && pp->ki_tdname[0]) { snprintf(cmdbuf, cmdlen, "%s{%s}", pp->ki_comm, pp->ki_tdname); } else { snprintf(cmdbuf, cmdlen, "%s", pp->ki_comm); } } else { if (pp->ki_flag & P_SYSTEM || pp->ki_args == NULL || (args = kvm_getargv(kd, pp, cmdlen)) == NULL || !(*args)) { if (ps.thread && pp->ki_flag & P_HADTHREADS && pp->ki_tdname[0]) { snprintf(cmdbuf, cmdlen, "[%s{%s}]", pp->ki_comm, pp->ki_tdname); } else { snprintf(cmdbuf, cmdlen, "[%s]", pp->ki_comm); } } else { char *src, *dst, *argbuf; char *cmd; size_t argbuflen; size_t len; argbuflen = cmdlen * 4; argbuf = (char *)malloc(argbuflen + 1); if (argbuf == NULL) { warn("malloc(%zu)", argbuflen + 1); free(cmdbuf); return NULL; } dst = argbuf; /* Extract cmd name from argv */ cmd = strrchr(*args, '/'); if (cmd == NULL) cmd = *args; else cmd++; for (; (src = *args++) != NULL; ) { if (*src == '\0') continue; len = (argbuflen - (dst - argbuf) - 1) / 4; strvisx(dst, src, strlen(src) < len ? strlen(src) : len, VIS_NL | VIS_CSTYLE); while (*dst != '\0') dst++; if ((argbuflen - (dst - argbuf) - 1) / 4 > 0) *dst++ = ' '; /* add delimiting space */ } if (dst != argbuf && dst[-1] == ' ') dst--; *dst = '\0'; if (strcmp(cmd, pp->ki_comm) != 0) { if (ps.thread && pp->ki_flag & P_HADTHREADS && pp->ki_tdname[0]) snprintf(cmdbuf, cmdlen, "%s (%s){%s}", argbuf, pp->ki_comm, pp->ki_tdname); else snprintf(cmdbuf, cmdlen, "%s (%s)", argbuf, pp->ki_comm); } else { if (ps.thread && pp->ki_flag & P_HADTHREADS && pp->ki_tdname[0]) snprintf(cmdbuf, cmdlen, "%s{%s}", argbuf, pp->ki_tdname); else strlcpy(cmdbuf, argbuf, cmdlen); } free(argbuf); } } if (ps.jail == 0) jid_buf[0] = '\0'; else snprintf(jid_buf, sizeof(jid_buf), "%*d", jidlength - 1, pp->ki_jid); if (displaymode == DISP_IO) { oldp = get_old_proc(pp); if (oldp != NULL) { ru.ru_inblock = RU(pp)->ru_inblock - RU(oldp)->ru_inblock; ru.ru_oublock = RU(pp)->ru_oublock - RU(oldp)->ru_oublock; ru.ru_majflt = RU(pp)->ru_majflt - RU(oldp)->ru_majflt; ru.ru_nvcsw = RU(pp)->ru_nvcsw - RU(oldp)->ru_nvcsw; ru.ru_nivcsw = RU(pp)->ru_nivcsw - RU(oldp)->ru_nivcsw; rup = &ru; } else { rup = RU(pp); } p_tot = rup->ru_inblock + rup->ru_oublock + rup->ru_majflt; s_tot = total_inblock + total_oublock + total_majflt; snprintf(fmt, sizeof(fmt), io_Proc_format, pp->ki_pid, jidlength, jid_buf, namelength, namelength, (*get_userid)(pp->ki_ruid), rup->ru_nvcsw, rup->ru_nivcsw, rup->ru_inblock, rup->ru_oublock, rup->ru_majflt, p_tot, s_tot == 0 ? 0.0 : (p_tot * 100.0 / s_tot), screen_width > cmdlengthdelta ? screen_width - cmdlengthdelta : 0, printable(cmdbuf)); free(cmdbuf); return (fmt); } /* format this entry */ if (smpmode) { if (state == SRUN && pp->ki_oncpu != NOCPU) cpu = pp->ki_oncpu; else cpu = pp->ki_lastcpu; } else cpu = 0; proc_fmt = smpmode ? smp_Proc_format : up_Proc_format; if (ps.thread != 0) thr_buf[0] = '\0'; else snprintf(thr_buf, sizeof(thr_buf), "%*d ", (int)(sizeof(thr_buf) - 2), pp->ki_numthreads); snprintf(fmt, sizeof(fmt), proc_fmt, pp->ki_pid, jidlength, jid_buf, namelength, namelength, (*get_userid)(pp->ki_ruid), thr_buf, pp->ki_pri.pri_level - PZERO, format_nice(pp), format_k2(PROCSIZE(pp)), format_k2(pagetok(pp->ki_rssize)), status, cpu, format_time(cputime), ps.wcpu ? 100.0 * weighted_cpu(pct, pp) : 100.0 * pct, screen_width > cmdlengthdelta ? screen_width - cmdlengthdelta : 0, printable(cmdbuf)); free(cmdbuf); /* return the result */ return (fmt); } static void getsysctl(const char *name, void *ptr, size_t len) { size_t nlen = len; if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) { fprintf(stderr, "top: sysctl(%s...) failed: %s\n", name, strerror(errno)); quit(23); } if (nlen != len) { fprintf(stderr, "top: sysctl(%s...) expected %lu, got %lu\n", name, (unsigned long)len, (unsigned long)nlen); quit(23); } } static const char * format_nice(const struct kinfo_proc *pp) { const char *fifo, *kthread; int rtpri; static char nicebuf[4 + 1]; fifo = PRI_NEED_RR(pp->ki_pri.pri_class) ? "" : "F"; kthread = (pp->ki_flag & P_KTHREAD) ? "k" : ""; switch (PRI_BASE(pp->ki_pri.pri_class)) { case PRI_ITHD: return ("-"); case PRI_REALTIME: /* * XXX: the kernel doesn't tell us the original rtprio and * doesn't really know what it was, so to recover it we * must be more chummy with the implementation than the * implementation is with itself. pri_user gives a * constant "base" priority, but is only initialized * properly for user threads. pri_native gives what the * kernel calls the "base" priority, but it isn't constant * since it is changed by priority propagation. pri_native * also isn't properly initialized for all threads, but it * is properly initialized for kernel realtime and idletime * threads. Thus we use pri_user for the base priority of * user threads (it is always correct) and pri_native for * the base priority of kernel realtime and idletime threads * (there is nothing better, and it is usually correct). * * The field width and thus the buffer are too small for * values like "kr31F", but such values shouldn't occur, * and if they do then the tailing "F" is not displayed. */ rtpri = ((pp->ki_flag & P_KTHREAD) ? pp->ki_pri.pri_native : pp->ki_pri.pri_user) - PRI_MIN_REALTIME; snprintf(nicebuf, sizeof(nicebuf), "%sr%d%s", kthread, rtpri, fifo); break; case PRI_TIMESHARE: if (pp->ki_flag & P_KTHREAD) return ("-"); snprintf(nicebuf, sizeof(nicebuf), "%d", pp->ki_nice - NZERO); break; case PRI_IDLE: /* XXX: as above. */ rtpri = ((pp->ki_flag & P_KTHREAD) ? pp->ki_pri.pri_native : pp->ki_pri.pri_user) - PRI_MIN_IDLE; snprintf(nicebuf, sizeof(nicebuf), "%si%d%s", kthread, rtpri, fifo); break; default: return ("?"); } return (nicebuf); } /* comparison routines for qsort */ static int compare_pid(const void *p1, const void *p2) { const struct kinfo_proc * const *pp1 = p1; const struct kinfo_proc * const *pp2 = p2; if ((*pp2)->ki_pid < 0 || (*pp1)->ki_pid < 0) abort(); return ((*pp1)->ki_pid - (*pp2)->ki_pid); } static int compare_tid(const void *p1, const void *p2) { const struct kinfo_proc * const *pp1 = p1; const struct kinfo_proc * const *pp2 = p2; if ((*pp2)->ki_tid < 0 || (*pp1)->ki_tid < 0) abort(); return ((*pp1)->ki_tid - (*pp2)->ki_tid); } /* * proc_compare - comparison function for "qsort" * Compares the resource consumption of two processes using five * distinct keys. The keys (in descending order of importance) are: * percent cpu, cpu ticks, state, resident set size, total virtual * memory usage. The process states are ordered as follows (from least * to most important): WAIT, zombie, sleep, stop, start, run. The * array declaration below maps a process state index into a number * that reflects this ordering. */ static int sorted_state[] = { 0, /* not used */ 3, /* sleep */ 1, /* ABANDONED (WAIT) */ 6, /* run */ 5, /* start */ 2, /* zombie */ 4 /* stop */ }; #define ORDERKEY_PCTCPU(a, b) do { \ double diff; \ if (ps.wcpu) \ diff = weighted_cpu(PCTCPU((b)), (b)) - \ weighted_cpu(PCTCPU((a)), (a)); \ else \ diff = PCTCPU((b)) - PCTCPU((a)); \ if (diff != 0) \ return (diff > 0 ? 1 : -1); \ } while (0) #define ORDERKEY_CPTICKS(a, b) do { \ int64_t diff = (int64_t)(b)->ki_runtime - (int64_t)(a)->ki_runtime; \ if (diff != 0) \ return (diff > 0 ? 1 : -1); \ } while (0) #define ORDERKEY_STATE(a, b) do { \ int diff = sorted_state[(b)->ki_stat] - sorted_state[(a)->ki_stat]; \ if (diff != 0) \ return (diff > 0 ? 1 : -1); \ } while (0) #define ORDERKEY_PRIO(a, b) do { \ int diff = (int)(b)->ki_pri.pri_level - (int)(a)->ki_pri.pri_level; \ if (diff != 0) \ return (diff > 0 ? 1 : -1); \ } while (0) #define ORDERKEY_THREADS(a, b) do { \ int diff = (int)(b)->ki_numthreads - (int)(a)->ki_numthreads; \ if (diff != 0) \ return (diff > 0 ? 1 : -1); \ } while (0) #define ORDERKEY_RSSIZE(a, b) do { \ long diff = (long)(b)->ki_rssize - (long)(a)->ki_rssize; \ if (diff != 0) \ return (diff > 0 ? 1 : -1); \ } while (0) #define ORDERKEY_MEM(a, b) do { \ long diff = (long)PROCSIZE((b)) - (long)PROCSIZE((a)); \ if (diff != 0) \ return (diff > 0 ? 1 : -1); \ } while (0) #define ORDERKEY_JID(a, b) do { \ int diff = (int)(b)->ki_jid - (int)(a)->ki_jid; \ if (diff != 0) \ return (diff > 0 ? 1 : -1); \ } while (0) /* compare_cpu - the comparison function for sorting by cpu percentage */ int #ifdef ORDER compare_cpu(void *arg1, void *arg2) #else proc_compare(void *arg1, void *arg2) #endif { struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; ORDERKEY_PCTCPU(p1, p2); ORDERKEY_CPTICKS(p1, p2); ORDERKEY_STATE(p1, p2); ORDERKEY_PRIO(p1, p2); ORDERKEY_RSSIZE(p1, p2); ORDERKEY_MEM(p1, p2); return (0); } #ifdef ORDER /* "cpu" compare routines */ int compare_size(), compare_res(), compare_time(), compare_prio(), compare_threads(); /* * "io" compare routines. Context switches aren't i/o, but are displayed * on the "io" display. */ int compare_iototal(), compare_ioread(), compare_iowrite(), compare_iofault(), compare_vcsw(), compare_ivcsw(); int (*compares[])() = { compare_cpu, compare_size, compare_res, compare_time, compare_prio, compare_threads, compare_iototal, compare_ioread, compare_iowrite, compare_iofault, compare_vcsw, compare_ivcsw, compare_jid, NULL }; /* compare_size - the comparison function for sorting by total memory usage */ int compare_size(void *arg1, void *arg2) { struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; ORDERKEY_MEM(p1, p2); ORDERKEY_RSSIZE(p1, p2); ORDERKEY_PCTCPU(p1, p2); ORDERKEY_CPTICKS(p1, p2); ORDERKEY_STATE(p1, p2); ORDERKEY_PRIO(p1, p2); return (0); } /* compare_res - the comparison function for sorting by resident set size */ int compare_res(void *arg1, void *arg2) { struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; ORDERKEY_RSSIZE(p1, p2); ORDERKEY_MEM(p1, p2); ORDERKEY_PCTCPU(p1, p2); ORDERKEY_CPTICKS(p1, p2); ORDERKEY_STATE(p1, p2); ORDERKEY_PRIO(p1, p2); return (0); } /* compare_time - the comparison function for sorting by total cpu time */ int compare_time(void *arg1, void *arg2) { struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; ORDERKEY_CPTICKS(p1, p2); ORDERKEY_PCTCPU(p1, p2); ORDERKEY_STATE(p1, p2); ORDERKEY_PRIO(p1, p2); ORDERKEY_RSSIZE(p1, p2); ORDERKEY_MEM(p1, p2); return (0); } /* compare_prio - the comparison function for sorting by priority */ int compare_prio(void *arg1, void *arg2) { struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; ORDERKEY_PRIO(p1, p2); ORDERKEY_CPTICKS(p1, p2); ORDERKEY_PCTCPU(p1, p2); ORDERKEY_STATE(p1, p2); ORDERKEY_RSSIZE(p1, p2); ORDERKEY_MEM(p1, p2); return (0); } /* compare_threads - the comparison function for sorting by threads */ int compare_threads(void *arg1, void *arg2) { struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; ORDERKEY_THREADS(p1, p2); ORDERKEY_PCTCPU(p1, p2); ORDERKEY_CPTICKS(p1, p2); ORDERKEY_STATE(p1, p2); ORDERKEY_PRIO(p1, p2); ORDERKEY_RSSIZE(p1, p2); ORDERKEY_MEM(p1, p2); return (0); } /* compare_jid - the comparison function for sorting by jid */ static int compare_jid(const void *arg1, const void *arg2) { struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; ORDERKEY_JID(p1, p2); ORDERKEY_PCTCPU(p1, p2); ORDERKEY_CPTICKS(p1, p2); ORDERKEY_STATE(p1, p2); ORDERKEY_PRIO(p1, p2); ORDERKEY_RSSIZE(p1, p2); ORDERKEY_MEM(p1, p2); return (0); } #endif /* ORDER */ /* assorted comparison functions for sorting by i/o */ int #ifdef ORDER compare_iototal(void *arg1, void *arg2) #else io_compare(void *arg1, void *arg2) #endif { struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; return (get_io_total(p2) - get_io_total(p1)); } #ifdef ORDER int compare_ioread(void *arg1, void *arg2) { struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; long dummy, inp1, inp2; (void) get_io_stats(p1, &inp1, &dummy, &dummy, &dummy, &dummy); (void) get_io_stats(p2, &inp2, &dummy, &dummy, &dummy, &dummy); return (inp2 - inp1); } int compare_iowrite(void *arg1, void *arg2) { struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; long dummy, oup1, oup2; (void) get_io_stats(p1, &dummy, &oup1, &dummy, &dummy, &dummy); (void) get_io_stats(p2, &dummy, &oup2, &dummy, &dummy, &dummy); return (oup2 - oup1); } int compare_iofault(void *arg1, void *arg2) { struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; long dummy, flp1, flp2; (void) get_io_stats(p1, &dummy, &dummy, &flp1, &dummy, &dummy); (void) get_io_stats(p2, &dummy, &dummy, &flp2, &dummy, &dummy); return (flp2 - flp1); } int compare_vcsw(void *arg1, void *arg2) { struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; long dummy, flp1, flp2; (void) get_io_stats(p1, &dummy, &dummy, &dummy, &flp1, &dummy); (void) get_io_stats(p2, &dummy, &dummy, &dummy, &flp2, &dummy); return (flp2 - flp1); } int compare_ivcsw(void *arg1, void *arg2) { struct kinfo_proc *p1 = *(struct kinfo_proc **)arg1; struct kinfo_proc *p2 = *(struct kinfo_proc **)arg2; long dummy, flp1, flp2; (void) get_io_stats(p1, &dummy, &dummy, &dummy, &dummy, &flp1); (void) get_io_stats(p2, &dummy, &dummy, &dummy, &dummy, &flp2); return (flp2 - flp1); } #endif /* ORDER */ /* * proc_owner(pid) - returns the uid that owns process "pid", or -1 if * the process does not exist. * It is EXTREMELY IMPORTANT that this function work correctly. * If top runs setuid root (as in SVR4), then this function * is the only thing that stands in the way of a serious * security problem. It validates requests for the "kill" * and "renice" commands. */ int proc_owner(int pid) { int cnt; struct kinfo_proc **prefp; struct kinfo_proc *pp; prefp = pref; cnt = pref_len; while (--cnt >= 0) { pp = *prefp++; if (pp->ki_pid == (pid_t)pid) return ((int)pp->ki_ruid); } return (-1); } static int swapmode(int *retavail, int *retfree) { int n; int pagesize = getpagesize(); struct kvm_swap swapary[1]; *retavail = 0; *retfree = 0; #define CONVERT(v) ((quad_t)(v) * pagesize / 1024) n = kvm_getswapinfo(kd, swapary, 1, 0); if (n < 0 || swapary[0].ksw_total == 0) return (0); *retavail = CONVERT(swapary[0].ksw_total); *retfree = CONVERT(swapary[0].ksw_total - swapary[0].ksw_used); n = (int)(swapary[0].ksw_used * 100.0 / swapary[0].ksw_total); return (n); } Index: user/alc/PQ_LAUNDRY/usr.bin/top/top.local.1 =================================================================== --- user/alc/PQ_LAUNDRY/usr.bin/top/top.local.1 (revision 290832) +++ user/alc/PQ_LAUNDRY/usr.bin/top/top.local.1 (revision 290833) @@ -1,75 +1,74 @@ .\" $FreeBSD$ .SH "FreeBSD NOTES" .SH DESCRIPTION OF MEMORY -Mem: 9220K Active, 1M Inact, 3284K Wired, 1M Cache, 2M Buf, 1320K Free -ARC: 2048K Total, 342K MRU, 760K MFU, 272K Anon, 232K Header, 442K Other +Mem: 9220K Active, 1M Inact, 1M Laundry, 3284K Wired, 2M Buf, 932K Free +ARC: 2048K Total, 342K MRU, 760K MFU, 272K Anon, 96K Header, 442K Other Swap: 91M Total, 79M Free, 13% Inuse, 80K In, 104K Out .TP .B K: Kilobyte .TP .B M: Megabyte .TP .B G: Gigabyte .TP .B %: 1/100 .SS Physical Memory Stats .TP .B Active: number of bytes active .TP .B Inact: -number of bytes inactive +number of clean bytes inactive .TP +.B Laundry: +number of dirty bytes inactive +.TP .B Wired: number of bytes wired down, including BIO-level cached file data pages -.TP -.B Cache: -number of clean bytes caching data that are available for -immediate reallocation .TP .B Buf: number of bytes used for BIO-level disk caching .TP .B Free: number of bytes free .SS ZFS ARC Stats These stats are only displayed when the ARC is in use. .TP .B Total: number of wired bytes used for the ZFS ARC .TP .B MRU: number of ARC bytes holding most recently used data .TP .B MFU: number of ARC bytes holding most frequently used data .TP .B Anon: number of ARC bytes holding in flight data .TP .B Header: number of ARC bytes holding headers .TP .B Other miscellaneous ARC bytes .SS Swap Stats .TP .B Total: total available swap usage .TP .B Free: total free swap usage .TP .B Inuse: swap usage .TP .B In: bytes paged in from swap devices (last interval) .TP .B Out: bytes paged out to swap devices (last interval) Index: user/alc/PQ_LAUNDRY/usr.bin/vmstat/vmstat.c =================================================================== --- user/alc/PQ_LAUNDRY/usr.bin/vmstat/vmstat.c (revision 290832) +++ user/alc/PQ_LAUNDRY/usr.bin/vmstat/vmstat.c (revision 290833) @@ -1,1583 +1,1581 @@ /* * Copyright (c) 1980, 1986, 1991, 1993 * The Regents of the University of California. 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. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1980, 1986, 1991, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #if 0 #ifndef lint static char sccsid[] = "@(#)vmstat.c 8.1 (Berkeley) 6/6/93"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static char da[] = "da"; static struct nlist namelist[] = { #define X_SUM 0 { "_vm_cnt" }, #define X_HZ 1 { "_hz" }, #define X_STATHZ 2 { "_stathz" }, #define X_NCHSTATS 3 { "_nchstats" }, #define X_INTRNAMES 4 { "_intrnames" }, #define X_SINTRNAMES 5 { "_sintrnames" }, #define X_INTRCNT 6 { "_intrcnt" }, #define X_SINTRCNT 7 { "_sintrcnt" }, #ifdef notyet #define X_DEFICIT XXX { "_deficit" }, #define X_REC XXX { "_rectime" }, #define X_PGIN XXX { "_pgintime" }, #define X_XSTATS XXX { "_xstats" }, #define X_END XXX #else #define X_END 8 #endif { "" }, }; static struct statinfo cur, last; static int num_devices, maxshowdevs; static long generation; static struct device_selection *dev_select; static int num_selected; static struct devstat_match *matches; static int num_matches = 0; static int num_devices_specified, num_selections; static long select_generation; static char **specified_devices; static devstat_select_mode select_mode; static struct vmmeter sum, osum; #define VMSTAT_DEFAULT_LINES 20 /* Default number of `winlines'. */ volatile sig_atomic_t wresized; /* Tty resized, when non-zero. */ static int winlines = VMSTAT_DEFAULT_LINES; /* Current number of tty rows. */ static int aflag; static int nflag; static int Pflag; static int hflag; static kvm_t *kd; #define FORKSTAT 0x01 #define INTRSTAT 0x02 #define MEMSTAT 0x04 #define SUMSTAT 0x08 #define TIMESTAT 0x10 #define VMSTAT 0x20 #define ZMEMSTAT 0x40 #define OBJSTAT 0x80 static void cpustats(void); static void pcpustats(int, u_long, int); static void devstats(void); static void doforkst(void); static void dointr(unsigned int, int); static void doobjstat(void); static void dosum(void); static void dovmstat(unsigned int, int); static void domemstat_malloc(void); static void domemstat_zone(void); static void kread(int, void *, size_t); static void kreado(int, void *, size_t, size_t); static char *kgetstr(const char *); static void needhdr(int); static void needresize(int); static void doresize(void); static void printhdr(int, u_long); static void usage(void); static long pct(long, long); static long long getuptime(void); static char **getdrivedata(char **); int main(int argc, char *argv[]) { int c, todo; unsigned int interval; float f; int reps; char *memf, *nlistf; char errbuf[_POSIX2_LINE_MAX]; memf = nlistf = NULL; interval = reps = todo = 0; maxshowdevs = 2; hflag = isatty(1); while ((c = getopt(argc, argv, "ac:fhHiM:mN:n:oPp:stw:z")) != -1) { switch (c) { case 'a': aflag++; break; case 'c': reps = atoi(optarg); break; case 'P': Pflag++; break; case 'f': todo |= FORKSTAT; break; case 'h': hflag = 1; break; case 'H': hflag = 0; break; case 'i': todo |= INTRSTAT; break; case 'M': memf = optarg; break; case 'm': todo |= MEMSTAT; break; case 'N': nlistf = optarg; break; case 'n': nflag = 1; maxshowdevs = atoi(optarg); if (maxshowdevs < 0) errx(1, "number of devices %d is < 0", maxshowdevs); break; case 'o': todo |= OBJSTAT; break; case 'p': if (devstat_buildmatch(optarg, &matches, &num_matches) != 0) errx(1, "%s", devstat_errbuf); break; case 's': todo |= SUMSTAT; break; case 't': #ifdef notyet todo |= TIMESTAT; #else errx(EX_USAGE, "sorry, -t is not (re)implemented yet"); #endif break; case 'w': /* Convert to milliseconds. */ f = atof(optarg); interval = f * 1000; break; case 'z': todo |= ZMEMSTAT; break; case '?': default: usage(); } } argc -= optind; argv += optind; if (todo == 0) todo = VMSTAT; if (memf != NULL) { kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); if (kd == NULL) errx(1, "kvm_openfiles: %s", errbuf); } retry_nlist: if (kd != NULL && (c = kvm_nlist(kd, namelist)) != 0) { if (c > 0) { /* * 'cnt' was renamed to 'vm_cnt'. If 'vm_cnt' is not * found try looking up older 'cnt' symbol. * */ if (namelist[X_SUM].n_type == 0 && strcmp(namelist[X_SUM].n_name, "_vm_cnt") == 0) { namelist[X_SUM].n_name = "_cnt"; goto retry_nlist; } warnx("undefined symbols:"); for (c = 0; c < (int)(sizeof(namelist)/sizeof(namelist[0])); c++) if (namelist[c].n_type == 0) (void)fprintf(stderr, " %s", namelist[c].n_name); (void)fputc('\n', stderr); } else warnx("kvm_nlist: %s", kvm_geterr(kd)); exit(1); } if (kd && Pflag) errx(1, "Cannot use -P with crash dumps"); if (todo & VMSTAT) { /* * Make sure that the userland devstat version matches the * kernel devstat version. If not, exit and print a * message informing the user of his mistake. */ if (devstat_checkversion(NULL) < 0) errx(1, "%s", devstat_errbuf); argv = getdrivedata(argv); } if (*argv) { f = atof(*argv); interval = f * 1000; if (*++argv) reps = atoi(*argv); } if (interval) { if (!reps) reps = -1; } else if (reps) interval = 1 * 1000; if (todo & FORKSTAT) doforkst(); if (todo & MEMSTAT) domemstat_malloc(); if (todo & ZMEMSTAT) domemstat_zone(); if (todo & SUMSTAT) dosum(); if (todo & OBJSTAT) doobjstat(); #ifdef notyet if (todo & TIMESTAT) dotimes(); #endif if (todo & INTRSTAT) dointr(interval, reps); if (todo & VMSTAT) dovmstat(interval, reps); exit(0); } static int mysysctl(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen) { int error; error = sysctlbyname(name, oldp, oldlenp, newp, newlen); if (error != 0 && errno != ENOMEM) err(1, "sysctl(%s)", name); return (error); } static char ** getdrivedata(char **argv) { if ((num_devices = devstat_getnumdevs(NULL)) < 0) errx(1, "%s", devstat_errbuf); cur.dinfo = (struct devinfo *)calloc(1, sizeof(struct devinfo)); last.dinfo = (struct devinfo *)calloc(1, sizeof(struct devinfo)); if (devstat_getdevs(NULL, &cur) == -1) errx(1, "%s", devstat_errbuf); num_devices = cur.dinfo->numdevs; generation = cur.dinfo->generation; specified_devices = (char **)malloc(sizeof(char *)); for (num_devices_specified = 0; *argv; ++argv) { if (isdigit(**argv)) break; num_devices_specified++; specified_devices = (char **)realloc(specified_devices, sizeof(char *) * num_devices_specified); specified_devices[num_devices_specified - 1] = *argv; } dev_select = NULL; if (nflag == 0 && maxshowdevs < num_devices_specified) maxshowdevs = num_devices_specified; /* * People are generally only interested in disk statistics when * they're running vmstat. So, that's what we're going to give * them if they don't specify anything by default. We'll also give * them any other random devices in the system so that we get to * maxshowdevs devices, if that many devices exist. If the user * specifies devices on the command line, either through a pattern * match or by naming them explicitly, we will give the user only * those devices. */ if ((num_devices_specified == 0) && (num_matches == 0)) { if (devstat_buildmatch(da, &matches, &num_matches) != 0) errx(1, "%s", devstat_errbuf); select_mode = DS_SELECT_ADD; } else select_mode = DS_SELECT_ONLY; /* * At this point, selectdevs will almost surely indicate that the * device list has changed, so we don't look for return values of 0 * or 1. If we get back -1, though, there is an error. */ if (devstat_selectdevs(&dev_select, &num_selected, &num_selections, &select_generation, generation, cur.dinfo->devices, num_devices, matches, num_matches, specified_devices, num_devices_specified, select_mode, maxshowdevs, 0) == -1) errx(1, "%s", devstat_errbuf); return(argv); } /* Return system uptime in nanoseconds */ static long long getuptime(void) { struct timespec sp; (void)clock_gettime(CLOCK_UPTIME, &sp); return((long long)sp.tv_sec * 1000000000LL + sp.tv_nsec); } static void fill_pcpu(struct pcpu ***pcpup, int* maxcpup) { struct pcpu **pcpu; int maxcpu, i; *pcpup = NULL; if (kd == NULL) return; maxcpu = kvm_getmaxcpu(kd); if (maxcpu < 0) errx(1, "kvm_getmaxcpu: %s", kvm_geterr(kd)); pcpu = calloc(maxcpu, sizeof(struct pcpu *)); if (pcpu == NULL) err(1, "calloc"); for (i = 0; i < maxcpu; i++) { pcpu[i] = kvm_getpcpu(kd, i); if (pcpu[i] == (struct pcpu *)-1) errx(1, "kvm_getpcpu: %s", kvm_geterr(kd)); } *maxcpup = maxcpu; *pcpup = pcpu; } static void free_pcpu(struct pcpu **pcpu, int maxcpu) { int i; for (i = 0; i < maxcpu; i++) free(pcpu[i]); free(pcpu); } static void fill_vmmeter(struct vmmeter *vmmp) { struct pcpu **pcpu; int maxcpu, i; if (kd != NULL) { kread(X_SUM, vmmp, sizeof(*vmmp)); fill_pcpu(&pcpu, &maxcpu); for (i = 0; i < maxcpu; i++) { if (pcpu[i] == NULL) continue; #define ADD_FROM_PCPU(i, name) \ vmmp->name += pcpu[i]->pc_cnt.name ADD_FROM_PCPU(i, v_swtch); ADD_FROM_PCPU(i, v_trap); ADD_FROM_PCPU(i, v_syscall); ADD_FROM_PCPU(i, v_intr); ADD_FROM_PCPU(i, v_soft); ADD_FROM_PCPU(i, v_vm_faults); ADD_FROM_PCPU(i, v_io_faults); ADD_FROM_PCPU(i, v_cow_faults); ADD_FROM_PCPU(i, v_cow_optim); ADD_FROM_PCPU(i, v_zfod); ADD_FROM_PCPU(i, v_ozfod); ADD_FROM_PCPU(i, v_swapin); ADD_FROM_PCPU(i, v_swapout); ADD_FROM_PCPU(i, v_swappgsin); ADD_FROM_PCPU(i, v_swappgsout); ADD_FROM_PCPU(i, v_vnodein); ADD_FROM_PCPU(i, v_vnodeout); ADD_FROM_PCPU(i, v_vnodepgsin); ADD_FROM_PCPU(i, v_vnodepgsout); ADD_FROM_PCPU(i, v_intrans); ADD_FROM_PCPU(i, v_tfree); ADD_FROM_PCPU(i, v_forks); ADD_FROM_PCPU(i, v_vforks); ADD_FROM_PCPU(i, v_rforks); ADD_FROM_PCPU(i, v_kthreads); ADD_FROM_PCPU(i, v_forkpages); ADD_FROM_PCPU(i, v_vforkpages); ADD_FROM_PCPU(i, v_rforkpages); ADD_FROM_PCPU(i, v_kthreadpages); #undef ADD_FROM_PCPU } free_pcpu(pcpu, maxcpu); } else { size_t size = sizeof(unsigned int); #define GET_VM_STATS(cat, name) \ mysysctl("vm.stats." #cat "." #name, &vmmp->name, &size, NULL, 0) /* sys */ GET_VM_STATS(sys, v_swtch); GET_VM_STATS(sys, v_trap); GET_VM_STATS(sys, v_syscall); GET_VM_STATS(sys, v_intr); GET_VM_STATS(sys, v_soft); /* vm */ GET_VM_STATS(vm, v_vm_faults); GET_VM_STATS(vm, v_io_faults); GET_VM_STATS(vm, v_cow_faults); GET_VM_STATS(vm, v_cow_optim); GET_VM_STATS(vm, v_zfod); GET_VM_STATS(vm, v_ozfod); GET_VM_STATS(vm, v_swapin); GET_VM_STATS(vm, v_swapout); GET_VM_STATS(vm, v_swappgsin); GET_VM_STATS(vm, v_swappgsout); GET_VM_STATS(vm, v_vnodein); GET_VM_STATS(vm, v_vnodeout); GET_VM_STATS(vm, v_vnodepgsin); GET_VM_STATS(vm, v_vnodepgsout); GET_VM_STATS(vm, v_intrans); GET_VM_STATS(vm, v_reactivated); GET_VM_STATS(vm, v_pdwakeups); GET_VM_STATS(vm, v_pdpages); - GET_VM_STATS(vm, v_tcached); GET_VM_STATS(vm, v_dfree); GET_VM_STATS(vm, v_pfree); GET_VM_STATS(vm, v_tfree); GET_VM_STATS(vm, v_page_size); GET_VM_STATS(vm, v_page_count); GET_VM_STATS(vm, v_free_reserved); GET_VM_STATS(vm, v_free_target); GET_VM_STATS(vm, v_free_min); GET_VM_STATS(vm, v_free_count); GET_VM_STATS(vm, v_wire_count); GET_VM_STATS(vm, v_active_count); GET_VM_STATS(vm, v_inactive_target); GET_VM_STATS(vm, v_inactive_count); - GET_VM_STATS(vm, v_cache_count); + GET_VM_STATS(vm, v_laundry_count); GET_VM_STATS(vm, v_pageout_free_min); GET_VM_STATS(vm, v_interrupt_free_min); /*GET_VM_STATS(vm, v_free_severe);*/ GET_VM_STATS(vm, v_forks); GET_VM_STATS(vm, v_vforks); GET_VM_STATS(vm, v_rforks); GET_VM_STATS(vm, v_kthreads); GET_VM_STATS(vm, v_forkpages); GET_VM_STATS(vm, v_vforkpages); GET_VM_STATS(vm, v_rforkpages); GET_VM_STATS(vm, v_kthreadpages); #undef GET_VM_STATS } } static void fill_vmtotal(struct vmtotal *vmtp) { if (kd != NULL) { /* XXX fill vmtp */ errx(1, "not implemented"); } else { size_t size = sizeof(*vmtp); mysysctl("vm.vmtotal", vmtp, &size, NULL, 0); if (size != sizeof(*vmtp)) errx(1, "vm.total size mismatch"); } } /* Determine how many cpu columns, and what index they are in kern.cp_times */ static int getcpuinfo(u_long *maskp, int *maxidp) { int maxcpu; int maxid; int ncpus; int i, j; int empty; size_t size; long *times; u_long mask; if (kd != NULL) errx(1, "not implemented"); mask = 0; ncpus = 0; size = sizeof(maxcpu); mysysctl("kern.smp.maxcpus", &maxcpu, &size, NULL, 0); if (size != sizeof(maxcpu)) errx(1, "sysctl kern.smp.maxcpus"); size = sizeof(long) * maxcpu * CPUSTATES; times = malloc(size); if (times == NULL) err(1, "malloc %zd bytes", size); mysysctl("kern.cp_times", times, &size, NULL, 0); maxid = (size / CPUSTATES / sizeof(long)) - 1; for (i = 0; i <= maxid; i++) { empty = 1; for (j = 0; empty && j < CPUSTATES; j++) { if (times[i * CPUSTATES + j] != 0) empty = 0; } if (!empty) { mask |= (1ul << i); ncpus++; } } if (maskp) *maskp = mask; if (maxidp) *maxidp = maxid; return (ncpus); } static void prthuman(u_int64_t val, int size) { char buf[10]; int flags; if (size < 5 || size > 9) errx(1, "doofus"); flags = HN_B | HN_NOSPACE | HN_DECIMAL; humanize_number(buf, size, val, "", HN_AUTOSCALE, flags); printf("%*s", size, buf); } static int hz, hdrcnt; static long *cur_cp_times; static long *last_cp_times; static size_t size_cp_times; static void dovmstat(unsigned int interval, int reps) { struct vmtotal total; time_t uptime, halfuptime; struct devinfo *tmp_dinfo; size_t size; int ncpus, maxid; u_long cpumask; int rate_adj; uptime = getuptime() / 1000000000LL; halfuptime = uptime / 2; rate_adj = 1; ncpus = 1; maxid = 0; /* * If the user stops the program (control-Z) and then resumes it, * print out the header again. */ (void)signal(SIGCONT, needhdr); /* * If our standard output is a tty, then install a SIGWINCH handler * and set wresized so that our first iteration through the main * vmstat loop will peek at the terminal's current rows to find out * how many lines can fit in a screenful of output. */ if (isatty(fileno(stdout)) != 0) { wresized = 1; (void)signal(SIGWINCH, needresize); } else { wresized = 0; winlines = VMSTAT_DEFAULT_LINES; } if (kd != NULL) { if (namelist[X_STATHZ].n_type != 0 && namelist[X_STATHZ].n_value != 0) kread(X_STATHZ, &hz, sizeof(hz)); if (!hz) kread(X_HZ, &hz, sizeof(hz)); } else { struct clockinfo clockrate; size = sizeof(clockrate); mysysctl("kern.clockrate", &clockrate, &size, NULL, 0); if (size != sizeof(clockrate)) errx(1, "clockrate size mismatch"); hz = clockrate.hz; } if (Pflag) { ncpus = getcpuinfo(&cpumask, &maxid); size_cp_times = sizeof(long) * (maxid + 1) * CPUSTATES; cur_cp_times = calloc(1, size_cp_times); last_cp_times = calloc(1, size_cp_times); } for (hdrcnt = 1;;) { if (!--hdrcnt) printhdr(maxid, cpumask); if (kd != NULL) { if (kvm_getcptime(kd, cur.cp_time) < 0) errx(1, "kvm_getcptime: %s", kvm_geterr(kd)); } else { size = sizeof(cur.cp_time); mysysctl("kern.cp_time", &cur.cp_time, &size, NULL, 0); if (size != sizeof(cur.cp_time)) errx(1, "cp_time size mismatch"); } if (Pflag) { size = size_cp_times; mysysctl("kern.cp_times", cur_cp_times, &size, NULL, 0); if (size != size_cp_times) errx(1, "cp_times mismatch"); } tmp_dinfo = last.dinfo; last.dinfo = cur.dinfo; cur.dinfo = tmp_dinfo; last.snap_time = cur.snap_time; /* * Here what we want to do is refresh our device stats. * getdevs() returns 1 when the device list has changed. * If the device list has changed, we want to go through * the selection process again, in case a device that we * were previously displaying has gone away. */ switch (devstat_getdevs(NULL, &cur)) { case -1: errx(1, "%s", devstat_errbuf); break; case 1: { int retval; num_devices = cur.dinfo->numdevs; generation = cur.dinfo->generation; retval = devstat_selectdevs(&dev_select, &num_selected, &num_selections, &select_generation, generation, cur.dinfo->devices, num_devices, matches, num_matches, specified_devices, num_devices_specified, select_mode, maxshowdevs, 0); switch (retval) { case -1: errx(1, "%s", devstat_errbuf); break; case 1: printhdr(maxid, cpumask); break; default: break; } } default: break; } fill_vmmeter(&sum); fill_vmtotal(&total); (void)printf("%1d %1d %1d", total.t_rq - 1, total.t_dw + total.t_pw, total.t_sw); #define vmstat_pgtok(a) ((a) * (sum.v_page_size >> 10)) #define rate(x) (((x) * rate_adj + halfuptime) / uptime) /* round */ if (hflag) { printf(""); prthuman(total.t_avm * (u_int64_t)sum.v_page_size, 5); printf(" "); prthuman(total.t_free * (u_int64_t)sum.v_page_size, 5); printf(" "); (void)printf("%5lu ", (unsigned long)rate(sum.v_vm_faults - osum.v_vm_faults)); } else { printf(" %7d", vmstat_pgtok(total.t_avm)); printf(" %7d ", vmstat_pgtok(total.t_free)); (void)printf("%4lu ", (unsigned long)rate(sum.v_vm_faults - osum.v_vm_faults)); } (void)printf("%3lu ", (unsigned long)rate(sum.v_reactivated - osum.v_reactivated)); (void)printf("%3lu ", (unsigned long)rate(sum.v_swapin + sum.v_vnodein - (osum.v_swapin + osum.v_vnodein))); (void)printf("%3lu ", (unsigned long)rate(sum.v_swapout + sum.v_vnodeout - (osum.v_swapout + osum.v_vnodeout))); (void)printf("%5lu ", (unsigned long)rate(sum.v_tfree - osum.v_tfree)); (void)printf("%4lu ", (unsigned long)rate(sum.v_pdpages - osum.v_pdpages)); devstats(); (void)printf("%4lu %5lu %5lu", (unsigned long)rate(sum.v_intr - osum.v_intr), (unsigned long)rate(sum.v_syscall - osum.v_syscall), (unsigned long)rate(sum.v_swtch - osum.v_swtch)); if (Pflag) pcpustats(ncpus, cpumask, maxid); else cpustats(); (void)printf("\n"); (void)fflush(stdout); if (reps >= 0 && --reps <= 0) break; osum = sum; uptime = interval; rate_adj = 1000; /* * We round upward to avoid losing low-frequency events * (i.e., >= 1 per interval but < 1 per millisecond). */ if (interval != 1) halfuptime = (uptime + 1) / 2; else halfuptime = 0; (void)usleep(interval * 1000); } } static void printhdr(int maxid, u_long cpumask) { int i, num_shown; num_shown = (num_selected < maxshowdevs) ? num_selected : maxshowdevs; if (hflag) { (void)printf("procs memory page%*s ", 19, ""); } else { (void)printf("procs memory page%*s ", 19, ""); } if (num_shown > 1) (void)printf(" disks %*s", num_shown * 4 - 7, ""); else if (num_shown == 1) (void)printf(" disk"); (void)printf(" faults "); if (Pflag) { for (i = 0; i <= maxid; i++) { if (cpumask & (1ul << i)) printf(" cpu%d ", i); } printf("\n"); } else printf(" cpu\n"); if (hflag) { (void)printf("r b w avm fre flt re pi po fr sr "); } else { (void)printf("r b w avm fre flt re pi po fr sr "); } for (i = 0; i < num_devices; i++) if ((dev_select[i].selected) && (dev_select[i].selected <= maxshowdevs)) (void)printf("%c%c%d ", dev_select[i].device_name[0], dev_select[i].device_name[1], dev_select[i].unit_number); (void)printf(" in sy cs"); if (Pflag) { for (i = 0; i <= maxid; i++) { if (cpumask & (1ul << i)) printf(" us sy id"); } printf("\n"); } else printf(" us sy id\n"); if (wresized != 0) doresize(); hdrcnt = winlines; } /* * Force a header to be prepended to the next output. */ static void needhdr(int dummy __unused) { hdrcnt = 1; } /* * When the terminal is resized, force an update of the maximum number of rows * printed between each header repetition. Then force a new header to be * prepended to the next output. */ void needresize(int signo) { wresized = 1; hdrcnt = 1; } /* * Update the global `winlines' count of terminal rows. */ void doresize(void) { int status; struct winsize w; for (;;) { status = ioctl(fileno(stdout), TIOCGWINSZ, &w); if (status == -1 && errno == EINTR) continue; else if (status == -1) err(1, "ioctl"); if (w.ws_row > 3) winlines = w.ws_row - 3; else winlines = VMSTAT_DEFAULT_LINES; break; } /* * Inhibit doresize() calls until we are rescheduled by SIGWINCH. */ wresized = 0; } #ifdef notyet static void dotimes(void) { unsigned int pgintime, rectime; kread(X_REC, &rectime, sizeof(rectime)); kread(X_PGIN, &pgintime, sizeof(pgintime)); kread(X_SUM, &sum, sizeof(sum)); (void)printf("%u reclaims, %u total time (usec)\n", sum.v_pgrec, rectime); (void)printf("average: %u usec / reclaim\n", rectime / sum.v_pgrec); (void)printf("\n"); (void)printf("%u page ins, %u total time (msec)\n", sum.v_pgin, pgintime / 10); (void)printf("average: %8.1f msec / page in\n", pgintime / (sum.v_pgin * 10.0)); } #endif static long pct(long top, long bot) { long ans; if (bot == 0) return(0); ans = (quad_t)top * 100 / bot; return (ans); } #define PCT(top, bot) pct((long)(top), (long)(bot)) static void dosum(void) { struct nchstats lnchstats; long nchtotal; fill_vmmeter(&sum); (void)printf("%9u cpu context switches\n", sum.v_swtch); (void)printf("%9u device interrupts\n", sum.v_intr); (void)printf("%9u software interrupts\n", sum.v_soft); (void)printf("%9u traps\n", sum.v_trap); (void)printf("%9u system calls\n", sum.v_syscall); (void)printf("%9u kernel threads created\n", sum.v_kthreads); (void)printf("%9u fork() calls\n", sum.v_forks); (void)printf("%9u vfork() calls\n", sum.v_vforks); (void)printf("%9u rfork() calls\n", sum.v_rforks); (void)printf("%9u swap pager pageins\n", sum.v_swapin); (void)printf("%9u swap pager pages paged in\n", sum.v_swappgsin); (void)printf("%9u swap pager pageouts\n", sum.v_swapout); (void)printf("%9u swap pager pages paged out\n", sum.v_swappgsout); (void)printf("%9u vnode pager pageins\n", sum.v_vnodein); (void)printf("%9u vnode pager pages paged in\n", sum.v_vnodepgsin); (void)printf("%9u vnode pager pageouts\n", sum.v_vnodeout); (void)printf("%9u vnode pager pages paged out\n", sum.v_vnodepgsout); (void)printf("%9u page daemon wakeups\n", sum.v_pdwakeups); (void)printf("%9u pages examined by the page daemon\n", sum.v_pdpages); (void)printf("%9u pages reactivated\n", sum.v_reactivated); (void)printf("%9u copy-on-write faults\n", sum.v_cow_faults); (void)printf("%9u copy-on-write optimized faults\n", sum.v_cow_optim); (void)printf("%9u zero fill pages zeroed\n", sum.v_zfod); (void)printf("%9u zero fill pages prezeroed\n", sum.v_ozfod); (void)printf("%9u intransit blocking page faults\n", sum.v_intrans); (void)printf("%9u total VM faults taken\n", sum.v_vm_faults); (void)printf("%9u page faults requiring I/O\n", sum.v_io_faults); (void)printf("%9u pages affected by kernel thread creation\n", sum.v_kthreadpages); (void)printf("%9u pages affected by fork()\n", sum.v_forkpages); (void)printf("%9u pages affected by vfork()\n", sum.v_vforkpages); (void)printf("%9u pages affected by rfork()\n", sum.v_rforkpages); - (void)printf("%9u pages cached\n", sum.v_tcached); (void)printf("%9u pages freed\n", sum.v_tfree); (void)printf("%9u pages freed by daemon\n", sum.v_dfree); (void)printf("%9u pages freed by exiting processes\n", sum.v_pfree); (void)printf("%9u pages active\n", sum.v_active_count); (void)printf("%9u pages inactive\n", sum.v_inactive_count); - (void)printf("%9u pages in VM cache\n", sum.v_cache_count); + (void)printf("%9u pages in the laundry\n", sum.v_laundry_count); (void)printf("%9u pages wired down\n", sum.v_wire_count); (void)printf("%9u pages free\n", sum.v_free_count); (void)printf("%9u bytes per page\n", sum.v_page_size); if (kd != NULL) { kread(X_NCHSTATS, &lnchstats, sizeof(lnchstats)); } else { size_t size = sizeof(lnchstats); mysysctl("vfs.cache.nchstats", &lnchstats, &size, NULL, 0); if (size != sizeof(lnchstats)) errx(1, "vfs.cache.nchstats size mismatch"); } nchtotal = lnchstats.ncs_goodhits + lnchstats.ncs_neghits + lnchstats.ncs_badhits + lnchstats.ncs_falsehits + lnchstats.ncs_miss + lnchstats.ncs_long; (void)printf("%9ld total name lookups\n", nchtotal); (void)printf( "%9s cache hits (%ld%% pos + %ld%% neg) system %ld%% per-directory\n", "", PCT(lnchstats.ncs_goodhits, nchtotal), PCT(lnchstats.ncs_neghits, nchtotal), PCT(lnchstats.ncs_pass2, nchtotal)); (void)printf("%9s deletions %ld%%, falsehits %ld%%, toolong %ld%%\n", "", PCT(lnchstats.ncs_badhits, nchtotal), PCT(lnchstats.ncs_falsehits, nchtotal), PCT(lnchstats.ncs_long, nchtotal)); } static void doforkst(void) { fill_vmmeter(&sum); (void)printf("%u forks, %u pages, average %.2f\n", sum.v_forks, sum.v_forkpages, sum.v_forks == 0 ? 0.0 : (double)sum.v_forkpages / sum.v_forks); (void)printf("%u vforks, %u pages, average %.2f\n", sum.v_vforks, sum.v_vforkpages, sum.v_vforks == 0 ? 0.0 : (double)sum.v_vforkpages / sum.v_vforks); (void)printf("%u rforks, %u pages, average %.2f\n", sum.v_rforks, sum.v_rforkpages, sum.v_rforks == 0 ? 0.0 : (double)sum.v_rforkpages / sum.v_rforks); } static void devstats(void) { int dn, state; long double transfers_per_second; long double busy_seconds; long tmp; for (state = 0; state < CPUSTATES; ++state) { tmp = cur.cp_time[state]; cur.cp_time[state] -= last.cp_time[state]; last.cp_time[state] = tmp; } busy_seconds = cur.snap_time - last.snap_time; for (dn = 0; dn < num_devices; dn++) { int di; if ((dev_select[dn].selected == 0) || (dev_select[dn].selected > maxshowdevs)) continue; di = dev_select[dn].position; if (devstat_compute_statistics(&cur.dinfo->devices[di], &last.dinfo->devices[di], busy_seconds, DSM_TRANSFERS_PER_SECOND, &transfers_per_second, DSM_NONE) != 0) errx(1, "%s", devstat_errbuf); (void)printf("%3.0Lf ", transfers_per_second); } } static void percent(double pct, int *over) { char buf[10]; int l; l = snprintf(buf, sizeof(buf), "%.0f", pct); if (l == 1 && *over) { printf("%s", buf); (*over)--; } else printf("%2s", buf); if (l > 2) (*over)++; } static void cpustats(void) { int state, over; double lpct, total; total = 0; for (state = 0; state < CPUSTATES; ++state) total += cur.cp_time[state]; if (total) lpct = 100.0 / total; else lpct = 0.0; over = 0; printf(" "); percent((cur.cp_time[CP_USER] + cur.cp_time[CP_NICE]) * lpct, &over); printf(" "); percent((cur.cp_time[CP_SYS] + cur.cp_time[CP_INTR]) * lpct, &over); printf(" "); percent(cur.cp_time[CP_IDLE] * lpct, &over); } static void pcpustats(int ncpus, u_long cpumask, int maxid) { int state, i; double lpct, total; long tmp; int over; /* devstats does this for cp_time */ for (i = 0; i <= maxid; i++) { if ((cpumask & (1ul << i)) == 0) continue; for (state = 0; state < CPUSTATES; ++state) { tmp = cur_cp_times[i * CPUSTATES + state]; cur_cp_times[i * CPUSTATES + state] -= last_cp_times[i * CPUSTATES + state]; last_cp_times[i * CPUSTATES + state] = tmp; } } over = 0; for (i = 0; i <= maxid; i++) { if ((cpumask & (1ul << i)) == 0) continue; total = 0; for (state = 0; state < CPUSTATES; ++state) total += cur_cp_times[i * CPUSTATES + state]; if (total) lpct = 100.0 / total; else lpct = 0.0; printf(" "); percent((cur_cp_times[i * CPUSTATES + CP_USER] + cur_cp_times[i * CPUSTATES + CP_NICE]) * lpct, &over); printf(" "); percent((cur_cp_times[i * CPUSTATES + CP_SYS] + cur_cp_times[i * CPUSTATES + CP_INTR]) * lpct, &over); printf(" "); percent(cur_cp_times[i * CPUSTATES + CP_IDLE] * lpct, &over); } } static unsigned int read_intrcnts(unsigned long **intrcnts) { size_t intrcntlen; if (kd != NULL) { kread(X_SINTRCNT, &intrcntlen, sizeof(intrcntlen)); if ((*intrcnts = malloc(intrcntlen)) == NULL) err(1, "malloc()"); kread(X_INTRCNT, *intrcnts, intrcntlen); } else { for (*intrcnts = NULL, intrcntlen = 1024; ; intrcntlen *= 2) { *intrcnts = reallocf(*intrcnts, intrcntlen); if (*intrcnts == NULL) err(1, "reallocf()"); if (mysysctl("hw.intrcnt", *intrcnts, &intrcntlen, NULL, 0) == 0) break; } } return (intrcntlen / sizeof(unsigned long)); } static void print_intrcnts(unsigned long *intrcnts, unsigned long *old_intrcnts, char *intrnames, unsigned int nintr, size_t istrnamlen, long long period_ms) { unsigned long *intrcnt, *old_intrcnt; uint64_t inttotal, old_inttotal, total_count, total_rate; char* intrname; unsigned int i; inttotal = 0; old_inttotal = 0; intrname = intrnames; for (i = 0, intrcnt=intrcnts, old_intrcnt=old_intrcnts; i < nintr; i++) { if (intrname[0] != '\0' && (*intrcnt != 0 || aflag)) { unsigned long count, rate; count = *intrcnt - *old_intrcnt; rate = (count * 1000 + period_ms / 2) / period_ms; (void)printf("%-*s %20lu %10lu\n", (int)istrnamlen, intrname, count, rate); } intrname += strlen(intrname) + 1; inttotal += *intrcnt++; old_inttotal += *old_intrcnt++; } total_count = inttotal - old_inttotal; total_rate = (total_count * 1000 + period_ms / 2) / period_ms; (void)printf("%-*s %20" PRIu64 " %10" PRIu64 "\n", (int)istrnamlen, "Total", total_count, total_rate); } static void dointr(unsigned int interval, int reps) { unsigned long *intrcnts; long long uptime, period_ms; unsigned long *old_intrcnts = NULL; size_t clen, inamlen, istrnamlen; char *intrnames, *intrname; uptime = getuptime(); /* Get the names of each interrupt source */ if (kd != NULL) { kread(X_SINTRNAMES, &inamlen, sizeof(inamlen)); if ((intrnames = malloc(inamlen)) == NULL) err(1, "malloc()"); kread(X_INTRNAMES, intrnames, inamlen); } else { for (intrnames = NULL, inamlen = 1024; ; inamlen *= 2) { if ((intrnames = reallocf(intrnames, inamlen)) == NULL) err(1, "reallocf()"); if (mysysctl("hw.intrnames", intrnames, &inamlen, NULL, 0) == 0) break; } } /* Determine the length of the longest interrupt name */ intrname = intrnames; istrnamlen = strlen("interrupt"); while(*intrname != '\0') { clen = strlen(intrname); if (clen > istrnamlen) istrnamlen = clen; intrname += strlen(intrname) + 1; } (void)printf("%-*s %20s %10s\n", (int)istrnamlen, "interrupt", "total", "rate"); /* * Loop reps times printing differential interrupt counts. If reps is * zero, then run just once, printing total counts */ period_ms = uptime / 1000000; while(1) { unsigned int nintr; long long old_uptime; nintr = read_intrcnts(&intrcnts); /* * Initialize old_intrcnts to 0 for the first pass, so * print_intrcnts will print total interrupts since boot */ if (old_intrcnts == NULL) { old_intrcnts = calloc(nintr, sizeof(unsigned long)); if (old_intrcnts == NULL) err(1, "calloc()"); } print_intrcnts(intrcnts, old_intrcnts, intrnames, nintr, istrnamlen, period_ms); free(old_intrcnts); old_intrcnts = intrcnts; if (reps >= 0 && --reps <= 0) break; usleep(interval * 1000); old_uptime = uptime; uptime = getuptime(); period_ms = (uptime - old_uptime) / 1000000; } } static void domemstat_malloc(void) { struct memory_type_list *mtlp; struct memory_type *mtp; int error, first, i; mtlp = memstat_mtl_alloc(); if (mtlp == NULL) { warn("memstat_mtl_alloc"); return; } if (kd == NULL) { if (memstat_sysctl_malloc(mtlp, 0) < 0) { warnx("memstat_sysctl_malloc: %s", memstat_strerror(memstat_mtl_geterror(mtlp))); return; } } else { if (memstat_kvm_malloc(mtlp, kd) < 0) { error = memstat_mtl_geterror(mtlp); if (error == MEMSTAT_ERROR_KVM) warnx("memstat_kvm_malloc: %s", kvm_geterr(kd)); else warnx("memstat_kvm_malloc: %s", memstat_strerror(error)); } } printf("%13s %5s %6s %7s %8s Size(s)\n", "Type", "InUse", "MemUse", "HighUse", "Requests"); for (mtp = memstat_mtl_first(mtlp); mtp != NULL; mtp = memstat_mtl_next(mtp)) { if (memstat_get_numallocs(mtp) == 0 && memstat_get_count(mtp) == 0) continue; printf("%13s %5" PRIu64 " %5" PRIu64 "K %7s %8" PRIu64 " ", memstat_get_name(mtp), memstat_get_count(mtp), (memstat_get_bytes(mtp) + 1023) / 1024, "-", memstat_get_numallocs(mtp)); first = 1; for (i = 0; i < 32; i++) { if (memstat_get_sizemask(mtp) & (1 << i)) { if (!first) printf(","); printf("%d", 1 << (i + 4)); first = 0; } } printf("\n"); } memstat_mtl_free(mtlp); } static void domemstat_zone(void) { struct memory_type_list *mtlp; struct memory_type *mtp; char name[MEMTYPE_MAXNAME + 1]; int error; mtlp = memstat_mtl_alloc(); if (mtlp == NULL) { warn("memstat_mtl_alloc"); return; } if (kd == NULL) { if (memstat_sysctl_uma(mtlp, 0) < 0) { warnx("memstat_sysctl_uma: %s", memstat_strerror(memstat_mtl_geterror(mtlp))); return; } } else { if (memstat_kvm_uma(mtlp, kd) < 0) { error = memstat_mtl_geterror(mtlp); if (error == MEMSTAT_ERROR_KVM) warnx("memstat_kvm_uma: %s", kvm_geterr(kd)); else warnx("memstat_kvm_uma: %s", memstat_strerror(error)); } } printf("%-20s %6s %6s %8s %8s %8s %4s %4s\n\n", "ITEM", "SIZE", "LIMIT", "USED", "FREE", "REQ", "FAIL", "SLEEP"); for (mtp = memstat_mtl_first(mtlp); mtp != NULL; mtp = memstat_mtl_next(mtp)) { strlcpy(name, memstat_get_name(mtp), MEMTYPE_MAXNAME); strcat(name, ":"); printf("%-20s %6" PRIu64 ", %6" PRIu64 ",%8" PRIu64 ",%8" PRIu64 ",%8" PRIu64 ",%4" PRIu64 ",%4" PRIu64 "\n", name, memstat_get_size(mtp), memstat_get_countlimit(mtp), memstat_get_count(mtp), memstat_get_free(mtp), memstat_get_numallocs(mtp), memstat_get_failures(mtp), memstat_get_sleeps(mtp)); } memstat_mtl_free(mtlp); printf("\n"); } static void display_object(struct kinfo_vmobject *kvo) { const char *str; printf("%5jd ", (uintmax_t)kvo->kvo_resident); printf("%5jd ", (uintmax_t)kvo->kvo_active); printf("%5jd ", (uintmax_t)kvo->kvo_inactive); printf("%3d ", kvo->kvo_ref_count); printf("%3d ", kvo->kvo_shadow_count); switch (kvo->kvo_memattr) { #ifdef VM_MEMATTR_UNCACHEABLE case VM_MEMATTR_UNCACHEABLE: str = "UC"; break; #endif #ifdef VM_MEMATTR_WRITE_COMBINING case VM_MEMATTR_WRITE_COMBINING: str = "WC"; break; #endif #ifdef VM_MEMATTR_WRITE_THROUGH case VM_MEMATTR_WRITE_THROUGH: str = "WT"; break; #endif #ifdef VM_MEMATTR_WRITE_PROTECTED case VM_MEMATTR_WRITE_PROTECTED: str = "WP"; break; #endif #ifdef VM_MEMATTR_WRITE_BACK case VM_MEMATTR_WRITE_BACK: str = "WB"; break; #endif #ifdef VM_MEMATTR_WEAK_UNCACHEABLE case VM_MEMATTR_WEAK_UNCACHEABLE: str = "UC-"; break; #endif #ifdef VM_MEMATTR_WB_WA case VM_MEMATTR_WB_WA: str = "WB"; break; #endif #ifdef VM_MEMATTR_NOCACHE case VM_MEMATTR_NOCACHE: str = "NC"; break; #endif #ifdef VM_MEMATTR_DEVICE case VM_MEMATTR_DEVICE: str = "DEV"; break; #endif #ifdef VM_MEMATTR_CACHEABLE case VM_MEMATTR_CACHEABLE: str = "C"; break; #endif #ifdef VM_MEMATTR_PREFETCHABLE case VM_MEMATTR_PREFETCHABLE: str = "PRE"; break; #endif default: str = "??"; break; } printf("%-3s ", str); switch (kvo->kvo_type) { case KVME_TYPE_NONE: str = "--"; break; case KVME_TYPE_DEFAULT: str = "df"; break; case KVME_TYPE_VNODE: str = "vn"; break; case KVME_TYPE_SWAP: str = "sw"; break; case KVME_TYPE_DEVICE: str = "dv"; break; case KVME_TYPE_PHYS: str = "ph"; break; case KVME_TYPE_DEAD: str = "dd"; break; case KVME_TYPE_SG: str = "sg"; break; case KVME_TYPE_UNKNOWN: default: str = "??"; break; } printf("%-2s ", str); printf("%-s\n", kvo->kvo_path); } static void doobjstat(void) { struct kinfo_vmobject *kvo; int cnt, i; kvo = kinfo_getvmobject(&cnt); if (kvo == NULL) { warn("Failed to fetch VM object list"); return; } printf("%5s %5s %5s %3s %3s %3s %2s %s\n", "RES", "ACT", "INACT", "REF", "SHD", "CM", "TP", "PATH"); for (i = 0; i < cnt; i++) display_object(&kvo[i]); free(kvo); } /* * kread reads something from the kernel, given its nlist index. */ static void kreado(int nlx, void *addr, size_t size, size_t offset) { const char *sym; if (namelist[nlx].n_type == 0 || namelist[nlx].n_value == 0) { sym = namelist[nlx].n_name; if (*sym == '_') ++sym; errx(1, "symbol %s not defined", sym); } if ((size_t)kvm_read(kd, namelist[nlx].n_value + offset, addr, size) != size) { sym = namelist[nlx].n_name; if (*sym == '_') ++sym; errx(1, "%s: %s", sym, kvm_geterr(kd)); } } static void kread(int nlx, void *addr, size_t size) { kreado(nlx, addr, size, 0); } static char * kgetstr(const char *strp) { int n = 0, size = 1; char *ret = NULL; do { if (size == n + 1) { ret = realloc(ret, size); if (ret == NULL) err(1, "%s: realloc", __func__); size *= 2; } if (kvm_read(kd, (u_long)strp + n, &ret[n], 1) != 1) errx(1, "%s: %s", __func__, kvm_geterr(kd)); } while (ret[n++] != '\0'); return (ret); } static void usage(void) { (void)fprintf(stderr, "%s%s", "usage: vmstat [-afHhimoPsz] [-M core [-N system]] [-c count] [-n devs]\n", " [-p type,if,pass] [-w wait] [disks] [wait [count]]\n"); exit(1); }