Skip to content

Commit bc4e8ae

Browse files
author
Philip Guo
committed
first pass at cumulative display mode
1 parent 6541e1e commit bc4e8ae

File tree

1 file changed

+61
-47
lines changed

1 file changed

+61
-47
lines changed

PyTutorGAE/pg_logger.py

Lines changed: 61 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ def filter_var_dict(d):
7878

7979
class PGLogger(bdb.Bdb):
8080

81-
def __init__(self, finalizer_func):
81+
def __init__(self, finalizer_func, cumulative_display=False):
8282
bdb.Bdb.__init__(self)
8383
self.mainpyfile = ''
8484
self._wait_for_mainpyfile = 0
@@ -87,6 +87,12 @@ def __init__(self, finalizer_func):
8787
# processes it
8888
self.finalizer_func = finalizer_func
8989

90+
# if True, then displays ALL stack frames that have ever existed
91+
# rather than only those currently on the stack (and their
92+
# lexical parents)
93+
self.cumulative_display = cumulative_display
94+
self.cumulative_display = True
95+
9096
# each entry contains a dict with the information for a single
9197
# executed line
9298
self.trace = []
@@ -98,10 +104,16 @@ def __init__(self, finalizer_func):
98104
# Value: parent frame
99105
self.closures = {}
100106

101-
# List of frames to KEEP AROUND after the function exits
102-
# because nested functions were defined within those frames.
103-
# (ORDER matters for aesthetics)
104-
self.zombie_parent_frames = []
107+
# Key: id() of frame object
108+
# Value: monotonically increasing small ID, based on call order
109+
self.frame_ordered_ids = {}
110+
self.cur_frame_id = 1
111+
112+
# List of frames to KEEP AROUND after the function exits.
113+
# If cumulative_display is True, then keep ALL frames in
114+
# zombie_frames; otherwise keep only frames where
115+
# nested functions were defined within them.
116+
self.zombie_frames = []
105117

106118
# all globals that ever appeared in the program, in the order in
107119
# which they appeared. note that this might be a superset of all
@@ -116,6 +128,10 @@ def __init__(self, finalizer_func):
116128
self.executed_script = None # Python script to be executed!
117129

118130

131+
def get_frame_id(self, cur_frame):
132+
return self.frame_ordered_ids[id(cur_frame)]
133+
134+
119135
# Returns the (lexical) parent frame of the function that was called
120136
# to create the stack frame 'frame'.
121137
#
@@ -148,19 +164,12 @@ def get_parent_frame(self, frame):
148164
return None
149165

150166

151-
def get_zombie_parent_frame_id(self, f):
152-
# should be None unless this is a zombie frame
153-
try:
154-
# make the frame id's one-indexed for clarity
155-
# (and to prevent possible confusion with None)
156-
return self.zombie_parent_frames.index(f) + 1
157-
except ValueError:
158-
pass
159-
return None
160-
161-
def lookup_zombie_frame_by_id(self, idx):
162-
# remember this is one-indexed
163-
return self.zombie_parent_frames[idx - 1]
167+
def lookup_zombie_frame_by_id(self, frame_id):
168+
# TODO: kinda inefficient
169+
for e in self.zombie_frames:
170+
if self.get_frame_id(e) == frame_id:
171+
return e
172+
assert False # should never get here
164173

165174

166175
# unused ...
@@ -227,10 +236,19 @@ def interaction(self, frame, traceback, event_type):
227236
self.encoder.reset_heap() # VERY VERY VERY IMPORTANT,
228237
# or else we won't properly capture heap object mutations in the trace!
229238

239+
if event_type == 'call':
240+
tfid = id(top_frame)
241+
assert tfid not in self.frame_ordered_ids
242+
self.frame_ordered_ids[tfid] = self.cur_frame_id
243+
self.cur_frame_id += 1
244+
245+
if self.cumulative_display:
246+
self.zombie_frames.append(top_frame)
247+
230248

231249
# only render zombie frames that are NO LONGER on the stack
232250
cur_stack_frames = [e[0] for e in self.stack]
233-
zombie_frames_to_render = [e for e in self.zombie_parent_frames if e not in cur_stack_frames]
251+
zombie_frames_to_render = [e for e in self.zombie_frames if e not in cur_stack_frames]
234252

235253

236254
# each element is a pair of (function name, ENCODED locals dict)
@@ -242,15 +260,13 @@ def create_encoded_stack_entry(cur_frame):
242260
ret = {}
243261

244262

245-
# your immediate parent frame ID is parent_frame_id_list[0]
246-
# and all other members are your further ancestors
247263
parent_frame_id_list = []
248264

249265
f = cur_frame
250266
while True:
251267
p = self.get_parent_frame(f)
252268
if p:
253-
pid = self.get_zombie_parent_frame_id(p)
269+
pid = self.get_frame_id(p)
254270
assert pid
255271
parent_frame_id_list.append(pid)
256272
f = p
@@ -299,7 +315,7 @@ def create_encoded_stack_entry(cur_frame):
299315
if type(v) in (types.FunctionType, types.MethodType):
300316
try:
301317
enclosing_frame = self.closures[v]
302-
enclosing_frame_id = self.get_zombie_parent_frame_id(enclosing_frame)
318+
enclosing_frame_id = self.get_frame_id(enclosing_frame)
303319
self.encoder.set_function_parent_frame_ID(encoded_val, enclosing_frame_id)
304320
except KeyError:
305321
pass
@@ -340,7 +356,8 @@ def create_encoded_stack_entry(cur_frame):
340356
assert e in encoded_locals
341357

342358
return dict(func_name=cur_name,
343-
frame_id=self.get_zombie_parent_frame_id(cur_frame),
359+
frame_id=self.get_frame_id(cur_frame),
360+
# TODO: fixme
344361
parent_frame_id_list=parent_frame_id_list,
345362
encoded_locals=encoded_locals,
346363
ordered_varnames=ordered_varnames)
@@ -355,8 +372,8 @@ def create_encoded_stack_entry(cur_frame):
355372
if (type(v) in (types.FunctionType, types.MethodType) and \
356373
v not in self.closures):
357374
self.closures[v] = top_frame
358-
if not top_frame in self.zombie_parent_frames:
359-
self.zombie_parent_frames.append(top_frame)
375+
if not top_frame in self.zombie_frames:
376+
self.zombie_frames.append(top_frame)
360377

361378

362379
# climb up until you find '<module>', which is (hopefully) the global scope
@@ -382,7 +399,7 @@ def create_encoded_stack_entry(cur_frame):
382399
if type(v) in (types.FunctionType, types.MethodType):
383400
try:
384401
enclosing_frame = self.closures[v]
385-
enclosing_frame_id = self.get_zombie_parent_frame_id(enclosing_frame)
402+
enclosing_frame_id = self.get_frame_id(enclosing_frame)
386403
self.encoder.set_function_parent_frame_ID(encoded_val, enclosing_frame_id)
387404
except KeyError:
388405
pass
@@ -402,40 +419,38 @@ def create_encoded_stack_entry(cur_frame):
402419
# making it look aesthetically pretty
403420
stack_to_render = [];
404421

405-
# first push all regular stack entries BACKWARDS
422+
# first push all regular stack entries
406423
if encoded_stack_locals:
407-
stack_to_render = encoded_stack_locals[::-1]
408-
for e in stack_to_render:
424+
for e in encoded_stack_locals:
409425
e['is_zombie'] = False
410426
e['is_highlighted'] = False
427+
stack_to_render.append(e)
411428

412-
stack_to_render[-1]['is_highlighted'] = True
429+
# highlight the top-most active stack entry
430+
stack_to_render[0]['is_highlighted'] = True
413431

414432

415-
# zombie_encoded_stack_locals consists of exited functions that have returned
416-
# nested functions. Push zombie stack entries at the BEGINNING of stack_to_render,
417-
# EXCEPT put zombie entries BEHIND regular entries that are their parents
418-
for e in zombie_encoded_stack_locals[::-1]:
433+
# now push all zombie stack entries
434+
for e in zombie_encoded_stack_locals:
419435
# don't display return value for zombie frames
436+
# TODO: reconsider ...
437+
'''
420438
try:
421439
e['ordered_varnames'].remove('__return__')
422440
except ValueError:
423441
pass
442+
'''
424443

425444
e['is_zombie'] = True
426445
e['is_highlighted'] = False # never highlight zombie entries
427446

428-
# j should be 0 most of the time, so we're always inserting new
429-
# elements to the front of stack_to_render (which is why we are
430-
# iterating backwards over zombie_stack_locals).
431-
j = 0
432-
while j < len(stack_to_render):
433-
if stack_to_render[j]['frame_id'] in e['parent_frame_id_list']:
434-
j += 1
435-
continue
436-
break
447+
stack_to_render.append(e)
448+
449+
# now sort by frame_id since that sorts frames in "chronological
450+
# order" based on the order they were invoked
451+
stack_to_render.sort(key=lambda e: e['frame_id'])
452+
437453

438-
stack_to_render.insert(j, e)
439454

440455
# create a unique hash for this stack entry, so that the
441456
# frontend can uniquely identify it when doing incremental
@@ -445,8 +460,7 @@ def create_encoded_stack_entry(cur_frame):
445460
# disambiguating recursion!)
446461
for (stack_index, e) in enumerate(stack_to_render):
447462
hash_str = e['func_name']
448-
if e['frame_id']:
449-
hash_str += '_f' + str(e['frame_id'])
463+
hash_str += '_f' + str(e['frame_id'])
450464
if e['parent_frame_id_list']:
451465
hash_str += '_p' + '_'.join([str(i) for i in e['parent_frame_id_list']])
452466
if e['is_zombie']:

0 commit comments

Comments
 (0)