Calculate best shm frame count

This commit is contained in:
Nicolas Mowen 2024-09-02 10:41:06 -06:00
parent 2c05bd1a4c
commit 50c28cc048
4 changed files with 37 additions and 24 deletions

View File

@ -537,7 +537,7 @@ class FrigateApp:
capture_process = mp.Process( capture_process = mp.Process(
target=capture_camera, target=capture_camera,
name=f"camera_capture:{name}", name=f"camera_capture:{name}",
args=(name, config, self.camera_metrics[name]), args=(name, config, self.shm_frame_count, self.camera_metrics[name]),
) )
capture_process.daemon = True capture_process.daemon = True
self.camera_metrics[name]["capture_process"] = capture_process self.camera_metrics[name]["capture_process"] = capture_process
@ -601,27 +601,34 @@ class FrigateApp:
self.frigate_watchdog.start() self.frigate_watchdog.start()
def check_shm(self) -> None: def check_shm(self) -> None:
available_shm = round(shutil.disk_usage("/dev/shm").total / pow(2, 20), 1) total_shm = round(shutil.disk_usage("/dev/shm").total / pow(2, 20), 1)
# required for log files # required for log files + nginx cache
min_req_shm = 40 min_req_shm = 40 + 10
if self.config.birdseye.restream:
min_req_shm += 8
available_shm = total_shm - min_req_shm
cam_average_shm = 0
for camera in self.config.cameras.values(): for camera in self.config.cameras.values():
min_req_shm += round( cam_average_shm += round(
( (camera.detect.width * camera.detect.height * 1.5 + 270480) / 1048576,
camera.detect.width
* camera.detect.height
* 1.5
* max(10, camera.detect.fps)
+ 270480
)
/ 1048576,
1, 1,
) )
if available_shm < min_req_shm: self.shm_frame_count = max(
50, int(available_shm / (cam_average_shm / len(self.config.cameras)))
)
logger.info(
f"Calculated {self.shm_frame_count} frames for each camera in SHM"
)
if self.shm_frame_count < 10:
logger.warning( logger.warning(
f"The current SHM size of {available_shm}MB is too small, recommend increasing it to at least {round(min_req_shm)}MB." f"The current SHM size of {total_shm}MB is too small, recommend increasing it to at least {round(min_req_shm + (cam_average_shm * 10))}MB."
) )
def init_auth(self) -> None: def init_auth(self) -> None:
@ -726,6 +733,7 @@ class FrigateApp:
self.init_historical_regions() self.init_historical_regions()
self.start_detected_frames_processor() self.start_detected_frames_processor()
self.start_camera_processors() self.start_camera_processors()
self.check_shm()
self.start_camera_capture_processes() self.start_camera_capture_processes()
self.start_audio_processors() self.start_audio_processors()
self.start_storage_maintainer() self.start_storage_maintainer()
@ -737,7 +745,6 @@ class FrigateApp:
self.start_event_cleanup() self.start_event_cleanup()
self.start_record_cleanup() self.start_record_cleanup()
self.start_watchdog() self.start_watchdog()
self.check_shm()
self.init_auth() self.init_auth()
# Flask only listens for SIGINT, so we need to catch SIGTERM and send SIGINT # Flask only listens for SIGINT, so we need to catch SIGTERM and send SIGINT

View File

@ -362,8 +362,7 @@ class BirdsEyeFrameManager:
) )
if frame is None: if frame is None:
# TODO: better frame management would prevent this edge case logger.debug(
logger.warning(
f"Unable to copy frame {camera}{frame_time} to birdseye." f"Unable to copy frame {camera}{frame_time} to birdseye."
) )
return return

View File

@ -294,7 +294,7 @@ class ReviewSegmentMaintainer(threading.Thread):
) )
if yuv_frame is None: if yuv_frame is None:
logger.warning(f"Failed to get frame {frame_id} from SHM") logger.debug(f"Failed to get frame {frame_id} from SHM")
return return
self.update_segment( self.update_segment(
@ -312,7 +312,7 @@ class ReviewSegmentMaintainer(threading.Thread):
) )
if yuv_frame is None: if yuv_frame is None:
logger.warning(f"Failed to get frame {frame_id} from SHM") logger.debug(f"Failed to get frame {frame_id} from SHM")
return return
segment.save_full_frame(camera_config, yuv_frame) segment.save_full_frame(camera_config, yuv_frame)
@ -413,7 +413,7 @@ class ReviewSegmentMaintainer(threading.Thread):
) )
if yuv_frame is None: if yuv_frame is None:
logger.warning(f"Failed to get frame {frame_id} from SHM") logger.debug(f"Failed to get frame {frame_id} from SHM")
return return
self.active_review_segments[camera].update_frame( self.active_review_segments[camera].update_frame(

View File

@ -95,6 +95,7 @@ def start_or_restart_ffmpeg(
def capture_frames( def capture_frames(
ffmpeg_process, ffmpeg_process,
config: CameraConfig, config: CameraConfig,
shm_frame_count: int,
frame_shape, frame_shape,
frame_manager: FrameManager, frame_manager: FrameManager,
frame_queue, frame_queue,
@ -109,7 +110,6 @@ def capture_frames(
skipped_eps = EventsPerSecond() skipped_eps = EventsPerSecond()
skipped_eps.start() skipped_eps.start()
shm_count = max(10, config.detect.fps)
shm_frames: list[str] = [] shm_frames: list[str] = []
while True: while True:
@ -124,7 +124,7 @@ def capture_frames(
# update frame cache and cleanup existing frames # update frame cache and cleanup existing frames
shm_frames.append(frame_name) shm_frames.append(frame_name)
if len(shm_frames) > shm_count: if len(shm_frames) > shm_frame_count:
expired_frame_name = shm_frames.pop(0) expired_frame_name = shm_frames.pop(0)
frame_manager.delete(expired_frame_name) frame_manager.delete(expired_frame_name)
except Exception: except Exception:
@ -166,6 +166,7 @@ class CameraWatchdog(threading.Thread):
self, self,
camera_name, camera_name,
config: CameraConfig, config: CameraConfig,
shm_frame_count: int,
frame_queue, frame_queue,
camera_fps, camera_fps,
skipped_fps, skipped_fps,
@ -176,6 +177,7 @@ class CameraWatchdog(threading.Thread):
self.logger = logging.getLogger(f"watchdog.{camera_name}") self.logger = logging.getLogger(f"watchdog.{camera_name}")
self.camera_name = camera_name self.camera_name = camera_name
self.config = config self.config = config
self.shm_frame_count = shm_frame_count
self.capture_thread = None self.capture_thread = None
self.ffmpeg_detect_process = None self.ffmpeg_detect_process = None
self.logpipe = LogPipe(f"ffmpeg.{self.camera_name}.detect") self.logpipe = LogPipe(f"ffmpeg.{self.camera_name}.detect")
@ -299,6 +301,7 @@ class CameraWatchdog(threading.Thread):
self.ffmpeg_pid.value = self.ffmpeg_detect_process.pid self.ffmpeg_pid.value = self.ffmpeg_detect_process.pid
self.capture_thread = CameraCapture( self.capture_thread = CameraCapture(
self.config, self.config,
self.shm_frame_count,
self.ffmpeg_detect_process, self.ffmpeg_detect_process,
self.frame_shape, self.frame_shape,
self.frame_queue, self.frame_queue,
@ -338,6 +341,7 @@ class CameraCapture(threading.Thread):
def __init__( def __init__(
self, self,
config: CameraConfig, config: CameraConfig,
shm_frame_count: int,
ffmpeg_process, ffmpeg_process,
frame_shape, frame_shape,
frame_queue, frame_queue,
@ -348,6 +352,7 @@ class CameraCapture(threading.Thread):
threading.Thread.__init__(self) threading.Thread.__init__(self)
self.name = f"capture:{config.name}" self.name = f"capture:{config.name}"
self.config = config self.config = config
self.shm_frame_count = shm_frame_count
self.frame_shape = frame_shape self.frame_shape = frame_shape
self.frame_queue = frame_queue self.frame_queue = frame_queue
self.fps = fps self.fps = fps
@ -362,6 +367,7 @@ class CameraCapture(threading.Thread):
capture_frames( capture_frames(
self.ffmpeg_process, self.ffmpeg_process,
self.config, self.config,
self.shm_frame_count,
self.frame_shape, self.frame_shape,
self.frame_manager, self.frame_manager,
self.frame_queue, self.frame_queue,
@ -372,7 +378,7 @@ class CameraCapture(threading.Thread):
) )
def capture_camera(name, config: CameraConfig, process_info): def capture_camera(name, config: CameraConfig, shm_frame_count: int, process_info):
stop_event = mp.Event() stop_event = mp.Event()
def receiveSignal(signalNumber, frame): def receiveSignal(signalNumber, frame):
@ -389,6 +395,7 @@ def capture_camera(name, config: CameraConfig, process_info):
camera_watchdog = CameraWatchdog( camera_watchdog = CameraWatchdog(
name, name,
config, config,
shm_frame_count,
frame_queue, frame_queue,
process_info["camera_fps"], process_info["camera_fps"],
process_info["skipped_fps"], process_info["skipped_fps"],