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