okami.mom/albedo
git clone https://git.nkp.pet/okami.mom/albedo
414af8e
main
1"""Run albedo_inspect against the live daemon. 2 3Start the daemon with ALBEDO_INSPECT=1 first. Then: 4python3 test/manual/inspect_daemon.py cpu [seconds] where the VM's work goes (default 30) 5python3 test/manual/inspect_daemon.py report memory by process, binary and session 6python3 test/manual/inspect_daemon.py stacks where every albedo process is waiting now 7python3 test/manual/inspect_daemon.py peak [ms] memory high-water mark (default 5000) 8python3 test/manual/inspect_daemon.py eval EXPRESSION any expression run on the daemon; it is 9printed with ~p unless it is iodata 10 11$ALBEDO_HOME (default ~/.albedo) says which daemon. 12""" 13 14import json 15import os 16from pathlib import Path 17import re 18import subprocess 19import sys 20import uuid 21 22HOME = Path (os .environ .get ("ALBEDO_HOME" ,Path .home ()/ ".albedo" )) 23 24 25def node ()-> str : 26pid = json .loads ((HOME / "daemon.json" ).read_text ())["pid" ] 27log = (HOME / "daemon.log" ).read_text (errors = "replace" ) 28found = re .findall (rf"inspect: node (albedo_ { pid } @\S+)" ,log ) 29if not found : 30sys .exit (f"daemon { pid } is not inspectable; restart it with ALBEDO_INSPECT=1" ) 31return found [- 1 ] 32 33 34def expression (argv :list [str ])-> tuple [str ,int ]: 35"""The call to make on the daemon, and how long to wait for it in seconds.""" 36match argv : 37case ["cpu" ,* rest ]: 38seconds = int (rest [0 ])if rest else 30 39return f"albedo_inspect:cpu( { seconds } )" ,seconds + 30 40case ["report" ]: 41return "albedo_inspect:report()" ,60 42case ["stacks" ]: 43return "albedo_inspect:stacks()" ,60 44case ["peak" ,* rest ]: 45ms = int (rest [0 ])if rest else 5000 46return f"albedo_inspect:peak( { ms } )" ,ms // 1000 + 30 47case ["eval" ,text ]: 48return text ,120 49sys .exit (__doc__ ) 50 51 52def main ()-> None : 53call ,timeout = expression (sys .argv [1 :]) 54target = node () 55cookie = (HOME / "inspect.cookie" ).read_text ().strip () 56program = ( 57f"Value = case rpc:call(' { target } ', erlang, apply, [fun() -> { call } end, []], " 58f' { timeout * 1000 } ) of {{badrpc, Reason}} -> io_lib:format("badrpc ~p~n", [Reason]); ' 59"V -> V end, " 60'io:put_chars(try iolist_to_binary(Value) catch _:_ -> io_lib:format("~p~n", [Value]) end), ' 61"halt()." 62 ) 63result = subprocess .run ( 64 [ 65"erl" , 66"+S" , 67"1:1" , 68"-sname" , 69f"probe_ { uuid . uuid4 (). hex [: 12 ] } " , 70"-setcookie" , 71cookie , 72"-noshell" , 73"-eval" , 74program , 75 ], 76capture_output = True , 77text = True , 78timeout = timeout + 15 , 79 ) 80sys .stdout .write (result .stdout ) 81sys .stderr .write (result .stderr ) 82sys .exit (result .returncode ) 83 84 85if __name__ == "__main__" : 86main ()