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