https://github.com/magnusmorton/trace-analysis
Tip revision: 4645af99638edea16d00e811c922b0fb9d6b86d9 authored by Magnus Morton on 11 January 2016, 20:33:10 UTC
subplots and recording output
subplots and recording output
Tip revision: 4645af9
trace.py
import instructions
import re
import operator as op
target_token_re = re.compile(r".*TargetToken\((?P<tt_val>\d*)\)")
high_cost = ['ARRAYLEN_GC_OP',
'STRLEN_OP',
'STRGETITEM_OP',
'GETFIELD_GC_PURE_OP',
'GETFIELD_RAW_PURE_OP',
'GETARRAYITEM_GC_PURE_OP',
'GETARRAYITEM_RAW_PURE_OP',
'UNICODELEN_OP',
'UNICODEGETITEM_OP',
'GETARRAYITEM_GC_OP',
'GETARRAYITEM_RAW_OP',
'GETINTERIORFIELD_GC_OP',
'RAW_LOAD_OP',
'GETFIELD_GC_OP',
'GETFIELD_RAW_OP',
'NEW_OP', #-> GcStruct, gcptrs inside are zeroed (not the rest)
'NEW_WITH_VTABLE_OP', #-> GcStruct with vtable, gcptrs inside are zeroed
'NEW_ARRAY_OP', #-> GcArray, not zeroed. only for arrays of primitives
'NEW_ARRAY_CLEAR_OP', #-> GcArray, fully zeroed
'NEWSTR_OP', #-> STR, the hash field is zeroed
'NEWUNICODE_OP', #-> UNICODE, the hash field is zeroed
'SETARRAYITEM_GC_OP',
'SETARRAYITEM_RAW_OP',
'SETINTERIORFIELD_GC_OP',
'SETINTERIORFIELD_RAW_OP', # right now, only used by tests
'RAW_STORE_OP',
'SETFIELD_GC_OP',
'ZERO_PTR_FIELD_OP', # only emitted by the rewrite, clears a pointer field
# at a given constant offset, no descr
'ZERO_ARRAY_OP']
def simple_cost(frag, i=None):
return len(filter( lambda x: x.split()[0] != "DEBUG_MERGE_POINT_OP",frag.ops[0:None]))
def mem_cost(frag, i=None):
if not i:
i = len(frag.ops)
j = 0
cost = 0
while j < i:
op = frag.ops[j].split()[0]
if op in high_cost:
cost += 1000
elif op != "DEBUG_MERGE_POINT_OP":
cost += 1
j+=1
return cost
def deriv_cost(frag, i=None):
if not i:
i = len(frag.ops)
j = 0
cost = 0
while j < i:
op = frag.ops[j].split()[0]
if op in instructions.object_ops:
cost += 861
elif op == "GUARD:":
cost += 88
elif op != "DEBUG_MERGE_POINT_OP":
cost += 1
j += 1
return cost
def null_cost(frag, i=None):
return 1
class Countable(object):
def class_counts(self, i=None):
if not i:
i = len(self.ops)
j = 0
counts = [0]*7
while j < i:
op = self.ops[j].split()[0]
if op in instructions.object_ops:
counts[0] += 1
elif op in instructions.array_ops:
counts[1] += 1
elif op in instructions.num_ops:
counts[2] += 1
elif op in instructions.alloc_ops:
counts[3] += 1
elif op == "GUARD:":
counts[4] += 1
elif op in instructions.string_ops:
counts[5] += 1
elif op in instructions.call_ops:
counts[6] += 1
j += 1
return counts
class Trace(Countable):
def __init__(self, ops, token=None):
self.ops = ops
self.token = token
def __eq__(self, other):
return hash(self) == hash(other)
def get_fragments(self, guards, current_label=None):
fragments = []
start_pos = 0
found_guards = {}
for i, op in enumerate(self.ops):
tokens = op.split()
if tokens[0] == "LABEL:":
if current_label:
fragments.append(Fragment(self.ops[start_pos:i], current_label, found_guards))
current_label = int(target_token_re.match(tokens[1]).group('tt_val'))
start_pos = i
found_guards = {}
if tokens[0] == "JUMP_OP":
if current_label:
fragments.append(Fragment(self.ops[start_pos:], current_label, found_guards))
else:
fragments.append(Fragment(self.ops,self.token, found_guards))
if tokens[0] == "GUARD:":
guard = int(tokens[1])
if guard in guards:
# store the index of the guard from the start of the trace
found_guards[guard] = i - start_pos
return fragments
class Bridge(Trace):
def __init__(self, ops, guard):
super(Bridge, self).__init__(ops)
self.guard = guard
def get_fragments(self, guards):
# just use the bridge's guard id as a label
return super(Bridge, self).get_fragments(guards, self.guard)
class Fragment(Countable):
model = None
def __init__(self, ops, label, guards):
self.ops = ops
self.label = label
self.guards = guards
def count2guard(self, guard):
return self.class_counts(self.guards[guard])
def cost_with_model(self, i=None):
if not Fragment.model:
raise "Model not defined"
if Fragment.model == [0,0,0,0,0,0,0]:
return 1
# order is [order, array, num, alloc, guards]
if not i:
i = len(self.ops)
j = 0
cost = 0
while j < i:
op = self.ops[j].split()[0]
if op in instructions.object_ops:
cost += Fragment.model[0]
elif op in instructions.array_ops:
cost += Fragment.model[1]
elif op in instructions.num_ops:
cost += Fragment.model[2]
elif op in instructions.alloc_ops:
cost += Fragment.model[3]
elif op == "GUARD:":
cost += Fragment.model[4]
j += 1
return cost
cost_fn = cost_with_model
def cost(self):
return Fragment.cost_fn(self)
def cost2guard(self, guard):
# return len(filter( lambda x: x != "DEBUG_MERGE_POINT_OP",self.ops[0:self.guards[guard]]))
return Fragment.cost_fn(self, self.guards[guard])
def __hash__(self):
hash_num = 0
for op in self.ops:
hash_num *= 251
hash_num += hash(op.split()[0])
return hash_num
class Program(object):
def __init__(self, name, fragments, counts, entry_points, times, tracing):
self.name = name
self.fragments = fragments
self.counts = counts
self.entry_points = entry_points
self.times = times
self.tracing = tracing
def average_time(self):
print self.name
return sum(self.times)/len(self.times)
def tracing_time(self):
return sum(self.tracing)/len(self.tracing)
def net_time(self):
return self.average_time() - self.tracing_time()
def hashed_counts(self):
hashed_counts = {}
for key, value in self.counts.iteritems():
if value:
if key in self.fragments:
hashed_counts[hash(self.fragments[key])] = value
return hashed_counts
def diff_class_counts(self, counts):
hashed_frags = {hash(frag):frag for frag in self.fragments.values()}
frag_counts = {key: frag.class_counts() for key, frag in hashed_frags.iteritems() if key in counts}
add_lists = lambda a, b: map(op.add, a, b)
scal_mul = lambda s, a: [s*i for i in a]
print counts
print frag_counts
return reduce( lambda x, y: add_lists(x, scal_mul(counts[y], frag_counts[y])), counts, [0,0,0,0,0,0,0])
def cost(self):
frag_costs = {}
eqn = {}
for key, value in self.counts.iteritems():
if value:
if key in self.fragments:
frag = self.fragments[key]
for key2,value2 in self.counts.iteritems():
if key2 in frag.guards:
guard_cost = frag.cost2guard(key2)
value = value - value2
# bug here - just add the key instead
eqn[hash(frag) + hash(key2)] = value2
frag_costs[hash(frag) + hash(key2)] = guard_cost
eqn[hash(frag)] = value
frag_costs[hash(frag)] = frag.cost()
# special case for loops with no labels
if len(self.fragments) > len(self.counts):
for key, value in self.fragments.iteritems():
if key in self.entry_points:
count = self.entry_points[key]
if count:
for key2,value2 in self.counts.iteritems():
if key2 in frag.guards:
guard_cost = frag.cost2guard(key2)
count = count - value2
eqn[hash(value) + hash(key2)] = value2
frag_costs[hash(value) + hash(key2)] = guard_cost
eqn[hash(value)] = count
frag_costs[hash(frag)] = frag.cost()
return reduce(lambda x, y: x + eqn[y] * frag_costs[y], eqn,0)
def class_counts(self):
frag_counts = {}
eqn = {}
for key, value in self.counts.iteritems():
if value:
if key in self.fragments:
frag = self.fragments[key]
for key2,value2 in self.counts.iteritems():
if key2 in frag.guards:
#for each bridge in the counts, subtract its count for
guard_count = frag.count2guard(key2)
value = value - value2
eqn[hash(frag) + key2] = value2
frag_counts[hash(frag) + key2] = guard_count
eqn[hash(frag)] = value
frag_counts[hash(frag)] = frag.class_counts()
# special case for loops with no labels
if len(self.fragments) > len(self.counts):
print "NO LABEL LOOP FOUND", self.name
for key, frag in self.fragments.iteritems():
if key in self.entry_points:
count = self.entry_points[key]
if count:
for key2,value2 in self.counts.iteritems():
if key2 in frag.guards:
guard_count = frag.count2guard(key2)
count = count - value2
eqn[hash(frag) + key2] = value2
frag_counts[hash(frag) + key2] = guard_count
eqn[hash(frag)] = count
frag_counts[hash(frag)] = frag.class_counts()
# sum all lists in frag_counts
add_lists = lambda a, b: map(op.add, a, b)
scal_mul = lambda s, a: [s*i for i in a]
return reduce( lambda x, y: add_lists(x, scal_mul(eqn[y], frag_counts[y])), eqn, [0,0,0,0,0,0,0])
def build_trace(fd, guard=0, token=None):
ops = []
line = fd.readline().rstrip()
trace = None
while line and line != "END TRACE":
ops.append(line.lstrip('<').rstrip('>'))
line = fd.readline().rstrip()
if guard > 0:
trace = Bridge(ops, guard)
else:
trace = Trace(ops, token)
return trace