Add a memdump page to the admin controller, makes heapy output slightly

browsable and provides an entry point to heapy (via editing the
template) while the server is running.
This commit is contained in:
Nate Coraor
2008-10-27 17:03:50 -04:00
parent b74f176613
commit 6940dae0ee
4 changed files with 127 additions and 5 deletions
+1
View File
@@ -35,6 +35,7 @@ class UniverseApplication( object ):
self.job_queue = jobs.JobQueue( self, job_dispatcher )
self.job_stop_queue = jobs.JobStopQueue( self, job_dispatcher )
self.heartbeat = None
self.memdump = None
# Start the heartbeat process if configured and available
if self.config.use_heartbeat:
from galaxy.util import heartbeat
+12 -5
View File
@@ -22,22 +22,29 @@ else:
self.fname = fname
signal.signal( signum, self.dump )
self.heapy = guppy.hpy()
self.heap = None
def dump( self, signum, stack ):
file = open( self.fname, "a" )
print >> file, "Memdump for pid %d at %s" % ( os.getpid(), time.asctime() )
print >> file
try:
h = self.heapy.heap()
self.heap = self.heapy.heap()
print >> file, "heap():"
print >> file, h
print >> file, self.heap
print >> file, "\nbyrcs:"
print >> file, h.byrcs
print >> file, self.heap.byrcs
print >> file, "\nbyrcs[0].byid:"
print >> file, h.byrcs[0].byid
print >> file, self.heap.byrcs[0].byid
print >> file, "\nget_rp():"
print >> file, h.get_rp()
print >> file, self.heap.get_rp()
self.heapy.setref()
except AssertionError:
pass
print >> file, "\nEnd dump\n"
file.close()
def setref( self ):
self.heapy.setref()
def get( self, update=False ):
if update:
self.heap = self.heapy.heap()
return self.heap
+39
View File
@@ -22,3 +22,42 @@ class Admin( BaseController ):
else:
msg = 'Invalid password'
return msg
@web.expose
def memdump( self, trans, ids = 'None', sorts = 'None', pages = 'None', new_id = None, new_sort = None, **kwd ):
if self.app.memdump is None:
return trans.show_error_message( "Memdump is not enabled (set <code>use_memdump = True</code> in universe_wsgi.ini)" )
heap = self.app.memdump.get()
p = util.Params( kwd )
msg = None
if p.dump:
heap = self.app.memdump.get( update = True )
msg = "Heap dump complete"
elif p.setref:
self.app.memdump.setref()
msg = "Reference point set (dump to see delta from this point)"
ids = ids.split( ',' )
sorts = sorts.split( ',' )
if new_id is not None:
ids.append( new_id )
sorts.append( 'None' )
elif new_sort is not None:
sorts[-1] = new_sort
breadcrumb = "<a href='%s' class='breadcrumb'>heap</a>" % web.url_for()
# new lists so we can assemble breadcrumb links
new_ids = []
new_sorts = []
for id, sort in zip( ids, sorts ):
new_ids.append( id )
if id != 'None':
breadcrumb += "<a href='%s' class='breadcrumb'>[%s]</a>" % ( web.url_for( ids=','.join( new_ids ), sorts=','.join( new_sorts ) ), id )
heap = heap[int(id)]
new_sorts.append( sort )
if sort != 'None':
breadcrumb += "<a href='%s' class='breadcrumb'>.by('%s')</a>" % ( web.url_for( ids=','.join( new_ids ), sorts=','.join( new_sorts ) ), sort )
heap = heap.by( sort )
ids = ','.join( new_ids )
sorts = ','.join( new_sorts )
if p.theone:
breadcrumb += ".theone"
heap = heap.theone
return trans.fill_template( '/admin/memdump.mako', heap = heap, ids = ids, sorts = sorts, breadcrumb = breadcrumb, msg = msg )
+75
View File
@@ -0,0 +1,75 @@
<%inherit file="/base.mako"/>
<%def name="title()">Memory Profiling</%def>
<%
import re
from xml.sax.saxutils import escape, unescape
%>
<style type="text/css">
a.breadcrumb:link,
a.breadcrumb:visited,
a.breadcrumb:active {
text-decoration: none;
}
a.breadcrumb:hover {
text-decoration: underline;
}
</style>
<h2>Memory Profiling</h2>
<ul class="manage-table-actions">
<li><a class="action-button" href="${h.url_for( controller='admin', action='memdump', dump=True )}">Dump memory (warning: hangs server!)</a></li>
<li><a class="action-button" href="${h.url_for( controller='admin', action='memdump', setref=True )}">Set reference point</a></li>
</ul>
<%def name="htmlize( heap )">
<%
s = escape( str( heap ) )
new_s = ""
id_re = re.compile('^(\s+)([0-9]+)')
for line in s.split( '\n' ):
try:
id = id_re.search( line ).group( 2 )
except:
id = None
new_s += re.sub( id_re, r'\1<a href="' + h.url_for( controller='admin', action='memdump', ids=ids, sorts=sorts, new_id=id ) + r'">\2</a>', line )
if id and heap[int(id)].count == 1:
new_s += " <a href='%s'>theone</a>\n" % h.url_for( ids=ids, sorts=sorts, new_id=id, theone=True )
else:
new_s += "\n"
return new_s
%>
</%def>
%if msg:
<div class="donemessage">${msg}</div>
%endif
%if heap is None:
No memory dump available. Click "Dump memory" to create one.
%else:
<pre>
<br/>
You are here: ${breadcrumb}<br/>
%if breadcrumb.endswith( 'theone' ):
${heap}
%else:
<nobr>
Sort:
<a href="${h.url_for( controller='admin', action='memdump', ids=ids, sorts=sorts, new_sort='Class')}">Class</a> |
<a href="${h.url_for( controller='admin', action='memdump', ids=ids, sorts=sorts, new_sort='Clodo' )}">Clodo</a> |
<a href="${h.url_for( controller='admin', action='memdump', ids=ids, sorts=sorts, new_sort='Id' )}">Id</a> |
<a href="${h.url_for( controller='admin', action='memdump', ids=ids, sorts=sorts, new_sort='Idset' )}">Idset</a> |
<a href="${h.url_for( controller='admin', action='memdump', ids=ids, sorts=sorts, new_sort='Module' )}">Module</a> |
<a href="${h.url_for( controller='admin', action='memdump', ids=ids, sorts=sorts, new_sort='Unity' )}">Unity</a> |
<a href="${h.url_for( controller='admin', action='memdump', ids=ids, sorts=sorts, new_sort='Rcs' )}">Rcs</a> |
<a href="${h.url_for( controller='admin', action='memdump', ids=ids, sorts=sorts, new_sort='Size' )}">Size</a> |
<a href="${h.url_for( controller='admin', action='memdump', ids=ids, sorts=sorts, new_sort='Type' )}">Type</a> |
<a href="${h.url_for( controller='admin', action='memdump', ids=ids, sorts=sorts, new_sort='Via' )}">Via</a>
</nobr>
${htmlize( heap )}
%endif
</pre>
%endif