Hone logo
Hone
Problems

Python Memory Profiler

Memory profiling is a crucial skill for any Python developer, especially when dealing with large datasets or complex applications. This challenge asks you to create a basic memory profiler that can track the memory usage of Python functions and identify potential memory leaks or inefficiencies. Understanding memory usage helps optimize code for performance and resource consumption.

Problem Description

You are tasked with creating a Python decorator called memory_profiler that measures and reports the memory usage of a function. The decorator should:

  1. Measure Memory Usage: Before and after the decorated function is executed, record the memory usage of the Python process using the psutil library.
  2. Calculate Difference: Calculate the difference in memory usage between the "after" and "before" states. This difference represents the memory consumed by the function.
  3. Report Memory Usage: Print a formatted string to the console indicating the function name and the memory consumed (in MB).
  4. Return Original Value: The decorator should not alter the return value of the decorated function. It should simply measure and report memory usage.
  5. Handle Exceptions: If the decorated function raises an exception, the decorator should still measure memory usage before the exception is propagated and report it.

Key Requirements:

  • Use the psutil library for memory usage measurement. Install it with pip install psutil.
  • Implement the memory_profiler decorator.
  • The output should be clear and informative, including the function name and memory consumed in MB.
  • The decorator should work correctly with functions that return values, take arguments, and raise exceptions.

Examples

Example 1:

def my_function():
    a = [i for i in range(1000000)]
    return sum(a)

@memory_profiler
def another_function():
    my_function()

another_function()

Expected Output (will vary slightly based on system):

Memory usage of function another_function: 10.5 MB

Example 2:

def risky_function():
    a = [i for i in range(1000000)]
    if True:
        raise ValueError("Something went wrong")
    return sum(a)

@memory_profiler
def calling_risky_function():
    risky_function()

calling_risky_function()

Expected Output (will vary slightly based on system):

Memory usage of function calling_risky_function: 10.5 MB

Example 3: (Function with arguments)

def process_list(data):
    result = [x * 2 for x in data]
    return result

@memory_profiler
def main_function(input_list):
    process_list(input_list)

main_function([1, 2, 3, 4, 5])

Expected Output (will vary slightly based on system):

Memory usage of function main_function: 3.2 MB

Constraints

  • Memory Measurement: Use psutil.Process().memory_info().rss to get the resident set size (RSS) in bytes, which represents the actual memory used by the process. Convert this to MB for reporting.
  • psutil Dependency: The solution must use the psutil library.
  • Decorator Implementation: The solution must be implemented as a decorator.
  • Performance: The decorator should have minimal overhead. Avoid unnecessary computations or memory allocations within the decorator itself.
  • Input: The decorated function can accept any number of arguments and return any type of value.
  • Output: The output should be printed to the console in a clear and readable format.

Notes

  • Consider using a try-except block within the decorator to handle exceptions raised by the decorated function.
  • The memory usage reported is an approximation and may vary depending on the system and other running processes.
  • Focus on the core functionality of measuring and reporting memory usage. Error handling beyond exception propagation is not required.
  • The rss value from psutil is a good indicator of memory usage, but other metrics (e.g., virtual memory size) could also be considered for more advanced profiling. This challenge focuses on rss.
  • Remember to import psutil at the beginning of your script.
Loading editor...
python