ValgrindのMassifを使用してプログラムのメモリ使用量をプロファイリングする
タグ: linux / 初版公開: 2014-09-28

Valgrindはメモリ管理のデバッグとプロファイリングのためのツールを提供するフレームワーク。 多くのLinuxやUnixをサポートしている。

このエントリではValgrindが提供するMassifというツールを使用して、あるプログラムのメモリ使用量をプロファイリングしてみる。

DebianならvalgrindパッケージをインストールすればValgrindが使用できるようになる。

apt-get install valgrind

プログラムはRubyで巨大なYAMLファイルを少しずつ読み込んで処理するで作成したload_documents.rbload_stream.rbを使用する。

  • load_documents.rb – 巨大ファイルの全内容を読み込んで処理するスクリプト(メモリ使用量大)
  • load_stream.rb – 巨大ファイルの少しずつ読み込んで処理するスクリプト(メモリ使用量小)

Massifを実行するには以下のようにする。 Massif経由でプログラムを実行するとプロファイリングのため非常に遅くなるので注意が必要。

valgrind --tool=massif 測定対象のプログラム

実行するとmassif.out.pidというファイルが出力される。 pidの部分にはプロセスIDが入る。

このファイルにプロファイリング結果が保存されているので、Valgrindのms_printというコマンドで内容を表示する。 ms_printの出力は膨大なので、実際にはlessなどのページャで読むと良い。

ms_print massif.out.pid

出力の冒頭にグラフが表示されている。 これで時系列でメモリ使用量がわかる。

以下はload_documents.rbのグラフ。 メモリを34MB使用している。 処理前にファイルの内容を全て読み込むため、最初の方でメモリ使用量が急増する様子がわかる。

--------------------------------------------------------------------------------
Command:            ruby load_documents.rb
Massif arguments:   (none)
ms_print arguments: massif.out.8336
--------------------------------------------------------------------------------


    MB
34.19^                                                                       #
     |                                                                       #
     |                                                                      @#
     |                                                                     @@#
     |                                                                    @@@#
     |                                                                   @@@@#
     |                         ::::::@:::::::::@@::::::::::::           @@@@@#
     |          ::@@::::::::::::::: :@:: ::: ::@ : :::: :: :::::::::::::@@@@@#
     |         :: @ :: :: :: : :::: :@:: ::: ::@ : :::: :: :::::::::: ::@@@@@#
     |       @@:: @ :: :: :: : :::: :@:: ::: ::@ : :::: :: :::::::::: ::@@@@@#
     |      @@ :: @ :: :: :: : :::: :@:: ::: ::@ : :::: :: :::::::::: ::@@@@@#
     |     @@@ :: @ :: :: :: : :::: :@:: ::: ::@ : :::: :: :::::::::: ::@@@@@#
     |     @@@ :: @ :: :: :: : :::: :@:: ::: ::@ : :::: :: :::::::::: ::@@@@@#
     |   @@@@@ :: @ :: :: :: : :::: :@:: ::: ::@ : :::: :: :::::::::: ::@@@@@#
     |  :@ @@@ :: @ :: :: :: : :::: :@:: ::: ::@ : :::: :: :::::::::: ::@@@@@#
     | ::@ @@@ :: @ :: :: :: : :::: :@:: ::: ::@ : :::: :: :::::::::: ::@@@@@#
     | ::@ @@@ :: @ :: :: :: : :::: :@:: ::: ::@ : :::: :: :::::::::: ::@@@@@#
     | ::@ @@@ :: @ :: :: :: : :::: :@:: ::: ::@ : :::: :: :::::::::: ::@@@@@#
     | ::@ @@@ :: @ :: :: :: : :::: :@:: ::: ::@ : :::: :: :::::::::: ::@@@@@#
     | ::@ @@@ :: @ :: :: :: : :::: :@:: ::: ::@ : :::: :: :::::::::: ::@@@@@#
   0 +----------------------------------------------------------------------->Gi
     0                                                                   11.73

一方、以下はload_stream.rbのグラフ。 メモリ使用量は約10MBと抑えられている。 こちらはメモリ使用量はほぼ一定であることがわかる。 ギザギザしているのはRubyのガベージコレクションだと思われる。

--------------------------------------------------------------------------------
Command:            ruby load_stream.rb
Massif arguments:   (none)
ms_print arguments: massif.out.8377
--------------------------------------------------------------------------------


    MB
10.24^                                                               :        
     |             #::::     ::::::      :@:::::     ::::::      ::::@      ::
     |            :#: ::     : ::::      :@: ::     ::: :::     @::::@     @::
     |    ::    @::#: ::    :: ::::     ::@: ::    :::: :::    :@::::@    :@::
     |   :::    @::#: ::   @:: ::::    :::@: ::   ::::: :::   ::@::::@   ::@::
     |  ::::  ::@::#: ::  :@:: ::::  :::::@: ::   ::::: :::   ::@::::@  :::@::
     | @:::: :: @::#: :: ::@:: ::::  : :::@: ::  :::::: ::: ::::@::::@ ::::@::
     | @::::::: @::#: :::::@:: :::: :: :::@: :: ::::::: :::@: ::@::::@:::::@::
     | @::::::: @::#: :::::@:: ::::::: :::@: :: ::::::: :::@: ::@::::@:::::@::
     | @::::::: @::#: :::::@:: ::::::: :::@: :: ::::::: :::@: ::@::::@:::::@::
     | @::::::: @::#: :::::@:: ::::::: :::@: :: ::::::: :::@: ::@::::@:::::@::
     | @::::::: @::#: :::::@:: ::::::: :::@: :: ::::::: :::@: ::@::::@:::::@::
     | @::::::: @::#: :::::@:: ::::::: :::@: :: ::::::: :::@: ::@::::@:::::@::
     | @::::::: @::#: :::::@:: ::::::: :::@: :: ::::::: :::@: ::@::::@:::::@::
     | @::::::: @::#: :::::@:: ::::::: :::@: :: ::::::: :::@: ::@::::@:::::@::
     | @::::::: @::#: :::::@:: ::::::: :::@: :: ::::::: :::@: ::@::::@:::::@::
     | @::::::: @::#: :::::@:: ::::::: :::@: :: ::::::: :::@: ::@::::@:::::@::
     | @::::::: @::#: :::::@:: ::::::: :::@: :: ::::::: :::@: ::@::::@:::::@::
     | @::::::: @::#: :::::@:: ::::::: :::@: :: ::::::: :::@: ::@::::@:::::@::
     | @::::::: @::#: :::::@:: ::::::: :::@: :: ::::::: :::@: ::@::::@:::::@::
   0 +----------------------------------------------------------------------->Gi
     0                                                                   11.68

このようにValgrindのMassifを使用すれば、あるプログラムのメモリ使用量のプロファイリングが簡単に行えることがわかった。