Hi,
I noticed that if I leave the system running for more than about a month, some
of the counters in the uvm view of systat(1) overflow and become negative. This
is because the members of struct uvmexp in sys/uvm/uvmexp.h are ints. The
kernel's internal counters are of course uint64_t so they don't overflow. It
only happens during the uvm_sysctl(9) call which casts the numbers to integers.
The function is uvmexp_read.
In the attached diff I took the path of least resistance and promoted some of
the counters to unsigned int. Ideally I would have liked to use int64_t or even
uint64_t, but I hit an issue in some of the architecture dependent code. An
example is:
/usr/src/sys/arch/alpha/alpha/trap.c:536 atomic_add_int(&uvmexp.syscalls, 1);
In other places the ++ operator is used to increment the counters and the 64 bit
types can be used.
I am not completely sure this is the best way to proceed, but even if this diff
is horrifying, I'd appreciate some feedback and advice, thanks!
Anindya
Index: sys/uvm/uvm_meter.c
===================================================================
RCS file: /cvs/src/sys/uvm/uvm_meter.c,v
retrieving revision 1.42
diff -u -p -r1.42 uvm_meter.c
--- sys/uvm/uvm_meter.c 28 Dec 2020 14:01:23 -0000 1.42
+++ sys/uvm/uvm_meter.c 28 Jun 2021 05:24:56 -0000
@@ -329,7 +329,7 @@ uvmexp_read(struct uvmexp *uexp)
counters_read(uvmexp_counters, counters, exp_ncounters);
/* stat counters */
- uexp->faults = (int)counters[faults];
+ uexp->faults = (unsigned int)counters[faults];
uexp->pageins = (int)counters[pageins];
/* fault subcounters */
@@ -379,10 +379,10 @@ uvmexp_print(int (*pr)(const char *, ...
(*pr)(" freemin=%d, free-target=%d, inactive-target=%d, "
"wired-max=%d\n", uexp.freemin, uexp.freetarg, uexp.inactarg,
uexp.wiredmax);
- (*pr)(" faults=%d, traps=%d, intrs=%d, ctxswitch=%d fpuswitch=%d\n",
+ (*pr)(" faults=%u, traps=%u, intrs=%u, ctxswitch=%u fpuswitch=%d\n",
uexp.faults, uexp.traps, uexp.intrs, uexp.swtch,
uexp.fpswtch);
- (*pr)(" softint=%d, syscalls=%d, kmapent=%d\n",
+ (*pr)(" softint=%u, syscalls=%u, kmapent=%d\n",
uexp.softs, uexp.syscalls, uexp.kmapent);
(*pr)(" fault counts:\n");
Index: sys/uvm/uvmexp.h
===================================================================
RCS file: /cvs/src/sys/uvm/uvmexp.h,v
retrieving revision 1.9
diff -u -p -r1.9 uvmexp.h
--- sys/uvm/uvmexp.h 4 Mar 2021 09:00:03 -0000 1.9
+++ sys/uvm/uvmexp.h 28 Jun 2021 05:24:56 -0000
@@ -90,12 +90,12 @@ struct uvmexp {
int unused06; /* formerly nfreeanon */
/* stat counters */
- int faults; /* page fault count */
- int traps; /* trap count */
- int intrs; /* interrupt count */
- int swtch; /* context switch count */
- int softs; /* software interrupt count */
- int syscalls; /* system calls */
+ unsigned int faults; /* page fault count */
+ unsigned int traps; /* trap count */
+ unsigned int intrs; /* interrupt count */
+ unsigned int swtch; /* context switch count */
+ unsigned int softs; /* software interrupt count */
+ unsigned int syscalls; /* system calls */
int pageins; /* pagein operation count */
/* pageouts are in pdpageouts below */
int unused07; /* formerly obsolete_swapins */
Index: usr.bin/systat/uvm.c
===================================================================
RCS file: /cvs/src/usr.bin/systat/uvm.c,v
retrieving revision 1.5
diff -u -p -r1.5 uvm.c
--- usr.bin/systat/uvm.c 28 Jun 2019 13:35:04 -0000 1.5
+++ usr.bin/systat/uvm.c 28 Jun 2021 05:24:57 -0000
@@ -37,22 +37,23 @@ void print_uvm(void);
int read_uvm(void);
int select_uvm(void);
-void print_uvmexp_field(field_def *, field_def *, int *, int *, const char *);
+void print_uvmexp_field(field_def *, field_def *, unsigned int *,
+ unsigned int *, const char *);
void print_uvmexp_line(int);
struct uvmexp uvmexp;
struct uvmexp last_uvmexp;
struct uvmline {
- int *v1;
- int *ov1;
- char *n1;
- int *v2;
- int *ov2;
- char *n2;
- int *v3;
- int *ov3;
- char *n3;
+ unsigned int *v1;
+ unsigned int *ov1;
+ char *n1;
+ unsigned int *v2;
+ unsigned int *ov2;
+ char *n2;
+ unsigned int *v3;
+ unsigned int *ov3;
+ char *n3;
};
struct uvmline uvmline[] = {
@@ -214,8 +215,8 @@ read_uvm(void)
}
void
-print_uvmexp_field(field_def *fvalue, field_def *fname, int *new, int *old,
- const char *name)
+print_uvmexp_field(field_def *fvalue, field_def *fname, unsigned int *new,
+ unsigned int *old, const char *name)
{
char *uppername;
size_t len, i;