1N/A#!/usr/bin/sh
1N/A#
1N/A# pfilestat
1N/A#
1N/A# This prints I/O statistics for each file descriptor within a process.
1N/A# In particular, the time break down during read() and write() events is
1N/A# measured.
1N/A#
1N/A# $Id: pfilestat 4 2007-08-01 11:01:38Z brendan $
1N/A#
1N/A# USAGE: pfilestat [-r|-w] pid
1N/A#
1N/A# FIELDS:
1N/A# STATE microstate: running, sleeping, waitcpu, read, write
1N/A# FDUM File Descriptor ID
1N/A# Time Percentage of wallclock time in each STATE
1N/A# File Name of file, if known
1N/A#
1N/A# COPYRIGHT: Copyright (c) 2006 Richard McDougall.
1N/A#
1N/A# CDDL HEADER START
1N/A#
1N/A# The contents of this file are subject to the terms of the
1N/A# Common Development and Distribution License, Version 1.0 only
1N/A# (the "License"). You may not use this file except in compliance
1N/A# with the License.
1N/A#
1N/A# You can obtain a copy of the license at Docs/cddl1.txt
1N/A# or http://www.opensolaris.org/os/licensing.
1N/A# See the License for the specific language governing permissions
1N/A# and limitations under the License.
1N/A#
1N/A# CDDL HEADER END
1N/A#
1N/A# ToDo:
1N/A# Trace readv() and writev().
1N/A#
1N/A# 20-Feb-2006 Richard McDougall created this.
1N/A# 24-Feb-2006 Brendan Gregg tweaked code.
1N/A# 20-Mar-2006 " " tweaked code.
1N/A# 20-Mar-2006 " " last update.
1N/A
1N/A
1N/A##############################
1N/A# --- Process Arguments ---
1N/A#
1N/A
1N/A### Default variables
1N/Aopt_read=0; opt_write=0
1N/A
1N/A### Process options
1N/Awhile getopts hrw name
1N/Ado
1N/A case $name in
1N/A r) opt_read=1 ;;
1N/A w) opt_write=1 ;;
1N/A h|?) cat <<-END >&2
1N/A USAGE: pfilestat [-r|-w] pid
1N/A -r # reads only
1N/A -w # writes only
1N/A eg,
1N/A pfilestat pid # default, r+w counts
1N/A pfilestat -r pid # read count only
1N/A END
1N/A exit 1
1N/A esac
1N/Adone
1N/Ashift `expr $OPTIND - 1`
1N/A
1N/APID=$1
1N/Aclearstr=`clear`
1N/A
1N/Aif [ -z "$PID" ]
1N/Athen
1N/A echo "Must supply pid"
1N/A exit 1
1N/Afi
1N/A
1N/A### Option logic
1N/Aif [ $opt_read -eq 0 -a $opt_write -eq 0 ]; then
1N/A opt_read=1; opt_write=1
1N/Afi
1N/A
1N/A
1N/A#################################
1N/A# --- Main Program, DTrace ---
1N/A#
1N/A/usr/sbin/dtrace -n '
1N/A #pragma D option quiet
1N/A
1N/A inline string CLEAR = "'$clearstr'";
1N/A inline int OPT_read = '$opt_read';
1N/A inline int OPT_write = '$opt_write';
1N/A inline int PID = '$PID';
1N/A
1N/A unsigned long long totaltime;
1N/A unsigned long long totalbytes;
1N/A
1N/A enum runstate {
1N/A READ,
1N/A WRITE,
1N/A OTHER
1N/A };
1N/A
1N/A /* print header */
1N/A dtrace:::BEGIN
1N/A {
1N/A printf("Tracing ");
1N/A OPT_read && OPT_write ? printf("reads and writes") : 1;
1N/A OPT_read && ! OPT_write ? printf("reads") : 1;
1N/A ! OPT_read && OPT_write ? printf("writes") : 1;
1N/A printf("...");
1N/A totaltime = 0;
1N/A totalbytes = 0;
1N/A last = timestamp;
1N/A stamp = timestamp;
1N/A }
1N/A
1N/A /* sample reads */
1N/A syscall::read:entry,
1N/A syscall::pread*:entry
1N/A /pid == PID && OPT_read/
1N/A {
1N/A runstate = READ;
1N/A @logical["running", (uint64_t)0, ""] = sum(timestamp - last);
1N/A totaltime += timestamp - last;
1N/A last = timestamp;
1N/A
1N/A self->fd = arg0 + 1;
1N/A }
1N/A
1N/A fbt::fop_read:entry,
1N/A fbt::fop_write:entry
1N/A /self->fd/
1N/A {
1N/A self->path = args[0]->v_path == 0 ? "<none>" :
1N/A cleanpath(args[0]->v_path);
1N/A }
1N/A
1N/A syscall::read:return,
1N/A syscall::pread*:return
1N/A /pid == PID && OPT_read/
1N/A {
1N/A runstate = OTHER;
1N/A this->bytes = (int)arg0 > 0 ? (int)arg0 : 0;
1N/A @logical["read", self->fd - 1, self->path] = sum(timestamp - last);
1N/A @bytes["read", self->fd - 1, self->path] = sum(this->bytes);
1N/A totalbytes += this->bytes;
1N/A totaltime += timestamp - last;
1N/A last = timestamp;
1N/A self->path = 0;
1N/A self->fd = 0;
1N/A }
1N/A
1N/A
1N/A /* sample writes */
1N/A syscall::write:entry,
1N/A syscall::pwrite*:entry
1N/A /pid == PID && OPT_write/
1N/A {
1N/A runstate = WRITE;
1N/A @logical["running", (uint64_t)0, ""] = sum(timestamp - last);
1N/A totaltime += timestamp - last;
1N/A last = timestamp;
1N/A
1N/A self->fd = (int)arg0 + 1;
1N/A }
1N/A
1N/A syscall::write:return,
1N/A syscall::pwrite*:return
1N/A /pid == PID && OPT_write/
1N/A {
1N/A runstate = OTHER;
1N/A this->bytes = (int)arg0 > 0 ? (int)arg0 : 0;
1N/A @logical["write", self->fd - 1, self->path] = sum(timestamp - last);
1N/A @bytes["write", self->fd - 1, self->path] = sum(this->bytes);
1N/A totalbytes += this->bytes;
1N/A totaltime += timestamp - last;
1N/A last = timestamp;
1N/A self->path = 0;
1N/A self->fd = 0;
1N/A }
1N/A
1N/A sched:::on-cpu
1N/A /pid == PID/
1N/A {
1N/A @logical["waitcpu", (uint64_t)0, ""] = sum(timestamp - last);
1N/A totaltime += timestamp - last;
1N/A last = timestamp;
1N/A }
1N/A
1N/A
1N/A sched:::off-cpu
1N/A /pid == PID/
1N/A {
1N/A @logical["running", (uint64_t)0, ""] = sum(timestamp - last);
1N/A totaltime += timestamp - last;
1N/A last = timestamp;
1N/A }
1N/A
1N/A sched:::sleep
1N/A /pid == PID/
1N/A {
1N/A @logical["running", (uint64_t)0, ""] = sum(timestamp - last);
1N/A totaltime += timestamp - last;
1N/A last = timestamp;
1N/A }
1N/A
1N/A sched:::wakeup
1N/A /args[1]->pr_pid == PID && runstate == OTHER/
1N/A {
1N/A @logical["sleep", (uint64_t)0, ""] = sum(timestamp - last);
1N/A totaltime += timestamp - last;
1N/A last = timestamp;
1N/A }
1N/A
1N/A sched:::wakeup
1N/A /args[1]->pr_pid == PID && runstate == READ/
1N/A {
1N/A @logical["sleep-r", (uint64_t)0, ""] = sum(timestamp - last);
1N/A totaltime += timestamp - last;
1N/A last = timestamp;
1N/A }
1N/A
1N/A sched:::wakeup
1N/A /args[1]->pr_pid == PID && runstate == WRITE/
1N/A {
1N/A @logical["sleep-w", (uint64_t)0, ""] = sum(timestamp - last);
1N/A totaltime += timestamp - last;
1N/A last = timestamp;
1N/A }
1N/A
1N/A sched:::enqueue
1N/A /args[1]->pr_pid == PID/
1N/A {
1N/A @logical["waitcpu", (uint64_t)0, ""] = sum(timestamp - last);
1N/A totaltime += timestamp - last;
1N/A last = timestamp;
1N/A }
1N/A
1N/A sched:::dequeue
1N/A /args[1]->pr_pid == PID/
1N/A {
1N/A @logical["waitcpu", (uint64_t)0, ""] = sum(timestamp - last);
1N/A totaltime += timestamp - last;
1N/A last = timestamp;
1N/A }
1N/A
1N/A /* print report */
1N/A profile:::tick-5s
1N/A {
1N/A printf("%s", CLEAR);
1N/A normalize(@logical, totaltime / 100);
1N/A trunc(@logical, 10);
1N/A printf("%10s %7s %9s %-44s\n", "STATE", "FDNUM", "Time", "Filename");
1N/A printa("%10s %7d %@8d%% %-44.44s\n", @logical);
1N/A trunc(@logical);
1N/A
1N/A delta = timestamp - stamp;
1N/A stamp = timestamp;
1N/A normalize(@bytes, (1024 * delta) / 1000000000);
1N/A trunc(@bytes, 10);
1N/A printf("\n%10s %7s %9s %-44s\n", "STATE", "FDNUM", "KB/s",
1N/A "Filename");
1N/A printa("%10s %7d %@9d %-44.44s\n", @bytes);
1N/A trunc(@bytes);
1N/A
1N/A printf("\nTotal event time (ms): %d Total Mbytes/sec: %d\n",
1N/A totaltime / 1000000,
1N/A (totalbytes * 1000000000) / (delta * 1048576));
1N/A
1N/A totaltime = 0;
1N/A totalbytes = 0;
1N/A last = timestamp;
1N/A }
1N/A
1N/A dtrace:::END
1N/A {
1N/A trunc(@logical);
1N/A trunc(@bytes);
1N/A }
1N/A'