1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
|
*** kvm_read.c.orig Fri Jun 4 15:45:13 1999
--- kvm_read.c Fri Jun 4 15:49:13 1999
***************
*** 0 ****
--- 1,194 ----
+ /*
+ * This file obtains memory usage via FreeBSD's kvm library.
+ * It is a modified version of read_mem.c which is
+ * Copyright (c) 1999 Albert Dorofeev <Albert@mail.dma.be>
+ * use this in place of that file for FreeBSD systems.
+ *
+ * This software is distributed under GPL. For details see LICENSE file.
+ */
+
+
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <fcntl.h>
+ #include <unistd.h>
+
+ #include "state.h"
+
+ #include <err.h>
+ #include <kvm.h>
+ #include <nlist.h>
+ #include <sys/rlist.h>
+ #include <sys/conf.h>
+ #include <sys/vmmeter.h>
+ #include <sys/types.h>
+ #include <sys/sysctl.h>
+ #include <vm/vm_param.h>
+
+ extern struct asmem_state state;
+
+ kvm_t *kd;
+
+ #define SVAR(var) __STRING(var) /* to force expansion */
+ #define KGET(idx, var) \
+ KGET1(idx, &var, sizeof(var), SVAR(var))
+ #define KGET1(idx, p, s, msg) \
+ KGET2(nl[idx].n_value, p, s, msg)
+ #define KGET2(addr, p, s, msg) \
+ if (kvm_read(kd, (u_long)(addr), p, s) != s) \
+ warnx("cannot read %s: %s", msg, kvm_geterr(kd))
+
+ struct nlist nl[] = {
+ #define VM_SWAPLIST 0
+ { "_swaplist" },/* list of free swap areas */
+ #define VM_SWDEVT 1
+ { "_swdevt" }, /* list of swap devices and sizes */
+ #define VM_NSWAP 2
+ { "_nswap" }, /* size of largest swap device */
+ #define VM_NSWDEV 3
+ { "_nswdev" }, /* number of swap devices */
+ #define VM_DMMAX 4
+ { "_dmmax" }, /* maximum size of a swap block */
+ #define X_CNT 5
+ { "_cnt" },
+ #define X_BUFSPACE 6
+ { "_bufspace" }, /* K in buffer cache */
+ { "" }
+ };
+
+ int close_meminfo()
+ {
+ kvm_close(kd);
+ return 0;
+ }
+
+ int read_meminfo()
+ {
+
+ int nswap, nswdev, dmmax;
+ int i, avail, nfree, used, bufspace = 0;
+ struct swdevt *sw;
+ struct vmmeter sum;
+ long *perdev;
+ struct rlist head;
+ struct rlisthdr swaplist;
+ struct rlist *swapptr;
+ u_long ptr;
+
+ KGET(VM_NSWAP, nswap);
+ KGET(VM_NSWDEV, nswdev);
+ KGET(VM_DMMAX, dmmax);
+ KGET1(VM_SWAPLIST, &swaplist, sizeof swaplist, "swaplist");
+ if ((sw = (struct swdevt*)malloc(nswdev * sizeof(*sw))) == NULL ||
+ (perdev = (long *)malloc(nswdev * sizeof(*perdev))) == NULL)
+ errx(1, "malloc");
+ KGET1(VM_SWDEVT, &ptr, sizeof ptr, "swdevt");
+ KGET2(ptr, sw, nswdev * sizeof(*sw), "*swdevt");
+
+ /* Count up swap space. */
+ nfree = 0;
+ memset(perdev, 0, nswdev * sizeof(*perdev));
+ swapptr = swaplist.rlh_list;
+ while (swapptr) {
+ int top, bottom, next_block;
+
+ KGET2(swapptr, &head, sizeof(struct rlist), "swapptr");
+
+ top = head.rl_end;
+ bottom = head.rl_start;
+
+ nfree += top - bottom + 1;
+
+ /*
+ * Swap space is split up among the configured disks.
+ *
+ * For interleaved swap devices, the first dmmax blocks
+ * of swap space some from the first disk, the next dmmax
+ * blocks from the next, and so on up to nswap blocks.
+ *
+ * The list of free space joins adjacent free blocks,
+ * ignoring device boundries. If we want to keep track
+ * of this information per device, we'll just have to
+ * extract it ourselves.
+ */
+ while (top / dmmax != bottom / dmmax) {
+ next_block = ((bottom + dmmax) / dmmax);
+ perdev[(bottom / dmmax) % nswdev] +=
+ next_block * dmmax - bottom;
+ bottom = next_block * dmmax;
+ }
+ perdev[(bottom / dmmax) % nswdev] +=
+ top - bottom + 1;
+
+ swapptr = head.rl_next;
+ }
+
+ avail = 0;
+ for (i = 0; i < nswdev; i++) {
+ int xsize, xfree;
+
+ /*
+ * Don't report statistics for partitions which have not
+ * yet been activated via swapon(8).
+ */
+ if (!(sw[i].sw_flags & SW_FREED))
+ continue;
+
+ /* The first dmmax is never allocated to avoid trashing of
+ * disklabels
+ */
+ xsize = sw[i].sw_nblks - dmmax;
+ xfree = perdev[i];
+ used = xsize - xfree;
+ avail += xsize;
+ }
+
+ /*
+ * If only one partition has been set up via swapon(8), we don't
+ * need to bother with totals.
+ */
+ used = avail - nfree;
+ free(sw);
+ free(perdev);
+
+ state.fresh.swap_total = avail * 512;
+ state.fresh.swap_used = used * 512;
+ state.fresh.swap_free = (avail - used) * 512;
+
+ KGET(X_CNT, sum);
+ KGET(X_BUFSPACE, bufspace);
+
+ state.fresh.total = sum.v_page_size * sum.v_page_count;
+ state.fresh.used = sum.v_page_size * (sum.v_page_count - sum.v_free_count);
+ state.fresh.free = sum.v_page_size * sum.v_free_count;
+ state.fresh.shared = 0;
+ state.fresh.cached = sum.v_page_size * sum.v_cache_count;
+
+ state.fresh.buffers = bufspace;
+ return(0);
+
+ }
+
+ int open_meminfo()
+ {
+
+ if (kd == 0) {
+ kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, 0);
+ if (kd != NULL) {
+ if (kvm_nlist(kd, nl) < 0) {
+ errx(1, "kvm_nlist: %s", kvm_geterr(kd));
+ }
+
+ if (nl[0].n_type == 0) {
+ errx(1, "no namelist");
+ }
+ } else {
+ warnx("kvm not available");
+ return(-1);
+ }
+ }
+ return(0);
+ }
+
+
|