callmonitor関数呼び出しを監視およびログに記録する簡単なツールpip install callmonitorまたはこのリポジトリをクローンし、
python setup.py install使いやすく、 @interceptデコレーターで機能を飾るだけです。例えば:
from callmonitor import intercept
@ intercept
def test_fn_2 ( x , y = 2 , z = 3 ):
passこれにより、コールデータベース( callmonitor.DB )とともに、入力( args 、 kwargs 、 argspec ) call-monitor/test_fn_2/<invocation count>のように保存します。
callmonitor出力を上書きしませんcall-monitorフォルダーが既に存在する場合(例:前の実行)、新しいフォルダーcall-monitor-1 、またはcall-monitor-2などが作成されます。このデータの保存方法の詳細については、 Data Structureに関するセクションを参照してください。
同じ場所への書き込みからさまざまなプロセスを回避するために、 callmonitor root( call-monitor )フォルダーに-tid=<N>を追加します。現在、 callmonitor mpi4py箱から出してサポートしています。MPI4PY.MPI.COMM_WORLD.GET_RANK mpi4py.MPI.COMM_WORLD.Get_rank() > 1場合、 callmonitor自動的にIM Multi -Threadedモードを実行していることを想定し、 -tid=<Get_rank()>を出力を追加します。あなたのプログラムが別のフラム(例: concurrent.Futures )でマルチスレッドされている場合、 callmonitor.Settingsを使用してスレッドIDをcallmonitor伝える必要があります。
from callmonitor import Settings
settings = Settings ()
settings . enable_multi_threading ( THREAD_ID ) interceptの最初の呼び出しの前に(データベースは最初に必要なときにディスクに作成されます。その時点で、 callmonitor.Settings callmonitor.Settings読み取られます。CallMonitor.Settingsに加えられた変更は、データベースが再作成された場合にのみ有効になります - callmonitor.CONTEXT.newを使用します。
Handlerを登録しますpickle機能入力を保存するという点でそれをカットしない場合があります。独自の派手なデータ型を保存する必要がある場合。 callmonitor 、下向きの引数ハンドラーを構築し、Global callmonitor.REGISTRYに登録する方法を提供します。レジストリは、関数入力が処理されるたびに照会されます。したがって、独自のArgHandlerを構築し、 callmonitor.REGISTRY.addを使用してそれらを追加すると、そのポイントから関連するデータタイプの引数を処理します。たとえば、 numpy独自のsave / load関数を提供します。私たちはすでに、そのようなnumpy arggumentハンドラーを構築(そして登録しています):
import numpy as np
from os . path import join
from callmonitor import Handler , REGISTRY
class NPHandler ( Handler ):
def load ( self , path ):
self . data = np . load ( join ( path , f"arg_ { self . target } .npy" ))
def save ( self , path ):
np . save ( join ( path , f"arg_ { self . target } .npy" ), self . data )
@ classmethod
def accumulator_done ( cls ):
pass
REGISTRY . add ( np . ndarray , NPHandler ) ( callmonitor.REGISTRY.addは、この特定のHandlerが必要な@interceptの最初の呼び出しの前に呼び出される必要があることを忘れないでください)。カスタムハンドラーは、 callmonitor.Handlerクラスを継承し、 save 、 load 、およびaccumulator_doneを定義する必要があります(最後のものは@classmethodです)。
callmonitor.load(<path>) <path>にデータベースをロードします( Data Structureのセクションを参照)。例えば:
from callmonitor import load
db = load ( "call-monitor" ) DB.getを使用して、データベースから個々の関数呼び出しデータを取得できるようになりました。
args , kwargs = db . get ( "function_name" , invocation_count ) (また、 .npyファイルとカスタムハンドラーを自動的にロードしますdb.get実行する前に、これらをcallmonitor.REGISTRYに登録することを忘れないでください)
覚えておいてください: invocation_count 1から始まります。したがって、 test_np_1への最初の呼び出しにアクセスするには、実行します。
In [ 4 ]: db . get ( "test_np_1" , 1 )
Out [ 4 ]: ([ 10 , array ([ 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ])], {})callmonitorとの対話次のユーザー向けクラスのトップレベルの要約を有効にしようとしています。
REGISTRYDBDB.get_args 、および__str__および__repr__関数を介したArgs 。たとえば、 callmonitor.REGISTRY 、どのデータタイプ/ハンドラーペアが構成されているかを示しています。 In [ 2 ]: callmonitor . REGISTRY
Out [ 2 ]:
{
< class 'numpy.ndarray' > : < class 'callmonitor.handler.NPHandler' >
}同様に、 DBオブジェクトには、呼び出された関数の要約と頻度が表示されます。
In [ 3 ]: db = callmonitor . load ( "call-monitor" )
In [ 4 ]: db
Out [ 4 ]:
{
Locked : True
test_np_1 : {
calls : 2
args : [ 'x' , 'n' ]
defaults : None
}
}Argsコンテナargs 、 kwargs 、およびargspec.defaultsを引き離すことは、特に特定の議論の価値を見つけようとしている場合は非常に退屈です。したがって、 callmonitor.DB 、 Argsオブジェクトを返すadditionl getter get_argsを提供します。 callmonitor.Argsは、各入力引数を属性として名前で保存するコンテナクラスです。例えば:
In [ 3 ]: args = db . get_args ( "test_fn_1" , 1 )
In [ 4 ]: args
Out [ 4 ]: dict_keys ([ 'x' , 'y' , 'z' ])
In [ 5 ]: args . x
Out [ 5 ]: 1注: callmonitor.Argsコンストラクターは、 FullArgSpecデフォルトからargsおよびkwargsではない任意の引数を記入します。元の関数を再現したい場合は、 callmonitor.DB.getによって返されたargsを呼び出し、 kwargsで十分です。
技術的にはデータベースではありませんが、 callmonitorが生成したディレクトリをより良い用語がないためにデータベースを呼び出します。各データベースは、 db.pklファイル(メタデータを含む)と各関数のフォルダー(各関数呼び出しが列挙されている)で構成されています。例えば:
call-monitor
├── db.pkl
├── test_fn_1
│ ├── 1
│ │ └── input_descriptor.pkl
│ └── 2
│ └── input_descriptor.pkl
└── test_fn_2
└── 1
└── input_descriptor.pkl
numpy入力には特に注意が払われます。これらはarg_<label>.npyと呼ばれます。ここで、 <label>は入力引数のインデックス、またはKWARGSのkwです。例えば:
call-monitor
├── db.pkl
└── test_np_1
├── 1
│ ├── arg_1.npy
│ └── input_descriptor.pkl
└── 2
├── arg_n.npy
└── input_descriptor.pkl
すべてのコールデータを単一のデータ構造に保存することを完全に考慮しました - おそらく実際のデータベースでさえあります。) - これを大規模に効率的に行うことは容易ではなく、このパッケージを面倒にするかもしれません。将来のバージョンには、多数の小さなファイルを避けるために、複数の小さな関数呼び出しを単一のアキュムレータオブジェクトに融合させる機能が含まれます。
バージョン0.3.0は、 callmonitorの多くの拡張機能を担当します。したがって、ネイティブの後方互換性を有効にすることはできませんでした。バージョン0.2.0データベースをバージョン0.3.0(またはそれ以降)に変換できるツールが現在開発中です。 0.2.0前のバージョンはサポートされなくなりました。