#!/usr/bin/ruby -w # # tdg - Thread Dump Grapher (any better name?) # # Given a Java Thread Dump file as argument, it prints out # a Grapviz (.dot) to generate a graph that shows which threads # are waiting on others for a lock. # (tested with a Sun JDK 1.4 thread dump) # class ThreadInfo attr_accessor :stack, :name, :locks, :to_lock, :tid, :runnable def stack() @stack end def stack=(stack) @stack = stack end def initialize(id, name) @tid = id @name = name @runnable = false @locks= [] @to_lock= nil end end ### Main filename = ARGV.shift if filename == nil || ! File.readable?(filename) : fail( "Usage: $0 ") end # Parse thread dump file lock_to_thread = {} threads = [] #thread_to_lock = {} File.open(filename) do |file| processing = false currentThread = nil file.each_line do |line| # skip heading lines that are not part of the Thread dump processing ||= ( line =~ /Full thread dump/ ) next if not processing case line when /^"(.*)".*tid=(\w+) +nid=\w+ (runnable)?/ currentThread = ThreadInfo.new($2, $1) currentThread.runnable = ($3 != nil) threads << currentThread when /locked <(\w+)>/ if currentThread != nil then currentThread.locks << $1 # thread_to_lock[currentThread.tid] ||= [] # thread_to_lock[currentThread.tid] << $1 lock_to_thread[$1] = currentThread.tid end when /waiting to lock <(\w+)>/ currentThread.to_lock = $1 if currentThread != nil end end end ## Generate output print < Thread#{lockOwner} [taillabel="#{t.to_lock}" arrowhead=normal,arrowtail=none]; EOS end end print "}"