diag: add startup-timing trace and /api/diag/timing endpoint

bbctrl.Trace records monotonic-anchored events from process start.
Ctrl, Comm, the Web layer and __init__ are instrumented so a single
GET /api/diag/timing returns a full timeline of import, controller
init, AVR connection, first websocket, and first GET /. The
restart-timing.js client posts performance.now() marks back so the
browser side can be aligned in the same view.

Used to drive the cold-boot optimisations that reduce listen latency
on the Pi by ~8s.
This commit is contained in:
2026-05-03 14:06:17 +02:00
parent 94270e7725
commit 0b5ab2ff3b
6 changed files with 367 additions and 11 deletions

View File

@@ -28,10 +28,12 @@
import os
import time
import bbctrl
import bbctrl.Trace as Trace
class Ctrl(object):
def __init__(self, args, ioloop, id):
Trace.mark('ctrl.init.start', id=id or '<default>')
self.args = args
self.ioloop = bbctrl.IOLoop(ioloop)
self.id = id
@@ -43,31 +45,47 @@ class Ctrl(object):
if args.demo: log_path = self.get_path(filename = 'bbctrl.log')
else: log_path = args.log
self.log = bbctrl.log.Log(args, self.ioloop, log_path)
Trace.mark('ctrl.log_open')
self.state = bbctrl.State(self)
self.config = bbctrl.Config(self)
Trace.mark('ctrl.state_config')
self.log.get('Ctrl').info('Starting %s' % self.id)
try:
if args.demo: self.avr = bbctrl.AVREmu(self)
else: self.avr = bbctrl.AVR(self)
with Trace.span('ctrl.avr'):
if args.demo: self.avr = bbctrl.AVREmu(self)
else: self.avr = bbctrl.AVR(self)
self.i2c = bbctrl.I2C(args.i2c_port, args.demo)
self.lcd = bbctrl.LCD(self)
self.mach = bbctrl.Mach(self, self.avr)
self.preplanner = bbctrl.Preplanner(self)
if not args.demo: self.jog = bbctrl.Jog(self)
self.pwr = bbctrl.Pwr(self)
with Trace.span('ctrl.i2c'):
self.i2c = bbctrl.I2C(args.i2c_port, args.demo)
with Trace.span('ctrl.lcd'):
self.lcd = bbctrl.LCD(self)
with Trace.span('ctrl.mach'):
self.mach = bbctrl.Mach(self, self.avr)
with Trace.span('ctrl.preplanner'):
self.preplanner = bbctrl.Preplanner(self)
if not args.demo:
with Trace.span('ctrl.jog'):
self.jog = bbctrl.Jog(self)
with Trace.span('ctrl.pwr'):
self.pwr = bbctrl.Pwr(self)
self.mach.connect()
with Trace.span('ctrl.mach.connect'):
self.mach.connect()
self.lcd.add_new_page(bbctrl.MainLCDPage(self))
self.lcd.add_new_page(bbctrl.IPLCDPage(self.lcd))
os.environ['GCODE_SCRIPT_PATH'] = self.get_upload()
except Exception: self.log.get('Ctrl').exception('Internal error: Control initialization failed')
Trace.mark('ctrl.init.end')
Trace.sd_notify('STATUS=ctrl initialized\n')
except Exception:
Trace.mark('ctrl.init.error')
self.log.get('Ctrl').exception('Internal error: Control initialization failed')
def __del__(self): print('Ctrl deleted')