diff -Nru python-memory-profiler-0.60/debian/changelog python-memory-profiler-0.61/debian/changelog --- python-memory-profiler-0.60/debian/changelog 2022-10-15 06:28:38.000000000 +0000 +++ python-memory-profiler-0.61/debian/changelog 2022-12-06 08:16:41.000000000 +0000 @@ -1,3 +1,11 @@ +python-memory-profiler (0.61-1) unstable; urgency=medium + + * Team upload. + * New upstream version 0.61 (Closes: #1025109) + * Drop upstreamed patch + + -- Jochen Sprickerhof Tue, 06 Dec 2022 09:16:41 +0100 + python-memory-profiler (0.60-1) unstable; urgency=medium * Team upload. diff -Nru python-memory-profiler-0.60/debian/patches/0003-use-io.open-instead-of-open.patch python-memory-profiler-0.61/debian/patches/0003-use-io.open-instead-of-open.patch --- python-memory-profiler-0.60/debian/patches/0003-use-io.open-instead-of-open.patch 2022-10-15 06:28:35.000000000 +0000 +++ python-memory-profiler-0.61/debian/patches/0003-use-io.open-instead-of-open.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -From: Fabian Pedregosa -Date: Wed, 9 Feb 2022 15:40:52 -0500 -Subject: use io.open instead of open - ---- - test/test_async.py | 13 ++++++------- - 1 file changed, 6 insertions(+), 7 deletions(-) - -diff --git a/test/test_async.py b/test/test_async.py -index 14cd9c0..00ab016 100644 ---- a/test/test_async.py -+++ b/test/test_async.py -@@ -4,16 +4,15 @@ from memory_profiler import profile - - - @profile --@asyncio.coroutine --def my_func(): -+async def my_func(): - a = [1] * (10 ** 6) - b = [2] * (2 * 10 ** 7) -- yield from asyncio.sleep(1e-2) -+ await asyncio.sleep(1e-2) - del b -- return 42 - -+async def main(): -+ task = asyncio.create_task(my_func()) -+ res = await asyncio.gather(task) - - if __name__ == '__main__': -- loop = asyncio.get_event_loop() -- res = loop.run_until_complete(my_func()) -- assert res == 42 -+ asyncio.run(main()) # main loop diff -Nru python-memory-profiler-0.60/debian/patches/series python-memory-profiler-0.61/debian/patches/series --- python-memory-profiler-0.60/debian/patches/series 2022-10-15 06:28:35.000000000 +0000 +++ python-memory-profiler-0.61/debian/patches/series 2022-12-06 08:16:41.000000000 +0000 @@ -1,3 +1,2 @@ 0001-Fix-deprecated-syntax.patch 0002-Use-Debian-mprof-name.patch -0003-use-io.open-instead-of-open.patch diff -Nru python-memory-profiler-0.60/examples/async_decorator.py python-memory-profiler-0.61/examples/async_decorator.py --- python-memory-profiler-0.60/examples/async_decorator.py 1970-01-01 00:00:00.000000000 +0000 +++ python-memory-profiler-0.61/examples/async_decorator.py 2022-11-15 17:53:56.000000000 +0000 @@ -0,0 +1,18 @@ +import asyncio + +from memory_profiler import profile + + +@profile +@asyncio.coroutine +def foo(): + a = [1] * (10 ** 6) + b = [2] * (2 * 10 ** 7) + yield from asyncio.sleep(1) + del b + return a + + +if __name__ == "__main__": + loop = asyncio.get_event_loop() + loop.run_until_complete(foo()) diff -Nru python-memory-profiler-0.60/.github/workflows/lint_python.yml python-memory-profiler-0.61/.github/workflows/lint_python.yml --- python-memory-profiler-0.60/.github/workflows/lint_python.yml 1970-01-01 00:00:00.000000000 +0000 +++ python-memory-profiler-0.61/.github/workflows/lint_python.yml 2022-11-15 17:53:56.000000000 +0000 @@ -0,0 +1,92 @@ +name: lint_python + +on: + push: + branches: + - master + tags: + - v* + pull_request: + branches: + - '**' + +jobs: + lint: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python: + - major_dot_minor: '3.10' + safety: false + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + # This allows the matrix to specify just the major.minor version while still + # expanding it to get the latest patch version including alpha releases. + # This avoids the need to update for each new alpha, beta, release candidate, + # and then finally an actual release version. actions/setup-python doesn't + # support this for PyPy presently so we get no help there. + # + # CPython -> 3.9.0-alpha - 3.9.X + # PyPy -> pypy-3.7 + python-version: ${{ fromJSON(format('["{0}", "{1}"]', format('{0}.0-alpha - {0}.X', matrix.python.major_dot_minor), matrix.python.major_dot_minor))[startsWith(matrix.python.major_dot_minor, 'pypy')] }} + architecture: x64 + - run: pip install --upgrade pip wheel + - run: pip install bandit black codespell flake8 flake8-2020 flake8-bugbear + flake8-comprehensions isort mypy pytest pyupgrade + - run: bandit --recursive --skip B101,B102,B307,B404,B603,B607 . + - run: black --check . || true + - run: codespell # --ignore-words-list="" --skip="*.css,*.js,*.lock" + - run: flake8 . --builtins=profile --count --select=E9,F63,F7,F82 --show-source --statistics + - run: flake8 . --count --exit-zero --max-complexity=10 --max-line-length=88 + --show-source --statistics + - run: isort --check-only --profile black . || true + - run: pip install --editable . + - run: pip install numpy pylab-sdk + - run: mkdir --parents --verbose .mypy_cache + - run: mypy --ignore-missing-imports --install-types --non-interactive . || true + - run: shopt -s globstar && pyupgrade --py36-plus **/*.py || true + + test: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python: + - major_dot_minor: '3.5' + safety: false + - major_dot_minor: '3.6' + safety: false + - major_dot_minor: '3.7' + safety: false + - major_dot_minor: '3.8' + safety: true + - major_dot_minor: '3.9' + safety: true + - major_dot_minor: '3.10' + safety: true + - major_dot_minor: '3.11' + safety: true + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + # This allows the matrix to specify just the major.minor version while still + # expanding it to get the latest patch version including alpha releases. + # This avoids the need to update for each new alpha, beta, release candidate, + # and then finally an actual release version. actions/setup-python doesn't + # support this for PyPy presently so we get no help there. + # + # CPython -> 3.9.0-alpha - 3.9.X + # PyPy -> pypy-3.7 + python-version: ${{ fromJSON(format('["{0}", "{1}"]', format('{0}.0-alpha - {0}.X', matrix.python.major_dot_minor), matrix.python.major_dot_minor))[startsWith(matrix.python.major_dot_minor, 'pypy')] }} + architecture: x64 + - run: pip install --upgrade pip wheel + - run: pip install pytest safety + - run: pip install --editable . + - run: pip install numpy pylab-sdk + - run: make test + - if: matrix.python.safety + run: safety check diff -Nru python-memory-profiler-0.60/MANIFEST.in python-memory-profiler-0.61/MANIFEST.in --- python-memory-profiler-0.60/MANIFEST.in 2021-12-18 13:37:49.000000000 +0000 +++ python-memory-profiler-0.61/MANIFEST.in 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -include README.rst -include COPYING -include mprof.bat diff -Nru python-memory-profiler-0.60/memory_profiler.py python-memory-profiler-0.61/memory_profiler.py --- python-memory-profiler-0.60/memory_profiler.py 2021-12-18 13:37:49.000000000 +0000 +++ python-memory-profiler-0.61/memory_profiler.py 2022-11-15 17:53:56.000000000 +0000 @@ -3,18 +3,20 @@ # .. we'll use this to pass it to the child script .. _CLEAN_GLOBALS = globals().copy() -__version__ = '0.60.0' +__version__ = '0.61.0' _CMD_USAGE = "python -m memory_profiler script_file.py" -from asyncio import coroutine, iscoroutinefunction +from asyncio import iscoroutinefunction from contextlib import contextmanager from functools import partial, wraps +from types import coroutine import builtins import inspect import linecache import logging import os +import io import pdb import subprocess import sys @@ -104,12 +106,12 @@ for child in getattr(process, children_attr)(recursive=True): if isinstance(memory_metric, str): meminfo = getattr(child, meminfo_attr)() - yield getattr(meminfo, memory_metric) / _TWO_20 + yield child.pid, getattr(meminfo, memory_metric) / _TWO_20 else: - yield getattr(child, meminfo_attr)()[memory_metric] / _TWO_20 + yield child.pid, getattr(child, meminfo_attr)()[memory_metric] / _TWO_20 except (psutil.NoSuchProcess, psutil.AccessDenied): # https://github.com/fabianp/memory_profiler/issues/71 - yield 0.0 + yield (0, 0.0) def _get_memory(pid, backend, timestamps=False, include_children=False, filename=None): @@ -137,7 +139,7 @@ else 'get_memory_info' mem = getattr(process, meminfo_attr)()[0] / _TWO_20 if include_children: - mem += sum(_get_child_memory(process, meminfo_attr)) + mem += sum([mem for (pid, mem) in _get_child_memory(process, meminfo_attr)]) if timestamps: return mem, time.time() else: @@ -164,7 +166,7 @@ mem = getattr(meminfo, memory_metric) / _TWO_20 if include_children: - mem += sum(_get_child_memory(process, meminfo_attr, memory_metric)) + mem += sum([mem for (pid, mem) in _get_child_memory(process, meminfo_attr, memory_metric)]) if timestamps: return mem, time.time() @@ -316,7 +318,7 @@ https://psutil.readthedocs.io/en/latest/index.html?highlight=memory_info#psutil.Process.memory_full_info max_iterations : int - Limits the number of iterations (calls to the process being monitored). Relevent + Limits the number of iterations (calls to the process being monitored). Relevant when the process is a python function. Returns @@ -409,13 +411,13 @@ # Write children to the stream file if multiprocess: - for idx, chldmem in enumerate(_get_child_memory(proc.pid)): + for idx, chldmem in _get_child_memory(proc.pid): stream.write("CHLD {0} {1:.6f} {2:.4f}\n".format(idx, chldmem, time.time())) else: # Create a nested list with the child memory if multiprocess: mem_usage = [mem_usage] - for chldmem in _get_child_memory(proc.pid): + for _, chldmem in _get_child_memory(proc.pid): mem_usage.append(chldmem) # Append the memory usage to the return value @@ -453,13 +455,13 @@ # Write children to the stream file if multiprocess: - for idx, chldmem in enumerate(_get_child_memory(proc)): + for idx, chldmem in _get_child_memory(proc): stream.write("CHLD {0} {1:.6f} {2:.4f}\n".format(idx, chldmem, time.time())) else: # Create a nested list with the child memory if multiprocess: mem_usage = [mem_usage] - for chldmem in _get_child_memory(proc): + for _, chldmem in _get_child_memory(proc): mem_usage.append(chldmem) # Append the memory usage to the return value @@ -1110,7 +1112,7 @@ counter += 1 tmp = memory_usage((_func_exec, (stmt, self.shell.user_ns)), timeout=timeout, interval=interval, - max_usage=True, + max_usage=True, max_iterations=1, include_children=include_children) mem_usage.append(tmp) @@ -1246,7 +1248,7 @@ try: if _backend == 'tracemalloc' and has_tracemalloc: tracemalloc.start() - with open(filename, encoding='utf-8') as f: + with io.open(filename, encoding='utf-8') as f: exec(compile(f.read(), filename, 'exec'), ns, ns) finally: if has_tracemalloc and tracemalloc.is_tracing(): @@ -1328,7 +1330,7 @@ help='backend using for getting memory info ' '(one of the {tracemalloc, psutil, posix, psutil_pss, psutil_uss, posix})') parser.add_argument("program", nargs=REMAINDER, - help='python script or module followed by command line arguements to run') + help='python script or module followed by command line arguments to run') args = parser.parse_args() if len(args.program) == 0: diff -Nru python-memory-profiler-0.60/mprof.py python-memory-profiler-0.61/mprof.py --- python-memory-profiler-0.60/mprof.py 2021-12-18 13:37:49.000000000 +0000 +++ python-memory-profiler-0.61/mprof.py 2022-11-15 17:53:56.000000000 +0000 @@ -838,6 +838,26 @@ else: pl.show() +def filter_mprofile_mem_usage_by_function(prof, func): + if func is None: + return prof["mem_usage"] + + if func not in prof["func_timestamp"]: + raise ValueError(str(func) + " was not found.") + + time_ranges = prof["func_timestamp"][func] + filtered_memory = [] + + # The check here could be improved, but it's done in this + # inefficient way to make sure we don't miss overlapping + # ranges. + for mib, ts in zip(prof["mem_usage"], prof["timestamp"]): + for rng in time_ranges: + if rng[0] <= ts <= rng[1]: + filtered_memory.append(mib) + + return filtered_memory + def peak_action(): desc = """Prints the peak memory used in data file `file.dat` generated using `mprof run`. If no .dat file is given, it will take the most recent @@ -845,12 +865,20 @@ parser = ArgumentParser(usage="mprof peak [options] [file.dat]", description=desc) parser.add_argument("profiles", nargs="*", help="profiles made by mprof run") + parser.add_argument("--func", dest="func", default=None, + help="""Show the peak for this function. Does not support child processes.""") args = parser.parse_args() filenames = get_profiles(args) for filename in filenames: prof = read_mprofile_file(filename) - print("{}\t{:.3f} MiB".format(prof["filename"], max(prof["mem_usage"]))) + try: + mem_usage = filter_mprofile_mem_usage_by_function(prof, args.func) + except ValueError: + print("{}\tNaN MiB".format(prof["filename"])) + continue + + print("{}\t{:.3f} MiB".format(prof["filename"], max(mem_usage))) for child, values in prof["children"].items(): child_peak = max([ mem_ts[0] for mem_ts in values ]) print(" Child {}\t\t\t{:.3f} MiB".format(child, child_peak)) diff -Nru python-memory-profiler-0.60/pyproject.toml python-memory-profiler-0.61/pyproject.toml --- python-memory-profiler-0.60/pyproject.toml 1970-01-01 00:00:00.000000000 +0000 +++ python-memory-profiler-0.61/pyproject.toml 2022-11-15 17:53:56.000000000 +0000 @@ -0,0 +1,6 @@ +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" + +[tool.codespell] +skip = './.git' diff -Nru python-memory-profiler-0.60/README.rst python-memory-profiler-0.61/README.rst --- python-memory-profiler-0.60/README.rst 2021-12-18 13:37:49.000000000 +0000 +++ python-memory-profiler-0.61/README.rst 2022-11-15 17:53:56.000000000 +0000 @@ -5,6 +5,9 @@ Memory Profiler ================= + +**Note:** This package is no longer actively maintained. I won't be actively responding to issues. If you'd like to volunteer to maintain it, please drop me a line at f@bianp.net + This is a python module for monitoring memory consumption of a process as well as line-by-line analysis of memory consumption for python programs. It is a pure python module which depends on the `psutil @@ -23,8 +26,22 @@ To install from source, download the package, extract and type:: - $ python setup.py install + $ pip install . + +=========== +Quick Start +=========== + +Use `mprof` to generate a full memory usage report of your executable and to plot it. + +.. code-block:: bash + + mprof run executable + mprof plot + +The plot would be something like this: +.. image:: https://i.stack.imgur.com/ixCH4.png ======= Usage @@ -135,10 +152,11 @@ time. Depending on the case, it can be difficult to identify the part of the code that is causing the highest memory usage. -Adding the `profile` decorator to a function and running the Python +Adding the `profile` decorator to a function(ensure no +`from memory_profiler import profile` statement) and running the Python script with - mprof run