w3resource

Implementing a Python decorator to measure memory usage of a function

Python Decorator: Exercise-11 with Solution

Write a Python program that implements a decorator to measure the memory usage of a function.

Sample Solution:

Python Code:

import tracemalloc

def measure_memory_usage(func):
    def wrapper(*args, **kwargs):
        tracemalloc.start()

        # Call the original function
        result = func(*args, **kwargs)

        snapshot = tracemalloc.take_snapshot()
        top_stats = snapshot.statistics("lineno")

        # Print the top memory-consuming lines
        print(f"Memory usage of {func.__name__}:")
        for stat in top_stats[:5]:
            print(stat)

        # Return the result
        return result

    return wrapper

# Example usage
@measure_memory_usage
def calculate_factorial(n):
    if n == 0:
        return 1
    else:
        return n * calculate_factorial(n - 1)

# Call the decorated function
result = calculate_factorial(5)
print("Factorial:", result)

Sample Output:

Memory usage of calculate_factorial:
/tmp/sessions/aeafebf7cb54338f/main.py:29: size=2128 B, count=9, average=236 B
/tmp/sessions/aeafebf7cb54338f/main.py:8: size=1376 B, count=5, average=275 B
/tmp/sessions/aeafebf7cb54338f/main.py:10: size=416 B, count=1, average=416 B
Memory usage of calculate_factorial:
/tmp/sessions/aeafebf7cb54338f/main.py:29: size=2128 B, count=9, average=236 B
/tmp/sessions/aeafebf7cb54338f/main.py:8: size=1312 B, count=4, average=328 B
/usr/local/lib/python3.10/tracemalloc.py:226: size=880 B, count=3, average=293 B
/usr/local/lib/python3.10/tracemalloc.py:173: size=800 B, count=2, average=400 B
/usr/local/lib/python3.10/tracemalloc.py:533: size=568 B, count=1, average=568 B
Memory usage of calculate_factorial:
/tmp/sessions/aeafebf7cb54338f/main.py:29: size=2016 B, count=7, average=288 B
/usr/local/lib/python3.10/tracemalloc.py:67: size=1280 B, count=20, average=64 B
/usr/local/lib/python3.10/tracemalloc.py:535: size=1240 B, count=3, average=413 B
/usr/local/lib/python3.10/tracemalloc.py:193: size=1104 B, count=23, average=48 B
/usr/local/lib/python3.10/tracemalloc.py:226: size=880 B, count=3, average=293 B
Memory usage of calculate_factorial:
/tmp/sessions/aeafebf7cb54338f/main.py:29: size=1904 B, count=5, average=381 B
/usr/local/lib/python3.10/tracemalloc.py:558: size=1416 B, count=29, average=49 B
/usr/local/lib/python3.10/tracemalloc.py:67: size=1344 B, count=21, average=64 B
/usr/local/lib/python3.10/tracemalloc.py:535: size=1240 B, count=3, average=413 B
/usr/local/lib/python3.10/tracemalloc.py:226: size=832 B, count=2, average=416 B
Memory usage of calculate_factorial:
/tmp/sessions/aeafebf7cb54338f/main.py:29: size=1856 B, count=4, average=464 B
/usr/local/lib/python3.10/tracemalloc.py:67: size=1408 B, count=22, average=64 B
/usr/local/lib/python3.10/tracemalloc.py:535: size=1240 B, count=3, average=413 B
/usr/local/lib/python3.10/tracemalloc.py:558: size=1232 B, count=25, average=49 B
/usr/local/lib/python3.10/tracemalloc.py:226: size=880 B, count=3, average=293 B
Factorial: 24

Explanation:

In the above exercise -

The decorator function "measure_memory_usage()" measures the memory usage of a function using the tracemalloc module. Here's a brief explanation of the code:

  • The measure_memory_usage decorator takes a function func as an argument.
  • Within the wrapper function, tracemalloc.start() is called to start tracing memory allocations.
  • The original function func is called with the provided arguments and the result is stored in the result variable.
  • tracemalloc.take_snapshot() is used to take a snapshot of the memory allocation at that point in the code.
  • The snapshot is used to retrieve memory statistics using snapshot.statistics("lineno"). This returns a list of statistics sorted by line number.
  • The decorator then prints the top memory-consuming lines by iterating over the top_stats list and printing them.
  • Finally, the original function result is returned.

In the example,

  • The calculate_factorial function is decorated with @measure_memory_usage to measure its memory usage.
  • The decorated function is called with an argument of 5 to calculate the factorial.
  • The factorial result is printed along with the memory usage statistics obtained from the decorator.

Flowchart:

Flowchart: Python - Implementing a Python decorator to measure memory usage of a function.

Have another way to solve this solution? Contribute your code (and comments) through Disqus.

Previous: Implementing a Python decorator for enforcing type checking on function arguments.
Next: Implementing a Python decorator for caching with expiration time in functions.

What is the difficulty level of this exercise?

Test your Programming skills with w3resource's quiz.



Follow us on Facebook and Twitter for latest update.