[pypy-svn] r68885 - in pypy/branch/logging2/pypy/tool: . test
arigo at codespeak.net
arigo at codespeak.net
Sun Nov 1 11:15:20 CET 2009
Author: arigo
Date: Sun Nov 1 11:15:20 2009
New Revision: 68885
Added:
pypy/branch/logging2/pypy/tool/test/test_logparser.py (contents, props changed)
Modified:
pypy/branch/logging2/pypy/tool/logparser.py
Log:
Incorporate the JIT in the numbers, and display
summary histograms.
Modified: pypy/branch/logging2/pypy/tool/logparser.py
==============================================================================
--- pypy/branch/logging2/pypy/tool/logparser.py (original)
+++ pypy/branch/logging2/pypy/tool/logparser.py Sun Nov 1 11:15:20 2009
@@ -33,14 +33,65 @@
def getsubcategories(log):
return [entry for entry in log if entry[0] != 'debug_print']
+def gettimebounds(log):
+ # returns (mintime, maxtime)
+ maincats = getsubcategories(log)
+ return (maincats[0][1], maincats[-1][2])
+
+def gettotaltimes(log):
+ # returns a dict {'label' or None: totaltime}
+ def rectime(category1, timestart1, timestop1, subcats):
+ substartstop = []
+ for entry in getsubcategories(subcats):
+ rectime(*entry)
+ substartstop.append(entry[1:3]) # (start, stop)
+ # compute the total time for category1 as the part of the
+ # interval [timestart1, timestop1] that is not covered by
+ # any interval from one of the subcats.
+ mytime = 0
+ substartstop.sort()
+ for substart, substop in substartstop:
+ if substart >= timestop1:
+ break
+ if substart > timestart1:
+ mytime += substart - timestart1
+ if timestart1 < substop:
+ timestart1 = substop
+ if timestart1 < timestop1:
+ mytime += timestop1 - timestart1
+ #
+ try:
+ result[category1] += mytime
+ except KeyError:
+ result[category1] = mytime
+ #
+ result = {}
+ timestart0, timestop0 = gettimebounds(log)
+ rectime(None, timestart0, timestop0, log)
+ return result
+
# ____________________________________________________________
COLORS = {
+ None: (248, 248, 248),
'': (160, 160, 160),
- 'gc-': (192, 0, 64),
+ 'gc-': (224, 0, 0),
'gc-minor': (192, 0, 16),
'gc-collect': (255, 0, 0),
+ 'jit-': (0, 224, 0),
+ 'jit-running': (192, 255, 160),
+ 'jit-tracing': (0, 255, 0),
+ 'jit-optimize': (160, 255, 0),
+ 'jit-backend': (0, 255, 144),
+ 'jit-blackhole': (0, 160, 0),
+ }
+SUMMARY = {
+ None: 'normal execution',
+ '': 'other',
+ 'gc-': 'gc',
+ 'jit-': 'jit',
+ 'jit-running': 'jit-running',
}
def getcolor(category):
@@ -73,14 +124,25 @@
_cache[text] = sx, sy, texthoriz, textvert
return _cache[text]
+def bevelrect(draw, (x1, y1, x2, y2), color):
+ if x2 <= x1:
+ x2 = x1 + 1 # minimal width
+ elif x2 >= x1 + 4:
+ draw.line((x1, y1+1, x1, y2-1), fill=getlightercolor(color))
+ x1 += 1
+ x2 -= 1
+ draw.line((x2, y1+1, x2, y2-1), fill=getdarkercolor(color))
+ draw.line((x1, y1, x2-1, y1), fill=getlightercolor(color))
+ y1 += 1
+ y2 -= 1
+ draw.line((x1, y2, x2-1, y2), fill=getdarkercolor(color))
+ draw.rectangle((x1, y1, x2-1, y2-1), fill=color)
+
+# ----------
-def get_timeline_image(log, width=900, height=150):
+def get_timeline_image(log, width, height):
from PIL import Image, ImageDraw
- width = int(width)
- height = int(height)
- maincats = getsubcategories(log)
- timestart0 = maincats[0][1]
- timestop0 = maincats[-1][2]
+ timestart0, timestop0 = gettimebounds(log)
assert timestop0 > timestart0
timefactor = float(width) / (timestop0 - timestart0)
#
@@ -91,21 +153,13 @@
x2 = int((timestop1 - timestart0) * timefactor)
y1 = (height - subheight) / 2
y2 = y1 + subheight
+ y1 = int(y1)
+ y2 = int(y2)
color = getcolor(category1)
if firstx1 is None:
firstx1 = x1
- if x2 <= x1:
- x2 = x1 + 1 # minimal width
- elif x2 >= x1 + 4:
- draw.line([x1, y1+1, x1, y2-1], fill=getlightercolor(color))
- x1 += 1
- x2 -= 1
- draw.line([x2, y1+1, x2, y2-1], fill=getdarkercolor(color))
- draw.line([x1, y1, x2-1, y1], fill=getlightercolor(color))
- y1 += 1
- y2 -= 1
- draw.line([x1, y2, x2-1, y2], fill=getdarkercolor(color))
- draw.rectangle([x1, y1, x2-1, y2-1], fill=color)
+ bevelrect(draw, (x1, y1, x2, y2), color)
+ subcats = getsubcategories(subcats)
if subcats:
x2 = recdraw(subcats, subheight * 0.94) - 1
sx, sy, texthoriz, textvert = getlabel(category1)
@@ -115,13 +169,131 @@
image.paste(textvert, (x1+1, y1+5), textvert)
return firstx1
#
- image = Image.new("RGBA", (width, height), (0, 0, 0, 0))
+ image = Image.new("RGBA", (width, height), (255, 255, 255, 0))
draw = ImageDraw.Draw(image)
- recdraw(maincats, height)
+ recdraw(getsubcategories(log), height)
return image
-def draw_timeline_image(log, output=None, **kwds):
- image = get_timeline_image(log, **kwds)
+# ----------
+
+def render_histogram(times, time0, labels, width, barheight):
+ # Render a histogram showing horizontal time bars are given by the
+ # 'times' dictionary. Each entry has the label specified by 'labels',
+ # or by default the key used in 'times'.
+ from PIL import Image, ImageDraw
+ times = [(time, key) for (key, time) in times.items()]
+ times.sort()
+ times.reverse()
+ images = []
+ for time, key in times:
+ fraction = float(time) / time0
+ if fraction < 0.01:
+ break
+ color = getcolor(key)
+ image = Image.new("RGBA", (width, barheight), (255, 255, 255, 0))
+ draw = ImageDraw.Draw(image)
+ x2 = int(fraction * width)
+ bevelrect(draw, (0, 0, x2, barheight), color)
+ # draw the labels "x%" and "key"
+ percent = "%.1f%%" % (100.0 * fraction,)
+ s1x, s1y, textpercent, vtextpercent = getlabel(percent)
+ s2x, _, textlabel, _ = getlabel(labels.get(key, key))
+ t1x = 5
+ if t1x + s1x >= x2 - 3:
+ if t1x + s1y < x2 - 3:
+ textpercent = vtextpercent
+ s1x = s1y
+ else:
+ t1x = x2 + 6
+ t2x = t1x + s1x + 12
+ if t2x + s2x >= x2 - 3:
+ t2x = max(t2x, x2 + 8)
+ image.paste(textpercent, (t1x, 5), textpercent)
+ image.paste(textlabel, (t2x, 5), textlabel)
+ images.append(image)
+ return combine(images, spacing=0, border=1, horizontal=False)
+
+def get_timesummary_single_image(totaltimes, totaltime0, componentdict,
+ width, barheight):
+ # Compress the totaltimes dict so that its only entries left are
+ # from componentdict. We do that by taking the times assigned to
+ # subkeys in totaltimes and adding them to the superkeys specified
+ # in componentdict.
+ totaltimes = totaltimes.copy()
+ for key, value in totaltimes.items():
+ if key in componentdict:
+ continue
+ del totaltimes[key]
+ if key is not None:
+ while key not in componentdict:
+ key = key[:-1]
+ try:
+ totaltimes[key] += value
+ except KeyError:
+ totaltimes[key] = value
+ return render_histogram(totaltimes, totaltime0, componentdict,
+ width, barheight)
+
+def get_timesummary_image(log, summarywidth, summarybarheight):
+ timestart0, timestop0 = gettimebounds(log)
+ totaltime0 = timestop0 - timestart0
+ totaltimes = gettotaltimes(log)
+ spacing = 50
+ width = (summarywidth - spacing) // 2
+ img1 = get_timesummary_single_image(totaltimes, totaltime0, SUMMARY,
+ width, summarybarheight)
+ if None in totaltimes:
+ del totaltimes[None]
+ img2 = render_histogram(totaltimes, totaltime0, {},
+ width, summarybarheight)
+ return combine([img1, img2], spacing=spacing, horizontal=True)
+
+# ----------
+
+def combine(imagelist, spacing=50, border=0, horizontal=False):
+ if len(imagelist) <= 1 and not border:
+ return imagelist[0]
+ from PIL import Image, ImageDraw
+ wlist = [image.size[0] for image in imagelist]
+ hlist = [image.size[1] for image in imagelist]
+ if horizontal:
+ w = sum(wlist) + spacing*(len(imagelist)-1)
+ h = max(hlist)
+ else:
+ w = max(wlist)
+ h = sum(hlist) + spacing*(len(imagelist)-1)
+ w += 2*border
+ h += 2*border
+ bigimage = Image.new("RGBA", (w, h), (255, 255, 255, 0))
+ if border:
+ draw = ImageDraw.Draw(bigimage)
+ draw.rectangle((0, 0, w-1, border-1), fill=(0, 0, 0))
+ draw.rectangle((0, h-border, w-1, h-1), fill=(0, 0, 0))
+ draw.rectangle((0, 0, border-1, h-1), fill=(0, 0, 0))
+ draw.rectangle((w-1, 0, w-border, h-1), fill=(0, 0, 0))
+ x = border
+ y = border
+ for image in imagelist:
+ bigimage.paste(image, (x, y))
+ if horizontal:
+ x += image.size[0] + spacing
+ else:
+ y += image.size[1] + spacing
+ return bigimage
+
+def draw_timeline_image(log, output=None, mainwidth=3000, mainheight=150,
+ summarywidth=850, summarybarheight=40):
+ mainwidth = int(mainwidth)
+ mainheight = int(mainheight)
+ summarywidth = int(summarywidth)
+ summarybarheight = int(summarybarheight)
+ images = []
+ if mainwidth > 0 and mainheight > 0:
+ images.append(get_timeline_image(log, mainwidth, mainheight))
+ if summarywidth > 0 and summarybarheight > 0:
+ images.append(get_timesummary_image(log, summarywidth,
+ summarybarheight))
+ image = combine(images, horizontal=False)
if output is None:
image.save(sys.stdout, format='png')
else:
@@ -131,7 +303,10 @@
ACTIONS = {
- 'draw-time': (draw_timeline_image, ['width=', 'height=', 'output=']),
+ 'draw-time': (draw_timeline_image, ['output=',
+ 'mainwidth=', 'mainheight=',
+ 'summarywidth=', 'summarybarheight=',
+ ]),
}
if __name__ == '__main__':
Added: pypy/branch/logging2/pypy/tool/test/test_logparser.py
==============================================================================
--- (empty file)
+++ pypy/branch/logging2/pypy/tool/test/test_logparser.py Sun Nov 1 11:15:20 2009
@@ -0,0 +1,13 @@
+from pypy.tool.logparser import *
+
+def test_gettotaltimes():
+ result = gettotaltimes([
+ ('foo', 2, 17, [
+ ('bar', 4, 5, []),
+ ('bar', 7, 9, []),
+ ]),
+ ('bar', 20, 30, []),
+ ])
+ assert result == {None: 3, # the hole between 17 and 20
+ 'foo': 15 - 1 - 2,
+ 'bar': 1 + 2 + 10}
More information about the Pypy-commit
mailing list