Portál AbcLinuxu, 30. dubna 2025 14:00

Pythoní attach-to-process pohodlněji

27.11.2015 23:30 | Přečteno: 1342× | programování | Výběrový blog | poslední úprava: 27.11.2015 23:58

Největší nedostatek pythonu z hlediska programátora jsem považoval absenci připojení k běžícímu procesu, pokud nebyl předtím nastartován v debuggeru. Před pár lety jsem na to našel hack a nedávno jsem zjistil, že jeho podobu implementovali do PyCharm IDE, kde to jde teď na pár kliknutí.

Je to už 6 let, co jsem psal návod, jak ohackovat Python přes gdb a dostat funkcionalitu známou jako attach-to-process z gdb. PyCharm to umí a má to implementováno dost podobným hackem, taky přes gdb. Jenže pro programátora mnohem pohodlněji, protože je to integrováno jako featura IDE. I v komunitní free verzi.

PyCharm vs můj starý hack

Hlavní rozdíl je, že se člověk nemusí starat o debug symboly. A implementace je o poznání složitější. GDB musí mít zabudovanou podporu pythonu, přes něj se pythoní proces interně ovládá. K tomu je potřebná knihovna závislá na platformě/architektuře. Přímo podporují x86/amd64, ale k dispozici jsou zdrojáky, takže by to šlo nejspíš použít i na jinou architekturu (pro nějaké embedded věci jako Raspberry Pi). Kombinaci remote debugger + attach-to-process jsem ještě nezkoušel, protože remote debugger je jenom v placené verzi - ale teoreticky by to asi mohlo fungovat.

Oproti mé staré metodě používá jiný způsob zabezpečení konzistentního stavu interpreteru - přes PyGILState_Ensure a PyGILState_Release. Pravděpodobně je to korektnější než můj původní hack. Pak se použije trik s PyRun_SimpleString, případně interní trasovací funkce _PYDEVD_ExecWithGILSetSysStrace.

Musím říct, že z funkcionality jsem příjemně překvapen. Asi jedinou chybu na kráse, co jsem zatím našel je, že po použití attach-to-process a odpojení od procesu mi ten proces nešel zabít bez SIGKILL.

Memory profiling s injekcemi

Nový největší nedostatek je místo původního chybějícího attach-to-process neexistence rozumného memory profileru pro python. Především pokud je potřeba z nějakého několik dní běžícího procesu vydumpovat stav objektů v alokátoru. O vizualizaci škoda mluvit, objgraph sice funguje, ale jeho použitelnost je dost slabá. Hlavně pokud těch objektů máte několik miliard. Podobně RunSnakeMem.

Jediné, co jsem v dané situaci považoval za marginálně použitelné, je meliae. V repozitářích se vyskuje, bohužel na druhé straně to taky už vypadá na mrtvý projekt. S gdb hackem lze statistiku udělat takhle (běžícího procesu, jinak nepotřebujete GDB):

# Stary hack s breaknutim uvnitr VM, viz puvodni zapisek
define breakvm
        tbreak ceval.c:1099
end

define meliae_dump
        breakvm
        continue
        call PyRun_SimpleString("from meliae import scanner; scanner.dump_all_objects('/tmp/meliae_dump.json')")
end

V GDB nebo přes GDB machine interface pak stačí zadat meliae_dump. Statistiku vypíšeme následovně:

from meliae import loader
om = loader.load('/tmp/meliae_dump.json')
s = om.summarize()
print s

Příklad výstupu (na jedné staré GUI aplikaci, co jsem měl zrovna po ruce):

Total 188023 objects, 654 types, Total size = 36.4MiB (38211601 bytes)
 Index   Count   %      Size   % Cum     Max Kind
     0    4211   2   8094536  21  21 3146008 dict
     1    3342   1   7016535  18  39 2097152 numpy.ndarray
     2   50560  26   5511918  14  53   19388 str
     3   51086  27   4423192  11  65    3040 tuple
     4     366   0   1662048   4  69   49488 module
     5    1237   0   1375544   3  73    1112 Path
     6    9534   5   1144080   2  76     120 function
     7    9016   4   1081920   2  79     120 code
     8     778   0    703312   1  81     904 type
     9     686   0    642096   1  82     936 PyQt4.QtCore.pyqtWrapperType
    10     180   0    614880   1  84    3416 Line2D
    11     529   0    482448   1  85     912 sip.enumtype
    12    2259   1    472160   1  86   36992 list
    13     134   0    457744   1  88    3416 Text
    14   15621   8    374904   0  89      24 sip.methoddescriptor
    15    3898   2    311840   0  89      80 wrapper_descriptor
    16    3222   1    283536   0  90      88 weakref
    17    9871   5    236904   0  91      24 float
    18     594   0    209088   0  91     352 WeakKeyDictionary
    19     138   0    153456   0  92    1112 Distribution

Vedlejší efekty meliae injekce

Samotný kód meliae způsobí, že procesu ještě vzroste používaná RAM (RSS) a to značně (řádově klidně 25-50%). Před použitím tam musí být rezerva. Když už proces swapuje, je pozdě. Nebo si počkáte.

Dumpy paměti celkem trvají a výsledkem je dost velký soubor, řádově jsem se pohyboval asi tolik GB, kolik měl sledovaný proces. Mnoho malých objektů. Po načtení a zpracování statistiky lze očekávat, že to spolkne asi tolik paměti, kolik měl soubor na disku.

S pydev gdb helper knihovnou z PyCharm by to šlo skombinovat lépe, aby to bylo přenositelnější, ale zatím jsem to nepotřeboval.        

Hodnocení: 100 %

        špatnédobré        

Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

Komentáře

Nástroje: Začni sledovat (2) ?Zašle upozornění na váš email při vložení nového komentáře. , Tisk

Vložit další komentář

Bystroushaak avatar 28.11.2015 06:35 Bystroushaak | skóre: 36 | blog: Bystroushaakův blog | Praha
Rozbalit Rozbalit vše Re: Pythoní attach-to-process pohodlněji
Odpovědět | Sbalit | Link | Blokovat | Admin
Zajímavé, neznal jsem.

Osobně většinou používám prosté python -m pdb script.py.
blog.rfox.eu

ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.