Hello community,
here is the log from the commit of package python-memory_profiler for
openSUSE:Factory checked in at 2020-01-22 22:46:37
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-memory_profiler (Old)
and /work/SRC/openSUSE:Factory/.python-memory_profiler.new.26092 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-memory_profiler"
Wed Jan 22 22:46:37 2020 rev:6 rq:766366 version:0.57.0
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-memory_profiler/python-memory_profiler.changes
2019-04-24 13:57:39.439978351 +0200
+++
/work/SRC/openSUSE:Factory/.python-memory_profiler.new.26092/python-memory_profiler.changes
2020-01-22 22:47:03.740599539 +0100
@@ -1,0 +2,6 @@
+Wed Jan 22 15:34:33 UTC 2020 - Martin Sirringhaus <[email protected]>
+
+- Update to 0.57.0:
+ * no upstream changelog available
+
+-------------------------------------------------------------------
Old:
----
memory_profiler-0.55.0.tar.gz
New:
----
memory_profiler-0.57.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-memory_profiler.spec ++++++
--- /var/tmp/diff_new_pack.vRu4zo/_old 2020-01-22 22:47:04.964600155 +0100
+++ /var/tmp/diff_new_pack.vRu4zo/_new 2020-01-22 22:47:04.968600157 +0100
@@ -1,7 +1,7 @@
#
# spec file for package python-memory_profiler
#
-# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2020 SUSE LLC
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -18,7 +18,7 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
Name: python-memory_profiler
-Version: 0.55.0
+Version: 0.57.0
Release: 0
Summary: A module for monitoring memory usage of a python program
License: BSD-3-Clause
++++++ memory_profiler-0.55.0.tar.gz -> memory_profiler-0.57.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/memory_profiler-0.55.0/PKG-INFO
new/memory_profiler-0.57.0/PKG-INFO
--- old/memory_profiler-0.55.0/PKG-INFO 2018-12-14 16:21:33.000000000 +0100
+++ new/memory_profiler-0.57.0/PKG-INFO 2020-01-11 01:45:10.000000000 +0100
@@ -1,8 +1,8 @@
Metadata-Version: 1.1
Name: memory_profiler
-Version: 0.55.0
+Version: 0.57.0
Summary: A module for monitoring memory usage of a python program
-Home-page: http://pypi.python.org/pypi/memory_profiler
+Home-page: https://github.com/pythonprofilers/memory_profiler
Author: Fabian Pedregosa
Author-email: [email protected]
License: BSD
@@ -158,6 +158,11 @@
:target: https://github.com/scikit-learn/scikit-learn/pull/2248
:height: 350px
+ or, with ``mprof plot --flame`` (the function and timestamp names will
appear on hover):
+
+ .. image:: ./images/flamegraph.png
+ :height: 350px
+
A discussion of these capabilities can be found `here
<http://fa.bianp.net/blog/2014/plot-memory-usage-as-a-function-of-time/>`_.
.. warning:: If your Python file imports the memory profiler `from
memory_profiler import profile` these timestamps will not be recorded. Comment
out the import, leave your functions decorated, and re-run.
@@ -205,6 +210,19 @@
the API directly, note that the return from ``memory_usage`` will
include the
child memory in a nested list along with the main process memory.
+ Plot settings
+ ===============================
+
+ By default, the command line call is set as the graph title. If you
wish to customize it, you can use the ``-t`` option to manually set the figure
title.
+
+
+ mprof plot -t 'Recorded memory usage'
+
+ You can also hide the function timestamps using the ``n`` flag, such as
+
+ mprof plot -n
+
+
Setting debugger breakpoints
=============================
It is possible to set breakpoints depending on the amount of memory
used.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/memory_profiler-0.55.0/README.rst
new/memory_profiler-0.57.0/README.rst
--- old/memory_profiler-0.55.0/README.rst 2018-12-13 16:49:08.000000000
+0100
+++ new/memory_profiler-0.57.0/README.rst 2019-11-05 21:56:35.000000000
+0100
@@ -150,6 +150,11 @@
:target: https://github.com/scikit-learn/scikit-learn/pull/2248
:height: 350px
+or, with ``mprof plot --flame`` (the function and timestamp names will appear
on hover):
+
+.. image:: ./images/flamegraph.png
+ :height: 350px
+
A discussion of these capabilities can be found `here
<http://fa.bianp.net/blog/2014/plot-memory-usage-as-a-function-of-time/>`_.
.. warning:: If your Python file imports the memory profiler `from
memory_profiler import profile` these timestamps will not be recorded. Comment
out the import, leave your functions decorated, and re-run.
@@ -197,6 +202,19 @@
the API directly, note that the return from ``memory_usage`` will include the
child memory in a nested list along with the main process memory.
+Plot settings
+===============================
+
+By default, the command line call is set as the graph title. If you wish to
customize it, you can use the ``-t`` option to manually set the figure title.
+
+
+ mprof plot -t 'Recorded memory usage'
+
+You can also hide the function timestamps using the ``n`` flag, such as
+
+ mprof plot -n
+
+
Setting debugger breakpoints
=============================
It is possible to set breakpoints depending on the amount of memory used.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/memory_profiler-0.55.0/memory_profiler.egg-info/PKG-INFO
new/memory_profiler-0.57.0/memory_profiler.egg-info/PKG-INFO
--- old/memory_profiler-0.55.0/memory_profiler.egg-info/PKG-INFO
2018-12-14 16:21:33.000000000 +0100
+++ new/memory_profiler-0.57.0/memory_profiler.egg-info/PKG-INFO
2020-01-11 01:45:10.000000000 +0100
@@ -1,8 +1,8 @@
Metadata-Version: 1.1
Name: memory-profiler
-Version: 0.55.0
+Version: 0.57.0
Summary: A module for monitoring memory usage of a python program
-Home-page: http://pypi.python.org/pypi/memory_profiler
+Home-page: https://github.com/pythonprofilers/memory_profiler
Author: Fabian Pedregosa
Author-email: [email protected]
License: BSD
@@ -158,6 +158,11 @@
:target: https://github.com/scikit-learn/scikit-learn/pull/2248
:height: 350px
+ or, with ``mprof plot --flame`` (the function and timestamp names will
appear on hover):
+
+ .. image:: ./images/flamegraph.png
+ :height: 350px
+
A discussion of these capabilities can be found `here
<http://fa.bianp.net/blog/2014/plot-memory-usage-as-a-function-of-time/>`_.
.. warning:: If your Python file imports the memory profiler `from
memory_profiler import profile` these timestamps will not be recorded. Comment
out the import, leave your functions decorated, and re-run.
@@ -205,6 +210,19 @@
the API directly, note that the return from ``memory_usage`` will
include the
child memory in a nested list along with the main process memory.
+ Plot settings
+ ===============================
+
+ By default, the command line call is set as the graph title. If you
wish to customize it, you can use the ``-t`` option to manually set the figure
title.
+
+
+ mprof plot -t 'Recorded memory usage'
+
+ You can also hide the function timestamps using the ``n`` flag, such as
+
+ mprof plot -n
+
+
Setting debugger breakpoints
=============================
It is possible to set breakpoints depending on the amount of memory
used.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/memory_profiler-0.55.0/memory_profiler.egg-info/SOURCES.txt
new/memory_profiler-0.57.0/memory_profiler.egg-info/SOURCES.txt
--- old/memory_profiler-0.55.0/memory_profiler.egg-info/SOURCES.txt
2018-12-14 16:21:33.000000000 +0100
+++ new/memory_profiler-0.57.0/memory_profiler.egg-info/SOURCES.txt
2020-01-11 01:45:10.000000000 +0100
@@ -25,5 +25,6 @@
test/test_nested.py
test/test_precision_command_line.py
test/test_precision_import.py
+test/test_stream_unicode.py
test/test_tracemalloc.py
test/test_unicode.py
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/memory_profiler-0.55.0/memory_profiler.py
new/memory_profiler-0.57.0/memory_profiler.py
--- old/memory_profiler-0.55.0/memory_profiler.py 2018-12-14
16:14:18.000000000 +0100
+++ new/memory_profiler-0.57.0/memory_profiler.py 2020-01-11
01:44:21.000000000 +0100
@@ -3,7 +3,7 @@
# .. we'll use this to pass it to the child script ..
_CLEAN_GLOBALS = globals().copy()
-__version__ = '0.55.0'
+__version__ = '0.57.0'
_CMD_USAGE = "python -m memory_profiler script_file.py"
@@ -18,6 +18,7 @@
import time
import traceback
import warnings
+import contextlib
if sys.platform == "win32":
# any value except signal.CTRL_C_EVENT and signal.CTRL_BREAK_EVENT
@@ -48,13 +49,11 @@
if PY2:
import __builtin__ as builtins
+ to_str = lambda x: x
from future_builtins import filter
else:
import builtins
-
-
- def unicode(x, *args):
- return str(x)
+ to_str = lambda x: str(x)
# .. get available packages ..
try:
@@ -239,7 +238,7 @@
def memory_usage(proc=-1, interval=.1, timeout=None, timestamps=False,
include_children=False, multiprocess=False, max_usage=False,
- retval=False, stream=None, backend=None):
+ retval=False, stream=None, backend=None, max_iterations=None):
"""
Return the memory usage of a process or piece of code
@@ -281,6 +280,10 @@
to this file instead of stored in memory and returned at the end of
the subprocess. Useful for long-running processes.
Implies timestamps=True.
+
+ max_iterations : int
+ Limits the number of iterations (calls to the process being
monitored). Relevent
+ when the process is a python function.
Returns
-------
@@ -301,13 +304,15 @@
ret = -1
if timeout is not None:
- max_iter = int(timeout / interval)
+ max_iter = int(round(timeout / interval))
elif isinstance(proc, int):
# external process and no timeout
max_iter = 1
else:
# for a Python function wait until it finishes
max_iter = float('inf')
+ if max_iterations is not None:
+ max_iter = max_iterations
if callable(proc):
proc = (proc, (), {})
@@ -321,7 +326,9 @@
else:
raise ValueError
+ current_iter = 0
while True:
+ current_iter += 1
child_conn, parent_conn = Pipe() # this will store MemTimer's
results
p = MemTimer(os.getpid(), interval, child_conn, backend,
timestamps=timestamps,
@@ -337,6 +344,9 @@
parent_conn.send(0) # finish timing
ret = parent_conn.recv()
n_measurements = parent_conn.recv()
+ if max_usage:
+ # Convert the one element list produced by MemTimer to a
singular value
+ ret = ret[0]
if retval:
ret = ret, returned
except Exception:
@@ -347,7 +357,8 @@
raise
p.join(5 * interval)
- if n_measurements > 4 or interval < 1e-6:
+
+ if (n_measurements > 4) or (current_iter == max_iter) or (interval
< 1e-6):
break
interval /= 10.
elif isinstance(proc, subprocess.Popen):
@@ -459,16 +470,25 @@
class _TimeStamperCM(object):
"""Time-stamping context manager."""
- def __init__(self, timestamps, filename, backend):
+ def __init__(self, timestamps, filename, backend, timestamper=None,
func=None):
self.timestamps = timestamps
self.filename = filename
self.backend = backend
+ self.ts = timestamper
+ self.func = func
def __enter__(self):
+ if self.ts is not None:
+ self.ts.current_stack_level += 1
+ self.ts.stack[self.func].append(self.ts.current_stack_level)
+
self.timestamps.append(
_get_memory(os.getpid(), self.backend, timestamps=True,
filename=self.filename))
def __exit__(self, *args):
+ if self.ts is not None:
+ self.ts.current_stack_level -= 1
+
self.timestamps.append(
_get_memory(os.getpid(), self.backend, timestamps=True,
filename=self.filename))
@@ -481,6 +501,8 @@
def __init__(self, backend):
self.functions = {}
self.backend = backend
+ self.current_stack_level = -1
+ self.stack = {}
def __call__(self, func=None, precision=None):
if func is not None:
@@ -515,11 +537,18 @@
filename = inspect.getsourcefile(func)
except TypeError:
filename = '<unknown>'
- return _TimeStamperCM(timestamps, filename, self.backend)
+ return _TimeStamperCM(
+ timestamps,
+ filename,
+ self.backend,
+ timestamper=self,
+ func=func
+ )
def add_function(self, func):
if func not in self.functions:
self.functions[func] = []
+ self.stack[func] = []
def wrap_function(self, func):
""" Wrap a function to timestamp it.
@@ -535,7 +564,8 @@
_get_memory(os.getpid(), self.backend, timestamps=True,
filename=filename)]
self.functions[func].append(timestamps)
try:
- return func(*args, **kwds)
+ with self.call_on_stack(func, *args, **kwds) as result:
+ return result
finally:
# end time
timestamps.append(_get_memory(os.getpid(), self.backend,
timestamps=True,
@@ -543,15 +573,24 @@
return f
+ @contextlib.contextmanager
+ def call_on_stack(self, func, *args, **kwds):
+ self.current_stack_level += 1
+ self.stack[func].append(self.current_stack_level)
+
+ yield func(*args, **kwds)
+
+ self.current_stack_level -= 1
+
def show_results(self, stream=None):
if stream is None:
stream = sys.stdout
for func, timestamps in self.functions.items():
function_name = "%s.%s" % (func.__module__, func.__name__)
- for ts in timestamps:
- stream.write("FUNC %s %.4f %.4f %.4f %.4f\n" % (
- (function_name,) + ts[0] + ts[1]))
+ for ts, level in zip(timestamps, self.stack[func]):
+ stream.write("FUNC %s %.4f %.4f %.4f %.4f %d\n" % (
+ (function_name,) + ts[0] + ts[1] + (level,)))
class CodeMap(dict):
@@ -778,7 +817,7 @@
mem = u''
inc = u''
tmp = template.format(lineno, mem, inc, all_lines[lineno - 1])
- stream.write(unicode(tmp, 'UTF-8'))
+ stream.write(to_str(tmp))
stream.write(u'\n\n')
@@ -1013,7 +1052,7 @@
timeout=timeout, interval=interval,
max_usage=True,
include_children=include_children)
- mem_usage.append(tmp[0])
+ mem_usage.append(tmp)
result = MemitResult(mem_usage, baseline, repeat, timeout, interval,
include_children)
@@ -1118,7 +1157,15 @@
def exec_with_profiler(filename, profiler, backend, passed_args=[]):
from runpy import run_module
builtins.__dict__['profile'] = profiler
- ns = dict(_CLEAN_GLOBALS, profile=profiler)
+ ns = dict(_CLEAN_GLOBALS,
+ profile=profiler,
+ # Make sure the __file__ variable is usable
+ # by the script we're profiling
+ __file__=filename)
+ # Make sure the script's directory in on sys.path
+ # credit to line_profiler
+ sys.path.insert(0, os.path.dirname(script_filename))
+
_backend = choose_backend(backend)
sys.argv = [filename] + passed_args
try:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/memory_profiler-0.55.0/mprof.py
new/memory_profiler-0.57.0/mprof.py
--- old/memory_profiler-0.55.0/mprof.py 2018-12-14 16:13:49.000000000 +0100
+++ new/memory_profiler-0.57.0/mprof.py 2019-11-05 21:56:35.000000000 +0100
@@ -7,10 +7,12 @@
import time
import math
import logging
+import itertools
from collections import defaultdict
from argparse import ArgumentParser, ArgumentError, REMAINDER,
RawTextHelpFormatter
+import importlib
import memory_profiler as mp
ALL_ACTIONS = ("run", "rm", "clean", "list", "plot")
@@ -202,7 +204,7 @@
'Option 4: (--python flag present)
"<PYTHON_MODULE> <ARG1> <ARG2>..." - profile python module\n'
)
args = parser.parse_args()
-
+
if len(args.program) == 0:
print("A program to run must be provided. Use -h for help")
sys.exit(1)
@@ -329,8 +331,12 @@
values = value.split(' ')
f_name, mem_start, start, mem_end, end = values[:5]
ts = func_ts.get(f_name, [])
- ts.append([float(start), float(end),
- float(mem_start), float(mem_end)])
+ to_append = [float(start), float(end), float(mem_start),
float(mem_end)]
+ if len(values) >= 6:
+ # There is a stack level field
+ stack_level = values[5]
+ to_append.append(int(stack_level))
+ ts.append(to_append)
func_ts[f_name] = ts
elif field == "CHLD":
@@ -450,6 +456,207 @@
return mprofile
+
+FLAME_PLOTTER_VARS = {
+ 'hovered_rect': None,
+ 'hovered_text': None,
+ 'alpha': None
+}
+
+def flame_plotter(filename, index=0, timestamps=True, children=True,
options=None):
+ try:
+ import pylab as pl
+ except ImportError as e:
+ print("matplotlib is needed for plotting.")
+ print(e)
+ sys.exit(1)
+ import numpy as np # pylab requires numpy anyway
+ mprofile = read_mprofile_file(filename)
+
+ if len(mprofile['timestamp']) == 0:
+ print('** No memory usage values have been found in the profile '
+ 'file.**\nFile path: {0}\n'
+ 'File may be empty or invalid.\n'
+ 'It can be deleted with "mprof rm {0}"'.format(
+ mprofile['filename']))
+ sys.exit(0)
+
+ # Merge function timestamps and memory usage together
+ ts = mprofile['func_timestamp']
+ t = mprofile['timestamp']
+ mem = mprofile['mem_usage']
+ chld = mprofile['children']
+
+ if len(ts) > 0:
+ for values in ts.values():
+ for v in values:
+ t.extend(v[:2])
+ mem.extend(v[2:4])
+
+ mem = np.asarray(mem)
+ t = np.asarray(t)
+ ind = t.argsort()
+ mem = mem[ind]
+ t = t[ind]
+
+ if ts:
+ stack_size = 1 + max(ex[4] for executions in ts.values() for ex in
executions)
+ else:
+ stack_size = 0
+ def level_to_saturation(level):
+ return 1 - 0.75 * level / stack_size
+
+ colors = [
+ itertools.cycle([
+ pl.matplotlib.colors.hsv_to_rgb((0, level_to_saturation(level),
1)),
+ pl.matplotlib.colors.hsv_to_rgb((0.1, level_to_saturation(level),
1)),
+ ]) for level in range(stack_size)
+ ]
+
+ # Plot curves
+ global_start = float(t[0])
+ t = t - global_start
+
+ max_mem = mem.max()
+ max_mem_ind = mem.argmax()
+
+ # cmap = pl.cm.get_cmap('gist_rainbow')
+ mem_line_colors = ("k", "b", "r", "g", "c", "y", "m")
+ mem_line_label = time.strftime("%d / %m / %Y - start at %H:%M:%S",
+ time.localtime(global_start)) \
+ + ".{0:03d}".format(int(round(math.modf(global_start)[0]
* 1000)))
+
+ pl.plot(t, mem, "-" + mem_line_colors[index % len(mem_line_colors)],
+ label=mem_line_label)
+
+ bottom, top = pl.ylim()
+ bottom += 0.001
+ top -= 0.001
+
+ ax = pl.gca()
+ ax.grid(True)
+ timestamp_ax = ax.twinx()
+ timestamp_ax.set_yticks([])
+ timestamp_ax.set_ylim((0, stack_size + 1))
+ timestamp_ax.grid(False)
+
+ # plot children, if any
+ if len(chld) > 0 and children:
+ cmpoint = (0,0) # maximal child memory
+
+ for idx, (proc, data) in enumerate(chld.items()):
+ # Create the numpy arrays from the series data
+ cts = np.asarray([item[1] for item in data]) - global_start
+ cmem = np.asarray([item[0] for item in data])
+
+ # Plot the line to the figure
+ pl.plot(cts, cmem, "+-" + mem_line_colors[(idx+1) %
len(mem_line_colors)],
+ label="child {}".format(proc))
+
+ # Detect the maximal child memory point
+ cmax_mem = cmem.max()
+ if cmax_mem > cmpoint[1]:
+ cmpoint = (cts[cmem.argmax()], cmax_mem)
+
+ # Add the marker lines for the maximal child memory usage
+ pl.vlines(cmpoint[0], pl.ylim()[0]+0.001, pl.ylim()[1] - 0.001, 'r',
'--')
+ pl.hlines(cmpoint[1], pl.xlim()[0]+0.001, pl.xlim()[1] - 0.001, 'r',
'--')
+
+ def mouse_motion_handler(event):
+ x, y = event.xdata, event.ydata
+ if x is not None and y is not None:
+ for coord, (name, text, rect) in rectangles.items():
+ x0, y0, x1, y1 = coord
+ if x0 < x < x1 and y0 < y < y1:
+ if FLAME_PLOTTER_VARS['hovered_rect'] == rect:
+ return
+
+ if FLAME_PLOTTER_VARS['hovered_rect'] is not None:
+
FLAME_PLOTTER_VARS['hovered_rect'].set_alpha(FLAME_PLOTTER_VARS['alpha'])
+ FLAME_PLOTTER_VARS['hovered_text'].set_color((0, 0, 0,
0))
+ FLAME_PLOTTER_VARS['hovered_rect'].set_linewidth(1)
+
+ FLAME_PLOTTER_VARS['hovered_text'] = text
+ FLAME_PLOTTER_VARS['hovered_rect'] = rect
+ FLAME_PLOTTER_VARS['alpha'] = rect.get_alpha()
+ FLAME_PLOTTER_VARS['hovered_rect'].set_alpha(0.8)
+ FLAME_PLOTTER_VARS['hovered_rect'].set_linewidth(3)
+ FLAME_PLOTTER_VARS['hovered_text'].set_color((0, 0, 0, 1))
+ pl.draw()
+ return
+
+ if FLAME_PLOTTER_VARS['hovered_rect'] is not None:
+ FLAME_PLOTTER_VARS['hovered_text'].set_color((0, 0, 0, 0))
+
FLAME_PLOTTER_VARS['hovered_rect'].set_alpha(FLAME_PLOTTER_VARS['alpha'])
+ FLAME_PLOTTER_VARS['hovered_rect'].set_linewidth(1)
+ pl.draw()
+ FLAME_PLOTTER_VARS['hovered_rect'] = None
+ FLAME_PLOTTER_VARS['hovered_text'] = None
+
+ def mouse_click_handler(event):
+ x, y = event.xdata, event.ydata
+ if x is None or y is None:
+ return
+
+ for coord, _ in rectangles.items():
+ x0, y0, x1, y1 = coord
+ if x0 < x < x1 and y0 < y < y1:
+ toolbar = pl.gcf().canvas.toolbar
+ toolbar.push_current()
+ timestamp_ax.set_xlim(x0, x1)
+ timestamp_ax.set_ylim(y0, stack_size + 1)
+ toolbar.push_current()
+ pl.draw()
+ return
+
+ # plot timestamps, if any
+ if len(ts) > 0 and timestamps:
+ func_num = 0
+ f_labels = function_labels(ts.keys())
+ rectangles = {}
+ for f, exec_ts in ts.items():
+ for execution in exec_ts:
+ x0, x1 = execution[:2]
+ y0 = execution[4]
+ y1 = y0 + 1
+ x0 -= global_start
+ x1 -= global_start
+ color = next(colors[y0])
+ rect, text = add_timestamp_rectangle(
+ timestamp_ax,
+ x0, x1, y0, y1, f,
+ color=color
+ )
+ rectangles[(x0, y0, x1, y1)] = (f, text, rect)
+ func_num += 1
+
+ # Disable hovering if there are too many rectangle to prevent slow down
+ if len(rectangles) < 100:
+ pl.gcf().canvas.mpl_connect('motion_notify_event',
mouse_motion_handler)
+ pl.gcf().canvas.mpl_connect('button_release_event',
mouse_click_handler)
+
+ if timestamps:
+ pl.hlines(max_mem,
+ pl.xlim()[0] + 0.001, pl.xlim()[1] - 0.001,
+ colors="r", linestyles="--")
+ pl.vlines(t[max_mem_ind], bottom, top,
+ colors="r", linestyles="--")
+
+ pl.sca(ax)
+
+ return mprofile
+
+
+def add_timestamp_rectangle(ax, x0, x1, y0, y1, func_name, color='none'):
+ rect = ax.fill_betweenx((y0, y1), x0, x1, color=color, alpha=0.5,
linewidth=1)
+ text = ax.text(x0, y1, func_name,
+ horizontalalignment='left',
+ verticalalignment='top',
+ color=(0, 0, 0, 0)
+ )
+ return rect, text
+
+
def function_labels(dotted_function_names):
state = {}
@@ -501,6 +708,8 @@
help="Save plot to file instead of displaying it.")
parser.add_argument("--window", "-w", dest="xlim", type=xlim_type,
help="Plot a time-subset of the data. E.g. to plot
between 0 and 20.5 seconds: --window 0,20.5")
+ parser.add_argument("--flame", "-f", dest="flame_mode",
action="store_true",
+ help="Plot the timestamps as a flame-graph instead of
the default brackets")
parser.add_argument("--backend",
help="Specify the Matplotlib backend to use")
parser.add_argument("profiles", nargs="*",
@@ -517,6 +726,7 @@
print("matplotlib is needed for plotting.")
print(e)
sys.exit(1)
+ pl.ioff()
profiles = glob.glob("mprofile_??????????????.dat")
profiles.sort()
@@ -547,7 +757,10 @@
sys.exit(-1)
fig = pl.figure(figsize=(14, 6), dpi=90)
- ax = fig.add_axes([0.1, 0.1, 0.6, 0.75])
+ if not args.flame_mode:
+ ax = fig.add_axes([0.1, 0.1, 0.6, 0.75])
+ else:
+ ax = fig.add_axes([0.1, 0.1, 0.8, 0.8])
if args.xlim is not None:
pl.xlim(args.xlim[0], args.xlim[1])
@@ -555,8 +768,11 @@
timestamps = False
else:
timestamps = True
+ plotter = plot_file
+ if args.flame_mode:
+ plotter = flame_plotter
for n, filename in enumerate(filenames):
- mprofile = plot_file(filename, index=n, timestamps=timestamps,
options=args)
+ mprofile = plotter(filename, index=n, timestamps=timestamps,
options=args)
pl.xlabel("time (in seconds)")
pl.ylabel("memory used (in MiB)")
@@ -568,9 +784,11 @@
# place legend within the plot, make partially transparent in
# case it obscures part of the lineplot
- leg = ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))
- leg.get_frame().set_alpha(0.5)
- pl.grid()
+ if not args.flame_mode:
+ leg = ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))
+ leg.get_frame().set_alpha(0.5)
+ pl.grid()
+
if args.output:
pl.savefig(args.output)
else:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/memory_profiler-0.55.0/setup.py
new/memory_profiler-0.57.0/setup.py
--- old/memory_profiler-0.55.0/setup.py 2018-12-13 16:49:08.000000000 +0100
+++ new/memory_profiler-0.57.0/setup.py 2019-11-05 21:56:35.000000000 +0100
@@ -46,7 +46,7 @@
version=find_version("memory_profiler.py"),
author='Fabian Pedregosa',
author_email='[email protected]',
- url='http://pypi.python.org/pypi/memory_profiler',
+ url='https://github.com/pythonprofilers/memory_profiler',
py_modules=['memory_profiler', 'mprof'],
entry_points={
'console_scripts' : ['mprof = mprof:main'],
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/memory_profiler-0.55.0/test/test_memory_usage.py
new/memory_profiler-0.57.0/test/test_memory_usage.py
--- old/memory_profiler-0.55.0/test/test_memory_usage.py 2018-12-13
16:49:08.000000000 +0100
+++ new/memory_profiler-0.57.0/test/test_memory_usage.py 2019-11-05
21:56:35.000000000 +0100
@@ -1,4 +1,5 @@
from memory_profiler import memory_usage
+import os
def some_func(*args, **kwargs):
@@ -10,6 +11,36 @@
mem, ret = memory_usage((some_func, (1, 2), dict(a=1)), retval=True)
assert ret[0] == (1, 2)
assert ret[1] == dict(a=1)
+
+
+def write_line(filepath):
+ with open(filepath, 'a') as the_file:
+ the_file.write('Testing\n')
+
+def test_max_iterations():
+ # Check that memory_usage works with max_iterations set (for python
functions).
+ this_dir = os.path.dirname(os.path.realpath(__file__))
+ file = os.path.join(this_dir, 'temp_test_max_iterations_file.txt')
+ mem = memory_usage((write_line, (file, ), dict()), max_usage=True,
max_iterations=1)
+ n_lines = sum(1 for line in open(file))
+ os.remove(file)
+ assert n_lines == 1
+
+
+def test_return_value_consistency():
+ # Test return values when watching process by PID
+ pid_mem_list = memory_usage(timeout=1)
+ assert type(pid_mem_list) == list, "Memory usage of process should be a
list"
+ pid_mem_max = memory_usage(timeout=1, max_usage=True)
+ assert type(pid_mem_max) == float, "Max memory usage of process should be
a number"
+ # Test return values when watching callable
+ func_mem_list = memory_usage((some_func, (42,), dict(a=42)))
+ assert type(func_mem_list) == list, "Memory usage of callable should be a
list"
+ func_mem_max = memory_usage((some_func, (42,), dict(a=42)), max_usage=True)
+ assert type(func_mem_max) == float, "Max memory usage of callable should
be a number"
+
if __name__ == "__main__":
test_memory_usage()
+ test_max_iterations()
+ test_return_value_consistency()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/memory_profiler-0.55.0/test/test_stream_unicode.py
new/memory_profiler-0.57.0/test/test_stream_unicode.py
--- old/memory_profiler-0.55.0/test/test_stream_unicode.py 1970-01-01
01:00:00.000000000 +0100
+++ new/memory_profiler-0.57.0/test/test_stream_unicode.py 2019-11-05
21:56:35.000000000 +0100
@@ -0,0 +1,14 @@
+# -*- coding: utf-8 -*-
+
+from memory_profiler import profile
+
+f = open('/dev/null', 'w')
+@profile(stream=f)
+def test_unicode(txt):
+ # test when unicode is present
+ txt = txt.replace (u"ی", u"ي") #Arabic Yah = ي
+ return txt
+
+
+if __name__ == '__main__':
+ test_unicode (u"ایست")