#!/usr/bin/stap
global starts
global times
global fds
global paths
global files
global reads
global writes
function
logmsg (path:string,
direction:string,
duration:long,
bytes:long)
{
now_ms = gettimeofday_ms()
now_s = now_ms / 1000
now_ms = now_ms % 1000
duration_ms = duration / 1000
duration_us = duration % 1000
printf("pid:%-5u @%10u.%03u (%03u.%03u) %s ~%uk %s\n",
pid(),
now_s, now_ms,
duration_ms, duration_us,
direction,
bytes / 1024,
path
)
}
function
logerr (path:string)
{
logmsg(path, "!", 0, 0)
}
function
delete_counters (fd:long)
{
p = pid()
delete reads[p,fd]
delete writes[p,fd]
delete files[p,fd]
delete fds[p]
delete starts[p]
delete times[p,fd]
}
function
interesting:long ()
{
if (argc == 0)
return 1
for (i = 1; i <= $#; i++)
if (pid() == strtol(argv[i], 10))
return 1
return 0
}
probe
syscall.open
{
if (!interesting())
next
paths[pid()] = user_string($filename)
}
probe
syscall.open.return
{
if (!interesting())
next
fd = $return
if (fd == -1) {
logerr(paths[p]);
next
}
p = pid()
reads[p,fd] = 0
writes[p,fd] = 0
files[p,fd] = paths[p]
delete paths[p]
}
probe
syscall.read
{
if (!interesting())
next
p = pid()
reads[p,$fd] += $count
starts[p] = gettimeofday_us()
fds[p] = $fd
}
probe
syscall.read.return,
syscall.write.return
{
if (!interesting())
next
p = pid()
fd = fds[p]
times[p,fd] <<< (gettimeofday_us() - starts[p])
}
probe
syscall.write
{
if (!interesting())
next
p = pid()
writes[p, $fd] += $count
starts[p] = gettimeofday_us()
fds[p] = $fd
}
probe
syscall.close
{
if (!interesting())
next
p = pid()
if (files[p,$fd] == "") {
delete_counters($fd)
next
}
read = reads[p,$fd]
write = writes[p,$fd]
if (!read && !write) {
delete_counters($fd)
next
} else if (!read && write) {
direction = ">"
bytes = write
} else if (read && !write) {
direction = "<"
bytes = read
} else if (read && write) {
direction = "="
bytes = 0
}
logmsg(files[p,$fd], direction, @sum(times[p,$fd]), bytes)
}