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 *
state2str(arc_info_state_t state)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
awr_cmp(const void * x,const void * y)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
drophandler(const dtrace_dropdata_t * data,void * arg)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
prochandler(struct ps_prochandle * P,const char * msg,void * arg)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
get_val(caddr_t base,dtrace_recdesc_t * rec)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
process_trace(const dtrace_probedata_t * data,void * arg)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
d_fatal(dtrace_hdl_t * dtp,char * msg)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
run_dtrace(char * bufsize,char * out_fn,avl_tree_t * awr,int argc,char ** argv)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
read_awr(avl_tree_t * awr,char * in_fn)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
read_arc(avl_tree_t * awr,char * in_fn,uint64_t color,int just_dump)444*f264e978SArne Jansen read_arc(avl_tree_t *awr, char *in_fn, uint64_t color, int just_dump)
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
502*f264e978SArne Jansen if (just_dump) {
503*f264e978SArne Jansen printf("dva %016llx:%016llx birth %8d "
504*f264e978SArne Jansen "spa %016llx "
505*f264e978SArne Jansen "size % 8x flags %016x state %s\n",
506*f264e978SArne Jansen ai.ai_dva.dva_word[0],
507*f264e978SArne Jansen ai.ai_dva.dva_word[1],
508*f264e978SArne Jansen ai.ai_birth,
509*f264e978SArne Jansen ai.ai_spa,
510*f264e978SArne Jansen ai.ai_size,
511*f264e978SArne Jansen ai.ai_flags,
512*f264e978SArne Jansen state2str(ai.ai_state));
513*f264e978SArne Jansen } else {
514ce0d9371SArne Jansen search.arn_ar.ar_spa = ai.ai_spa;
515ce0d9371SArne Jansen search.arn_ar.ar_dva0 = ai.ai_dva.dva_word[0];
516ce0d9371SArne Jansen search.arn_ar.ar_dva1 = ai.ai_dva.dva_word[1];
517ce0d9371SArne Jansen search.arn_ar.ar_birth = ai.ai_birth;
518ce0d9371SArne Jansen
519ce0d9371SArne Jansen arn = avl_find(awr, &search, NULL);
520ce0d9371SArne Jansen if (arn) {
521ce0d9371SArne Jansen arn->arn_color = color;
522ce0d9371SArne Jansen arn->arn_flags = ai.ai_flags;
523ce0d9371SArne Jansen arn->arn_state = ai.ai_state;
524ce0d9371SArne Jansen }
525ce0d9371SArne Jansen }
526*f264e978SArne Jansen }
527ce0d9371SArne Jansen close(fd);
528ce0d9371SArne Jansen }
529ce0d9371SArne Jansen
530ce0d9371SArne Jansen #define BUFSZ 1048576 /* 1MB */
531ce0d9371SArne Jansen static void
get_arc(avl_tree_t * awr,uint64_t color,char * out_fn)532ce0d9371SArne Jansen get_arc(avl_tree_t *awr, uint64_t color, char *out_fn)
533ce0d9371SArne Jansen {
534ce0d9371SArne Jansen int ret;
535ce0d9371SArne Jansen int fd;
536ce0d9371SArne Jansen void *buf = malloc(BUFSZ);
537ce0d9371SArne Jansen zfs_cmd_t cmd = {0};
538ce0d9371SArne Jansen arc_info_t *ai;
539ce0d9371SArne Jansen arc_info_hdr_t *aih;
540ce0d9371SArne Jansen int ofd = -1;
541ce0d9371SArne Jansen int hdr_written = 0;
542ce0d9371SArne Jansen char wbuf[16384];
543ce0d9371SArne Jansen int wptr = 0;
544ce0d9371SArne Jansen
545ce0d9371SArne Jansen fd = open("/dev/zfs", O_RDWR);
546ce0d9371SArne Jansen if (fd == -1) {
547ce0d9371SArne Jansen fprintf(stderr, "failed to open /dev/zfs: %s\n",
548ce0d9371SArne Jansen strerror(errno));
549ce0d9371SArne Jansen exit(1);
550ce0d9371SArne Jansen }
551ce0d9371SArne Jansen assert(buf);
552ce0d9371SArne Jansen cmd.zc_obj = 0;
553ce0d9371SArne Jansen cmd.zc_nvlist_dst = (uint64_t)buf;
554ce0d9371SArne Jansen cmd.zc_nvlist_dst_size = BUFSZ;
555ce0d9371SArne Jansen
556ce0d9371SArne Jansen if (out_fn != NULL) {
557ce0d9371SArne Jansen ofd = open(out_fn, O_CREAT | O_TRUNC | O_WRONLY, 0644);
558ce0d9371SArne Jansen if (ofd == -1) {
559ce0d9371SArne Jansen printf("cannot open output file %s: %s\n",
560ce0d9371SArne Jansen out_fn, strerror(errno));
561ce0d9371SArne Jansen exit(1);
562ce0d9371SArne Jansen }
563ce0d9371SArne Jansen }
564ce0d9371SArne Jansen do {
565ce0d9371SArne Jansen int i;
566ce0d9371SArne Jansen
567ce0d9371SArne Jansen ret = ioctl(fd, ZFS_IOC_ARC_INFO, &cmd);
568ce0d9371SArne Jansen if (ret == -1) {
569ce0d9371SArne Jansen printf("ioctl failed with %d=%s\n", errno,
570ce0d9371SArne Jansen strerror(errno));
571ce0d9371SArne Jansen exit(1);
572ce0d9371SArne Jansen }
573ce0d9371SArne Jansen aih = buf;
574ce0d9371SArne Jansen ai = buf + sizeof(aih);
575ce0d9371SArne Jansen if (ofd != -1 && !hdr_written) {
576ce0d9371SArne Jansen arc_content_hdr_t ach;
577ce0d9371SArne Jansen
578ce0d9371SArne Jansen memcpy(ach.ach_magic, ARCWATCH_CONTENT_MAGIC,
579ce0d9371SArne Jansen sizeof(ach.ach_magic));
580ce0d9371SArne Jansen ach.ach_version = ARCWATCH_CONTENT_VERSION;
581ce0d9371SArne Jansen ach.ach_buckets = aih->aih_buckets;
582ce0d9371SArne Jansen ach.ach_buf_locks = aih->aih_buf_locks;
583ce0d9371SArne Jansen ret = write(ofd, &ach, sizeof(ach));
584ce0d9371SArne Jansen if (ret == -1) {
585ce0d9371SArne Jansen printf("cannot write to output file: %s\n",
586ce0d9371SArne Jansen strerror(errno));
587ce0d9371SArne Jansen exit(1);
588ce0d9371SArne Jansen }
589ce0d9371SArne Jansen hdr_written = 1;
590ce0d9371SArne Jansen }
591ce0d9371SArne Jansen for (i = 0; i < aih->aih_entries; ++i) {
592ce0d9371SArne Jansen ai = ((arc_info_t *)(aih + 1)) + i;
593ce0d9371SArne Jansen if (g_verbose) {
594a1ff4d1fSSimon Klinkert printf("dva %016llx:%016llx birth %7d "
595ce0d9371SArne Jansen "spa %016llx "
596ce0d9371SArne Jansen "size % 8d flags %016x state %s\n",
597ce0d9371SArne Jansen ai->ai_dva.dva_word[0],
598ce0d9371SArne Jansen ai->ai_dva.dva_word[1],
599ce0d9371SArne Jansen ai->ai_birth,
600ce0d9371SArne Jansen ai->ai_spa,
601ce0d9371SArne Jansen ai->ai_size,
602ce0d9371SArne Jansen ai->ai_flags,
603ce0d9371SArne Jansen state2str(ai->ai_state));
604ce0d9371SArne Jansen }
605ce0d9371SArne Jansen if (awr) {
606ce0d9371SArne Jansen arc_read_node_t search;
607ce0d9371SArne Jansen arc_read_node_t *arn;
608ce0d9371SArne Jansen
609ce0d9371SArne Jansen search.arn_ar.ar_spa = ai->ai_spa;
610ce0d9371SArne Jansen search.arn_ar.ar_dva0 = ai->ai_dva.dva_word[0];
611ce0d9371SArne Jansen search.arn_ar.ar_dva1 = ai->ai_dva.dva_word[1];
612ce0d9371SArne Jansen search.arn_ar.ar_birth = ai->ai_birth;
613ce0d9371SArne Jansen
614ce0d9371SArne Jansen arn = avl_find(awr, &search, NULL);
615ce0d9371SArne Jansen if (arn) {
616ce0d9371SArne Jansen arn->arn_color = color;
617ce0d9371SArne Jansen arn->arn_flags = ai->ai_flags;
618ce0d9371SArne Jansen arn->arn_state = ai->ai_state;
619ce0d9371SArne Jansen }
620ce0d9371SArne Jansen }
621ce0d9371SArne Jansen if (ofd != -1) {
622ce0d9371SArne Jansen if (wptr + sizeof(*ai) > sizeof(wbuf)) {
623ce0d9371SArne Jansen ret = write(ofd, wbuf, wptr);
624ce0d9371SArne Jansen if (ret == -1) {
625ce0d9371SArne Jansen printf("cannot write to output "
626ce0d9371SArne Jansen "file: %s\n",
627ce0d9371SArne Jansen strerror(errno));
628ce0d9371SArne Jansen exit(1);
629ce0d9371SArne Jansen }
630ce0d9371SArne Jansen wptr = 0;
631ce0d9371SArne Jansen }
632ce0d9371SArne Jansen memcpy(wbuf + wptr, ai, sizeof(*ai));
633ce0d9371SArne Jansen wptr += sizeof(*ai);
634ce0d9371SArne Jansen }
635ce0d9371SArne Jansen }
636ce0d9371SArne Jansen cmd.zc_obj = aih->aih_next;
637ce0d9371SArne Jansen } while (cmd.zc_obj != 0);
638ce0d9371SArne Jansen
639ce0d9371SArne Jansen if (wptr > 0) {
640ce0d9371SArne Jansen ret = write(ofd, wbuf, wptr);
641ce0d9371SArne Jansen if (ret == -1) {
642ce0d9371SArne Jansen printf("cannot write to output "
643ce0d9371SArne Jansen "file: %s\n",
644ce0d9371SArne Jansen strerror(errno));
645ce0d9371SArne Jansen }
646ce0d9371SArne Jansen exit(1);
647ce0d9371SArne Jansen }
6486675f517SSimon Klinkert close(fd);
649ce0d9371SArne Jansen close(ofd);
650ce0d9371SArne Jansen free(buf);
651ce0d9371SArne Jansen }
652ce0d9371SArne Jansen
653ce0d9371SArne Jansen static void
awr_stat(avl_tree_t * awr,uint64_t color)654ce0d9371SArne Jansen awr_stat(avl_tree_t *awr, uint64_t color)
655ce0d9371SArne Jansen {
656ce0d9371SArne Jansen arc_read_node_t *arn = avl_first(awr);
657ce0d9371SArne Jansen uint64_t bufs_total = 0;
658ce0d9371SArne Jansen uint64_t bufs_in_l1 = 0;
659ce0d9371SArne Jansen uint64_t bufs_in_l1_ghost = 0;
660ce0d9371SArne Jansen uint64_t bufs_in_l2 = 0;
661ce0d9371SArne Jansen uint64_t bytes_total = 0;
662ce0d9371SArne Jansen uint64_t bytes_in_l1 = 0;
663ce0d9371SArne Jansen uint64_t bytes_in_l1_ghost = 0;
664ce0d9371SArne Jansen uint64_t bytes_in_l2 = 0;
665ce0d9371SArne Jansen
666ce0d9371SArne Jansen while (arn) {
667ce0d9371SArne Jansen arc_read_t *ar = &arn->arn_ar;
668ce0d9371SArne Jansen if (g_verbose) {
669ce0d9371SArne Jansen printf("dva %016llx:%016llx birth % 8d "
670ce0d9371SArne Jansen "spa %016llx size % 8d ",
671ce0d9371SArne Jansen ar->ar_dva0,
672ce0d9371SArne Jansen ar->ar_dva1,
673ce0d9371SArne Jansen ar->ar_birth,
674ce0d9371SArne Jansen ar->ar_spa,
675ce0d9371SArne Jansen ar->ar_size,
676ce0d9371SArne Jansen arn->arn_color);
677ce0d9371SArne Jansen if (arn->arn_color == color)
678ce0d9371SArne Jansen printf("flags %016x state %s\n",
679ce0d9371SArne Jansen arn->arn_flags,
680ce0d9371SArne Jansen state2str(arn->arn_state));
681ce0d9371SArne Jansen else
682ce0d9371SArne Jansen printf("not in ARC\n");
683ce0d9371SArne Jansen }
684ce0d9371SArne Jansen if (arn->arn_color == color) {
685ce0d9371SArne Jansen if (arn->arn_state == AIS_MRU ||
686ce0d9371SArne Jansen arn->arn_state == AIS_MFU) {
687ce0d9371SArne Jansen ++bufs_in_l1;
688ce0d9371SArne Jansen bytes_in_l1 += ar->ar_size;
689ce0d9371SArne Jansen } else if (arn->arn_state == AIS_MRU_GHOST ||
690ce0d9371SArne Jansen arn->arn_state == AIS_MFU_GHOST) {
691ce0d9371SArne Jansen ++bufs_in_l1_ghost;
692ce0d9371SArne Jansen bytes_in_l1_ghost =+ ar->ar_size;
693ce0d9371SArne Jansen }
694ce0d9371SArne Jansen if (arn->arn_flags & ARC_FLAG_HAS_L2HDR) {
695ce0d9371SArne Jansen ++bufs_in_l2;
696ce0d9371SArne Jansen bytes_in_l2 += ar->ar_size;
697ce0d9371SArne Jansen }
698ce0d9371SArne Jansen }
699ce0d9371SArne Jansen ++bufs_total;
700ce0d9371SArne Jansen bytes_total += ar->ar_size;
701ce0d9371SArne Jansen arn = AVL_NEXT(awr, arn);
702ce0d9371SArne Jansen }
703ce0d9371SArne Jansen if (g_verbose) {
704ce0d9371SArne Jansen printf("\n");
705ce0d9371SArne Jansen }
706ce0d9371SArne Jansen printf(" | bufs | bytes\n");
707ce0d9371SArne Jansen printf("---------+------------+-----------------\n");
708ce0d9371SArne Jansen printf(" in l1 | % 10lld | %16lld\n", bufs_in_l1, bytes_in_l1);
709ce0d9371SArne Jansen printf("l1 ghost | % 10lld | %16lld\n", bufs_in_l1_ghost,
710ce0d9371SArne Jansen bytes_in_l1_ghost);
711ce0d9371SArne Jansen printf(" in l2 | % 10lld | %16lld\n", bufs_in_l2, bytes_in_l2);
712ce0d9371SArne Jansen printf(" total | % 10lld | %16lld\n", bufs_total, bytes_total);
713ce0d9371SArne Jansen printf("\n");
714ce0d9371SArne Jansen }
715ce0d9371SArne Jansen
716ce0d9371SArne Jansen static void
usage(const char * basename)717ce0d9371SArne Jansen usage(const char *basename)
718ce0d9371SArne Jansen {
719ce0d9371SArne Jansen (void) fprintf(stderr,
720ce0d9371SArne Jansen "Usage: %s -d [options]\n"
721ce0d9371SArne Jansen " %s {-c | -i} [options] [command [args]]\n\n"
722ce0d9371SArne Jansen "\tOptions:\n"
723ce0d9371SArne Jansen "\t -c run command and record read blocks\n"
724ce0d9371SArne Jansen "\t -i filename read previously recorded output from -o instead\n"
725ce0d9371SArne Jansen "\t of running a command\n"
726ce0d9371SArne Jansen "\t -b bufsize change tracing bufsize\n"
727ce0d9371SArne Jansen "\t -a dump arc\n"
728ce0d9371SArne Jansen "\t -v verbose\n"
729ce0d9371SArne Jansen "\t -w watch decay of buffers in arc\n"
730ce0d9371SArne Jansen "\t -d seconds watch interval\n"
731ce0d9371SArne Jansen "\t -o filename write output to file\n",
732ce0d9371SArne Jansen basename, basename);
733ce0d9371SArne Jansen exit(1);
734ce0d9371SArne Jansen }
735ce0d9371SArne Jansen
736ce0d9371SArne Jansen /*
737ce0d9371SArne Jansen * TODO: compare 2 traces
738ce0d9371SArne Jansen * TODO: compare 2 arc infos
739ce0d9371SArne Jansen * TODO: persistent spa numbering
740ce0d9371SArne Jansen */
741ce0d9371SArne Jansen int
main(int argc,char ** argv)742ce0d9371SArne Jansen main(int argc, char **argv)
743ce0d9371SArne Jansen {
744ce0d9371SArne Jansen extern char *optarg;
745ce0d9371SArne Jansen extern int optind;
746ce0d9371SArne Jansen int c;
747ce0d9371SArne Jansen char *bufsize = "4m";
748ce0d9371SArne Jansen int run_cmd = 0;
749ce0d9371SArne Jansen int watch = 0;
750ce0d9371SArne Jansen char *basename;
751ce0d9371SArne Jansen char *out_fn = NULL;
752ce0d9371SArne Jansen char *in_fn = NULL;
753ce0d9371SArne Jansen avl_tree_t awr;
754ce0d9371SArne Jansen uint64_t color = 0;
755ce0d9371SArne Jansen int interval = 10;
756ce0d9371SArne Jansen int dump_arc = 0;
757ce0d9371SArne Jansen char *arc_fn = NULL;
758ce0d9371SArne Jansen
759ce0d9371SArne Jansen avl_create(&awr, awr_cmp, sizeof(arc_read_node_t),
760ce0d9371SArne Jansen offsetof(arc_read_node_t, arn_node));
761ce0d9371SArne Jansen basename = strrchr(argv[0], '/');
762ce0d9371SArne Jansen if (basename == NULL)
763ce0d9371SArne Jansen basename = argv[0];
764ce0d9371SArne Jansen
765ce0d9371SArne Jansen while ((c = getopt(argc, argv, "b:o:i:cvwhd:aI:")) != EOF) {
766ce0d9371SArne Jansen switch(c) {
767ce0d9371SArne Jansen case 'b':
768ce0d9371SArne Jansen bufsize = optarg;
769ce0d9371SArne Jansen break;
770ce0d9371SArne Jansen case 'c':
771ce0d9371SArne Jansen run_cmd = 1;
772ce0d9371SArne Jansen break;
773ce0d9371SArne Jansen case 'w':
774ce0d9371SArne Jansen watch = 1;
775ce0d9371SArne Jansen break;
776ce0d9371SArne Jansen case 'v':
777ce0d9371SArne Jansen ++g_verbose;
778ce0d9371SArne Jansen break;
779ce0d9371SArne Jansen case 'o':
780ce0d9371SArne Jansen out_fn = optarg;
781ce0d9371SArne Jansen break;
782ce0d9371SArne Jansen case 'i':
783ce0d9371SArne Jansen in_fn = optarg;
784ce0d9371SArne Jansen break;
785ce0d9371SArne Jansen case 'I':
786ce0d9371SArne Jansen arc_fn = optarg;
787ce0d9371SArne Jansen break;
788ce0d9371SArne Jansen case 'a':
789ce0d9371SArne Jansen dump_arc = 1;
790ce0d9371SArne Jansen break;
791ce0d9371SArne Jansen case 'd':
792ce0d9371SArne Jansen interval = atoi(optarg);
793ce0d9371SArne Jansen break;
794ce0d9371SArne Jansen case 'h':
795ce0d9371SArne Jansen default:
796ce0d9371SArne Jansen usage(basename);
797ce0d9371SArne Jansen }
798ce0d9371SArne Jansen }
799ce0d9371SArne Jansen
800ce0d9371SArne Jansen if (optind != argc && !run_cmd) {
801ce0d9371SArne Jansen fprintf(stderr, "command given without -c switch\n");
802ce0d9371SArne Jansen exit(1);
803ce0d9371SArne Jansen }
804ce0d9371SArne Jansen if (dump_arc) {
805ce0d9371SArne Jansen get_arc(NULL, 0, out_fn);
806ce0d9371SArne Jansen exit(0);
807ce0d9371SArne Jansen }
808ce0d9371SArne Jansen if (arc_fn != NULL && !run_cmd && in_fn == NULL) {
809*f264e978SArne Jansen read_arc(&awr, arc_fn, 1, 1);
810ce0d9371SArne Jansen exit(1);
811ce0d9371SArne Jansen }
812ce0d9371SArne Jansen if (arc_fn != NULL && watch) {
813ce0d9371SArne Jansen fprintf(stderr, "-I given with -w\n");
814ce0d9371SArne Jansen exit(1);
815ce0d9371SArne Jansen }
816ce0d9371SArne Jansen if (run_cmd && (in_fn != NULL)) {
817ce0d9371SArne Jansen fprintf(stderr, "-i and -c are mutually exclusive\n");
818ce0d9371SArne Jansen exit(1);
819ce0d9371SArne Jansen }
820ce0d9371SArne Jansen if (run_cmd) {
821ce0d9371SArne Jansen if (optind == argc) {
822ce0d9371SArne Jansen fprintf(stderr, "no command given\n");
823ce0d9371SArne Jansen exit(1);
824ce0d9371SArne Jansen }
825ce0d9371SArne Jansen run_dtrace(bufsize, out_fn, &awr, argc - optind, argv + optind);
826ce0d9371SArne Jansen }
827ce0d9371SArne Jansen if (in_fn)
828ce0d9371SArne Jansen read_awr(&awr, in_fn);
829ce0d9371SArne Jansen if (watch) {
830ce0d9371SArne Jansen while (1) {
831ce0d9371SArne Jansen get_arc(&awr, ++color, NULL);
832ce0d9371SArne Jansen awr_stat(&awr, color);
833ce0d9371SArne Jansen sleep(10);
834ce0d9371SArne Jansen }
835ce0d9371SArne Jansen }
836ce0d9371SArne Jansen if (arc_fn) {
837*f264e978SArne Jansen read_arc(&awr, arc_fn, 1, 0);
838ce0d9371SArne Jansen awr_stat(&awr, 1);
839ce0d9371SArne Jansen }
840ce0d9371SArne Jansen
841ce0d9371SArne Jansen exit(0);
842ce0d9371SArne Jansen }
843