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 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 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 150 mib_vm_init(struct mib_node * node) 151 { 152 153 MIB_INIT_ENODE(node, mib_vm_table); 154 } 155