callmonitor - простой инструмент для мониторинга и журнала вызовов функции pip install callmonitorили клонировать это репо и:
python setup.py install Это просто использовать, просто украсьте любую функцию с помощью декоратора @intercept . Например:
from callmonitor import intercept
@ intercept
def test_fn_2 ( x , y = 2 , z = 3 ):
pass Это сохранит входные данные ( args , kwargs и argspec ) вместе с базой данных вызовов ( callmonitor.DB ) к: call-monitor/test_fn_2/<invocation count> .
callmonitor не перезаписывает вывод Если папка call-monitor уже существует (например, предыдущий запуск), то создается новая папка call-monitor-1 или call-monitor-2 и т. Д. См. Разделы по Data Structure для получения более подробной информации о том, как сохраняются эти данные.
Чтобы избежать различных процессов от записи в одно и то же место, callmonitor прилагает -tid=<N> в папку Root ( call-monitor ). В настоящее время callmonitor поддерживает mpi4py из коробки: Если mpi4py.MPI.COMM_WORLD.Get_rank() > 1 , callmonitor автоматически предполагает, что он работает в многопоточном режиме и добавляет -tid=<Get_rank()> к выводу. Если ваша программа многопоточная с другой фрампой (например, concurrent.Futures ), вам нужно сообщить callmonitor ваш идентификатор потока, используя callmonitor.Settings :
from callmonitor import Settings
settings = Settings ()
settings . enable_multi_threading ( THREAD_ID ) Перед первым вызовом intercept (база данных создается на диске, когда он сначала необходим, именно в этот момент будет прочитана callmonitor.Settings . Любые изменения, внесенные в callmonitor.Settings , впоследствии вступят в силу только в случае воссоздания базы данных - с использованием callmonitor.CONTEXT.new ).
Handler аргументов s Иногда 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 должен быть вызван до первого вызова @intercept , который нуждается в этом конкретном Handler ). Пользовательский обработчик должен наследовать класс 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 и любые пользовательские обработчики - не забудьте зарегистрировать их в callmonitor.REGISTRY , прежде чем выполнять db.get )
Помните: 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 и Args через функции __str__ и __repr__ . Например, callmonitor.REGISTRY показывает, какие пары DataType/Handler настроены: 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 intecler Выбрать args , kwargs и argspec.defaults может быть очень утомительным - особенно если вы пытаетесь выяснить ценность конкретного аргумента. Следовательно, callmonitor.DB предоставляет дополнение getter - get_args , который возвращает объект 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 заполнит любые аргументы, не в args и kwargs из по умолчанию FullArgSpec . Если вы просто хотите воссоздать исходную функцию, позвоните args , а kwargs возвращаются callmonitor.DB.get .
Несмотря на то, что технически не является базой данных , давайте назовем каталоги, сгенерированные 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> является либо индексом входного аргумента, либо kw для Kwargs. Например:
call-monitor
├── db.pkl
└── test_np_1
├── 1
│ ├── arg_1.npy
│ └── input_descriptor.pkl
└── 2
├── arg_n.npy
└── input_descriptor.pkl
Полное рассмотрение было уделено сохранению всех данных вызовов в одной структуре данных - может быть, даже реальная база данных;) - но сделать это эффективно в масштабе нелегко и может сделать этот пакет громоздким. Будущие версии будут включать в себя возможность объединить несколько небольших вызовов функций в один объект аккумулятора, чтобы избежать большого количества небольших файлов.
Версия 0.3.0 Brigns Много улучшений для callmonitor . Поэтому мы больше не могли обеспечить нативную обратную совместимость. В настоящее время разрабатывается инструмент, который может конвертировать базу данных 0.2.0 в версию 0.3.0 (или более поздней). Версии, предварительно датирующие 0,2,0, больше не поддерживаются.