#!/usr/intel/pkgs/python/2.4/bin/python2.4
#!/usr/bin/python
"""
usage code_cache_gui.py
This GUI was designed to work with the event_trace pintool.
When started it opens the file "ctrace.out" for reading
cache trace data. (event_trace opens this very same file by default and
it is best to make it a named pipe, i.e. "mkfifo ctrace.out.)
It is possible to specify another file using the "-f" option.
Tracing does not start until the "tracing button" in the lower left corner is hit.
The main window does not update certain columns automatically, hit the reload
button to do this.
It is possible to dump the current content of the main window into file.
This file can then be loaded using the "-f" option.
"""
import sys
sys.path.append("/proj/vssad/users/rmmuth/lib/python2.4/site-packages/gtk-2.0")
import gtk
import gobject
import os
import getopt
import re
#import math
import string
import bisect
#######################################################
##
#######################################################
class Trace:
Traces = {} # maps trace id to trace data
CodeCache = [] # maps code cache address to trace data
Counter = {}
def __init__(self,id,type,iaddr,caddr,nbbl,nins,codesize,stubsize,rtn):
assert( not self.__class__.Traces.has_key(id) )
self.__class__.Traces[id] = self
self.__class__.CodeCache.append( (caddr,self) )
self.__class__.Counter[iaddr] = 1 + self.__class__.Counter.get(iaddr,0)
self._id = id
self._type = type
self._iaddr = iaddr
self._caddr = caddr
self._nbbl = nbbl
self._nins = nins
self._hibranch = -1
self._codesize = codesize
self._stubsize = stubsize
self._rtn = rtn
self._in = []
self._out = []
return
def trace2markup(self):
return "%s[0x%08x, %d, %d] (0x%08x,%s) i:%s o:%s" % (self._type,self._caddr,self._codesize, self._hibranch,
self._iaddr,self._rtn,
stringify_trace_set(self._in),
stringify_trace_set(self._out))
def trace2text(self):
""" used for dumping trace into file, FIXME needs to have it own format"""
return "@%sTRACE %d 0x%08x 0x%08x %d %d %d %d %s\n" % ( self._type, self._id, self._iaddr, self._caddr,
self._nbbl, self._nins, self._codesize, self._stubsize,
self._rtn)
def trace2link(self):
s = ""
for l in self._out:
s+= "@LINK 0x%08x 0x%08x\n" % (self._caddr + max(0,self._hibranch), l._caddr)
return s
def contains_address(self,address):
return self._caddr <= address < self._caddr + self._codesize
def trace2model(self):
return (self._id, self._type, "0x%08x" % self._iaddr, self.__class__.Counter.get(self._iaddr),
"0x%08x" % self._caddr, self._nbbl,
self._nins, self._codesize, self._hibranch, self._stubsize, self._rtn,
stringify_trace_set(self._in), stringify_trace_set(self._out) )
def add_edge(self,trace,branch_offset):
if branch_offset > trace._hibranch: trace._hibranch = branch_offset
self._in.append(trace)
trace._out.append(self)
return
def FindTraceById(id):
return Trace.Traces.get(id,None)
def FindTraceByAddress(address):
print "looking for 0x%x" % address
index = -1 + bisect.bisect_left(Trace.CodeCache, (address,1) ) # the "1" is a hack to make the binary search work
print "found ",index
return Trace.CodeCache[index][1]
def stringify_trace_set(set):
return "{" + string.join( [str(i._id) for i in set],",") + "}"
def DumpTraceFile(filename):
out = file(filename,"w+")
for (addr, trace) in Trace.CodeCache:
out.write( trace.trace2text() )
for (addr, trace) in Trace.CodeCache:
out.write( trace.trace2link() )
out.close()
return
#######################################################
##
#######################################################
class CodeCacheWidget:
DisplayModes = ['detailed','plain']
TableRows = [
(gobject.TYPE_UINT,"id"),
(gobject.TYPE_STRING,"type"),
# gobject.TYPE_UINT64,
# gobject.TYPE_UINT64,
(gobject.TYPE_STRING,"orig addr"),
(gobject.TYPE_UINT, "#n"),
(gobject.TYPE_STRING,"cache addr"),
(gobject.TYPE_UINT, "#bbl"),
(gobject.TYPE_UINT, "#ins"),
(gobject.TYPE_UINT, "code"),
(gobject.TYPE_INT, "hibr"),
(gobject.TYPE_UINT, "stub"),
(gobject.TYPE_STRING,"routine"),
(gobject.TYPE_STRING,"in-edges"),
(gobject.TYPE_STRING,"out-edges")]
def create_list_widget(self):
window = gtk.ScrolledWindow()
window.set_policy(gtk.POLICY_AUTOMATIC,gtk.POLICY_AUTOMATIC)
window.set_shadow_type (gtk.SHADOW_ETCHED_IN);
window.show()
view = gtk.TreeView(self._model)
for (n,(obj,title)) in enumerate(CodeCacheWidget.TableRows):
renderer = gtk.CellRendererText()
if obj == gobject.TYPE_UINT or obj == gobject.TYPE_INT:
renderer.set_property('xalign', 1.0)
column = gtk.TreeViewColumn(title, renderer, text=n)
column.set_resizable(1)
view.append_column(column)
column.set_sort_column_id(n)
view.set_search_column(1);
view.show()
window.add(view)
return window
def __init__(self):
# widgets
self._widget = None
self._model = None
self._status = None
self._label = None
# other
self._NumId = 0
self._NumBbl = 0
self._NumIns = 0
self._SizeCode = 0
self._SizeStub = 0
self._SizeX = 0
self._breakpoints = []
#
vbox = gtk.VBox()
vbox.show()
self._widget = vbox #<<<<<<<<<<<<<
############################################################################
## title row
############################################################################
hbox = gtk.HBox()
hbox.show()
vbox.pack_start(hbox,0,0)
label = gtk.Label()
label.set_markup("ha!")
label.show()
self._status = label #<<<<<<<<<<<<<
hbox.pack_start(label,0,0)
def button_reload(widget):
self._model.clear()
if self._mode == "plain":
for (addr,trace) in Trace.CodeCache:
if trace._type == "X": continue
self.add_trace(trace)
elif self._mode == "detailed":
for (addr,trace) in Trace.CodeCache:
self.add_trace(trace)
else:
assert(0)
self.update_status()
return
button = gtk.Button("Refresh Display")
button.show()
hbox.pack_end(button,0,0)
button.connect("clicked", button_reload)
self._mode = None
def combobox_changed(widget):
self._mode = widget.get_text()
return
combo = gtk.Combo()
combo.set_use_arrows_always(1)
# combo.disable_activate()
combo.entry.set_editable(0)
combo.set_popdown_strings(CodeCacheWidget.DisplayModes)
combo.entry.connect("changed", combobox_changed)
combo.show()
combobox_changed(combo.entry)
hbox.pack_end(combo,0,0,0)
############################################################################
## table
############################################################################
self._model = apply(gtk.ListStore,[obj for (obj,title) in CodeCacheWidget.TableRows])
if 1:
window = self.create_list_widget()
vbox.pack_start(window)
else:
hpane = gtk.HPaned()
hpane.show()
vbox.pack_start(hpane)
window = self.create_list_widget()
hpane.add1(window)
window = self.create_list_widget()
hpane.add2(window)
############################################################################
## individual trace
############################################################################
frame = gtk.Frame("Individual Trace")
# frame.set_shadow_type( gtk.SHADOW_ETCHED_IN)
frame.show()
vbox.pack_start(frame,0,0)
hbox = gtk.HBox()
hbox.show()
frame.add(hbox)
button = gtk.Button(" Flush ")
button.show()
hbox.pack_end(button,0,0)
label = gtk.Label(" id ")
label.show()
hbox.pack_start(label,0,0)
adjustment = gtk.Adjustment(value=0, lower=0, upper=1000000000, step_incr=1, page_incr=100, page_size=100)
spinbutton = gtk.SpinButton(adjustment, climb_rate=1.0, digits=0)
spinbutton.show()
hbox.pack_start(spinbutton,0,0)
label = gtk.Label()
label.set_markup("")
label.show()
self._label = label #<<<<<<<<<<<<<
hbox.pack_start(label,0,0)
def id_change(widget):
id = int(widget.get_value())
trace = FindTraceById(id)
self._label.set_markup( trace and trace.trace2markup() or "trace not found")
return
adjustment.connect("value_changed", id_change)
adjustment.set_value(0)
############################################################################
## action
############################################################################
frame = gtk.Frame("Trace Cache")
frame.show()
vbox.pack_start(frame,0,0)
hbox = gtk.HBox()
hbox.show()
frame.add(hbox)
button = gtk.Button(" Flush ")
button.show()
hbox.pack_end(button,0,0)
def button_stats(widget):
print self._status.get_text()
return
button = gtk.Button(" Print Stats ")
button.show()
hbox.pack_end(button,0,0)
button.connect("clicked", button_stats)
self._dump_counter = 0
def inc_and_set_count(widget):
self._dump_counter += 1
widget.set_label(" Save As: dump.%d.trace " % self._dump_counter)
return
def button_dump_trace(widget):
DumpTraceFile( "dump.%d.trace" % self._dump_counter)
inc_and_set_count(widget)
return
button = gtk.Button("")
inc_and_set_count( button )
button.show()
hbox.pack_end(button,0,0)
button.connect("clicked", button_dump_trace)
############################################################################
## breakpoints
############################################################################
frame = gtk.Frame("Break Points")
frame.show()
vbox.pack_start(frame,0,0)
hbox = gtk.HBox()
hbox.show()
frame.add(hbox)
self._tracing = 0
def button_resume(widget):
if self._tracing: return
self._tracing = 1
widget.set_label("Tracing ...")
gobject.io_add_watch(self._tf, gobject.IO_IN , TrackFile)
return
button = gtk.Button("Start Tracing")
button.show()
hbox.pack_end(button,0,0)
button.connect("clicked", button_resume)
self._trace_button = button #<<<<<<<<<<<<<
button = gtk.CheckButton("Break on Flush")
button.show()
hbox.pack_end(button,0,0)
def breakpoint_changed(widget):
self._breakpoints = [string.strip(s) for s in string.split(widget.get_text(),",")]
for (index,value) in enumerate(self._breakpoints):
try:
self._breakpoints[index] = long(value,0)
except:
pass
print "breakpoints: ", self._breakpoints
return
entry = gtk.Entry()
entry.show()
# entry.connect("activate", breakpoint_changed)
entry.connect("changed", breakpoint_changed)
hbox.pack_start(entry)
return
def get_widget(self): return self._widget
def register_tracefile(self,tf):
# assert( not self._tf)
self._tf = tf
return
def add_trace(self,trace):
self._model.append(trace.trace2model() )
return
def IncCountBbl(self,val):
self._NumBbl += val
return
def IncCountIns(self,val):
self._NumIns += val
return
def IncSizeCode(self,val):
self._SizeCode += val
return
def IncSizeStub(self,val):
self._SizeStub += val
return
def IncSizeX(self,val):
self._SizeX += val
return
def stop_tracing(self,message):
self._tracing = 0
self._trace_button.set_label(message)
return
def IsBreakpoint(self, rtn, addr):
for b in self._breakpoints:
if type(b) == type(addr) and b == addr:
GlobalCodeCacheWidget.stop_tracing(" Break at 0x%08x " % addr)
return 1
elif type(b) == type(rtn) and b == rtn:
GlobalCodeCacheWidget.stop_tracing(" Break in \"%s\" " % rtn)
return 1
return 0
def update_status(self):
if self._mode == "detailed":
self._status.set_markup("#id: %d #bbl: %d #ins: %d xsize: %d codesize: %d stubsize: %d" % \
(len(self._model),self._NumBbl,self._NumIns,self._SizeX,self._SizeCode,self._SizeStub))
elif self._mode == "plain":
self._status.set_markup("#traces: %d #bbl: %d #ins: %d codesize: %d " % \
(len(self._model),self._NumBbl,self._NumIns,self._SizeCode))
else:
assert(0)
return
#######################################################
##
#######################################################
num_lines = 0
def TrackFile(a,b):
global GlobalCodeCacheWidget
global num_lines
start = num_lines
line = None # the whole termination handling is fairly ugly - and was done by trial and error
print "receiving data ",a,
# print a,b
while os.fstat( a.fileno() )[6] > 20:
line = a.readline()
if line == "": # the whole termination handling is fairly ugly - and was done by trial and error
print "reached eof"
break
num_lines += 1
token = string.split(line)
tag = token[0]
if tag == "@LINK":
# continue
src_addr = long(token[1],0)
dst_addr = long(token[2],0)
src_trace = FindTraceByAddress(src_addr)
# if not src_trace.contains_address(src_addr):
# print "bad src trace at %x,%x for %x " % (src_trace._caddr,src_trace._codesize,src_addr)
# assert(0)
dst_trace = FindTraceByAddress(dst_addr)
# if not dst_trace._caddr == dst_addr:
# assert(0)
dst_trace.add_edge(src_trace,src_addr - src_trace._caddr)
elif tag == "@XTRACE" or tag == "@ITRACE":
id = int(token[1])
iaddr = long(token[2],0)
caddr = long(token[3],0)
nbbl = int(token[4])
nins = int(token[5])
codesize = int(token[6])
stubsize = int(token[7])
rtn = token[8]
type = tag[1]
trace = Trace(id,type,iaddr,caddr,nbbl,nins,codesize,stubsize,rtn)
GlobalCodeCacheWidget.add_trace( trace )
GlobalCodeCacheWidget.IncCountBbl( nbbl)
GlobalCodeCacheWidget.IncCountIns( nins)
if tag == "@XTRACE":
assert( stubsize == 0 )
GlobalCodeCacheWidget.IncSizeX(codesize)
else:
GlobalCodeCacheWidget.IncSizeCode(codesize)
GlobalCodeCacheWidget.IncSizeStub(stubsize)
if GlobalCodeCacheWidget.IsBreakpoint(rtn,iaddr):
print "hit breakpoint for", rtn,iaddr
line = ""
break
else:
print "unknown tag", line
# if n >= 100: break
GlobalCodeCacheWidget.update_status()
print "read %6d,%3d lines" % (start,num_lines-start)
if line == "": return 0 # the whole termination handling is fairly ugly - and was done by trial and error
return 1
#######################################################
##
#######################################################
def Main(argv):
global GlobalCodeCacheWidget
try:
opts, args = getopt.getopt(argv, "hf:")
except getopt.error:
print "Error: bad option"
print __doc__
return -1
tracefile = "ctrace.out"
for o, a in opts:
if o == "-h":
print __doc__
return 0
elif o == "-f":
tracefile = a
else:
print "Error: unsupported option " + o
print __doc__
return -1
window = gtk.Window()
def ActionDestroy(args,window):
window.destroy()
gtk.mainquit()
return
window.connect("destroy", ActionDestroy,window)
window.set_title('Code Cache GUI')
window.set_border_width(0)
GlobalCodeCacheWidget = CodeCacheWidget()
# import fcntl
tf = file(tracefile,'r',1)
GlobalCodeCacheWidget.register_tracefile(tf)
# fd = tf.fileno()
# fl = fcntl.fcntl(fd, fcntl.F_GETFL)
# fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
widget = GlobalCodeCacheWidget.get_widget()
window.add(widget)
window.show()
window.set_usize( 800, 600)
gtk.main()
#######################################################
##
#######################################################
if __name__ == "__main__":
sys.exit( Main( sys.argv[1:]) )
#######################################################
## eof
#######################################################