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