4 * cc -I/usr/src/sys bufqueues.c -o /usr/local/bin/bufqueues -lkvm
8 * Output buf(9) queues usages
10 * Copyright (c) 2015 The DragonFly Project. All rights reserved.
12 * This code is derived from software contributed to The DragonFly Project
13 * by Matthew Dillon <dillon@backplane.com>
14 * by Antonio Huete Jimenez <tuxillo@quantumachine.net>
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
20 * 1. Redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer.
22 * 2. Redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in
24 * the documentation and/or other materials provided with the
26 * 3. Neither the name of The DragonFly Project nor the names of its
27 * contributors may be used to endorse or promote products derived
28 * from this software without specific, prior written permission.
30 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
31 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
32 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
33 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
34 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
35 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
36 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
38 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
39 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
40 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 #define _KERNEL_STRUCTURES_
45 #include <sys/param.h>
49 #include <sys/queue.h>
68 TAILQ_HEAD(bqueues
, buf
);
74 BQUEUE_NONE
, /* not on any queue */
75 BQUEUE_LOCKED
, /* locked buffers */
76 BQUEUE_CLEAN
, /* non-B_DELWRI buffers */
77 BQUEUE_DIRTY
, /* B_DELWRI buffers */
78 BQUEUE_DIRTY_HW
, /* B_DELWRI buffers - heavy weight */
79 BQUEUE_EMPTYKVA
, /* empty buffer headers with KVA assignment */
80 BQUEUE_EMPTY
, /* empty buffer headers */
82 BUFFER_QUEUES
/* number of buffer queues */
87 struct bqueues bufqueues
[BUFFER_QUEUES
];
92 static int kkread(kvm_t
*kd
, u_long addr
, void *buf
, size_t nbytes
, int out
);
93 static void scan_queues(kvm_t
*kd
, int cpu
, struct bufpcpu
*bqp
);
94 static void loaddelay(struct timespec
*ts
, const char *arg
);
96 static const char *q2s(int queue
);
99 int qcounter
[BUFFER_QUEUES
];
105 main(int ac
, char **av
)
107 const char *corefile
= NULL
;
108 const char *sysfile
= NULL
;
109 struct bufpcpu bpcpu
;
110 struct timespec delay
= { 1, 0 };
117 while ((ch
= getopt(ac
, av
, "M:N:v")) != -1) {
129 fprintf(stderr
, "%s [-M core] [-N system]\n", av
[0]);
136 if ((kd
= kvm_open(sysfile
, corefile
, NULL
, O_RDONLY
, "kvm:")) == NULL
) {
140 if (kvm_nlist(kd
, Nl
) != 0) {
146 loaddelay(&delay
, av
[0]);
148 kkread(kd
, Nl
[1].n_value
, &ncpus
, sizeof(ncpus
), 1);
149 kkread(kd
, Nl
[2].n_value
, &nbuf
, sizeof(nbuf
), 1);
151 for (count
= 0; ; ++count
) {
152 for (cpu
= 0; cpu
< ncpus
; cpu
++) {
153 kkread(kd
, Nl
[0].n_value
+ cpu
* sizeof(struct bufpcpu
),
154 &bpcpu
, sizeof(struct bufpcpu
), 1);
155 scan_queues(kd
, cpu
, &bpcpu
);
158 if (count
&& !verboseopt
) {
159 if ((count
& 15) == 1)
160 printf(" NONE LOCKED CLEAN DIRTY "
161 "DIRTY_HW EMPTYKVA EMPTY OFF-QUEUE KVMFAIL\n");
162 printf("%6d %7d %6d %6d %9d %9d %6d %10d %7d\n",
163 qcounter
[0], qcounter
[1], qcounter
[2],
164 qcounter
[3], qcounter
[4], qcounter
[5],
165 qcounter
[6], (nbuf
- totalcount
), failcount
);
168 /* If in verbose mode only output detailed bufs info once */
171 nanosleep(&delay
, NULL
);
172 bzero(&qcounter
, sizeof(qcounter
));
179 static const char *q2s(int queue
)
190 case BQUEUE_DIRTY_HW
:
192 case BQUEUE_EMPTYKVA
:
202 scan_queues(kvm_t
*kd
, int cpu
, struct bufpcpu
*bqp
)
207 for (q
= 0; q
< BUFFER_QUEUES
; q
++) {
208 if (bqp
->bufqueues
[q
].tqh_first
== NULL
)
210 kkread(kd
, (u_long
)bqp
->bufqueues
[q
].tqh_first
, &b
, sizeof(b
), 1);
211 tmp
= bqp
->bufqueues
[q
].tqh_first
;
214 while (tmp
!= NULL
) {
216 printf("cpu=%d queue=%8s buf=%p", cpu
, q2s(q
), tmp
);
217 tmp
= b
.b_freelist
.tqe_next
;
218 if (kkread(kd
, (u_long
)tmp
, &b
, sizeof(b
), 0) == -1) {
226 totalcount
++; /* All scanned bufs */
232 * Convert a delay string (e.g. "0.1") into a timespec.
236 loaddelay(struct timespec
*ts
, const char *arg
)
240 d
= strtod(arg
, NULL
);
244 ts
->tv_nsec
= (int)(modf(d
, &d
) * 1000000000.0);
248 kkread(kvm_t
*kd
, u_long addr
, void *buf
, size_t nbytes
, int out
)
250 if (kvm_read(kd
, addr
, buf
, nbytes
) != nbytes
) {