@@ -60,8 +60,6 @@ def unicode(x, *args):
6060except ImportError :
6161 has_tracemalloc = False
6262
63- _backend = None
64-
6563
6664class MemitResult (object ):
6765 """memit magic run details.
@@ -88,13 +86,13 @@ def _repr_pretty_(self, p, cycle):
8886 p .text (u'<MemitResult : ' + msg + u'>' )
8987
9088
91- def _get_memory (pid , timestamps = False , include_children = False , filename = None ):
92- # .. only for current process and only on unix ..
89+ def _get_memory (pid , backend , timestamps = False , include_children = False , filename = None ):
90+ # .. low function to get memory consumption ..
9391 if pid == - 1 :
9492 pid = os .getpid ()
9593
9694 def tracemalloc_tool ():
97- # .. cross-platform but but requires Python 3.4 or higher
95+ # .. cross-platform but but requires Python 3.4 or higher ..
9896 stat = next (filter (lambda item : str (item ).startswith (filename ),
9997 tracemalloc .take_snapshot ().statistics ('filename' )))
10098 mem = stat .size / _TWO_20
@@ -156,7 +154,7 @@ def posix_tool():
156154 else :
157155 return - 1
158156
159- if _backend == 'tracemalloc' and \
157+ if backend == 'tracemalloc' and \
160158 (filename is None or filename == '<unknown>' ):
161159 raise RuntimeError (
162160 'There is no access to source file of the profiled function'
@@ -165,20 +163,21 @@ def posix_tool():
165163 tools = {'tracemalloc' : tracemalloc_tool ,
166164 'psutil' : ps_util_tool ,
167165 'posix' : posix_tool }
168- return tools [_backend ]()
166+ return tools [backend ]()
169167
170168
171169class MemTimer (Process ):
172170 """
173171 Fetch memory consumption from over a time interval
174172 """
175173
176- def __init__ (self , monitor_pid , interval , pipe , max_usage = False ,
174+ def __init__ (self , monitor_pid , interval , pipe , backend , max_usage = False ,
177175 * args , ** kw ):
178176 self .monitor_pid = monitor_pid
179177 self .interval = interval
180178 self .pipe = pipe
181179 self .cont = True
180+ self .backend = backend
182181 self .max_usage = max_usage
183182 self .n_measurements = 1
184183
@@ -187,16 +186,17 @@ def __init__(self, monitor_pid, interval, pipe, max_usage=False,
187186
188187 # get baseline memory usage
189188 self .mem_usage = [
190- _get_memory (self .monitor_pid , timestamps = self .timestamps ,
189+ _get_memory (self .monitor_pid , self . backend , timestamps = self .timestamps ,
191190 include_children = self .include_children )]
192191 super (MemTimer , self ).__init__ (* args , ** kw )
193192
194193 def run (self ):
195194 self .pipe .send (0 ) # we're ready
196195 stop = False
197196 while True :
198- cur_mem = _get_memory (self .monitor_pid , timestamps = self .timestamps ,
199- include_children = self .include_children )
197+ cur_mem = _get_memory (
198+ self .monitor_pid , self .backend , timestamps = self .timestamps ,
199+ include_children = self .include_children ,)
200200 if not self .max_usage :
201201 self .mem_usage .append (cur_mem )
202202 else :
@@ -213,7 +213,7 @@ def run(self):
213213
214214def memory_usage (proc = - 1 , interval = .1 , timeout = None , timestamps = False ,
215215 include_children = False , max_usage = False , retval = False ,
216- stream = None ):
216+ stream = None , backend = None ):
217217 """
218218 Return the memory usage of a process or piece of code
219219
@@ -259,8 +259,7 @@ def memory_usage(proc=-1, interval=.1, timeout=None, timestamps=False,
259259 ret : return value of the profiled function
260260 Only returned if retval is set to True
261261 """
262- if _backend is None :
263- choose_backend ()
262+ backend = choose_backend (backend )
264263 if stream is not None :
265264 timestamps = True
266265
@@ -292,7 +291,7 @@ def memory_usage(proc=-1, interval=.1, timeout=None, timestamps=False,
292291
293292 while True :
294293 child_conn , parent_conn = Pipe () # this will store MemTimer's results
295- p = MemTimer (os .getpid (), interval , child_conn ,
294+ p = MemTimer (os .getpid (), interval , child_conn , backend ,
296295 timestamps = timestamps ,
297296 max_usage = max_usage ,
298297 include_children = include_children )
@@ -313,16 +312,17 @@ def memory_usage(proc=-1, interval=.1, timeout=None, timestamps=False,
313312 line_count = 0
314313 while True :
315314 if not max_usage :
316- mem_usage = _get_memory (proc .pid , timestamps = timestamps ,
317- include_children = include_children )
315+ mem_usage = _get_memory (
316+ proc .pid , backend , timestamps = timestamps ,
317+ include_children = include_children )
318318 if stream is not None :
319319 stream .write ("MEM {0:.6f} {1:.4f}\n " .format (* mem_usage ))
320320 else :
321321 ret .append (mem_usage )
322322 else :
323323 ret = max (ret ,
324- _get_memory (proc . pid ,
325- include_children = include_children ))
324+ _get_memory (
325+ proc . pid , backend , include_children = include_children ))
326326 time .sleep (interval )
327327 line_count += 1
328328 # flush every 50 lines. Make 'tail -f' usable on profile file
@@ -344,15 +344,16 @@ def memory_usage(proc=-1, interval=.1, timeout=None, timestamps=False,
344344 while counter < max_iter :
345345 counter += 1
346346 if not max_usage :
347- mem_usage = _get_memory (proc , timestamps = timestamps ,
348- include_children = include_children )
347+ mem_usage = _get_memory (
348+ proc , backend , timestamps = timestamps ,
349+ include_children = include_children )
349350 if stream is not None :
350351 stream .write ("MEM {0:.6f} {1:.4f}\n " .format (* mem_usage ))
351352 else :
352353 ret .append (mem_usage )
353354 else :
354355 ret = max ([ret ,
355- _get_memory (proc , include_children = include_children )
356+ _get_memory (proc , backend , include_children = include_children )
356357 ])
357358
358359 time .sleep (interval )
@@ -390,26 +391,28 @@ def _find_script(script_name):
390391class _TimeStamperCM (object ):
391392 """Time-stamping context manager."""
392393
393- def __init__ (self , timestamps , filename ):
394- self ._timestamps = timestamps
395- self ._filename = filename
394+ def __init__ (self , timestamps , filename , backend ):
395+ self .timestamps = timestamps
396+ self .filename = filename
397+ self .backend = backend
396398
397399 def __enter__ (self ):
398- self ._timestamps .append (
399- _get_memory (os .getpid (), timestamps = True , filename = self ._filename ))
400+ self .timestamps .append (
401+ _get_memory (os .getpid (), self . backend , timestamps = True , filename = self .filename ))
400402
401403 def __exit__ (self , * args ):
402- self ._timestamps .append (
403- _get_memory (os .getpid (), timestamps = True , filename = self ._filename ))
404+ self .timestamps .append (
405+ _get_memory (os .getpid (), self . backend , timestamps = True , filename = self .filename ))
404406
405407
406408class TimeStamper :
407409 """ A profiler that just records start and end execution times for
408410 any decorated function.
409411 """
410412
411- def __init__ (self ):
413+ def __init__ (self , backend ):
412414 self .functions = {}
415+ self .backend = backend
413416
414417 def __call__ (self , func = None , precision = None ):
415418 if func is not None :
@@ -444,7 +447,7 @@ def timestamp(self, name="<block>"):
444447 filename = inspect .getsourcefile (func )
445448 except TypeError :
446449 filename = '<unknown>'
447- return _TimeStamperCM (timestamps , filename )
450+ return _TimeStamperCM (timestamps , filename , self . backend )
448451
449452 def add_function (self , func ):
450453 if func not in self .functions :
@@ -461,13 +464,13 @@ def f(*args, **kwds):
461464 except TypeError :
462465 filename = '<unknown>'
463466 timestamps = [
464- _get_memory (os .getpid (), timestamps = True , filename = filename )]
467+ _get_memory (os .getpid (), self . backend , timestamps = True , filename = filename )]
465468 self .functions [func ].append (timestamps )
466469 try :
467470 return func (* args , ** kwds )
468471 finally :
469472 # end time
470- timestamps .append (_get_memory (os .getpid (), timestamps = True ,
473+ timestamps .append (_get_memory (os .getpid (), self . backend , timestamps = True ,
471474 filename = filename ))
472475
473476 return f
@@ -484,9 +487,10 @@ def show_results(self, stream=None):
484487
485488
486489class CodeMap (dict ):
487- def __init__ (self , include_children ):
490+ def __init__ (self , include_children , backend ):
488491 self .include_children = include_children
489492 self ._toplevel = []
493+ self .backend = backend
490494
491495 def add (self , code , toplevel_code = None ):
492496 if code in self :
@@ -517,7 +521,7 @@ def add(self, code, toplevel_code=None):
517521 self .add (subcode , toplevel_code = toplevel_code )
518522
519523 def trace (self , code , lineno ):
520- memory = _get_memory (- 1 , include_children = self .include_children ,
524+ memory = _get_memory (- 1 , self . backend , include_children = self .include_children ,
521525 filename = code .co_filename )
522526 # if there is already a measurement for that line get the max
523527 previous_memory = self [code ].get (lineno , 0 )
@@ -538,10 +542,13 @@ class LineProfiler(object):
538542
539543 def __init__ (self , ** kw ):
540544 include_children = kw .get ('include_children' , False )
541- self .code_map = CodeMap (include_children = include_children )
545+ backend = kw .get ('backend' , 'psutil' )
546+ self .code_map = CodeMap (
547+ include_children = include_children , backend = backend )
542548 self .enable_count = 0
543549 self .max_mem = kw .get ('max_mem' , None )
544550 self .prevlines = []
551+ self .backend = choose_backend (kw .get ('backend' , None ))
545552
546553 def __call__ (self , func = None , precision = 1 ):
547554 if func is not None :
@@ -583,14 +590,6 @@ def f(*args, **kwds):
583590
584591 return f
585592
586- def run (self , cmd ):
587- """ Profile a single executable statement in the main namespace.
588- """
589- # TODO: can this be removed ?
590- import __main__
591- main_dict = __main__ .__dict__
592- return self .runctx (cmd , main_dict , main_dict )
593-
594593 def runctx (self , cmd , globals , locals ):
595594 """ Profile a single executable statement in the given namespaces.
596595 """
@@ -630,14 +629,14 @@ def trace_memory_usage(self, frame, event, arg):
630629 self .code_map .trace (frame .f_code , self .prevlines .pop ())
631630
632631 if self ._original_trace_function is not None :
633- ( self ._original_trace_function ) (frame , event , arg )
632+ self ._original_trace_function (frame , event , arg )
634633
635634 return self .trace_memory_usage
636635
637636 def trace_max_mem (self , frame , event , arg ):
638637 # run into PDB as soon as memory is higher than MAX_MEM
639638 if event in ('line' , 'return' ) and frame .f_code in self .code_map :
640- c = _get_memory (- 1 , filename = frame .f_code .co_filename )
639+ c = _get_memory (- 1 , self . backend , filename = frame .f_code .co_filename )
641640 if c >= self .max_mem :
642641 t = ('Current memory {0:.2f} MiB exceeded the '
643642 'maximum of {1:.2f} MiB\n ' .format (c , self .max_mem ))
@@ -986,12 +985,11 @@ def profile(func=None, stream=None, precision=1, backend='psutil'):
986985 """
987986 Decorator that will run the function and print a line-by-line profile
988987 """
989- choose_backend (backend )
990- if _backend == 'tracemalloc' and not tracemalloc .is_tracing ():
988+ if backend == 'tracemalloc' and not tracemalloc .is_tracing ():
991989 tracemalloc .start ()
992990 if func is not None :
993991 def wrapper (* args , ** kwargs ):
994- prof = LineProfiler ()
992+ prof = LineProfiler (backend = backend )
995993 val = prof (func )(* args , ** kwargs )
996994 show_results (prof , stream = stream , precision = precision )
997995 return val
@@ -1024,16 +1022,16 @@ def choose_backend(new_backend=None):
10241022
10251023 for n_backend , is_available in backends :
10261024 if is_available :
1027- global _backend
10281025 _backend = n_backend
10291026 break
10301027 if _backend == 'no_backend' :
10311028 raise NotImplementedError (
10321029 'Tracemalloc or psutil module is required for non-unix '
10331030 'platforms' )
10341031 if _backend != new_backend and new_backend is not None :
1035- print ('{0} can not be used, {1} used instead' .format (new_backend ,
1036- _backend ))
1032+ raise ValueError ('{0} can not be used, {1} used instead' .format (
1033+ new_backend , _backend ))
1034+ return _backend
10371035
10381036
10391037# Insert in the built-ins to have profile
@@ -1129,10 +1127,11 @@ def flush(self):
11291127 sys .argv [:] = args # Remove every memory_profiler arguments
11301128
11311129 script_filename = _find_script (args [0 ])
1130+ _backend = choose_backend (options .backend )
11321131 if options .timestamp :
1133- prof = TimeStamper ()
1132+ prof = TimeStamper (_backend )
11341133 else :
1135- prof = LineProfiler (max_mem = options .max_mem )
1134+ prof = LineProfiler (max_mem = options .max_mem , backend = _backend )
11361135
11371136 try :
11381137 exec_with_profiler (script_filename , prof , options .backend )
0 commit comments