.. role:: python(code) :language: python .. index:: profiling; memory .. `profiling data size `_ `memory usage `_ .. _`sec:mem`: Memory profiling ---------------- Memory profiling is much more cumbersome than time profiling. + :python:`memory_profiler` (external dependency) allows a line by line memory usage analysis of decorated functions. + :python:`tracemalloc` (standard) for manual instrumentation Using the :python:`memory_profiler.profile` decorator, a console output is produced, for example: .. code-block:: python from memory_profiler import profile @profile def task_2(size: int) -> None: _ = [0] * size .. code-block:: console Line # Mem usage Increment Occurrences Line Contents ============================================================= 24 150.0 MiB 150.0 MiB 1 @profile 25 def task_2(size: int) -> None: 26 211.1 MiB 61.0 MiB 1 _ = [0] * size .. admonition:: Exercise (easy) What was the ``size`` value for the example above to make sense? .. _`ex:data_size`: .. collapse:: Correction An int is 8B, a MB is :math:`1024^2 B`, :math:`61\times1024^2/8\approx8` million ints. To measure a specific memory usage variation : .. code-block:: python :linenos: tracemalloc.start() _, peak_before = tracemalloc.get_traced_memory() # do something _, peak_after = tracemalloc.get_traced_memory() .. admonition:: Exercise (easy) Verify the :python:`memory_profiler` values using :python:`tracemalloc` on ``task_2``. .. _`ex:memory_usage`: .. collapse:: Correction .. code-block:: python :linenos: tracemalloc.start() _, peak_before = tracemalloc.get_traced_memory() task_2(8_000_000) _, peak_after = tracemalloc.get_traced_memory() print((peak_after - peak_before) / (1024 * 1024)) # 61 MB