callmonitor - เครื่องมือง่าย ๆ ในการตรวจสอบและบันทึกการเรียกใช้ฟังก์ชัน pip install callmonitorหรือโคลน repo นี้และ:
python setup.py install ใช้งานง่ายเพียงแค่ตกแต่งฟังก์ชั่นใด ๆ ด้วย @intercept Decorator เช่น:
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> ไปยังโฟลเดอร์รูท ( call-monitor ) ขณะนี้ callmonitor รองรับ mpi4py นอกกรอบ: ถ้า mpi4py.MPI.COMM_WORLD.Get_rank() > 1 , callmonitor โดยอัตโนมัติสมมติว่ามันกำลังใช้โหมด IM Multi -Threaded และผนวก -tid=<Get_rank()> ไปยังเอาต์พุต หากโปรแกรมของคุณมีหลายเธรดด้วยเฟรมเวิร์คอื่น (เช่น concurrent.Futures . futures) คุณต้องบอก callmonitor ID เธรดของคุณโดยใช้ callmonitor.Settings :
from callmonitor import Settings
settings = Settings ()
settings . enable_multi_threading ( THREAD_ID ) ก่อนที่ จะทำการสกัด intercept ครั้งแรก (ฐานข้อมูลถูกสร้างขึ้นบนดิสก์เมื่อมีความจำเป็นครั้งแรกมันจะอยู่ที่จุดนั้นเมื่อ callmonitor.Settings อ่านการเปลี่ยนแปลงใด ๆ ที่เกิดขึ้นกับ callmonitor.Settings หลังจากนั้นจะมีผลถ้าฐานข้อมูลถูกสร้างขึ้นใหม่โดยใช้ callmonitor.CONTEXT.new )
Handler อาร์กิวเมนต์ของคุณเอง บางครั้ง pickle ก็จะไม่ตัดในแง่ของการบันทึกฟังก์ชั่นอินพุต - เช่น เมื่อเราต้องการบันทึกประเภทข้อมูลแฟนซีของเราเอง callmonitor จัดเตรียมวิธีการสร้างตัวจัดการอาร์กิวเมนต์ของคุณและลงทะเบียนไปยัง Global callmonitor.REGISTRY รีจิสทรีจะถูกสอบถามทุกครั้งที่มีการประมวลผลอินพุตฟังก์ชั่นดังนั้นหากคุณสร้าง ArgHandler ของคุณเองและเพิ่มพวกเขาโดยใช้ callmonitor.REGISTRY.add มันจะประมวลผลอาร์กิวเมนต์ใด ๆ ของข้อมูลที่เกี่ยวข้องจากจุดนั้นไปข้างหน้า เช่น numpy ให้ฟังก์ชั่น save / load ของตัวเอง เราได้สร้างตัวจัดการ arggument 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 แสดงให้เห็นว่าข้อมูลคู่/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 Container การแยก 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 constructor จะเติมในอาร์กิวเมนต์ใด ๆ ที่ไม่ได้อยู่ใน 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 อีกต่อไป