xref: /titanic_53/usr/src/cmd/arcwatch/arcwatch.c (revision ce0d9371c4da921f289a8bc7fd846d3bf1b8cca7)
1*ce0d9371SArne Jansen #include <stdio.h>
2*ce0d9371SArne Jansen #include <stdlib.h>
3*ce0d9371SArne Jansen #include <unistd.h>
4*ce0d9371SArne Jansen #include <sys/types.h>
5*ce0d9371SArne Jansen #include <sys/stat.h>
6*ce0d9371SArne Jansen #include <sys/wait.h>
7*ce0d9371SArne Jansen #include <fcntl.h>
8*ce0d9371SArne Jansen #include <sys/fs/zfs.h>
9*ce0d9371SArne Jansen #include <sys/zfs_ioctl.h>
10*ce0d9371SArne Jansen #include <string.h>
11*ce0d9371SArne Jansen #include <errno.h>
12*ce0d9371SArne Jansen #include <dtrace.h>
13*ce0d9371SArne Jansen #include <assert.h>
14*ce0d9371SArne Jansen #include <sys/avl.h>
15*ce0d9371SArne Jansen #include <sys/arc.h>
16*ce0d9371SArne Jansen #include <stddef.h>
17*ce0d9371SArne Jansen #include <pthread.h>
18*ce0d9371SArne Jansen 
19*ce0d9371SArne Jansen #define ARCWATCH_READ_MAGIC "awrd"
20*ce0d9371SArne Jansen #define ARCWATCH_READ_VERSION 1
21*ce0d9371SArne Jansen 
22*ce0d9371SArne Jansen typedef struct arc_read_hdr {
23*ce0d9371SArne Jansen 	char		arh_magic[4];
24*ce0d9371SArne Jansen 	uint32_t	arh_version;
25*ce0d9371SArne Jansen } arc_read_hdr_t;
26*ce0d9371SArne Jansen 
27*ce0d9371SArne Jansen typedef struct arc_read {
28*ce0d9371SArne Jansen 	uint64_t	ar_objset;
29*ce0d9371SArne Jansen 	uint64_t	ar_object;
30*ce0d9371SArne Jansen 	uint64_t	ar_level;
31*ce0d9371SArne Jansen 	uint64_t	ar_blkid;
32*ce0d9371SArne Jansen 	uint64_t	ar_size;
33*ce0d9371SArne Jansen 	uint64_t	ar_type;
34*ce0d9371SArne Jansen 	uint64_t	ar_dva0;
35*ce0d9371SArne Jansen 	uint64_t	ar_dva1;
36*ce0d9371SArne Jansen 	uint64_t	ar_birth;
37*ce0d9371SArne Jansen 	uint64_t	ar_spa;
38*ce0d9371SArne Jansen } arc_read_t;
39*ce0d9371SArne Jansen 
40*ce0d9371SArne Jansen #define ARNS_IN_L1_CACHE	1
41*ce0d9371SArne Jansen #define ARNS_IN_L2_CACHE	2
42*ce0d9371SArne Jansen typedef struct arc_read_node {
43*ce0d9371SArne Jansen 	arc_read_t	arn_ar;
44*ce0d9371SArne Jansen 	avl_node_t	arn_node;
45*ce0d9371SArne Jansen 	uint64_t	arn_color;
46*ce0d9371SArne Jansen 	uint64_t	arn_state;
47*ce0d9371SArne Jansen 	uint64_t	arn_flags;
48*ce0d9371SArne Jansen } arc_read_node_t;
49*ce0d9371SArne Jansen 
50*ce0d9371SArne Jansen #define ARCWATCH_CONTENT_MAGIC "awct"
51*ce0d9371SArne Jansen #define ARCWATCH_CONTENT_VERSION 1
52*ce0d9371SArne Jansen 
53*ce0d9371SArne Jansen typedef struct arc_content_hdr {
54*ce0d9371SArne Jansen 	char		ach_magic[4];
55*ce0d9371SArne Jansen 	uint32_t	ach_version;
56*ce0d9371SArne Jansen 	uint64_t	ach_buckets;
57*ce0d9371SArne Jansen 	uint64_t	ach_buf_locks;
58*ce0d9371SArne Jansen } arc_content_hdr_t;
59*ce0d9371SArne Jansen 
60*ce0d9371SArne Jansen static const char *
61*ce0d9371SArne Jansen state2str(arc_info_state_t state)
62*ce0d9371SArne Jansen {
63*ce0d9371SArne Jansen 	switch (state) {
64*ce0d9371SArne Jansen 	case AIS_ANON:		return "anon";
65*ce0d9371SArne Jansen 	case AIS_MRU:		return "mru";
66*ce0d9371SArne Jansen 	case AIS_MRU_GHOST:	return "mru_ghost";
67*ce0d9371SArne Jansen 	case AIS_MFU:		return "mfu";
68*ce0d9371SArne Jansen 	case AIS_MFU_GHOST:	return "mfu_ghost";
69*ce0d9371SArne Jansen 	case AIS_L2C_ONLY:	return "l2c_only";
70*ce0d9371SArne Jansen 	case AIS_NO_L1HDR:	return "no_l1hdr";
71*ce0d9371SArne Jansen 	default:
72*ce0d9371SArne Jansen 	case AIS_UNKNOWN:	return "unknown";
73*ce0d9371SArne Jansen 	}
74*ce0d9371SArne Jansen }
75*ce0d9371SArne Jansen 
76*ce0d9371SArne Jansen static int g_verbose = 0;
77*ce0d9371SArne Jansen 
78*ce0d9371SArne Jansen static char *d_prog =
79*ce0d9371SArne Jansen 	"dtrace:::BEGIN\n"
80*ce0d9371SArne Jansen 	"{\n"
81*ce0d9371SArne Jansen 	"        trackedpid[pid] = 0;\n"
82*ce0d9371SArne Jansen 	"        self->child = 0;\n"
83*ce0d9371SArne Jansen 	"        OPT_follow = 1;\n"
84*ce0d9371SArne Jansen 	"}\n"
85*ce0d9371SArne Jansen 	"syscall::fork*:entry\n"
86*ce0d9371SArne Jansen 	"/OPT_follow && (pid == $target || self->child)/\n"
87*ce0d9371SArne Jansen 	"{\n"
88*ce0d9371SArne Jansen 	"        trackedpid[pid] = 1;\n"
89*ce0d9371SArne Jansen 	"}\n"
90*ce0d9371SArne Jansen 	"syscall::fork*:return\n"
91*ce0d9371SArne Jansen 	"/OPT_follow && trackedpid[ppid]/\n"
92*ce0d9371SArne Jansen 	"{\n"
93*ce0d9371SArne Jansen 	"        self->child = 1;\n"
94*ce0d9371SArne Jansen 	"}\n"
95*ce0d9371SArne Jansen 	"fbt::dbuf_hold_impl:entry\n"
96*ce0d9371SArne Jansen 	"/pid == $target || self->child/\n"
97*ce0d9371SArne Jansen 	"{\n"
98*ce0d9371SArne Jansen 	"        self->dbp = args[6];\n"
99*ce0d9371SArne Jansen 	"        self->type = args[0]->dn_type;\n"
100*ce0d9371SArne Jansen 	"}\n"
101*ce0d9371SArne Jansen 	"fbt::dbuf_hold_impl:return\n"
102*ce0d9371SArne Jansen 	"/self->dbp && (*self->dbp)->db_state == 4/\n"
103*ce0d9371SArne Jansen 	"{\n"
104*ce0d9371SArne Jansen 	"        this->db = *self->dbp;\n"
105*ce0d9371SArne Jansen 	"        this->os = this->db->db_objset;\n"
106*ce0d9371SArne Jansen 	"        this->hdr = this->db->db_buf ? this->db->db_buf->b_hdr : 0;\n"
107*ce0d9371SArne Jansen 	"        trace(this->os->os_dsl_dataset ?\n"
108*ce0d9371SArne Jansen 	"              this->os->os_dsl_dataset->ds_object : 0);\n"
109*ce0d9371SArne Jansen 	"        trace(this->db->db.db_object);\n"
110*ce0d9371SArne Jansen 	"        trace(this->db->db_level);\n"
111*ce0d9371SArne Jansen 	"        trace(this->db->db_blkid);\n"
112*ce0d9371SArne Jansen 	"        trace(this->db->db.db_size);\n"
113*ce0d9371SArne Jansen 	"        trace(self->type);\n"
114*ce0d9371SArne Jansen 	"        trace(this->hdr ? this->hdr->b_dva.dva_word[0] : 0);\n"
115*ce0d9371SArne Jansen 	"        trace(this->hdr ? this->hdr->b_dva.dva_word[1] : 0);\n"
116*ce0d9371SArne Jansen 	"        trace(this->hdr ? this->hdr->b_birth : 0);\n"
117*ce0d9371SArne Jansen 	"        trace(this->hdr ? this->hdr->b_spa : 0);\n"
118*ce0d9371SArne Jansen 	"        self->dbp = 0;\n"
119*ce0d9371SArne Jansen 	"        self->type = 0;\n"
120*ce0d9371SArne Jansen 	"}\n";
121*ce0d9371SArne Jansen 
122*ce0d9371SArne Jansen static int
123*ce0d9371SArne Jansen awr_cmp(const void *x, const void *y)
124*ce0d9371SArne Jansen {
125*ce0d9371SArne Jansen 	const arc_read_node_t *a = x;
126*ce0d9371SArne Jansen 	const arc_read_node_t *b = y;
127*ce0d9371SArne Jansen 
128*ce0d9371SArne Jansen 	if (a->arn_ar.ar_spa < b->arn_ar.ar_spa)
129*ce0d9371SArne Jansen 		return -1;
130*ce0d9371SArne Jansen 	if (a->arn_ar.ar_spa > b->arn_ar.ar_spa)
131*ce0d9371SArne Jansen 		return 1;
132*ce0d9371SArne Jansen 	if (a->arn_ar.ar_dva0 < b->arn_ar.ar_dva0)
133*ce0d9371SArne Jansen 		return -1;
134*ce0d9371SArne Jansen 	if (a->arn_ar.ar_dva0 > b->arn_ar.ar_dva0)
135*ce0d9371SArne Jansen 		return 1;
136*ce0d9371SArne Jansen 	if (a->arn_ar.ar_dva1 < b->arn_ar.ar_dva1)
137*ce0d9371SArne Jansen 		return -1;
138*ce0d9371SArne Jansen 	if (a->arn_ar.ar_dva1 > b->arn_ar.ar_dva1)
139*ce0d9371SArne Jansen 		return 1;
140*ce0d9371SArne Jansen 	if (a->arn_ar.ar_birth < b->arn_ar.ar_birth)
141*ce0d9371SArne Jansen 		return -1;
142*ce0d9371SArne Jansen 	if (a->arn_ar.ar_birth > b->arn_ar.ar_birth)
143*ce0d9371SArne Jansen 		return 1;
144*ce0d9371SArne Jansen 	return 0;
145*ce0d9371SArne Jansen }
146*ce0d9371SArne Jansen 
147*ce0d9371SArne Jansen static int
148*ce0d9371SArne Jansen drophandler(const dtrace_dropdata_t *data, void *arg)
149*ce0d9371SArne Jansen {
150*ce0d9371SArne Jansen 	fprintf(stderr, "type %d drops %lld\n", data->dtdda_kind, data->dtdda_drops);
151*ce0d9371SArne Jansen 	fprintf(stderr, "dtrace drops encountered. Try increasing buffers.\n");
152*ce0d9371SArne Jansen 	exit(1);
153*ce0d9371SArne Jansen }
154*ce0d9371SArne Jansen 
155*ce0d9371SArne Jansen static void
156*ce0d9371SArne Jansen prochandler(struct ps_prochandle *P, const char *msg, void *arg)
157*ce0d9371SArne Jansen {
158*ce0d9371SArne Jansen 	int *proc_done = arg;
159*ce0d9371SArne Jansen 
160*ce0d9371SArne Jansen 	*proc_done = 1;
161*ce0d9371SArne Jansen }
162*ce0d9371SArne Jansen 
163*ce0d9371SArne Jansen static uint64_t
164*ce0d9371SArne Jansen get_val(caddr_t base, dtrace_recdesc_t *rec)
165*ce0d9371SArne Jansen {
166*ce0d9371SArne Jansen 	uint64_t val = 0;
167*ce0d9371SArne Jansen 
168*ce0d9371SArne Jansen 	assert(rec->dtrd_action == DTRACEACT_DIFEXPR);
169*ce0d9371SArne Jansen 	assert(rec->dtrd_size > 0);
170*ce0d9371SArne Jansen 	assert(rec->dtrd_size <= 8);
171*ce0d9371SArne Jansen 
172*ce0d9371SArne Jansen 	memcpy(&val, base + rec->dtrd_offset, rec->dtrd_size);
173*ce0d9371SArne Jansen 
174*ce0d9371SArne Jansen 	return val;
175*ce0d9371SArne Jansen }
176*ce0d9371SArne Jansen 
177*ce0d9371SArne Jansen typedef struct trace_args {
178*ce0d9371SArne Jansen 	int		ofd;
179*ce0d9371SArne Jansen 	avl_tree_t	*awr;
180*ce0d9371SArne Jansen 	pthread_mutex_t	mtx;
181*ce0d9371SArne Jansen 	int		ptr;
182*ce0d9371SArne Jansen 	char		buf[16384];
183*ce0d9371SArne Jansen } trace_args_t;
184*ce0d9371SArne Jansen 
185*ce0d9371SArne Jansen static int
186*ce0d9371SArne Jansen process_trace(const dtrace_probedata_t *data, void *arg)
187*ce0d9371SArne Jansen {
188*ce0d9371SArne Jansen 	dtrace_eprobedesc_t *edesc = data->dtpda_edesc;
189*ce0d9371SArne Jansen 	caddr_t base = data->dtpda_data;
190*ce0d9371SArne Jansen 	dtrace_recdesc_t *rec = edesc->dtepd_rec;
191*ce0d9371SArne Jansen 	trace_args_t *ta = arg;
192*ce0d9371SArne Jansen 	arc_read_t ar;
193*ce0d9371SArne Jansen 	int ret;
194*ce0d9371SArne Jansen 
195*ce0d9371SArne Jansen 	assert(edesc->dtepd_nrecs == 15);
196*ce0d9371SArne Jansen 
197*ce0d9371SArne Jansen 	ar.ar_objset = get_val(base, rec + 3);
198*ce0d9371SArne Jansen 	ar.ar_object = get_val(base, rec + 4);
199*ce0d9371SArne Jansen 	ar.ar_level = get_val(base, rec + 5);
200*ce0d9371SArne Jansen 	ar.ar_blkid = get_val(base, rec + 6);
201*ce0d9371SArne Jansen 	ar.ar_size = get_val(base, rec + 7);
202*ce0d9371SArne Jansen 	ar.ar_type = get_val(base, rec + 8);
203*ce0d9371SArne Jansen 	ar.ar_dva0 = get_val(base, rec + 9);
204*ce0d9371SArne Jansen 	ar.ar_dva1 = get_val(base, rec + 10);
205*ce0d9371SArne Jansen 	ar.ar_birth = get_val(base, rec + 11);
206*ce0d9371SArne Jansen 	ar.ar_spa = get_val(base, rec + 12);
207*ce0d9371SArne Jansen 
208*ce0d9371SArne Jansen 	if (ta->ofd != -1) {
209*ce0d9371SArne Jansen 		pthread_mutex_lock(&ta->mtx);
210*ce0d9371SArne Jansen 		if (ta->ptr + sizeof(ar) > sizeof(ta->buf)) {
211*ce0d9371SArne Jansen 			ret = write(ta->ofd, ta->buf, ta->ptr);
212*ce0d9371SArne Jansen 			if (ret == -1) {
213*ce0d9371SArne Jansen 				fprintf(stderr,
214*ce0d9371SArne Jansen 					"cannot write to output file: %s\n",
215*ce0d9371SArne Jansen 					strerror(errno));
216*ce0d9371SArne Jansen 				exit(1);
217*ce0d9371SArne Jansen 			}
218*ce0d9371SArne Jansen 			ta->ptr = 0;
219*ce0d9371SArne Jansen 		}
220*ce0d9371SArne Jansen 		memcpy(ta->buf + ta->ptr, &ar, sizeof(ar));
221*ce0d9371SArne Jansen 		ta->ptr += sizeof(ar);
222*ce0d9371SArne Jansen 		pthread_mutex_unlock(&ta->mtx);
223*ce0d9371SArne Jansen 	}
224*ce0d9371SArne Jansen 
225*ce0d9371SArne Jansen 	if (ta->awr) {
226*ce0d9371SArne Jansen 		arc_read_node_t *arn;
227*ce0d9371SArne Jansen 
228*ce0d9371SArne Jansen 		arn = calloc(sizeof(*arn), 1);
229*ce0d9371SArne Jansen 		assert(arn);
230*ce0d9371SArne Jansen 		arn->arn_ar = ar;
231*ce0d9371SArne Jansen 		pthread_mutex_lock(&ta->mtx);
232*ce0d9371SArne Jansen 		if (avl_find(ta->awr, arn, NULL) == NULL)
233*ce0d9371SArne Jansen 			avl_add(ta->awr, arn);
234*ce0d9371SArne Jansen 		pthread_mutex_unlock(&ta->mtx);
235*ce0d9371SArne Jansen 	}
236*ce0d9371SArne Jansen 
237*ce0d9371SArne Jansen 	if (g_verbose) {
238*ce0d9371SArne Jansen 		printf("spa %llx objset %lld object %lld level %lld blkid "
239*ce0d9371SArne Jansen 		    "%lld size %lld type %lld dva %16x:%16x birth %lld\n",
240*ce0d9371SArne Jansen 		    ar.ar_spa, ar.ar_objset, ar.ar_object, ar.ar_level,
241*ce0d9371SArne Jansen 		    ar.ar_blkid, ar.ar_size, ar.ar_type,
242*ce0d9371SArne Jansen 		    ar.ar_dva0, ar.ar_dva1, ar.ar_birth);
243*ce0d9371SArne Jansen 	}
244*ce0d9371SArne Jansen 
245*ce0d9371SArne Jansen 	return (DTRACE_CONSUME_NEXT);
246*ce0d9371SArne Jansen }
247*ce0d9371SArne Jansen 
248*ce0d9371SArne Jansen static void
249*ce0d9371SArne Jansen d_fatal(dtrace_hdl_t *dtp, char *msg)
250*ce0d9371SArne Jansen {
251*ce0d9371SArne Jansen 	fprintf(stderr, "%s: %s\n", msg, dtrace_errmsg(dtp, dtrace_errno(dtp)));
252*ce0d9371SArne Jansen 	exit(1);
253*ce0d9371SArne Jansen }
254*ce0d9371SArne Jansen 
255*ce0d9371SArne Jansen static int
256*ce0d9371SArne Jansen run_dtrace(char *bufsize, char *out_fn, avl_tree_t *awr, int argc, char **argv)
257*ce0d9371SArne Jansen {
258*ce0d9371SArne Jansen 	dtrace_prog_t *dp;
259*ce0d9371SArne Jansen 	dtrace_hdl_t *dtp;
260*ce0d9371SArne Jansen 	dtrace_proginfo_t info;
261*ce0d9371SArne Jansen 	struct ps_prochandle *p;
262*ce0d9371SArne Jansen 	int err;
263*ce0d9371SArne Jansen 	int proc_done = 0;
264*ce0d9371SArne Jansen 	int done = 0;
265*ce0d9371SArne Jansen 	int ofd = -1;
266*ce0d9371SArne Jansen 	arc_read_hdr_t arh = { 0 };
267*ce0d9371SArne Jansen 	trace_args_t ta = { 0 };
268*ce0d9371SArne Jansen 
269*ce0d9371SArne Jansen 	ta.ofd = -1;
270*ce0d9371SArne Jansen 	ta.awr = awr;
271*ce0d9371SArne Jansen 	pthread_mutex_init(&ta.mtx, NULL);
272*ce0d9371SArne Jansen 
273*ce0d9371SArne Jansen 	if (out_fn) {
274*ce0d9371SArne Jansen 		ofd = open(out_fn, O_CREAT | O_TRUNC | O_WRONLY, 0644);
275*ce0d9371SArne Jansen 		if (ofd == -1) {
276*ce0d9371SArne Jansen 			printf("cannot open output file %s: %s\n",
277*ce0d9371SArne Jansen 			    out_fn, strerror(errno));
278*ce0d9371SArne Jansen 			exit(1);
279*ce0d9371SArne Jansen 		}
280*ce0d9371SArne Jansen 		memcpy(arh.arh_magic, ARCWATCH_READ_MAGIC,
281*ce0d9371SArne Jansen 		    sizeof(arh.arh_magic));
282*ce0d9371SArne Jansen 		arh.arh_version = ARCWATCH_READ_VERSION;
283*ce0d9371SArne Jansen 		err = write(ofd, &arh, sizeof(arh));
284*ce0d9371SArne Jansen 		if (err == -1) {
285*ce0d9371SArne Jansen 			printf("cannot write to output file: %s\n",
286*ce0d9371SArne Jansen 			    strerror(errno));
287*ce0d9371SArne Jansen 			exit(1);
288*ce0d9371SArne Jansen 		}
289*ce0d9371SArne Jansen 		ta.ofd = ofd;
290*ce0d9371SArne Jansen 	}
291*ce0d9371SArne Jansen 
292*ce0d9371SArne Jansen 	dtp = dtrace_open(DTRACE_VERSION, 0, &err);
293*ce0d9371SArne Jansen 	if (dtp == NULL) {
294*ce0d9371SArne Jansen 		printf("cannot open dtrace library: %s\n",
295*ce0d9371SArne Jansen 		    dtrace_errmsg(NULL, err));
296*ce0d9371SArne Jansen 		exit(1);
297*ce0d9371SArne Jansen 	}
298*ce0d9371SArne Jansen 
299*ce0d9371SArne Jansen 	if (dtrace_handle_drop(dtp, &drophandler, NULL) == -1)
300*ce0d9371SArne Jansen 		d_fatal(dtp, "couldn't establish drop handler");
301*ce0d9371SArne Jansen 
302*ce0d9371SArne Jansen 	if (dtrace_handle_proc(dtp, &prochandler, &proc_done) == -1)
303*ce0d9371SArne Jansen 		d_fatal(dtp, "failed to establish proc handler");
304*ce0d9371SArne Jansen 
305*ce0d9371SArne Jansen 	if (dtrace_setopt(dtp, "bufsize", bufsize) == -1)
306*ce0d9371SArne Jansen 		d_fatal(dtp, "failed to set bufsize");
307*ce0d9371SArne Jansen 
308*ce0d9371SArne Jansen 	/* XXX TODO understand dynvar drops */
309*ce0d9371SArne Jansen 	if (dtrace_setopt(dtp, "dynvarsize", "4m") == -1)
310*ce0d9371SArne Jansen 		d_fatal(dtp, "failed to set dynvarsize");
311*ce0d9371SArne Jansen 
312*ce0d9371SArne Jansen 	if (dtrace_setopt(dtp, "temporal", "no") == -1)
313*ce0d9371SArne Jansen 		d_fatal(dtp, "failed to set temporal");
314*ce0d9371SArne Jansen 
315*ce0d9371SArne Jansen 	if (dtrace_setopt(dtp, "switchrate", "100hz") == -1)
316*ce0d9371SArne Jansen 		d_fatal(dtp, "failed to set switchrate");
317*ce0d9371SArne Jansen 
318*ce0d9371SArne Jansen 	if (dtrace_setopt(dtp, "cleanrate", "100hz") == -1)
319*ce0d9371SArne Jansen 		d_fatal(dtp, "failed to set cleanrate");
320*ce0d9371SArne Jansen 
321*ce0d9371SArne Jansen 	p = dtrace_proc_create(dtp, argv[0], &argv[0]);
322*ce0d9371SArne Jansen 	if (p == NULL)
323*ce0d9371SArne Jansen 		d_fatal(dtp, "creating process failed");
324*ce0d9371SArne Jansen 
325*ce0d9371SArne Jansen 	dp = dtrace_program_strcompile(dtp, d_prog, DTRACE_PROBESPEC_NAME, 0,
326*ce0d9371SArne Jansen 	    0, NULL);
327*ce0d9371SArne Jansen 	if (dp == NULL)
328*ce0d9371SArne Jansen 		d_fatal(dtp, "failed to compile program");
329*ce0d9371SArne Jansen 
330*ce0d9371SArne Jansen 	if (dtrace_program_exec(dtp, dp, &info) == -1)
331*ce0d9371SArne Jansen 		d_fatal(dtp, "failed to enable probes");
332*ce0d9371SArne Jansen 
333*ce0d9371SArne Jansen 	if (dtrace_go(dtp))
334*ce0d9371SArne Jansen 		d_fatal(dtp, "couldn't start tracing");
335*ce0d9371SArne Jansen 
336*ce0d9371SArne Jansen 	(void) dtrace_proc_continue(dtp, p);
337*ce0d9371SArne Jansen 
338*ce0d9371SArne Jansen 	do {
339*ce0d9371SArne Jansen 		dtrace_sleep(dtp);
340*ce0d9371SArne Jansen 
341*ce0d9371SArne Jansen 		if (proc_done) {
342*ce0d9371SArne Jansen 			done = 1;
343*ce0d9371SArne Jansen 			(void) dtrace_stop(dtp);
344*ce0d9371SArne Jansen 		}
345*ce0d9371SArne Jansen 
346*ce0d9371SArne Jansen 		err = dtrace_work(dtp, stdout, process_trace, NULL, &ta);
347*ce0d9371SArne Jansen 		if (err == DTRACE_WORKSTATUS_DONE)
348*ce0d9371SArne Jansen 			done = 1;
349*ce0d9371SArne Jansen 	} while (!done);
350*ce0d9371SArne Jansen 
351*ce0d9371SArne Jansen 	if (ta.ptr > 0) {
352*ce0d9371SArne Jansen 		err = write(ta.ofd, ta.buf, ta.ptr);
353*ce0d9371SArne Jansen 		if (err == -1) {
354*ce0d9371SArne Jansen 			fprintf(stderr,
355*ce0d9371SArne Jansen 				"cannot write to output file: %s\n",
356*ce0d9371SArne Jansen 				strerror(errno));
357*ce0d9371SArne Jansen 			exit(1);
358*ce0d9371SArne Jansen 		}
359*ce0d9371SArne Jansen 	}
360*ce0d9371SArne Jansen 	(void) dtrace_close(dtp);
361*ce0d9371SArne Jansen 	if (ofd != -1)
362*ce0d9371SArne Jansen 		close(ofd);
363*ce0d9371SArne Jansen 
364*ce0d9371SArne Jansen 	return (0);
365*ce0d9371SArne Jansen }
366*ce0d9371SArne Jansen 
367*ce0d9371SArne Jansen static void
368*ce0d9371SArne Jansen read_awr(avl_tree_t *awr, char *in_fn)
369*ce0d9371SArne Jansen {
370*ce0d9371SArne Jansen 	int fd;
371*ce0d9371SArne Jansen 	int ret;
372*ce0d9371SArne Jansen 	arc_read_hdr_t arh;
373*ce0d9371SArne Jansen 	char buf[1000 * sizeof(arc_read_t)];
374*ce0d9371SArne Jansen 	int blen = 0;
375*ce0d9371SArne Jansen 	int ptr = 0;
376*ce0d9371SArne Jansen 
377*ce0d9371SArne Jansen 	fd = open(in_fn, O_RDONLY);
378*ce0d9371SArne Jansen 	if (fd == -1) {
379*ce0d9371SArne Jansen 		fprintf(stderr, "failed to open input: %s\n",
380*ce0d9371SArne Jansen 			strerror(errno));
381*ce0d9371SArne Jansen 		exit(1);
382*ce0d9371SArne Jansen 	}
383*ce0d9371SArne Jansen 	ret = read(fd, &arh, sizeof(arh));
384*ce0d9371SArne Jansen 	if (ret == -1) {
385*ce0d9371SArne Jansen 		fprintf(stderr, "failed to read input: %s\n",
386*ce0d9371SArne Jansen 			strerror(errno));
387*ce0d9371SArne Jansen 		exit(1);
388*ce0d9371SArne Jansen 	}
389*ce0d9371SArne Jansen 	if (ret != sizeof(arh)) {
390*ce0d9371SArne Jansen 		fprintf(stderr, "failed to read input: truncated file\n");
391*ce0d9371SArne Jansen 		exit(1);
392*ce0d9371SArne Jansen 	}
393*ce0d9371SArne Jansen 	if (memcmp(arh.arh_magic, ARCWATCH_READ_MAGIC, 4) != 0) {
394*ce0d9371SArne Jansen 		fprintf(stderr, "failed to read input: bad file magic\n");
395*ce0d9371SArne Jansen 		exit(1);
396*ce0d9371SArne Jansen 	}
397*ce0d9371SArne Jansen 	if (arh.arh_version != ARCWATCH_READ_VERSION) {
398*ce0d9371SArne Jansen 		fprintf(stderr, "failed to read input: bad file version\n");
399*ce0d9371SArne Jansen 		exit(1);
400*ce0d9371SArne Jansen 	}
401*ce0d9371SArne Jansen 	while (1) {
402*ce0d9371SArne Jansen 		arc_read_node_t *arn = calloc(sizeof(*arn), 1);
403*ce0d9371SArne Jansen 
404*ce0d9371SArne Jansen 		assert(arn);
405*ce0d9371SArne Jansen 		if (blen == ptr) {
406*ce0d9371SArne Jansen 			ret = read(fd, buf, sizeof(buf));
407*ce0d9371SArne Jansen 			if (ret == 0)
408*ce0d9371SArne Jansen 				break;
409*ce0d9371SArne Jansen 			if (ret == -1) {
410*ce0d9371SArne Jansen 				fprintf(stderr, "failed to read input: %s\n",
411*ce0d9371SArne Jansen 					strerror(errno));
412*ce0d9371SArne Jansen 				exit(1);
413*ce0d9371SArne Jansen 			}
414*ce0d9371SArne Jansen 			blen = ret;
415*ce0d9371SArne Jansen 			ptr = 0;
416*ce0d9371SArne Jansen 		}
417*ce0d9371SArne Jansen 		if ((blen - ptr) < sizeof(arn->arn_ar)) {
418*ce0d9371SArne Jansen 			fprintf(stderr,
419*ce0d9371SArne Jansen 				"failed to read input: truncated file\n");
420*ce0d9371SArne Jansen 			exit(1);
421*ce0d9371SArne Jansen 		}
422*ce0d9371SArne Jansen 		memcpy(&arn->arn_ar, buf + ptr, sizeof(arn->arn_ar));
423*ce0d9371SArne Jansen 		ptr += sizeof(arn->arn_ar);
424*ce0d9371SArne Jansen 
425*ce0d9371SArne Jansen 		if (g_verbose >= 2) {
426*ce0d9371SArne Jansen 			arc_read_t *ar = &arn->arn_ar;
427*ce0d9371SArne Jansen 
428*ce0d9371SArne Jansen 			printf("spa %llx objset % 8lld object % 8lld "
429*ce0d9371SArne Jansen 			    "level %lld blkid % 8lld size % 6lld type % 3lld "
430*ce0d9371SArne Jansen 			    "dva %016x:%016x birth % 8lld\n",
431*ce0d9371SArne Jansen 			    ar->ar_spa, ar->ar_objset, ar->ar_object,
432*ce0d9371SArne Jansen 			    ar->ar_level, ar->ar_blkid, ar->ar_size,
433*ce0d9371SArne Jansen 			    ar->ar_type, ar->ar_dva0, ar->ar_dva1,
434*ce0d9371SArne Jansen 			    ar->ar_birth);
435*ce0d9371SArne Jansen 		}
436*ce0d9371SArne Jansen 
437*ce0d9371SArne Jansen 		if (avl_find(awr, arn, NULL) == NULL)
438*ce0d9371SArne Jansen 			avl_add(awr, arn);
439*ce0d9371SArne Jansen 	}
440*ce0d9371SArne Jansen 	close(fd);
441*ce0d9371SArne Jansen }
442*ce0d9371SArne Jansen 
443*ce0d9371SArne Jansen static void
444*ce0d9371SArne Jansen read_arc(avl_tree_t *awr, char *in_fn, uint64_t color)
445*ce0d9371SArne Jansen {
446*ce0d9371SArne Jansen 	int fd;
447*ce0d9371SArne Jansen 	int ret;
448*ce0d9371SArne Jansen 	arc_content_hdr_t ach;
449*ce0d9371SArne Jansen 	char buf[1000 * sizeof(arc_info_t)];
450*ce0d9371SArne Jansen 	int ptr = 0;
451*ce0d9371SArne Jansen 	int blen = 0;
452*ce0d9371SArne Jansen 
453*ce0d9371SArne Jansen 	fd = open(in_fn, O_RDONLY);
454*ce0d9371SArne Jansen 	if (fd == -1) {
455*ce0d9371SArne Jansen 		fprintf(stderr, "failed to open input: %s\n",
456*ce0d9371SArne Jansen 			strerror(errno));
457*ce0d9371SArne Jansen 		exit(1);
458*ce0d9371SArne Jansen 	}
459*ce0d9371SArne Jansen 	ret = read(fd, &ach, sizeof(ach));
460*ce0d9371SArne Jansen 	if (ret == -1) {
461*ce0d9371SArne Jansen 		fprintf(stderr, "failed to read input: %s\n",
462*ce0d9371SArne Jansen 			strerror(errno));
463*ce0d9371SArne Jansen 		exit(1);
464*ce0d9371SArne Jansen 	}
465*ce0d9371SArne Jansen 	if (ret != sizeof(ach)) {
466*ce0d9371SArne Jansen 		fprintf(stderr, "failed to read input: truncated file\n");
467*ce0d9371SArne Jansen 		exit(1);
468*ce0d9371SArne Jansen 	}
469*ce0d9371SArne Jansen 	if (memcmp(ach.ach_magic, ARCWATCH_CONTENT_MAGIC, 4) != 0) {
470*ce0d9371SArne Jansen 		fprintf(stderr, "failed to read input: bad file magic\n");
471*ce0d9371SArne Jansen 		exit(1);
472*ce0d9371SArne Jansen 	}
473*ce0d9371SArne Jansen 	if (ach.ach_version != ARCWATCH_CONTENT_VERSION) {
474*ce0d9371SArne Jansen 		fprintf(stderr, "failed to read input: bad file version\n");
475*ce0d9371SArne Jansen 		exit(1);
476*ce0d9371SArne Jansen 	}
477*ce0d9371SArne Jansen 	while (1) {
478*ce0d9371SArne Jansen 		arc_info_t ai;
479*ce0d9371SArne Jansen 		arc_read_node_t search;
480*ce0d9371SArne Jansen 		arc_read_node_t *arn;
481*ce0d9371SArne Jansen 
482*ce0d9371SArne Jansen 		if (blen == ptr) {
483*ce0d9371SArne Jansen 			ret = read(fd, buf, sizeof(buf));
484*ce0d9371SArne Jansen 			if (ret == 0)
485*ce0d9371SArne Jansen 				break;
486*ce0d9371SArne Jansen 			if (ret == -1) {
487*ce0d9371SArne Jansen 				fprintf(stderr, "failed to read input: %s\n",
488*ce0d9371SArne Jansen 					strerror(errno));
489*ce0d9371SArne Jansen 				exit(1);
490*ce0d9371SArne Jansen 			}
491*ce0d9371SArne Jansen 			blen = ret;
492*ce0d9371SArne Jansen 			ptr = 0;
493*ce0d9371SArne Jansen 		}
494*ce0d9371SArne Jansen 		if ((blen - ptr) < sizeof(ai)) {
495*ce0d9371SArne Jansen 			fprintf(stderr,
496*ce0d9371SArne Jansen 				"failed to read input: truncated file\n");
497*ce0d9371SArne Jansen 			exit(1);
498*ce0d9371SArne Jansen 		}
499*ce0d9371SArne Jansen 		memcpy(&ai, buf + ptr, sizeof(ai));
500*ce0d9371SArne Jansen 		ptr += sizeof(ai);
501*ce0d9371SArne Jansen 
502*ce0d9371SArne Jansen 		search.arn_ar.ar_spa = ai.ai_spa;
503*ce0d9371SArne Jansen 		search.arn_ar.ar_dva0 = ai.ai_dva.dva_word[0];
504*ce0d9371SArne Jansen 		search.arn_ar.ar_dva1 = ai.ai_dva.dva_word[1];
505*ce0d9371SArne Jansen 		search.arn_ar.ar_birth = ai.ai_birth;
506*ce0d9371SArne Jansen 
507*ce0d9371SArne Jansen 		arn = avl_find(awr, &search, NULL);
508*ce0d9371SArne Jansen 		if (arn) {
509*ce0d9371SArne Jansen 			arn->arn_color = color;
510*ce0d9371SArne Jansen 			arn->arn_flags = ai.ai_flags;
511*ce0d9371SArne Jansen 			arn->arn_state = ai.ai_state;
512*ce0d9371SArne Jansen 		}
513*ce0d9371SArne Jansen 	}
514*ce0d9371SArne Jansen 	close(fd);
515*ce0d9371SArne Jansen }
516*ce0d9371SArne Jansen 
517*ce0d9371SArne Jansen #define BUFSZ 1048576	/* 1MB */
518*ce0d9371SArne Jansen static void
519*ce0d9371SArne Jansen get_arc(avl_tree_t *awr, uint64_t color, char *out_fn)
520*ce0d9371SArne Jansen {
521*ce0d9371SArne Jansen 	int ret;
522*ce0d9371SArne Jansen 	int fd;
523*ce0d9371SArne Jansen 	void *buf = malloc(BUFSZ);
524*ce0d9371SArne Jansen 	zfs_cmd_t cmd = {0};
525*ce0d9371SArne Jansen 	arc_info_t *ai;
526*ce0d9371SArne Jansen 	arc_info_hdr_t *aih;
527*ce0d9371SArne Jansen 	int ofd = -1;
528*ce0d9371SArne Jansen 	int hdr_written = 0;
529*ce0d9371SArne Jansen 	char wbuf[16384];
530*ce0d9371SArne Jansen 	int wptr = 0;
531*ce0d9371SArne Jansen 
532*ce0d9371SArne Jansen 	fd = open("/dev/zfs", O_RDWR);
533*ce0d9371SArne Jansen 	if (fd == -1) {
534*ce0d9371SArne Jansen 		fprintf(stderr, "failed to open /dev/zfs: %s\n",
535*ce0d9371SArne Jansen 		    strerror(errno));
536*ce0d9371SArne Jansen 		exit(1);
537*ce0d9371SArne Jansen 	}
538*ce0d9371SArne Jansen 	assert(buf);
539*ce0d9371SArne Jansen 	cmd.zc_obj = 0;
540*ce0d9371SArne Jansen 	cmd.zc_nvlist_dst = (uint64_t)buf;
541*ce0d9371SArne Jansen 	cmd.zc_nvlist_dst_size = BUFSZ;
542*ce0d9371SArne Jansen 
543*ce0d9371SArne Jansen 	if (out_fn != NULL) {
544*ce0d9371SArne Jansen 		ofd = open(out_fn, O_CREAT | O_TRUNC | O_WRONLY, 0644);
545*ce0d9371SArne Jansen 		if (ofd == -1) {
546*ce0d9371SArne Jansen 			printf("cannot open output file %s: %s\n",
547*ce0d9371SArne Jansen 			    out_fn, strerror(errno));
548*ce0d9371SArne Jansen 			exit(1);
549*ce0d9371SArne Jansen 		}
550*ce0d9371SArne Jansen 	}
551*ce0d9371SArne Jansen 	do {
552*ce0d9371SArne Jansen 		int i;
553*ce0d9371SArne Jansen 
554*ce0d9371SArne Jansen 		ret = ioctl(fd, ZFS_IOC_ARC_INFO, &cmd);
555*ce0d9371SArne Jansen 		if (ret == -1) {
556*ce0d9371SArne Jansen 			printf("ioctl failed with %d=%s\n", errno,
557*ce0d9371SArne Jansen 			    strerror(errno));
558*ce0d9371SArne Jansen 			exit(1);
559*ce0d9371SArne Jansen 		}
560*ce0d9371SArne Jansen 		aih = buf;
561*ce0d9371SArne Jansen 		ai = buf + sizeof(aih);
562*ce0d9371SArne Jansen 		if (ofd != -1 && !hdr_written) {
563*ce0d9371SArne Jansen 			arc_content_hdr_t ach;
564*ce0d9371SArne Jansen 
565*ce0d9371SArne Jansen 			memcpy(ach.ach_magic, ARCWATCH_CONTENT_MAGIC,
566*ce0d9371SArne Jansen 			    sizeof(ach.ach_magic));
567*ce0d9371SArne Jansen 			ach.ach_version = ARCWATCH_CONTENT_VERSION;
568*ce0d9371SArne Jansen 			ach.ach_buckets = aih->aih_buckets;
569*ce0d9371SArne Jansen 			ach.ach_buf_locks = aih->aih_buf_locks;
570*ce0d9371SArne Jansen 			ret = write(ofd, &ach, sizeof(ach));
571*ce0d9371SArne Jansen 			if (ret == -1) {
572*ce0d9371SArne Jansen 				printf("cannot write to output file: %s\n",
573*ce0d9371SArne Jansen 				    strerror(errno));
574*ce0d9371SArne Jansen 				exit(1);
575*ce0d9371SArne Jansen 			}
576*ce0d9371SArne Jansen 			hdr_written = 1;
577*ce0d9371SArne Jansen 		}
578*ce0d9371SArne Jansen 		for (i = 0; i < aih->aih_entries; ++i) {
579*ce0d9371SArne Jansen 			ai = ((arc_info_t *)(aih + 1)) + i;
580*ce0d9371SArne Jansen 			if (g_verbose) {
581*ce0d9371SArne Jansen 				printf("dva %016llx:%016llx birth %d "
582*ce0d9371SArne Jansen 					"spa %016llx "
583*ce0d9371SArne Jansen 					"size % 8d flags %016x state %s\n",
584*ce0d9371SArne Jansen 					ai->ai_dva.dva_word[0],
585*ce0d9371SArne Jansen 					ai->ai_dva.dva_word[1],
586*ce0d9371SArne Jansen 					ai->ai_birth,
587*ce0d9371SArne Jansen 					ai->ai_spa,
588*ce0d9371SArne Jansen 					ai->ai_size,
589*ce0d9371SArne Jansen 					ai->ai_flags,
590*ce0d9371SArne Jansen 					state2str(ai->ai_state));
591*ce0d9371SArne Jansen 			}
592*ce0d9371SArne Jansen 			if (awr) {
593*ce0d9371SArne Jansen 				arc_read_node_t search;
594*ce0d9371SArne Jansen 				arc_read_node_t *arn;
595*ce0d9371SArne Jansen 
596*ce0d9371SArne Jansen 				search.arn_ar.ar_spa = ai->ai_spa;
597*ce0d9371SArne Jansen 				search.arn_ar.ar_dva0 = ai->ai_dva.dva_word[0];
598*ce0d9371SArne Jansen 				search.arn_ar.ar_dva1 = ai->ai_dva.dva_word[1];
599*ce0d9371SArne Jansen 				search.arn_ar.ar_birth = ai->ai_birth;
600*ce0d9371SArne Jansen 
601*ce0d9371SArne Jansen 				arn = avl_find(awr, &search, NULL);
602*ce0d9371SArne Jansen 				if (arn) {
603*ce0d9371SArne Jansen 					arn->arn_color = color;
604*ce0d9371SArne Jansen 					arn->arn_flags = ai->ai_flags;
605*ce0d9371SArne Jansen 					arn->arn_state = ai->ai_state;
606*ce0d9371SArne Jansen 				}
607*ce0d9371SArne Jansen 			}
608*ce0d9371SArne Jansen 			if (ofd != -1) {
609*ce0d9371SArne Jansen 				if (wptr + sizeof(*ai) > sizeof(wbuf)) {
610*ce0d9371SArne Jansen 					ret = write(ofd, wbuf, wptr);
611*ce0d9371SArne Jansen 					if (ret == -1) {
612*ce0d9371SArne Jansen 						printf("cannot write to output "
613*ce0d9371SArne Jansen 							"file: %s\n",
614*ce0d9371SArne Jansen 						    strerror(errno));
615*ce0d9371SArne Jansen 						exit(1);
616*ce0d9371SArne Jansen 					}
617*ce0d9371SArne Jansen 					wptr = 0;
618*ce0d9371SArne Jansen 				}
619*ce0d9371SArne Jansen 				memcpy(wbuf + wptr, ai, sizeof(*ai));
620*ce0d9371SArne Jansen 				wptr += sizeof(*ai);
621*ce0d9371SArne Jansen 			}
622*ce0d9371SArne Jansen 		}
623*ce0d9371SArne Jansen 		cmd.zc_obj = aih->aih_next;
624*ce0d9371SArne Jansen 	} while (cmd.zc_obj != 0);
625*ce0d9371SArne Jansen 
626*ce0d9371SArne Jansen 	if (wptr > 0) {
627*ce0d9371SArne Jansen 		ret = write(ofd, wbuf, wptr);
628*ce0d9371SArne Jansen 		if (ret == -1) {
629*ce0d9371SArne Jansen 			printf("cannot write to output "
630*ce0d9371SArne Jansen 				"file: %s\n",
631*ce0d9371SArne Jansen 			    strerror(errno));
632*ce0d9371SArne Jansen 		}
633*ce0d9371SArne Jansen 		exit(1);
634*ce0d9371SArne Jansen 	}
635*ce0d9371SArne Jansen 	close(ofd);
636*ce0d9371SArne Jansen 	free(buf);
637*ce0d9371SArne Jansen }
638*ce0d9371SArne Jansen 
639*ce0d9371SArne Jansen static void
640*ce0d9371SArne Jansen awr_stat(avl_tree_t *awr, uint64_t color)
641*ce0d9371SArne Jansen {
642*ce0d9371SArne Jansen 	arc_read_node_t *arn = avl_first(awr);
643*ce0d9371SArne Jansen 	uint64_t bufs_total = 0;
644*ce0d9371SArne Jansen 	uint64_t bufs_in_l1 = 0;
645*ce0d9371SArne Jansen 	uint64_t bufs_in_l1_ghost = 0;
646*ce0d9371SArne Jansen 	uint64_t bufs_in_l2 = 0;
647*ce0d9371SArne Jansen 	uint64_t bytes_total = 0;
648*ce0d9371SArne Jansen 	uint64_t bytes_in_l1 = 0;
649*ce0d9371SArne Jansen 	uint64_t bytes_in_l1_ghost = 0;
650*ce0d9371SArne Jansen 	uint64_t bytes_in_l2 = 0;
651*ce0d9371SArne Jansen 
652*ce0d9371SArne Jansen 	while (arn) {
653*ce0d9371SArne Jansen 		arc_read_t *ar = &arn->arn_ar;
654*ce0d9371SArne Jansen 		if (g_verbose) {
655*ce0d9371SArne Jansen 			printf("dva %016llx:%016llx birth % 8d "
656*ce0d9371SArne Jansen 			       "spa %016llx size % 8d ",
657*ce0d9371SArne Jansen 				ar->ar_dva0,
658*ce0d9371SArne Jansen 				ar->ar_dva1,
659*ce0d9371SArne Jansen 				ar->ar_birth,
660*ce0d9371SArne Jansen 				ar->ar_spa,
661*ce0d9371SArne Jansen 				ar->ar_size,
662*ce0d9371SArne Jansen 				arn->arn_color);
663*ce0d9371SArne Jansen 			if (arn->arn_color == color)
664*ce0d9371SArne Jansen 				printf("flags %016x state %s\n",
665*ce0d9371SArne Jansen 				    arn->arn_flags,
666*ce0d9371SArne Jansen 				    state2str(arn->arn_state));
667*ce0d9371SArne Jansen 			else
668*ce0d9371SArne Jansen 				printf("not in ARC\n");
669*ce0d9371SArne Jansen 		}
670*ce0d9371SArne Jansen 		if (arn->arn_color == color) {
671*ce0d9371SArne Jansen 			if (arn->arn_state == AIS_MRU ||
672*ce0d9371SArne Jansen 			    arn->arn_state == AIS_MFU) {
673*ce0d9371SArne Jansen 				++bufs_in_l1;
674*ce0d9371SArne Jansen 				bytes_in_l1 += ar->ar_size;
675*ce0d9371SArne Jansen 			} else if (arn->arn_state == AIS_MRU_GHOST ||
676*ce0d9371SArne Jansen 			           arn->arn_state == AIS_MFU_GHOST) {
677*ce0d9371SArne Jansen 				++bufs_in_l1_ghost;
678*ce0d9371SArne Jansen 				bytes_in_l1_ghost =+ ar->ar_size;
679*ce0d9371SArne Jansen 			}
680*ce0d9371SArne Jansen 			if (arn->arn_flags & ARC_FLAG_HAS_L2HDR) {
681*ce0d9371SArne Jansen 				++bufs_in_l2;
682*ce0d9371SArne Jansen 				bytes_in_l2 += ar->ar_size;
683*ce0d9371SArne Jansen 			}
684*ce0d9371SArne Jansen 		}
685*ce0d9371SArne Jansen 		++bufs_total;
686*ce0d9371SArne Jansen 		bytes_total += ar->ar_size;
687*ce0d9371SArne Jansen 		arn = AVL_NEXT(awr, arn);
688*ce0d9371SArne Jansen 	}
689*ce0d9371SArne Jansen 	if (g_verbose) {
690*ce0d9371SArne Jansen 		printf("\n");
691*ce0d9371SArne Jansen 	}
692*ce0d9371SArne Jansen 	printf("         |       bufs |            bytes\n");
693*ce0d9371SArne Jansen 	printf("---------+------------+-----------------\n");
694*ce0d9371SArne Jansen 	printf("   in l1 | % 10lld | %16lld\n", bufs_in_l1, bytes_in_l1);
695*ce0d9371SArne Jansen 	printf("l1 ghost | % 10lld | %16lld\n", bufs_in_l1_ghost,
696*ce0d9371SArne Jansen 	    bytes_in_l1_ghost);
697*ce0d9371SArne Jansen 	printf("   in l2 | % 10lld | %16lld\n", bufs_in_l2, bytes_in_l2);
698*ce0d9371SArne Jansen 	printf("   total | % 10lld | %16lld\n", bufs_total, bytes_total);
699*ce0d9371SArne Jansen 	printf("\n");
700*ce0d9371SArne Jansen }
701*ce0d9371SArne Jansen 
702*ce0d9371SArne Jansen static void
703*ce0d9371SArne Jansen usage(const char *basename)
704*ce0d9371SArne Jansen {
705*ce0d9371SArne Jansen 	(void) fprintf(stderr,
706*ce0d9371SArne Jansen 	    "Usage: %s -d [options]\n"
707*ce0d9371SArne Jansen 	    "       %s {-c | -i} [options] [command [args]]\n\n"
708*ce0d9371SArne Jansen 	    "\tOptions:\n"
709*ce0d9371SArne Jansen 	    "\t  -c           run command and record read blocks\n"
710*ce0d9371SArne Jansen 	    "\t  -i filename  read previously recorded output from -o instead\n"
711*ce0d9371SArne Jansen 	    "\t               of running a command\n"
712*ce0d9371SArne Jansen 	    "\t  -b bufsize   change tracing bufsize\n"
713*ce0d9371SArne Jansen 	    "\t  -a           dump arc\n"
714*ce0d9371SArne Jansen 	    "\t  -v           verbose\n"
715*ce0d9371SArne Jansen 	    "\t  -w           watch decay of buffers in arc\n"
716*ce0d9371SArne Jansen 	    "\t  -d seconds   watch interval\n"
717*ce0d9371SArne Jansen 	    "\t  -o filename  write output to file\n",
718*ce0d9371SArne Jansen 	    basename, basename);
719*ce0d9371SArne Jansen 	exit(1);
720*ce0d9371SArne Jansen }
721*ce0d9371SArne Jansen 
722*ce0d9371SArne Jansen /*
723*ce0d9371SArne Jansen  * TODO: compare 2 traces
724*ce0d9371SArne Jansen  * TODO: compare 2 arc infos
725*ce0d9371SArne Jansen  * TODO: persistent spa numbering
726*ce0d9371SArne Jansen  */
727*ce0d9371SArne Jansen int
728*ce0d9371SArne Jansen main(int argc, char **argv)
729*ce0d9371SArne Jansen {
730*ce0d9371SArne Jansen         extern char *optarg;
731*ce0d9371SArne Jansen         extern int optind;
732*ce0d9371SArne Jansen         int c;
733*ce0d9371SArne Jansen 	char *bufsize = "4m";
734*ce0d9371SArne Jansen 	int run_cmd = 0;
735*ce0d9371SArne Jansen 	int watch = 0;
736*ce0d9371SArne Jansen 	char *basename;
737*ce0d9371SArne Jansen 	char *out_fn = NULL;
738*ce0d9371SArne Jansen 	char *in_fn = NULL;
739*ce0d9371SArne Jansen 	avl_tree_t awr;
740*ce0d9371SArne Jansen 	uint64_t color = 0;
741*ce0d9371SArne Jansen 	int interval = 10;
742*ce0d9371SArne Jansen 	int dump_arc = 0;
743*ce0d9371SArne Jansen 	char *arc_fn = NULL;
744*ce0d9371SArne Jansen 
745*ce0d9371SArne Jansen 	avl_create(&awr, awr_cmp, sizeof(arc_read_node_t),
746*ce0d9371SArne Jansen 	    offsetof(arc_read_node_t, arn_node));
747*ce0d9371SArne Jansen 	basename = strrchr(argv[0], '/');
748*ce0d9371SArne Jansen 	if (basename == NULL)
749*ce0d9371SArne Jansen 		basename = argv[0];
750*ce0d9371SArne Jansen 
751*ce0d9371SArne Jansen 	while ((c = getopt(argc, argv, "b:o:i:cvwhd:aI:")) != EOF) {
752*ce0d9371SArne Jansen 		switch(c) {
753*ce0d9371SArne Jansen 		case 'b':
754*ce0d9371SArne Jansen 			bufsize = optarg;
755*ce0d9371SArne Jansen 			break;
756*ce0d9371SArne Jansen 		case 'c':
757*ce0d9371SArne Jansen 			run_cmd = 1;
758*ce0d9371SArne Jansen 			break;
759*ce0d9371SArne Jansen 		case 'w':
760*ce0d9371SArne Jansen 			watch = 1;
761*ce0d9371SArne Jansen 			break;
762*ce0d9371SArne Jansen 		case 'v':
763*ce0d9371SArne Jansen 			++g_verbose;
764*ce0d9371SArne Jansen 			break;
765*ce0d9371SArne Jansen 		case 'o':
766*ce0d9371SArne Jansen 			out_fn = optarg;
767*ce0d9371SArne Jansen 			break;
768*ce0d9371SArne Jansen 		case 'i':
769*ce0d9371SArne Jansen 			in_fn = optarg;
770*ce0d9371SArne Jansen 			break;
771*ce0d9371SArne Jansen 		case 'I':
772*ce0d9371SArne Jansen 			arc_fn = optarg;
773*ce0d9371SArne Jansen 			break;
774*ce0d9371SArne Jansen 		case 'a':
775*ce0d9371SArne Jansen 			dump_arc = 1;
776*ce0d9371SArne Jansen 			break;
777*ce0d9371SArne Jansen 		case 'd':
778*ce0d9371SArne Jansen 			interval = atoi(optarg);
779*ce0d9371SArne Jansen 			break;
780*ce0d9371SArne Jansen 		case 'h':
781*ce0d9371SArne Jansen 		default:
782*ce0d9371SArne Jansen 			usage(basename);
783*ce0d9371SArne Jansen 		}
784*ce0d9371SArne Jansen 	}
785*ce0d9371SArne Jansen 
786*ce0d9371SArne Jansen 	if (optind != argc && !run_cmd) {
787*ce0d9371SArne Jansen 		fprintf(stderr, "command given without -c switch\n");
788*ce0d9371SArne Jansen 		exit(1);
789*ce0d9371SArne Jansen 	}
790*ce0d9371SArne Jansen 	if (dump_arc) {
791*ce0d9371SArne Jansen 		get_arc(NULL, 0, out_fn);
792*ce0d9371SArne Jansen 		exit(0);
793*ce0d9371SArne Jansen 	}
794*ce0d9371SArne Jansen 	if (arc_fn != NULL && !run_cmd && in_fn == NULL) {
795*ce0d9371SArne Jansen 		fprintf(stderr, "-I given without -c and -i\n");
796*ce0d9371SArne Jansen 		exit(1);
797*ce0d9371SArne Jansen 	}
798*ce0d9371SArne Jansen 	if (arc_fn != NULL && watch) {
799*ce0d9371SArne Jansen 		fprintf(stderr, "-I given with -w\n");
800*ce0d9371SArne Jansen 		exit(1);
801*ce0d9371SArne Jansen 	}
802*ce0d9371SArne Jansen 	if (run_cmd && (in_fn != NULL)) {
803*ce0d9371SArne Jansen 		fprintf(stderr, "-i and -c are mutually exclusive\n");
804*ce0d9371SArne Jansen 		exit(1);
805*ce0d9371SArne Jansen 	}
806*ce0d9371SArne Jansen 	if (run_cmd) {
807*ce0d9371SArne Jansen 		if (optind == argc) {
808*ce0d9371SArne Jansen 			fprintf(stderr, "no command given\n");
809*ce0d9371SArne Jansen 			exit(1);
810*ce0d9371SArne Jansen 		}
811*ce0d9371SArne Jansen 		run_dtrace(bufsize, out_fn, &awr, argc - optind, argv + optind);
812*ce0d9371SArne Jansen 	}
813*ce0d9371SArne Jansen 	if (in_fn)
814*ce0d9371SArne Jansen 		read_awr(&awr, in_fn);
815*ce0d9371SArne Jansen 	if (watch) {
816*ce0d9371SArne Jansen 		while (1) {
817*ce0d9371SArne Jansen 			get_arc(&awr, ++color, NULL);
818*ce0d9371SArne Jansen 			awr_stat(&awr, color);
819*ce0d9371SArne Jansen 			sleep(10);
820*ce0d9371SArne Jansen 		}
821*ce0d9371SArne Jansen 	}
822*ce0d9371SArne Jansen 	if (arc_fn) {
823*ce0d9371SArne Jansen 		read_arc(&awr, arc_fn, 1);
824*ce0d9371SArne Jansen 		awr_stat(&awr, 1);
825*ce0d9371SArne Jansen 	}
826*ce0d9371SArne Jansen 
827*ce0d9371SArne Jansen 	exit(0);
828*ce0d9371SArne Jansen }
829