Commits

Leandro Lameiro  committed 9dceb48

Refactors the code to smaller functions, adds legends and uses new font for text.

  • Participants
  • Parent commits 57e8e59
  • Branches adds_legends_to_graph

Comments (0)

Files changed (4)

File scripts/LiberationSans-Bold.ttf

Binary file added.

File scripts/binlog.py

 from acts import *
 
 def unpack(raw):
-    for i in range(0, len(raw), 8):
-        ull = struct.unpack_from('Q', raw, i)[0]
+    ulls = struct.unpack('%dQ' % (len(raw)/8), raw)
+    for ull in ulls:
         s = (ull >> 60) & 0xf
         r = (ull >> 55) & 0x1f
         t = ull & ~(0x1ff << 55)
         #if t > 1160909415950669: break
         if s:
             h.enter(s, r, t)
-        else:
+        else:  # s = 0 means exit last state
             h.exit(r, t)
 
     #assert len(h.stack) == 1

File scripts/legendimgs.py

 # Create the legend
+import Image, ImageDraw, ImageFont
+import acts
 
-import os, sys
-import Image, ImageDraw, ImageFont
-import vis, acts
+font=ImageFont.truetype('LiberationSans-Bold.ttf', 22)
 
 SIZE = (32, 32)
+BLACK = (0, 0, 0)
 
-for i, c in enumerate(vis.states):
-    if i == 0: continue
+def _draw_legend(d, fill_color, outline_color, pos_x, pos_y, name):
+    d.rectangle((pos_x, pos_y, pos_x+SIZE[0], pos_y+SIZE[1]), fill_color, outline_color)
+    w,h = font.getsize(name)
+    d.text((pos_x + SIZE[0] + 5, pos_y+SIZE[1]/2-h/2), name, fill=BLACK, font=font)
+
+def draw_lengends(d, fill_colors, outline_color, pos_x, pos_y, names):      
+    for i, (name, fill_color) in enumerate(zip(names, fill_colors)):
+        _draw_legend(d, fill_color, outline_color, i*(pos_x+SIZE[0]+80) , pos_y, name)
+
+if __name__ == '__main__':
+    import vis
     im = Image.new('RGBA', SIZE)
     d = ImageDraw.Draw(im)
-    d.rectangle((0, 0, SIZE[0], SIZE[1]), fill=c, outline=vis.BLACK)
-    im.save('img/%s.png'%acts.states[i])
 
+    states = vis.states
+    outline_color = BLACK
+    
+    for i, c in list(enumerate(states))[1:]:
+        draw_legend(d, c, outline_color, 0, 0)
+        im.save('img/%s.png'%acts.states[i])

File scripts/vis.py

 import Image, ImageDraw, ImageFont
 
 from config import *
+import acts
 from acts import *
 from binlog import parse_input, collect
 from progressbar import ProgressBar
 from time import clock
+import legendimgs
 
 BLACK = (0, 0, 0)
 WHITE = (255, 255, 255)
-font = ImageFont.load_default()
+font = ImageFont.truetype('LiberationSans-Bold.ttf', 16)
+
+W, H, HA, HB, H_LEGENDS = 1600, 256, 64, 64, 64
+H_OFFSET_TIMELINES = H + 4 + HA + 4 + HB
+H_OFFSET_LEGENDS   = H + 4 + HA + 4 + HB + 30
+HZ =          H + 4 + HA + 4 + HB + H_LEGENDS
 
 states = [
     (0, 0, 0),
     (0, 160, 30),
 ]
 
+assert len(states) == len(acts.states), 'Number of states in vis.py and acts.py should be the same'
+
 timeslices_ms = [
     1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000 ]
 
     
     return Data(duration, summary, transitions)
 
-def draw(data, outfile):
-    total, summary, ts = data.duration, data.summary, data.transitions
 
-    W, H, HA, HB = 1600, 256, 64, 64
-    HZ = H + 4 + HA + 4 + HB
-    im = Image.new('RGBA', (W, HZ + 20))
-    d = ImageDraw.Draw(im)
-
-    # Filter
+def filter_data(ts):
     if 0:
+        print 'Filtering data...', 
         a, b = 10*2.2e9, 12*2.2e9
         ts = [(s, t-a) for s, t in ts if a <= t <= b ]
-    total_ms = total / CPU_SPEED * 1000
-
-    pp = 1.0 * total / (W*H)
-    pc_us = 1.0 * total / CPU_SPEED / W * 1e6
-    print "Parsed %d items, t=%f, t/pixel=%f"%(len(ts), total/CPU_SPEED, pp/CPU_SPEED*1000)
-
+        print 'Done'
+    return ts
+def draw_speedup_line(eps, d):
     d.rectangle((0, H + 4, W, H + 4 + HA), (255, 255, 255))
 
+    epmax = 2.5*H
+
+    d.line((0, H+4+HA-1.0*H/epmax*HA, W,  H+4+HA-1.0*H/epmax*HA), fill=(192, 192, 192))
+    d.line((0, H+4+HA-1.0*H/epmax*HA, W,  H+4+HA-1.0*H/epmax*HA), fill=(192, 192, 192))
+    d.line((0, H+4+HA-2.5*H/epmax*HA, W,  H+4+HA-2.5*H/epmax*HA), fill=(192, 192, 192))    
+    
+    last = None
+    for i in range(W):
+        n = 0
+        sm = 0
+        for j in range(max(0, i-3), min(W-1, i+3)):
+            sm += eps[j]
+            n += 1
+        ep = sm / n
+
+        ep_scaled = 1.0 * ep / epmax * HA
+        px = (i, H + 4 + HA - int(ep_scaled))
+        if last:
+            d.line((px, last), fill=(0, 0, 0))
+        last = px
+        #d.point((i, H + 4 + HA - int(ep_scaled)), fill=(0, 0, 0))
+
+def draw_timelines(total_ms, pc_us, d):
+    i = 0
+    while True:
+        divs = total_ms / timeslices_ms[i]
+        if divs < 15: break
+        if i == len(timeslices_ms) - 1: break
+        i += 1
+
+    timeslice = timeslices_ms[i]
+    t = timeslice
+    c = (128, 128, 128)
+    while t < total_ms:
+        x = t / total_ms * W
+        y = 0
+        while y < H_OFFSET_TIMELINES:
+            d.line((x, y, x, y + 8), fill=c)
+            y += 12
+        text = '%d ms'%t
+        w, h = font.getsize(text)
+        d.text((x-w/2, H_OFFSET_TIMELINES), text, fill=BLACK, font=font)
+        t += timeslice
+
+    d.text((0, H_OFFSET_TIMELINES), '[%.1fus]'%pc_us, fill=BLACK)
+
+
+def draw_summary_graph(summary, states, total, d):
+    
+    t = 0
+    ppt = 1.0 * W / total
+    
+    for dt, c in zip(summary, states):
+        x1 = int(t * ppt)
+        y1 = H + 4 + HA + 5 
+        x2 = int((t+dt) * ppt)
+        y2 = H + 4 + HA + 4 + HB
+        d.rectangle((x1, y1, x2, y2), fill=c)
+        t += dt
+
+def draw_main_graph(pp, ts, pb, d):
     eps = []
 
     # estimated progress of program run 
     ep = 0
+    
+    blip = W*H//50
 
-    # text progress indicator for graph generation
-    pb = ProgressBar('draw main', W*H)
-    blip = W*H//50
 
     # Flush events. We need to save them and draw them after filling the main area
     # because otherwise they will be overwritten. Format is (x, y, r) to plot flush at,
     for i in range(W*H):
         if i % blip == 0:
             pb.update(i)
-        x, y = i/H, i%H
+            pass
+        x, y = i/H, i % H
 
         t0 = pp * i
         t1 = t0 + pp
         color = [ 0, 0, 0 ]
         tx = t0
         while ti < len(ts):
-            state, reason, time = ts[ti];
+            state, reason, time = ts[ti]
             # States past this limit are actually events rather than state transitions
             if state >= event_start:
                 events.append((x, y, reason))
         if i % H == H - 1:
             eps.append(ep)
             ep = 0
-
+            
+    return eps, events
+    
+def draw_events(events, flush_reasons, d):
     for x, y, r in events:
         d.ellipse((x-5, y-5, x+5, y+5), fill=(255, 222, 222), outline=(160, 10, 10))
         ch = flush_reasons[r]
         d.text((x-2, y-5), ch, fill=BLACK, font=font)
 
-    print
+def draw_legends(d):
+    fill_colors = states[1:]
+    names = acts.states[1:]
 
+    legendimgs.draw_lengends(d, fill_colors, BLACK, 32, H_OFFSET_LEGENDS, names)
+
+def draw(data, outfile):
+    total, summary, ts = data.duration, data.summary, data.transitions
+    
+    im = Image.new('RGBA', (W, HZ + 20))
+    d = ImageDraw.Draw(im)
+    
+    ts = filter_data(ts)
+
+    total_ms = total / CPU_SPEED * 1000
+    pp = 1.0 * total / (W*H)
+    pc_us = 1.0 * total / CPU_SPEED / W * 1e6
+    print "Parsed %d items, t=%f, t/pixel=%f"%(len(ts), total/CPU_SPEED, pp/CPU_SPEED*1000)
+    
+    # text progress indicator for graph generation
+    pb = ProgressBar('draw main', W*H)
+    eps, events = draw_main_graph(pp, ts, pb, d)    
     pb.finish()
 
-    epmax = 2.5*H
-
-    d.line((0, H+4+HA-1.0*H/epmax*HA, W,  H+4+HA-1.0*H/epmax*HA), fill=(192, 192, 192))
-    d.line((0, H+4+HA-2.5*H/epmax*HA, W,  H+4+HA-2.5*H/epmax*HA), fill=(192, 192, 192))
-
-    last = None
-    for i in range(W):
-        n = 0
-        sm = 0
-        for j in range(max(0, i-3), min(W-1, i+3)):
-            sm += eps[j]
-            n += 1
-        ep = sm / n
-
-        ep_scaled = 1.0 * ep / epmax * HA
-        px = (i, H + 4 + HA - int(ep_scaled))
-        if last:
-            d.line((px, last), fill=(0, 0, 0))
-        last = px
-        #d.point((i, H + 4 + HA - int(ep_scaled)), fill=(0, 0, 0))
-
-    t = 0
-    ppt = 1.0 * W / total
-    if True:
-        for dt, c in zip(summary, states):
-            x1 = int(t * ppt)
-            y1 = H + 4 + HA + 5 
-            x2 = int((t+dt) * ppt)
-            y2 = H + 4 + HA + 4 + HB
-            d.rectangle((x1, y1, x2, y2), fill=c)
-            t += dt
-
-    # Time lines
-    i = 0
-    while True:
-        divs = total_ms / timeslices_ms[i]
-        if divs < 15: break
-        if i == len(timeslices_ms) - 1: break
-        i += 1
-
-    timeslice = timeslices_ms[i]
-    t = timeslice
-    c = (128, 128, 128)
-    while t < total_ms:
-        x = t / total_ms * W
-        y = 0
-        while y < HZ:
-            d.line((x, y, x, y + 8), fill=c)
-            y += 12
-        text = '%d ms'%t
-        w, h = font.getsize(text)
-        d.text((x-w/2, HZ), text, fill=BLACK, font=font)
-        t += timeslice
-
-    d.text((0, HZ), '[%.1fus]'%pc_us, fill=BLACK)
+    draw_events(events, flush_reasons, d)
+    draw_speedup_line(eps, d)
+    draw_summary_graph(summary, states, total, d)
+    draw_timelines(total_ms, pc_us, d)
+    draw_legends(d)
 
     im.save(outfile, "PNG")
 
     options, args = parser.parse_args()
 
     if len(args) == 0 or len(args) > 2:
-        print >> stderr, 'need output filename argument'
+        print >> sys.stderr, 'need output filename argument'
         sys.exit(1)
     if len(args) == 1:
         outfile = args[0]