aboutsummaryrefslogtreecommitdiffhomepage
path: root/utils/hacks/TreeGraphs/TreeGraph.py
diff options
context:
space:
mode:
authorDaniel Dunbar <daniel@zuster.org>2010-05-02 17:59:13 +0000
committerDaniel Dunbar <daniel@zuster.org>2010-05-02 17:59:13 +0000
commitf4cdc443fb86f715ab93f3528aff23452a5bb3a3 (patch)
treeffab5077611d32a8b95c9d9b4f96b47703190e82 /utils/hacks/TreeGraphs/TreeGraph.py
parentbae2fa50234b0a575a18a119019e5d96f7ff7ecf (diff)
downloadklee-f4cdc443fb86f715ab93f3528aff23452a5bb3a3.tar.gz
Add a little hack for visualizing KLEE branching.
- This consumes the treestream files produced with --write-paths or --write-sym-paths, and renders out the tree in a very ad-hoc funky way. Your mileage may vary! :) Example image: http://klee.llvm.org/data/treegraph_example.jpg Example movie: http://klee.llvm.org/data/treegraph_example.avi git-svn-id: https://llvm.org/svn/llvm-project/klee/trunk@102869 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'utils/hacks/TreeGraphs/TreeGraph.py')
-rwxr-xr-xutils/hacks/TreeGraphs/TreeGraph.py295
1 files changed, 295 insertions, 0 deletions
diff --git a/utils/hacks/TreeGraphs/TreeGraph.py b/utils/hacks/TreeGraphs/TreeGraph.py
new file mode 100755
index 00000000..28bd9fd6
--- /dev/null
+++ b/utils/hacks/TreeGraphs/TreeGraph.py
@@ -0,0 +1,295 @@
+#!/usr/bin/python
+
+from __future__ import division
+import sys
+from types import GeneratorType
+
+import DumpTreeStream
+from Graphics.Canvas import PdfCanvas
+from Graphics.Geometry import vec2
+import os, time
+import math, os, random
+
+def generator_fold(it):
+ """generator_fold(it) -> iterator
+
+ Given _it_, return a new iterator over the elements of _it_,
+ (recursively) folding in any elements whenever an iterator
+ result happens to also be a generator. This simplifies the
+ writing of iterators over recursive data structures.
+ """
+
+ for res in it:
+ if isinstance(res,GeneratorType):
+ for res in generator_fold(res):
+ yield res
+ else:
+ yield res
+
+
+def drawTree(a, b, maxDepth, sizes, depth=0):
+ yield (a, b)
+ if depth<maxDepth:
+ height = sizes[depth]
+ yield drawTree(b, vec2.add(b, (-height,height)),
+ maxDepth, sizes, depth+1)
+ yield drawTree(b, vec2.add(b, (+height,height)),
+ maxDepth, sizes, depth+1)
+
+def makeTreeGraph(output, symPath, count, shuffle=False):
+ random.seed(10)
+ c = PdfCanvas(output, basePos=(0,0), baseScale=(72*5,72*5),
+ pageSize=(72*10,72*10))
+
+ c.startDrawing()
+ c.setColor(1,1,1)
+ c.drawFilledCircle((0,0),.9)
+ c.setColor(0,0,0)
+ c.setLineWidth(5)
+ c.drawOutlineCircle((0,0),.9)
+ c.setLineWidth(1)
+# c.setColor(.2,.6,.3)
+
+ N = 8
+ sizes = [.5**(i+1) for i in range(N)]
+ res = drawTree((0.,-.9), (0.,-.5), N, [1.3*s/sum(sizes) for s in sizes])
+# [c.drawLine(a,b) for a,b in generator_fold(res)]
+
+ def mapIt(center, radius, spanAngle, (x,y)):
+ a = vec2.sub(center,(0,radius))
+ b = vec2.add(center,vec2.fromangle(math.pi*.5 + 2*x*spanAngle, radius))
+ return vec2.lerp(a, b, y)
+ m = lambda pt: mapIt((0,0),.9,math.pi*.7, pt)
+ toBox = lambda pt: vec2.div(vec2.add(pt,(0.,.9)),
+ (2*1.3,1.7))
+ def lm((x,y)):
+ x,y = toBox((x,y))
+ N = 100
+ return m((x,1-math.log(1+(1-y**4),2)))
+ return m((x,(N**(1+y)-N)/(N**2-N)))
+ return m((x,y))
+# c.drawOutlineBox((-.5,0),(.5,1))
+
+ #[c.drawLine(lm(a),lm(b)) for a,b in generator_fold(res)]
+
+ spanAngle = math.pi*.9
+ zeroRad = vec2.length(vec2.sub(vec2.fromangle(math.pi*3/2,.9),
+ vec2.fromangle(math.pi*.5 + spanAngle,.9)))
+ oneRad = .9
+ if 0:
+ for i in range(N):
+ t = i/(N-1)
+ c.drawOutlineCircle(vec2.add((0.,-.9), (0.,t*.9)),
+ zeroRad + (oneRad-zeroRad)*t)
+
+ def getTreePos(depth, maxDepth, index, ranges=None, depthOrder=None):
+ isoT = depth/(maxDepth-1)
+ isoCent = vec2.add((0.,-.9),(0.,isoT*.9))
+ isoRadius = zeroRad + (oneRad-zeroRad)*isoT
+ total = 2**(depth+1)
+ # isoSpanAngle = math.pi*.5 - vec2.toangle(vec2.sub(vec2.fromangle(math.pi*.5 + spanAngle,.9),
+ # isoCent))
+ isoSpanAngle = math.pi*.1 + (math.pi*.7 - math.pi*.1)*isoT
+ if ranges:
+ min,max = ranges
+ if max[depth]==min[depth]:
+ x = 0.
+ else:
+ x = (index - min[depth])/(max[depth]-min[depth])
+ elif depthOrder:
+ idx = depthOrder[depth].index(index)
+ x = idx/(len(depthOrder[depth])-1)
+ else:
+ x = index/(total-1)
+ return vec2.add(isoCent,vec2.fromangle(math.pi*.5 + (2*x-1)*isoSpanAngle, isoRadius))
+
+ treeData = DumpTreeStream.getTreeStream(symPath)
+ treeDataItems = treeData.items()
+ treeDataItems.sort()
+
+ N = max([len(p) for _,p in treeDataItems])
+# N = min(20,N)
+
+ minDepthIndex = [2**(i+1) for i in range(N)]
+ maxDepthIndex = [0 for i in range(N)]
+ depthIndices = [set() for i in range(N+2)]
+ for id,path in treeDataItems:
+ depth = -1
+ index = 0
+ for p in path[:N]:
+ depth += 1
+ index = index*2 + (p=='1')
+ depthIndices[depth].add(index)
+ if 1:
+ low = index*2
+ hi = index*2+1
+ mid = index*2 + .5
+ M = 5
+ for x in range(depth+1,min(N,depth+M)):
+ t = (x-(depth+1))/(M-1)
+ depthIndices[x].add(low + (mid-low)*t)
+ depthIndices[x].add(hi + (mid-hi)*t)
+ low *= 2
+ hi *= 2 + 1
+ mid = mid*2 + .5
+ else:
+ depthIndices[depth+1].add(index*2)
+ depthIndices[depth+1].add(index*2+1)
+ depthIndices[depth+2].add(index*2*2)
+ depthIndices[depth+2].add(index*4+3)
+ minDepthIndex[depth] = min(index,minDepthIndex[depth])
+ maxDepthIndex[depth] = max(index,maxDepthIndex[depth])
+ if 0:
+ for d in range(1,N)[::-1]:
+ minDepthIndex[d] = min(minDepthIndex[d-1]*2,minDepthIndex[d])
+ maxDepthIndex[d] = max(maxDepthIndex[d-1]*2,maxDepthIndex[d])
+ for d in range(N):
+ depthIndices[d] = list(depthIndices[d])
+ depthIndices[d].sort()
+
+ def drawPoints(list):
+ for pt in list:
+ c.drawPoint(pt)
+
+ def catmullRom1((p0,p1,p2,p3), t):
+ return (0.5 * (( 2*p1 ) +
+ ( -p0 + p2 ) * t +
+ ( 2*p0 - 5*p1 + 4*p2 - p3) * t*t +
+ ( -p0 + 3*p1 - 3*p2 + p3) * t*t*t))
+ def catmullRom2((p0,p1,p2,p3), t):
+ return (catmullRom1((p0[0],p1[0],p2[0],p3[0]),t),
+ catmullRom1((p0[1],p1[1],p2[1],p3[1]),t))
+
+ c.setLineWidth(2)
+# c.setColor(.2,.6,.3)
+ lines = set()
+ segments = set()
+ segments2 = dict()
+ allPoints = set()
+ side = set()
+ paths = []
+
+ paths_to_draw = treeDataItems
+ if shuffle:
+ paths_to_draw = list(treeDataItems)
+ random.shuffle(paths_to_draw)
+
+ for id,path in paths_to_draw[:count]:
+ depth = -1
+ index = 0
+ pts = [(0.,-.9)]
+ for p in path[:N]:
+ depth += 1
+ index = index*2 + (p=='1')
+ pts.append(getTreePos(depth,N,index,None,depthIndices))
+ # pts.append(getTreePos(depth,N,index,(minDepthIndex,maxDepthIndex)))
+ allPoints |= set(pts)
+ if len(pts)>3:
+ paths.append(pts)
+ for i in range(0,len(pts)-1):
+ p0 = pts[max(0,i-1)]
+ p1 = pts[i]
+ p2 = pts[min(len(pts)-1,i+1)]
+ p3 = pts[min(len(pts)-1,i+2)]
+ #segments[(p1,p2)] = segments.get((p1,p2),[]) + [(p0,p1)]
+
+ if (p1,p2) not in side:
+ segments.add((p0,p1,p2,p3))
+ side.add((p1,p2))
+# drawPoints((b,vec2.add(b,vec2.mulN(vec2.normalizeOrZero(vec2.sub(b,a)),l*.4)),
+# cx,cx))
+# c.drawLineStrip(pts)
+# for a,b in zip(pts,pts[1:]):
+# lines.add((a,b))
+ for a,b in lines:
+ c.drawLine(a,b)
+ for (p1,p2),extra in segments2.items():
+ a,b = zip(*extra)
+ a = vec2.divN(reduce(vec2.add, a),len(a))
+ b = vec2.divN(reduce(vec2.add, b),len(b))
+ c.drawLineStrip([catmullRom2((a,p1,p2,b),x/10.) for x in range(10+1)])
+ if 1:
+ side = set()
+ nPaths = []
+ for path in paths:
+ path = list(path)
+ path = [(0.,-.9)] + path
+ depth = 0
+ while len(path)>3 and (path[1],path[2]) in side:
+ depth += 1
+ path = path[1:]
+ nPaths.append((depth,path))
+ side |= set(zip(path,path[1:]))
+# for path in nPaths:
+# c.drawLineStrip(path)
+ for depth,path in nPaths:
+ ppts = []
+ for i in range(1,len(path)-1):
+ p0 = path[max(0,i-1)]
+ p1 = path[i]
+ p2 = path[min(len(path)-1,i+1)]
+ p3 = path[min(len(path)-1,i+2)]
+ for x in range(10):
+ ppts.append(catmullRom2((p0,p1,p2,p3),x/10.))
+ #ppts.append(p1)
+ ppts.append(path[-1])
+ if 1:
+ up = []
+ down = []
+ ref = path[0]
+ for i,pt in enumerate(ppts):
+ ref = ppts[min(len(ppts)-1,i+1)]
+ vec = vec2.sub(pt,ref)
+ l = vec2.length(vec)
+ if l<.000001:
+ vec = (1.,0.)
+ else:
+ vec = vec2.rotate90(vec2.divN(vec,l))
+ width = .001 * (1. - (depth + i/20.)/N)
+ up.append(vec2.add(pt, vec2.mulN(vec, width)))
+ down.append(vec2.add(pt, vec2.mulN(vec, -width)))
+ ref = pt
+# c.drawLineStrip(up)
+# c.drawLineStrip(down)
+ c.drawFilledPolygon(down + up[::-1])
+ else:
+ c.drawLineStrip(ppts)
+# print len(paths),sum(map(len,paths))
+# print len(nPaths),sum(map(len,nPaths))
+ else:
+ for P in segments:
+ c.drawLineStrip([catmullRom2(P,x/10.) for x in range(10+1)])
+ if 0:
+ c.setPointSize(10)
+ c.drawPoints(allPoints)
+
+ if 0:
+ N = 20
+ for i in range(N+1):
+ t = 2*i/N - 1
+ c.drawLine(m((t,0)), m((t,1)))
+
+ c.endDrawing()
+
+def main():
+ from optparse import OptionParser
+ op = OptionParser("usage: %prog [options] <tree-stream-path> <output-path>")
+ op.add_option('','--count', dest='count', type=int, default=-1,
+ help="number of distinct paths to draw")
+ op.add_option('','--shuffle', dest='shuffle', action='store_true',
+ default=False)
+ opts,args = op.parse_args()
+
+ if len(args) != 2:
+ parser.error('invalid number of arguments')
+
+ symPath,output = args
+ makeTreeGraph(output, symPath, opts.count, opts.shuffle)
+
+if __name__=='__main__':
+ try:
+ main()
+ except:
+ import sys,traceback
+ traceback.print_exc(file= sys.__stdout__)
+ sys.__stdout__.flush()