mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-05-01 19:17:41 +03:00
Only store PID instead of entire process reference
This commit is contained in:
parent
4dd5e9c66e
commit
85dcfdd670
@ -85,8 +85,8 @@ class FrigateApp:
|
|||||||
self.detectors: dict[str, ObjectDetectProcess] = {}
|
self.detectors: dict[str, ObjectDetectProcess] = {}
|
||||||
self.detection_shms: list[mp.shared_memory.SharedMemory] = []
|
self.detection_shms: list[mp.shared_memory.SharedMemory] = []
|
||||||
self.log_queue: Queue = mp.Queue()
|
self.log_queue: Queue = mp.Queue()
|
||||||
self.camera_metrics: dict[str, CameraMetrics] = {}
|
|
||||||
self.metrics_manager = mp.Manager()
|
self.metrics_manager = mp.Manager()
|
||||||
|
self.camera_metrics: dict[str, CameraMetrics] = self.metrics_manager.dict()
|
||||||
self.embeddings_metrics: DataProcessorMetrics | None = (
|
self.embeddings_metrics: DataProcessorMetrics | None = (
|
||||||
DataProcessorMetrics(
|
DataProcessorMetrics(
|
||||||
self.metrics_manager, list(config.classification.custom.keys())
|
self.metrics_manager, list(config.classification.custom.keys())
|
||||||
@ -128,7 +128,7 @@ class FrigateApp:
|
|||||||
def init_camera_metrics(self) -> None:
|
def init_camera_metrics(self) -> None:
|
||||||
# create camera_metrics
|
# create camera_metrics
|
||||||
for camera_name in self.config.cameras.keys():
|
for camera_name in self.config.cameras.keys():
|
||||||
self.camera_metrics[camera_name] = CameraMetrics()
|
self.camera_metrics[camera_name] = CameraMetrics(self.metrics_manager)
|
||||||
self.ptz_metrics[camera_name] = PTZMetrics(
|
self.ptz_metrics[camera_name] = PTZMetrics(
|
||||||
autotracker_enabled=self.config.cameras[
|
autotracker_enabled=self.config.cameras[
|
||||||
camera_name
|
camera_name
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import multiprocessing as mp
|
import multiprocessing as mp
|
||||||
|
from multiprocessing.managers import SyncManager
|
||||||
from multiprocessing.sharedctypes import Synchronized
|
from multiprocessing.sharedctypes import Synchronized
|
||||||
from multiprocessing.synchronize import Event
|
from multiprocessing.synchronize import Event
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
|
|
||||||
class CameraMetrics:
|
class CameraMetrics:
|
||||||
@ -16,25 +16,25 @@ class CameraMetrics:
|
|||||||
|
|
||||||
frame_queue: mp.Queue
|
frame_queue: mp.Queue
|
||||||
|
|
||||||
process: Optional[mp.Process]
|
process_pid: Synchronized
|
||||||
capture_process: Optional[mp.Process]
|
capture_process_pid: Synchronized
|
||||||
ffmpeg_pid: Synchronized
|
ffmpeg_pid: Synchronized
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, manager: SyncManager):
|
||||||
self.camera_fps = mp.Value("d", 0)
|
self.camera_fps = manager.Value("d", 0)
|
||||||
self.detection_fps = mp.Value("d", 0)
|
self.detection_fps = manager.Value("d", 0)
|
||||||
self.detection_frame = mp.Value("d", 0)
|
self.detection_frame = manager.Value("d", 0)
|
||||||
self.process_fps = mp.Value("d", 0)
|
self.process_fps = manager.Value("d", 0)
|
||||||
self.skipped_fps = mp.Value("d", 0)
|
self.skipped_fps = manager.Value("d", 0)
|
||||||
self.read_start = mp.Value("d", 0)
|
self.read_start = manager.Value("d", 0)
|
||||||
self.audio_rms = mp.Value("d", 0)
|
self.audio_rms = manager.Value("d", 0)
|
||||||
self.audio_dBFS = mp.Value("d", 0)
|
self.audio_dBFS = manager.Value("d", 0)
|
||||||
|
|
||||||
self.frame_queue = mp.Queue(maxsize=2)
|
self.frame_queue = manager.Queue(maxsize=2)
|
||||||
|
|
||||||
self.process = None
|
self.process_pid = manager.Value("i", 0)
|
||||||
self.capture_process = None
|
self.capture_process_pid = manager.Value("i", 0)
|
||||||
self.ffmpeg_pid = mp.Value("i", 0)
|
self.ffmpeg_pid = manager.Value("i", 0)
|
||||||
|
|
||||||
|
|
||||||
class PTZMetrics:
|
class PTZMetrics:
|
||||||
|
|||||||
@ -54,6 +54,8 @@ class CameraMaintainer(threading.Thread):
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
self.shm_count = self.__calculate_shm_frame_count()
|
self.shm_count = self.__calculate_shm_frame_count()
|
||||||
|
self.camera_processes: dict[str, mp.Process] = {}
|
||||||
|
self.capture_processes: dict[str, mp.Process] = {}
|
||||||
|
|
||||||
def __init_historical_regions(self) -> None:
|
def __init_historical_regions(self) -> None:
|
||||||
# delete region grids for removed or renamed cameras
|
# delete region grids for removed or renamed cameras
|
||||||
@ -120,7 +122,7 @@ class CameraMaintainer(threading.Thread):
|
|||||||
|
|
||||||
def __start_camera_processor(
|
def __start_camera_processor(
|
||||||
self, name: str, config: CameraConfig, runtime: bool = False
|
self, name: str, config: CameraConfig, runtime: bool = False
|
||||||
) -> mp.Process:
|
) -> None:
|
||||||
if not config.enabled_in_config:
|
if not config.enabled_in_config:
|
||||||
logger.info(f"Camera processor not started for disabled camera {name}")
|
logger.info(f"Camera processor not started for disabled camera {name}")
|
||||||
return
|
return
|
||||||
@ -168,13 +170,14 @@ class CameraMaintainer(threading.Thread):
|
|||||||
),
|
),
|
||||||
daemon=True,
|
daemon=True,
|
||||||
)
|
)
|
||||||
|
self.camera_processes[config.name] = camera_process
|
||||||
camera_process.start()
|
camera_process.start()
|
||||||
|
self.camera_metrics[config.name].process_pid.value = camera_process.pid
|
||||||
logger.info(f"Camera processor started for {config.name}: {camera_process.pid}")
|
logger.info(f"Camera processor started for {config.name}: {camera_process.pid}")
|
||||||
return camera_process
|
|
||||||
|
|
||||||
def __start_camera_capture(
|
def __start_camera_capture(
|
||||||
self, name: str, config: CameraConfig, runtime: bool = False
|
self, name: str, config: CameraConfig, runtime: bool = False
|
||||||
) -> mp.Process:
|
) -> None:
|
||||||
if not config.enabled_in_config:
|
if not config.enabled_in_config:
|
||||||
logger.info(f"Capture process not started for disabled camera {name}")
|
logger.info(f"Capture process not started for disabled camera {name}")
|
||||||
return
|
return
|
||||||
@ -191,26 +194,26 @@ class CameraMaintainer(threading.Thread):
|
|||||||
args=(config, count, self.camera_metrics[name]),
|
args=(config, count, self.camera_metrics[name]),
|
||||||
)
|
)
|
||||||
capture_process.daemon = True
|
capture_process.daemon = True
|
||||||
|
self.capture_processes[name] = capture_process
|
||||||
capture_process.start()
|
capture_process.start()
|
||||||
|
self.camera_metrics[name].capture_process_pid.value = capture_process.pid
|
||||||
logger.info(f"Capture process started for {name}: {capture_process.pid}")
|
logger.info(f"Capture process started for {name}: {capture_process.pid}")
|
||||||
return capture_process
|
|
||||||
|
|
||||||
def __stop_camera_capture_process(self, camera: str) -> None:
|
def __stop_camera_capture_process(self, camera: str) -> None:
|
||||||
capture_process = self.camera_metrics[camera].capture_process
|
capture_process = self.capture_processes[camera]
|
||||||
if capture_process is not None:
|
if capture_process is not None:
|
||||||
logger.info(f"Waiting for capture process for {camera} to stop")
|
logger.info(f"Waiting for capture process for {camera} to stop")
|
||||||
capture_process.terminate()
|
capture_process.terminate()
|
||||||
capture_process.join()
|
capture_process.join()
|
||||||
|
|
||||||
def __stop_camera_process(self, camera: str) -> None:
|
def __stop_camera_process(self, camera: str) -> None:
|
||||||
metrics = self.camera_metrics[camera]
|
camera_process = self.camera_processes[camera]
|
||||||
camera_process = metrics.process
|
|
||||||
if camera_process is not None:
|
if camera_process is not None:
|
||||||
logger.info(f"Waiting for process for {camera} to stop")
|
logger.info(f"Waiting for process for {camera} to stop")
|
||||||
camera_process.terminate()
|
camera_process.terminate()
|
||||||
camera_process.join()
|
camera_process.join()
|
||||||
logger.info(f"Closing frame queue for {camera}")
|
logger.info(f"Closing frame queue for {camera}")
|
||||||
empty_and_close_queue(metrics.frame_queue)
|
empty_and_close_queue(self.camera_metrics[camera].frame_queue)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self.__init_historical_regions()
|
self.__init_historical_regions()
|
||||||
@ -226,30 +229,26 @@ class CameraMaintainer(threading.Thread):
|
|||||||
for update_type, updated_cameras in updates.items():
|
for update_type, updated_cameras in updates.items():
|
||||||
if update_type == CameraConfigUpdateEnum.add.name:
|
if update_type == CameraConfigUpdateEnum.add.name:
|
||||||
for camera in updated_cameras:
|
for camera in updated_cameras:
|
||||||
camera_process = self.__start_camera_processor(
|
self.__start_camera_processor(
|
||||||
camera,
|
camera,
|
||||||
self.update_subscriber.camera_configs[camera],
|
self.update_subscriber.camera_configs[camera],
|
||||||
runtime=True,
|
runtime=True,
|
||||||
)
|
)
|
||||||
capture_process = self.__start_camera_capture(
|
self.__start_camera_capture(
|
||||||
camera,
|
camera,
|
||||||
self.update_subscriber.camera_configs[camera],
|
self.update_subscriber.camera_configs[camera],
|
||||||
runtime=True,
|
runtime=True,
|
||||||
)
|
)
|
||||||
self.camera_metrics[config.name].process = camera_process
|
|
||||||
self.camera_metrics[
|
|
||||||
config.name
|
|
||||||
].capture_process = capture_process
|
|
||||||
elif update_type == CameraConfigUpdateEnum.remove.name:
|
elif update_type == CameraConfigUpdateEnum.remove.name:
|
||||||
self.__stop_camera_capture_process(camera)
|
self.__stop_camera_capture_process(camera)
|
||||||
self.__stop_camera_process(camera)
|
self.__stop_camera_process(camera)
|
||||||
|
|
||||||
# ensure the capture processes are done
|
# ensure the capture processes are done
|
||||||
for camera in self.camera_metrics.keys():
|
for camera in self.camera_processes.keys():
|
||||||
self.__stop_camera_capture_process(camera)
|
self.__stop_camera_capture_process(camera)
|
||||||
|
|
||||||
# ensure the camera processors are done
|
# ensure the camera processors are done
|
||||||
for camera in self.camera_metrics.keys():
|
for camera in self.capture_processes.keys():
|
||||||
self.__stop_camera_process(camera)
|
self.__stop_camera_process(camera)
|
||||||
|
|
||||||
self.update_subscriber.stop()
|
self.update_subscriber.stop()
|
||||||
|
|||||||
@ -271,10 +271,12 @@ def stats_snapshot(
|
|||||||
stats["cameras"] = {}
|
stats["cameras"] = {}
|
||||||
for name, camera_stats in camera_metrics.items():
|
for name, camera_stats in camera_metrics.items():
|
||||||
total_detection_fps += camera_stats.detection_fps.value
|
total_detection_fps += camera_stats.detection_fps.value
|
||||||
pid = camera_stats.process.pid if camera_stats.process else None
|
pid = camera_stats.process_pid.value if camera_stats.process_pid.value else None
|
||||||
ffmpeg_pid = camera_stats.ffmpeg_pid.value if camera_stats.ffmpeg_pid else None
|
ffmpeg_pid = camera_stats.ffmpeg_pid.value if camera_stats.ffmpeg_pid else None
|
||||||
capture_pid = (
|
capture_pid = (
|
||||||
camera_stats.capture_process.pid if camera_stats.capture_process else None
|
camera_stats.capture_process_pid.value
|
||||||
|
if camera_stats.capture_process_pid.value
|
||||||
|
else None
|
||||||
)
|
)
|
||||||
stats["cameras"][name] = {
|
stats["cameras"][name] = {
|
||||||
"camera_fps": round(camera_stats.camera_fps.value, 2),
|
"camera_fps": round(camera_stats.camera_fps.value, 2),
|
||||||
|
|||||||
@ -173,7 +173,7 @@ export default function CameraMetrics({
|
|||||||
});
|
});
|
||||||
series[key]["detect"].data.push({
|
series[key]["detect"].data.push({
|
||||||
x: statsIdx,
|
x: statsIdx,
|
||||||
y: stats.cpu_usages[camStats.pid.toString()].cpu,
|
y: stats.cpu_usages[camStats.pid?.toString()]?.cpu,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user