1 /* MIB service - vm.c - implementation of the CTL_VM subtree */
2
3 #include "mib.h"
4
5 #include <sys/resource.h>
6 #include <uvm/uvm_extern.h>
7
8 /*
9 * Implementation of CTL_VM VM_LOADAVG.
10 */
11 static ssize_t
mib_vm_loadavg(struct mib_call * call __unused,struct mib_node * node __unused,struct mib_oldp * oldp,struct mib_newp * newp __unused)12 mib_vm_loadavg(struct mib_call * call __unused,
13 struct mib_node * node __unused, struct mib_oldp * oldp,
14 struct mib_newp * newp __unused)
15 {
16 struct loadavg loadavg;
17 struct loadinfo loadinfo;
18 unsigned long proc_load;
19 u32_t ticks_per_slot, ticks;
20 unsigned int p;
21 int unfilled_ticks;
22 int h, slots, latest, slot;
23 int minutes[3] = { 1, 5, 15 };
24
25 assert(__arraycount(loadavg.ldavg) == __arraycount(minutes));
26
27 if (sys_getloadinfo(&loadinfo) != OK)
28 return EINVAL;
29
30 memset(&loadavg, 0, sizeof(loadavg));
31
32 /*
33 * The following code is inherited from the old MINIX libc.
34 */
35
36 /* How many ticks are missing from the newest-filled slot? */
37 ticks_per_slot = _LOAD_UNIT_SECS * sys_hz();
38 unfilled_ticks =
39 ticks_per_slot - (loadinfo.last_clock % ticks_per_slot);
40
41 for (p = 0; p < __arraycount(loadavg.ldavg); p++) {
42 latest = loadinfo.proc_last_slot;
43 slots = minutes[p] * 60 / _LOAD_UNIT_SECS;
44 proc_load = 0;
45
46 /*
47 * Add up the total number of process ticks for this number
48 * of minutes (minutes[p]). Start with the newest slot, which
49 * is latest, and count back for the number of slots that
50 * correspond to the right number of minutes. Take wraparound
51 * into account by calculating the index modulo _LOAD_HISTORY,
52 * which is the number of slots of history kept.
53 */
54 for (h = 0; h < slots; h++) {
55 slot = (latest - h + _LOAD_HISTORY) % _LOAD_HISTORY;
56 proc_load += loadinfo.proc_load_history[slot];
57 }
58
59 /*
60 * The load average over this number of minutes is the number
61 * of process-ticks divided by the number of ticks, not
62 * counting the number of ticks the last slot hasn't been
63 * around yet.
64 */
65 ticks = slots * ticks_per_slot - unfilled_ticks;
66
67 loadavg.ldavg[p] = 100UL * proc_load / ticks;
68 }
69
70 loadavg.fscale = 100L;
71
72 return mib_copyout(oldp, 0, &loadavg, sizeof(loadavg));
73 }
74
75 /*
76 * Implementation of CTL_VM VM_UVMEXP2.
77 */
78 static ssize_t
mib_vm_uvmexp2(struct mib_call * call __unused,struct mib_node * node __unused,struct mib_oldp * oldp,struct mib_newp * newp __unused)79 mib_vm_uvmexp2(struct mib_call * call __unused,
80 struct mib_node * node __unused, struct mib_oldp * oldp,
81 struct mib_newp * newp __unused)
82 {
83 struct vm_stats_info vsi;
84 struct uvmexp_sysctl ues;
85 unsigned int shift;
86
87 if (vm_info_stats(&vsi) != OK)
88 return EINVAL;
89
90 memset(&ues, 0, sizeof(ues));
91
92 /*
93 * TODO: by far most of the structure is not filled correctly yet,
94 * since the MINIX3 system does not provide much of the information
95 * exposed by NetBSD. This will gradually have to be filled in.
96 * For now, we provide just some basic information used by top(1).
97 */
98 ues.pagesize = vsi.vsi_pagesize;
99 ues.pagemask = vsi.vsi_pagesize - 1;
100 for (shift = 0; shift < CHAR_BIT * sizeof(void *); shift++)
101 if ((1U << shift) == vsi.vsi_pagesize)
102 break;
103 if (shift < CHAR_BIT * sizeof(void *))
104 ues.pageshift = shift;
105 ues.npages = vsi.vsi_total;
106 ues.free = vsi.vsi_free;
107 ues.filepages = vsi.vsi_cached;
108 /*
109 * We use one of the structure's unused fields to expose information
110 * not exposed by NetBSD, namely the largest area of physically
111 * contiguous memory. If NetBSD repurposes this field, we have to find
112 * another home for it (or expose it through a separate node or so).
113 */
114 ues.unused1 = vsi.vsi_largest;
115
116 return mib_copyout(oldp, 0, &ues, sizeof(ues));
117 }
118
119 /* The CTL_VM nodes. */
120 static struct mib_node mib_vm_table[] = {
121 /* 1*/ /* VM_METER: not yet supported */
122 /* 2*/ [VM_LOADAVG] = MIB_FUNC(_P | _RO | CTLTYPE_STRUCT,
123 sizeof(struct loadavg), mib_vm_loadavg,
124 "loadavg", "System load average history"),
125 /* 3*/ /* VM_UVMEXP: not yet supported */
126 /* 4*/ /* VM_NKMEMPAGES: not yet supported */
127 /* 5*/ [VM_UVMEXP2] = MIB_FUNC(_P | _RO | CTLTYPE_STRUCT,
128 sizeof(struct uvmexp_sysctl),
129 mib_vm_uvmexp2, "uvmexp2",
130 "Detailed system-wide virtual memory "
131 "statistics (MI)"),
132 /* 6*/ /* VM_ANONMIN: not yet supported */
133 /* 7*/ /* VM_EXECMIN: not yet supported */
134 /* 8*/ /* VM_FILEMIN: not yet supported */
135 /* 9*/ [VM_MAXSLP] = MIB_INT(_P | _RO, MAXSLP, "maxslp",
136 "Maximum process sleep time before being "
137 "swapped"),
138 /*10*/ [VM_USPACE] = MIB_INT(_P | _RO, 0, "uspace", "Number of "
139 "bytes allocated for a kernel stack"),
140 /* MINIX3 processes don't have k-stacks */
141 /*11*/ /* VM_ANONMAX: not yet supported */
142 /*12*/ /* VM_EXECMAX: not yet supported */
143 /*13*/ /* VM_FILEMAX: not yet supported */
144 };
145
146 /*
147 * Initialize the CTL_VM subtree.
148 */
149 void
mib_vm_init(struct mib_node * node)150 mib_vm_init(struct mib_node * node)
151 {
152
153 MIB_INIT_ENODE(node, mib_vm_table);
154 }
155