Used this primarily to sanity-check what synthetic tools claim they are doing.
dtrace -qn '
long lastoff[char *];
long nextoff[char *];
long lastdist[char *];
long bytesW;
int first[char *];
nfsv4:::op-write-start /!first[args[1]->noi_curpath]/ {
first[args[1]->noi_curpath]++;
lastoff[args[1]->noi_curpath] = args[2]->offset / 1024;
bytesW += args[2]->data_len;
/* We predict next offset, assuming that size of IO is constant, which
* is something we expect if IO is sequential with fix length chunks.
*/
nextoff[args[1]->noi_curpath] =
(args[2]->offset / 1024) + (args[2]->data_len / 1024);
}
nfsv4:::op-write-start
/ lastoff[args[1]->noi_curpath] != (args[2]->offset / 1024) / {
this->p = args[1]->noi_curpath;
this->cur = args[2]->offset / 1024;
this->iosz = args[2]->data_len / 1024;
bytesW += args[2]->data_len;
@qoff[this->iosz] = quantize(lastoff[this->p]);
this->dist = this->cur > lastoff[this->p] ?
this->cur - lastoff[this->p] :
lastoff[this->p] - this->cur;
/* If our current offset is greater than previous offset, we are moving
* in the forward direction, and if it is actually lower than previous
* offset, we are moving in reverse direction. Direction changes are
* indicative of random IO.
*/
this->is_fw = this->cur > lastoff[this->p] ? 1 : 0;
/* nextoff[this->p] was computed previously, by adding size of last
* io to offset at that point. If our current position in the file
* equals our predicted position, stored in nextoff[this->p], we are
* doing fixed size sequential IO.
*/
this->is_seq = this->cur == nextoff[this->p];
@seqcnt[this->is_seq ? "SEQUENTIAL" : "RANDOM" ] = count();
@tot[this->is_seq ? "SEQUENTIAL" : "RANDOM" ] = sum(this->iosz);
this->dir_label = this->is_fw ? "Forward [ => ]" : "Reverse [ <= ]";
@qdist[this->dir_label] = quantize(this->dist);
lastoff[this->p] = (this->cur) - lastoff[this->p];
/* We predict next offset, assuming that size of IO is constant, which
* is something we expect if IO is sequential with fix length chunks.
*/
nextoff[this->p] = this->cur + this->iosz;
}
tick-1sec /bytesW/ {
this->b = bytesW;
bytesW = 0;
@avKBps = avg(this->b >> 10);
@minKBps = min(this->b >> 10);
@maxKBps = max(this->b >> 10);
}
END {
printa(" Seek Distance with IO Size: %d(KB) %@d\n", @qoff);
printa(" %s %@d\n", @qdist);
printf("-/- Basic Statistics -/-\n");
printa("Throughput [Avg]: %8@d(KB) | [Min]: %8@d(KB) | [Max]: %8@d(KB)\n",
@avKBps, @minKBps, @maxKBps);
printa("%s IOs count: %@d totaling %@d(KB)\n", @seqcnt, @tot);
}'