web-dev-qa-db-ja.com

Python関数による*最大*メモリ使用量の追跡

関数の呼び出し中に割り当てられるRAMの最大量は(Pythonの場合)であるかを調べたいと思います。SOに関連する他の質問があります追跡RAM使用:

どのPythonメモリプロファイラが推奨されますか?

Pythonでメモリ使用量をプロファイルするにはどうすればよいですか?

しかし、これらはheap()メソッド(グッピーの場合)が呼び出されたときのメモリ使用量をさらに追跡できるようです。ただし、追跡したいのは、変更できない外部ライブラリの関数であり、多くのRAMを使用するようになりますが、関数の実行が完了すると解放されます関数呼び出し中に使用されたRAMの合計量が何であったかを知る方法はありますか?

40
astrofrog

この質問はかなりおもしろそうで、Guppy/Heapyを調べる理由になりました。ありがとうございます。

Heapyにソースをzero運で変更せずに関数呼び出し/プロセスを監視させるために、約2時間試してみました。

組み込みのPythonライブラリ resource を使用してタスクを実行する方法を見つけました。ドキュメントにはRU_MAXRSS値が返されます。別のSO user noted それがkBであったこと。MacOSX 7.3を実行し、以下のテストコード中にシステムリソースが上昇するのを観察すると、戻り値はBytesで、kBytesではありません。

resourceライブラリを使用してライブラリの呼び出しを監視する方法に関する10000ftのビューは、別の(監視可能な)スレッドで関数を起動し、メインスレッドでそのプロセスのシステムリソースを追跡することでした。以下に、テストするために実行する必要がある2つのファイルを示します。

ライブラリリソースモニター- whatever_you_want.py

import resource
import time

from stoppable_thread import StoppableThread


class MyLibrarySniffingClass(StoppableThread):
    def __init__(self, target_lib_call, arg1, arg2):
        super(MyLibrarySniffingClass, self).__init__()
        self.target_function = target_lib_call
        self.arg1 = arg1
        self.arg2 = arg2
        self.results = None

    def startup(self):
        # Overload the startup function
        print "Calling the Target Library Function..."

    def cleanup(self):
        # Overload the cleanup function
        print "Library Call Complete"

    def mainloop(self):
        # Start the library Call
        self.results = self.target_function(self.arg1, self.arg2)

        # Kill the thread when complete
        self.stop()

def SomeLongRunningLibraryCall(arg1, arg2):
    max_dict_entries = 2500
    delay_per_entry = .005

    some_large_dictionary = {}
    dict_entry_count = 0

    while(1):
        time.sleep(delay_per_entry)
        dict_entry_count += 1
        some_large_dictionary[dict_entry_count]=range(10000)

        if len(some_large_dictionary) > max_dict_entries:
            break

    print arg1 + " " +  arg2
    return "Good Bye World"

if __name__ == "__main__":
    # Lib Testing Code
    mythread = MyLibrarySniffingClass(SomeLongRunningLibraryCall, "Hello", "World")
    mythread.start()

    start_mem = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
    delta_mem = 0
    max_memory = 0
    memory_usage_refresh = .005 # Seconds

    while(1):
        time.sleep(memory_usage_refresh)
        delta_mem = (resource.getrusage(resource.RUSAGE_SELF).ru_maxrss) - start_mem
        if delta_mem > max_memory:
            max_memory = delta_mem

        # Uncomment this line to see the memory usuage during run-time 
        # print "Memory Usage During Call: %d MB" % (delta_mem / 1000000.0)

        # Check to see if the library call is complete
        if mythread.isShutdown():
            print mythread.results
            break;

    print "\nMAX Memory Usage in MB: " + str(round(max_memory / 1000.0, 3))

停止可能なスレッド- stoppable_thread.py

import threading
import time

class StoppableThread(threading.Thread):
    def __init__(self):
        super(StoppableThread, self).__init__()
        self.daemon = True
        self.__monitor = threading.Event()
        self.__monitor.set()
        self.__has_shutdown = False

    def run(self):
        '''Overloads the threading.Thread.run'''
        # Call the User's Startup functions
        self.startup()

        # Loop until the thread is stopped
        while self.isRunning():
            self.mainloop()

        # Clean up
        self.cleanup()

        # Flag to the outside world that the thread has exited
        # AND that the cleanup is complete
        self.__has_shutdown = True

    def stop(self):
        self.__monitor.clear()

    def isRunning(self):
        return self.__monitor.isSet()

    def isShutdown(self):
        return self.__has_shutdown


    ###############################
    ### User Defined Functions ####
    ###############################

    def mainloop(self):
        '''
        Expected to be overwritten in a subclass!!
        Note that Stoppable while(1) is handled in the built in "run".
        '''
        pass

    def startup(self):
        '''Expected to be overwritten in a subclass!!'''
        pass

    def cleanup(self):
        '''Expected to be overwritten in a subclass!!'''
        pass
28
Adam Lewis

memory_profiler でこれを行うことができます。関数 memory_usageは値のリストを返します。これらは時間の経過に伴うメモリ使用量を表します(デフォルトでは.1秒のチャンク)。最大値が必要な場合は、そのリストの最大値を取ってください。小さな例:

from memory_profiler import memory_usage
from time import sleep

def f():
    # a function that with growing
    # memory consumption
    a = [0] * 1000
    sleep(.1)
    b = a * 100
    sleep(.1)
    c = b * 100
    return a

mem_usage = memory_usage(f)
print('Memory usage (in chunks of .1 seconds): %s' % mem_usage)
print('Maximum memory usage: %s' % max(mem_usage))

私の場合(memory_profiler 0.25)ifは次の出力を出力します:

Memory usage (in chunks of .1 seconds): [45.65625, 45.734375, 46.41015625, 53.734375]
Maximum memory usage: 53.734375
26

これはWindowsで動作するようです。他のオペレーティングシステムについては知らない。

In [50]: import os

In [51]: import psutil

In [52]: process = psutil.Process(os.getpid())

In [53]: process.get_ext_memory_info().peak_wset
Out[53]: 41934848
5
sethp

pythonライブラリリソースを使用して、メモリ使用量を取得できます。

import resource
resource.getrusage(resource.RUSAGE_SELF).ru_maxrss

1000で除算したMBで変換するために、キロバイト単位のメモリ使用量を提供します。

3
VPS

@Vader Bの回答の改善(そのままでは機能しませんでした):

$ /usr/bin/time --verbose  ./myscript.py
        Command being timed: "./myscript.py"
        User time (seconds): 16.78
        System time (seconds): 2.74
        Percent of CPU this job got: 117%
        Elapsed (wall clock) time (h:mm:ss or m:ss): 0:16.58
        Average shared text size (kbytes): 0
        Average unshared data size (kbytes): 0
        Average stack size (kbytes): 0
        Average total size (kbytes): 0
        Maximum resident set size (kbytes): 616092   # WE NEED THIS!!!
        Average resident set size (kbytes): 0
        Major (requiring I/O) page faults: 0
        Minor (reclaiming a frame) page faults: 432750
        Voluntary context switches: 1075
        Involuntary context switches: 118503
        Swaps: 0
        File system inputs: 0
        File system outputs: 800
        Socket messages sent: 0
        Socket messages received: 0
        Signals delivered: 0
        Page size (bytes): 4096
        Exit status: 0
2
JenyaKh

標準のUnixユーティリティtimeは、プロセスの最大メモリ使用量と、プログラムの他の有用な統計を追跡します。

出力例(maxresidentはキロバイト単位の最大メモリ使用量です。):

> time python ./scalabilty_test.py
45.31user 1.86system 0:47.23elapsed 99%CPU (0avgtext+0avgdata 369824maxresident)k
0inputs+100208outputs (0major+99494minor)pagefaults 0swaps
1
Vader B