Skip to content

Commit 03411e9

Browse files
committed
remove global variable _backend
1 parent 946aa5e commit 03411e9

1 file changed

Lines changed: 53 additions & 54 deletions

File tree

memory_profiler.py

Lines changed: 53 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,6 @@ def unicode(x, *args):
6060
except ImportError:
6161
has_tracemalloc = False
6262

63-
_backend = None
64-
6563

6664
class 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

171169
class 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

214214
def 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):
390391
class _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

406408
class 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

486489
class 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

Comments
 (0)