#!/usr/bin/perl # # intrtime - Sample and print interrput handler times. # Written using DTrace (Solaris 10 x86 build 63). # # Time spent by the kernel servicing interrupts is not easily # meausrable under Unix, intrtime gives a break down of the # interrupt types and times spent services each. # # 01-Mar-2005, ver 0.84 (check for newer versions) # # # USAGE: intrtime [secs] # # intrtime # default output, 1 second # intrtime 10 # sample for 10 seconds # # FIELDS: # # Interrput Interrput name # Time(ns) Total time spent in this interrput (ns) # Time% Percent this time is of TOTAL(dur) # TOTAL(int) Total time spent in interrupts # TOTAL(dur) Duration for this sample # # NOTE: This currently does not count the number of CPUs, so # Time% should really be divided by the number of CPUs handling # interrupts. # # SEE ALSO: Chapter 22, Solaris Dynamic Tracing Guide, docs.sun.com. # intrstat (and I wish I had discovered this sooner!) # # Standard Disclaimer: This is freeware, use at your own risk. # # Author: Brendan Gregg [Sydney, Australia] # # 27-Feb-2005 Brendan Gregg Created this. # 01-Mar-2005 " " Now using device major names. # ### Process Arguments &usage() if $ARGV[0] =~ /^-/; &usage() if $ARGV[0] =~ /^\D/; $secs = $ARGV[0] || 1; $| = 1; ### name_to_major to major_to_name open(MAJOR,"/etc/name_to_major") || die("ERROR1: Can't read /etc/name_to_major: $!\n"); chomp(@Lines = ); close MAJOR; foreach $line (@Lines) { ($name,$num) = split(' ',$line); $Major_to_name{$num} = $name; } # # DTrace Script # $intr_d = '/usr/sbin/dtrace -qn \' /* This measures interrput thread times */ dtrace:::BEGIN { self->begin = timestamp; secs = ' . $secs . '; } profile:::tick-1sec /secs > 0/ { secs--; } profile:::tick-1sec /secs == 0/ { exit(0); } sdt:::interrupt-start { self->start = timestamp; } sdt:::interrupt-complete { this->delta = timestamp - self->start; this->devinfo = (struct dev_info *)arg0; major = this->devinfo == 0 ? -1 : this->devinfo->devi_major; @Ints[major] = sum(this->delta); @Totals["TOTAL(int)"] = sum(this->delta); self->start = 0; } dtrace:::END { @Totals["TOTAL(dur)"] = sum(timestamp - self->begin); printa("%12d %16@d\n",@Ints); printa("%12s %16@d\n",@Totals); }\''; # # Execute DTrace # @Lines = `$intr_d`; # # Print Report # foreach $line (@Lines) { $line =~ s/^ *//; ($major,$ns) = split(' ',$line); $totaldur = $ns if $major eq "TOTAL(dur)"; } printf("%12s %16s %7s\n","Interrupt","Time(ns)","%Time"); foreach $line (@Lines) { next if $line =~ /^\s*$/; ($major,$ns) = split(' ',$line); if ($major !~ /^\s*TOTAL/) { next if $major < 0 || $major > 65536; # translate majors to device names, $name = $Major_to_name{$major}; # (the answerbook has an elegant dtrace method for this) } else { $name = $major; } printf("%12s %16s %7.2f\n",$name,$ns,($ns*100/$totaldur)); } # usage - print usage and exit. # sub usage { print STDERR "USAGE: intrtime [secs]\n"; print STDERR " eg,\n"; print STDERR " intrtime # default output, 1 second\n"; print STDERR " intrtime 10 # sample for 10 seconds\n"; exit(1); }