Dtrace one-liners for gathering insight from IO probes.
dtrace -qn '
BEGIN {
start = walltimestamp;
}
io:::start {
@bytes[args[0]->b_flags & B_READ ? "R" : "W"] = quantize(args[0]->b_bcount);
@s[args[0]->b_flags & B_READ ? "R" : "W"] = sum(args[0]->b_bcount);
@iops[args[0]->b_flags & B_READ ? "R" : "W"] = count();
@avsz[args[0]->b_flags & B_READ ? "R" : "W"] = avg(args[0]->b_bcount);
@bytesbycmd[execname, args[0]->b_flags & B_READ ?
"R" : "W"] = quantize(args[0]->b_bcount);
}
END {
/* Convert runtime to seconds to calculate IOPS.
However, this does not account for idle time. */
this->runtime = (walltimestamp - start) / 1000000000;
normalize(@iops, this->runtime);
normalize(@s, 1024);
printa("Operation [%s]: %@d(KB) IOPS: %@d Avg. IOsize: %@d%@d\n",
@s, @iops, @avsz, @bytes);
printa("Program: %s [%s] %@d\n", @bytesbycmd);
}'
// Basic IO size and byte sum, split by READ/WRITE.
dtrace -qn '
BEGIN {
start = walltimestamp;
}
io:::start {
@bytes[args[0]->b_flags & B_READ ? "R" : "W"] = quantize(args[0]->b_bcount);
@s[args[0]->b_flags & B_READ ? "R" : "W"] = sum(args[0]->b_bcount);
@iops[args[0]->b_flags & B_READ ? "R" : "W"] = count();
@avsz[args[0]->b_flags & B_READ ? "R" : "W"] = avg(args[0]->b_bcount);
@bytesbycmd[execname, args[0]->b_flags & B_READ ?
"R" : "W"] = quantize(args[0]->b_bcount);
}
END {
/* Convert runtime to seconds to calculate IOPS.
However, this does not account for idle time. */
this->runtime = (walltimestamp - start) / 1000000000;
normalize(@iops, this->runtime);
normalize(@s, 1024);
printa("Operation [%s]: %@d(KB) IOPS: %@d Avg. IOsize: %@d%@d\n",
@s, @iops, @avsz, @bytes);
printa("Program: %s [%s] %@d\n", @bytesbycmd);
}'
// Observe by device name count of IOs of whatever IO sizes are being issued.
// This can become severely verbose on real, active systems. For lab use only.
dtrace -qn 'int x; io:::start {@[args[1]->dev_pathname, args[0]->b_bcount] = count(); x++;} tick-1sec /x/ {printa("Device: %s IO Bytes: %d Count: %@d\n", @); x = 0; trunc(@);}'
// Focus on a specific IO size, only selecting scsi_vhci devices.
// In this case we select only 8K IOs.
dtrace -qn 'int x; io:::start
/strstr(args[1]->dev_pathname, "/devices/scsi_vhci") != NULL && args[0]->b_bcount == 8192/ {
@cnt[args[1]->dev_pathname, args[0]->b_flags & B_READ ? "R" : "W"] = count();
@s[args[1]->dev_pathname, args[0]->b_flags & B_READ ? "R" : "W"] = sum(args[0]->b_bcount);
x=1;
}
END /x/ {
printa("Device: %s CMD: %s Count: %@d Sum: %@d\n", @cnt, @s);
}'
// Focus on IOs smaller than X size, otherwise identical to above.
// In this case we are focused on 8K< IOs.
dtrace -qn 'int x; io:::start
/strstr(args[1]->dev_pathname, "/devices/scsi_vhci") != NULL && args[0]->b_bcount <= 8 << 10/ {
@rcnt[args[1]->dev_pathname, args[0]->b_bcount] = sum(args[0]->b_flags & B_READ ? 1 : 0);
@wcnt[args[1]->dev_pathname, args[0]->b_bcount] = sum(args[0]->b_flags & B_READ ? 0 : 1);
@rs[args[1]->dev_pathname, args[0]->b_bcount] = sum(args[0]->b_flags & B_READ ? args[0]->b_bcount : 0);
@ws[args[1]->dev_pathname, args[0]->b_bcount] = sum(args[0]->b_flags & B_READ ? 0 : args[0]->b_bcount);
x=1;
}
END /x/ {
printa("Device: %s IOSize: %d R: %@d W: %@d Bytes[R]: %@d Bytes[W]: %@d\n",
@rcnt, @wcnt, @rs, @ws);
}'
// Get a detailed output where each line is a one-line summary for single drive
// over sampling period.
// Example output:
// Device: /devices/scsi_vhci/disk@g500117310073da20:a IOSize: 8192 R: 0 W: 464 Bytes[R]: 0 Bytes[W]: 3801088
dtrace -qn 'int x; io:::start
/strstr(args[1]->dev_pathname, "/devices/scsi_vhci") != NULL/ {
@rcnt[args[1]->dev_pathname, args[0]->b_bcount] = sum(args[0]->b_flags & B_READ ? 1 : 0);
@wcnt[args[1]->dev_pathname, args[0]->b_bcount] = sum(args[0]->b_flags & B_READ ? 0 : 1);
@rs[args[1]->dev_pathname, args[0]->b_bcount] = sum(args[0]->b_flags & B_READ ? args[0]->b_bcount : 0);
@ws[args[1]->dev_pathname, args[0]->b_bcount] = sum(args[0]->b_flags & B_READ ? 0 : args[0]->b_bcount);
x=1;
}
END /x/ {
printa("Device: %s IOSize: %d R: %@d W: %@d Bytes[R]: %@d Bytes[W]: %@d\n",
@rcnt, @wcnt, @rs, @ws);
}'
// Same as above, but only active while the command is being exec'd. This is useful for counting
// blocks sent to device with dd.
# dtrace -qn 'int x; io:::start {@[args[1]->dev_pathname, args[0]->b_bcount] = count(); x++; } END /x/ {printa("Device: %s IO Bytes: %d Count: %@d\n", @); x = 0; trunc(@);}' \
-c 'dd if=/dev/rdsk/c1t5d0s0 of=/dev/null bs=512 count=1'
// Select devices with blkdev@ in the path. This seems to be the case for NMVe devices,
// which is what I am interested in at the moment.
dtrace -qn '
int x;
io:::start /strstr(args[1]->dev_pathname, "blkdev@") !=NULL/
{
@[args[1]->dev_pathname, args[0]->b_bcount] = count();
x++;
}
tick-1sec /x/ {
printa("Device: %s IO Bytes: %d Count: %@d\n", @);
x = 0; trunc(@);
}'
dtrace -qn 'int x; io:::start
/strstr(args[1]->dev_pathname, "/devices/scsi_vhci") != NULL && args[0]->b_bcount <= 8 << 10/ {
@rcnt[args[1]->dev_pathname, args[0]->b_bcount] = sum(args[0]->b_flags & B_READ ? 1 : 0);
@wcnt[args[1]->dev_pathname, args[0]->b_bcount] = sum(args[0]->b_flags & B_READ ? 0 : 1);
@rs[args[1]->dev_pathname, args[0]->b_bcount] = sum(args[0]->b_flags & B_READ ? args[0]->b_bcount : 0);
@ws[args[1]->dev_pathname, args[0]->b_bcount] = sum(args[0]->b_flags & B_READ ? 0 : args[0]->b_bcount);
x=1;
}
END /x/ {
printa("Device: %s IOSize: %d R: %@d W: %@d Bytes[R]: %@d Bytes[W]: %@d\n",
@rcnt, @wcnt, @rs, @ws);
}'