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(
target=capture_camera,
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
self.camera_metrics[name]["capture_process"] = capture_process
@ -601,27 +601,34 @@ class FrigateApp:
self.frigate_watchdog.start()
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
min_req_shm = 40
# required for log files + nginx cache
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():
min_req_shm += round(
(
camera.detect.width
* camera.detect.height
* 1.5
* max(10, camera.detect.fps)
+ 270480
)
/ 1048576,
cam_average_shm += round(
(camera.detect.width * camera.detect.height * 1.5 + 270480) / 1048576,
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(
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:
@ -726,6 +733,7 @@ class FrigateApp:
self.init_historical_regions()
self.start_detected_frames_processor()
self.start_camera_processors()
self.check_shm()
self.start_camera_capture_processes()
self.start_audio_processors()
self.start_storage_maintainer()
@ -737,7 +745,6 @@ class FrigateApp:
self.start_event_cleanup()
self.start_record_cleanup()
self.start_watchdog()
self.check_shm()
self.init_auth()
# 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:
# TODO: better frame management would prevent this edge case
logger.warning(
logger.debug(
f"Unable to copy frame {camera}{frame_time} to birdseye."
)
return

View File

@ -294,7 +294,7 @@ class ReviewSegmentMaintainer(threading.Thread):
)
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
self.update_segment(
@ -312,7 +312,7 @@ class ReviewSegmentMaintainer(threading.Thread):
)
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
segment.save_full_frame(camera_config, yuv_frame)
@ -413,7 +413,7 @@ class ReviewSegmentMaintainer(threading.Thread):
)
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
self.active_review_segments[camera].update_frame(

View File

@ -95,6 +95,7 @@ def start_or_restart_ffmpeg(
def capture_frames(
ffmpeg_process,
config: CameraConfig,
shm_frame_count: int,
frame_shape,
frame_manager: FrameManager,
frame_queue,
@ -109,7 +110,6 @@ def capture_frames(
skipped_eps = EventsPerSecond()
skipped_eps.start()
shm_count = max(10, config.detect.fps)
shm_frames: list[str] = []
while True:
@ -124,7 +124,7 @@ def capture_frames(
# update frame cache and cleanup existing frames
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)
frame_manager.delete(expired_frame_name)
except Exception:
@ -166,6 +166,7 @@ class CameraWatchdog(threading.Thread):
self,
camera_name,
config: CameraConfig,
shm_frame_count: int,
frame_queue,
camera_fps,
skipped_fps,
@ -176,6 +177,7 @@ class CameraWatchdog(threading.Thread):
self.logger = logging.getLogger(f"watchdog.{camera_name}")
self.camera_name = camera_name
self.config = config
self.shm_frame_count = shm_frame_count
self.capture_thread = None
self.ffmpeg_detect_process = None
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.capture_thread = CameraCapture(
self.config,
self.shm_frame_count,
self.ffmpeg_detect_process,
self.frame_shape,
self.frame_queue,
@ -338,6 +341,7 @@ class CameraCapture(threading.Thread):
def __init__(
self,
config: CameraConfig,
shm_frame_count: int,
ffmpeg_process,
frame_shape,
frame_queue,
@ -348,6 +352,7 @@ class CameraCapture(threading.Thread):
threading.Thread.__init__(self)
self.name = f"capture:{config.name}"
self.config = config
self.shm_frame_count = shm_frame_count
self.frame_shape = frame_shape
self.frame_queue = frame_queue
self.fps = fps
@ -362,6 +367,7 @@ class CameraCapture(threading.Thread):
capture_frames(
self.ffmpeg_process,
self.config,
self.shm_frame_count,
self.frame_shape,
self.frame_manager,
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()
def receiveSignal(signalNumber, frame):
@ -389,6 +395,7 @@ def capture_camera(name, config: CameraConfig, process_info):
camera_watchdog = CameraWatchdog(
name,
config,
shm_frame_count,
frame_queue,
process_info["camera_fps"],
process_info["skipped_fps"],