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