Skip to content

Commit 8cdbd7a

Browse files
committed
Split timing loggers across worker thread
1 parent f3d3118 commit 8cdbd7a

1 file changed

Lines changed: 44 additions & 32 deletions

File tree

‎dlclivegui/services/dlc_processor.py‎

Lines changed: 44 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,14 @@ def __init__(self) -> None:
183183
self._gpu_inference_times: deque[float] = deque(maxlen=60)
184184
self._processor_overhead_times: deque[float] = deque(maxlen=60)
185185

186-
self._timing = WorkerTimingStats(
187-
"DLCLiveProcessor",
186+
self._enqueue_timing = WorkerTimingStats(
187+
"DLCLiveEnqueue",
188+
logger=logger,
189+
log_interval=1.0,
190+
enabled=bool(DLC_DO_LOG_TIMING or ENABLE_PROFILING),
191+
)
192+
self._worker_timing = WorkerTimingStats(
193+
"DLCLiveWorker",
188194
logger=logger,
189195
log_interval=1.0,
190196
enabled=bool(DLC_DO_LOG_TIMING or ENABLE_PROFILING),
@@ -250,7 +256,7 @@ def enqueue_frame(self, frame: np.ndarray, timestamp: float) -> None:
250256
q = self._queue
251257
should_start = t is None or not t.is_alive()
252258

253-
with self._timing.measure("DLC.enqueue.copy_frame"):
259+
with self._enqueue_timing.measure("DLC.enqueue.copy_frame"):
254260
frame_c = frame.copy()
255261
enq_time = time.perf_counter()
256262

@@ -276,6 +282,9 @@ def enqueue_frame(self, frame: np.ndarray, timestamp: float) -> None:
276282
timestamp,
277283
)
278284
self._start_worker_locked(frame_c, timestamp)
285+
286+
self._enqueue_timing.note_frame()
287+
self._enqueue_timing.maybe_log()
279288
return
280289
# Worker is now running; refresh queue snapshot.
281290
q = self._queue
@@ -287,15 +296,18 @@ def enqueue_frame(self, frame: np.ndarray, timestamp: float) -> None:
287296

288297
while True:
289298
try:
290-
with self._timing.measure("DLC.enqueue.put"):
299+
with self._enqueue_timing.measure("DLC.enqueue.put"):
291300
q.put_nowait(item)
292301
with self._stats_lock:
293302
self._frames_enqueued += 1
303+
304+
self._enqueue_timing.note_frame()
305+
self._enqueue_timing.maybe_log()
294306
return
295307

296308
except queue.Full:
297309
try:
298-
with self._timing.measure("DLC.enqueue.drop_stale"):
310+
with self._enqueue_timing.measure("DLC.enqueue.drop_stale"):
299311
q.get_nowait()
300312
try:
301313
q.task_done()
@@ -534,7 +546,7 @@ def _timed_processor(self):
534546
def timed_process(pose, _op=original, _holder=holder, **kwargs):
535547
start = time.perf_counter()
536548
try:
537-
with self._timing.measure("DLC.processor.process"):
549+
with self._worker_timing.measure("DLC.processor.process"):
538550
return _op(pose, **kwargs)
539551
finally:
540552
_holder[0] = time.perf_counter() - start
@@ -579,22 +591,22 @@ def _process_frame(
579591
if self._dlc is None:
580592
raise RuntimeError("DLCLive instance is not initialized.")
581593
# Time GPU inference (and processor overhead when present)
582-
with self._timing.measure("DLC.prepare_frame"):
594+
with self._worker_timing.measure("DLC.prepare_frame"):
583595
frame = self._prepare_input_frame(frame)
584596
with self._timed_processor() as proc_holder:
585597
inference_start = time.perf_counter()
586598

587-
with self._timing.measure("DLC.process_frame"):
599+
with self._worker_timing.measure("DLC.process_frame"):
588600
processed_frame = self._dlc.process_frame(frame)
589601

590-
with self._timing.measure("DLC.runner.get_pose"):
602+
with self._worker_timing.measure("DLC.runner.get_pose"):
591603
self._dlc.pose = self._dlc.runner.get_pose(processed_frame)
592604

593-
# with self._timing.measure("DLC.post_process_pose"):
605+
# with self._worker_timing.measure("DLC.post_process_pose"):
594606
# raw_pose: Any = self._dlc._post_process_pose(processed_frame, frame_time=timestamp)
595607

596608
inference_time = time.perf_counter() - inference_start
597-
with self._timing.measure("DLC.validate_pose"):
609+
with self._worker_timing.measure("DLC.validate_pose"):
598610
pose_arr: np.ndarray = validate_pose_array(self._dlc.pose, source_backend=PoseBackends.DLC_LIVE)
599611
pose_packet = PosePacket(
600612
schema_version=0,
@@ -613,7 +625,7 @@ def _process_frame(
613625

614626
# Emit pose (measure signal overhead)
615627
signal_start = time.perf_counter()
616-
with self._timing.measure("DLC.emit.pose_ready"):
628+
with self._worker_timing.measure("DLC.emit.pose_ready"):
617629
self.pose_ready.emit(PoseResult(pose=pose_packet.keypoints, timestamp=timestamp, packet=pose_packet))
618630
signal_time = time.perf_counter() - signal_start
619631

@@ -635,8 +647,8 @@ def _process_frame(
635647
self._gpu_inference_times.append(gpu_inference_time)
636648
self._processor_overhead_times.append(processor_overhead)
637649

638-
self._timing.note_frame()
639-
self._timing.maybe_log()
650+
self._worker_timing.note_frame()
651+
self._worker_timing.maybe_log()
640652
self.frame_processed.emit()
641653

642654
def _worker_loop(self, init_frame: np.ndarray, init_timestamp: float) -> None:
@@ -645,7 +657,7 @@ def _worker_loop(self, init_frame: np.ndarray, init_timestamp: float) -> None:
645657
if not self._settings.model_path:
646658
raise RuntimeError("No DLCLive model path configured.")
647659

648-
with self._timing.measure("DLC.build_options"):
660+
with self._worker_timing.measure("DLC.build_options"):
649661
dyn = self._settings.dynamic
650662
if not isinstance(dyn, (list, tuple)) or len(dyn) != 3:
651663
try:
@@ -683,12 +695,12 @@ def _worker_loop(self, init_frame: np.ndarray, init_timestamp: float) -> None:
683695
raise RuntimeError(
684696
"DLCLive class is not available. Ensure the dlclive package is installed and can be imported."
685697
)
686-
with self._timing.measure("DLC.construct"):
698+
with self._worker_timing.measure("DLC.construct"):
687699
self._dlc = DLCLive(**options)
688-
self._timing.maybe_log()
700+
self._worker_timing.maybe_log()
689701
except Exception as exc:
690-
self._timing.note_error()
691-
self._timing.maybe_log()
702+
self._worker_timing.note_error()
703+
self._worker_timing.maybe_log()
692704
with self._lifecycle_lock:
693705
self._state = WorkerState.FAULTED
694706
raise RuntimeError(
@@ -699,7 +711,7 @@ def _worker_loop(self, init_frame: np.ndarray, init_timestamp: float) -> None:
699711
logger.debug("DLC worker stop requested during construction; exiting before init_inference.")
700712
return
701713

702-
with self._timing.measure("DLC.prepare_init_frame"):
714+
with self._worker_timing.measure("DLC.prepare_init_frame"):
703715
init_frame = self._prepare_input_frame(init_frame)
704716

705717
if logger.isEnabledFor(logging.DEBUG):
@@ -710,20 +722,20 @@ def _worker_loop(self, init_frame: np.ndarray, init_timestamp: float) -> None:
710722
init_frame.flags["C_CONTIGUOUS"],
711723
)
712724
# First inference to initialize
713-
with self._timing.measure("DLC.init_inference"):
725+
with self._worker_timing.measure("DLC.init_inference"):
714726
self._dlc.init_inference(init_frame)
715727

716728
self._debug_log_dlc_runner_device()
717-
self._timing.note_frame()
718-
self._timing.maybe_log()
729+
self._worker_timing.note_frame()
730+
self._worker_timing.maybe_log()
719731

720732
if self._stop_event.is_set():
721733
logger.debug("DLC worker stop requested after init_inference; exiting before RUNNING state.")
722734
return
723735

724736
# Pass DLCLive cfg to processor if available
725737
if hasattr(self._dlc, "processor") and hasattr(self._dlc.processor, "set_dlc_cfg"):
726-
with self._timing.measure("DLC.processor.set_dlc_cfg"):
738+
with self._worker_timing.measure("DLC.processor.set_dlc_cfg"):
727739
self._dlc.processor.set_dlc_cfg(getattr(self._dlc, "cfg", None))
728740

729741
self._initialized = True
@@ -777,8 +789,8 @@ def _worker_loop(self, init_frame: np.ndarray, init_timestamp: float) -> None:
777789
try:
778790
self._process_frame(frame, ts, enq, queue_wait_time=0.0)
779791
except Exception as exc:
780-
self._timing.note_error()
781-
self._timing.maybe_log()
792+
self._worker_timing.note_error()
793+
self._worker_timing.maybe_log()
782794
logger.exception("Pose inference failed", exc_info=exc)
783795
self.error.emit(str(exc))
784796
finally:
@@ -791,14 +803,14 @@ def _worker_loop(self, init_frame: np.ndarray, init_timestamp: float) -> None:
791803
# Normal operation: timed get
792804
try:
793805
wait_start = time.perf_counter()
794-
with self._timing.measure("DLC.queue_get"):
806+
with self._worker_timing.measure("DLC.queue_wait"):
795807
item = q.get(timeout=0.05)
796808
queue_wait_time = time.perf_counter() - wait_start
797809
except queue.Empty:
798810
continue
799811
except Exception as exc:
800-
self._timing.note_error()
801-
self._timing.maybe_log()
812+
self._worker_timing.note_error()
813+
self._worker_timing.maybe_log()
802814
logger.exception("Error getting item from queue", exc_info=exc)
803815
with self._lifecycle_lock:
804816
self._state = WorkerState.FAULTED
@@ -809,8 +821,8 @@ def _worker_loop(self, init_frame: np.ndarray, init_timestamp: float) -> None:
809821
frame, ts, enq = item
810822
self._process_frame(frame, ts, enq, queue_wait_time=queue_wait_time)
811823
except Exception as exc:
812-
self._timing.note_error()
813-
self._timing.maybe_log()
824+
self._worker_timing.note_error()
825+
self._worker_timing.maybe_log()
814826
logger.exception("Pose inference failed", exc_info=exc)
815827
self.error.emit(str(exc))
816828
finally:
@@ -821,7 +833,7 @@ def _worker_loop(self, init_frame: np.ndarray, init_timestamp: float) -> None:
821833

822834
logger.info("DLC worker thread exiting")
823835

824-
self._timing.maybe_log()
836+
self._worker_timing.maybe_log()
825837

826838

827839
class DLCService:

0 commit comments

Comments
 (0)