1818import time
1919import traceback
2020import warnings
21+ import contextlib
2122
2223if sys .platform == "win32" :
2324 # any value except signal.CTRL_C_EVENT and signal.CTRL_BREAK_EVENT
@@ -460,16 +461,25 @@ def _find_script(script_name):
460461class _TimeStamperCM (object ):
461462 """Time-stamping context manager."""
462463
463- def __init__ (self , timestamps , filename , backend ):
464+ def __init__ (self , timestamps , filename , backend , timestamper = None , func = None ):
464465 self .timestamps = timestamps
465466 self .filename = filename
466467 self .backend = backend
468+ self .ts = timestamper
469+ self .func = func
467470
468471 def __enter__ (self ):
472+ if self .ts is not None :
473+ self .ts .current_stack_level += 1
474+ self .ts .stack [self .func ].append (self .ts .current_stack_level )
475+
469476 self .timestamps .append (
470477 _get_memory (os .getpid (), self .backend , timestamps = True , filename = self .filename ))
471478
472479 def __exit__ (self , * args ):
480+ if self .ts is not None :
481+ self .ts .current_stack_level -= 1
482+
473483 self .timestamps .append (
474484 _get_memory (os .getpid (), self .backend , timestamps = True , filename = self .filename ))
475485
@@ -482,6 +492,8 @@ class TimeStamper:
482492 def __init__ (self , backend ):
483493 self .functions = {}
484494 self .backend = backend
495+ self .current_stack_level = - 1
496+ self .stack = {}
485497
486498 def __call__ (self , func = None , precision = None ):
487499 if func is not None :
@@ -516,11 +528,18 @@ def timestamp(self, name="<block>"):
516528 filename = inspect .getsourcefile (func )
517529 except TypeError :
518530 filename = '<unknown>'
519- return _TimeStamperCM (timestamps , filename , self .backend )
531+ return _TimeStamperCM (
532+ timestamps ,
533+ filename ,
534+ self .backend ,
535+ timestamper = self ,
536+ func = func
537+ )
520538
521539 def add_function (self , func ):
522540 if func not in self .functions :
523541 self .functions [func ] = []
542+ self .stack [func ] = []
524543
525544 def wrap_function (self , func ):
526545 """ Wrap a function to timestamp it.
@@ -536,23 +555,33 @@ def f(*args, **kwds):
536555 _get_memory (os .getpid (), self .backend , timestamps = True , filename = filename )]
537556 self .functions [func ].append (timestamps )
538557 try :
539- return func (* args , ** kwds )
558+ with self .call_on_stack (func , * args , ** kwds ) as result :
559+ return result
540560 finally :
541561 # end time
542562 timestamps .append (_get_memory (os .getpid (), self .backend , timestamps = True ,
543563 filename = filename ))
544564
545565 return f
546566
567+ @contextlib .contextmanager
568+ def call_on_stack (self , func , * args , ** kwds ):
569+ self .current_stack_level += 1
570+ self .stack [func ].append (self .current_stack_level )
571+
572+ yield func (* args , ** kwds )
573+
574+ self .current_stack_level -= 1
575+
547576 def show_results (self , stream = None ):
548577 if stream is None :
549578 stream = sys .stdout
550579
551580 for func , timestamps in self .functions .items ():
552581 function_name = "%s.%s" % (func .__module__ , func .__name__ )
553- for ts in timestamps :
554- stream .write ("FUNC %s %.4f %.4f %.4f %.4f\n " % (
555- (function_name ,) + ts [0 ] + ts [1 ]))
582+ for ts , level in zip ( timestamps , self . stack [ func ]) :
583+ stream .write ("FUNC %s %.4f %.4f %.4f %.4f %d \n " % (
584+ (function_name ,) + ts [0 ] + ts [1 ] + ( level ,) ))
556585
557586
558587class CodeMap (dict ):
0 commit comments