diff --git a/frigate/app.py b/frigate/app.py
index a07a4465f..d23073d77 100644
--- a/frigate/app.py
+++ b/frigate/app.py
@@ -8,6 +8,7 @@ import signal
import sys
from typing import Optional
from types import FrameType
+import psutil
import traceback
from peewee_migrate import Router
@@ -58,6 +59,7 @@ class FrigateApp:
self.plus_api = PlusApi()
self.camera_metrics: dict[str, CameraMetricsTypes] = {}
self.record_metrics: dict[str, RecordMetricsTypes] = {}
+ self.processes: dict[str, int] = {}
def set_environment_vars(self) -> None:
for key, value in self.config.environment_vars.items():
@@ -77,6 +79,7 @@ class FrigateApp:
)
self.log_process.daemon = True
self.log_process.start()
+ self.processes["logger"] = self.log_process.pid or 0
root_configurer(self.log_queue)
def init_config(self) -> None:
@@ -171,6 +174,12 @@ class FrigateApp:
migrate_db.close()
+ def init_go2rtc(self) -> None:
+ for proc in psutil.process_iter(["pid", "name"]):
+ if proc.info["name"] == "go2rtc":
+ logger.info(f"go2rtc process pid: {proc.info['pid']}")
+ self.processes["go2rtc"] = proc.info["pid"]
+
def init_recording_manager(self) -> None:
recording_process = mp.Process(
target=manage_recordings,
@@ -180,6 +189,7 @@ class FrigateApp:
recording_process.daemon = True
self.recording_process = recording_process
recording_process.start()
+ self.processes["recording"] = recording_process.pid or 0
logger.info(f"Recording process started: {recording_process.pid}")
def bind_database(self) -> None:
@@ -191,7 +201,7 @@ class FrigateApp:
def init_stats(self) -> None:
self.stats_tracking = stats_init(
- self.config, self.camera_metrics, self.detectors
+ self.config, self.camera_metrics, self.detectors, self.processes
)
def init_web_server(self) -> None:
@@ -412,6 +422,7 @@ class FrigateApp:
self.init_database()
self.init_onvif()
self.init_recording_manager()
+ self.init_go2rtc()
self.bind_database()
self.init_dispatcher()
except Exception as e:
diff --git a/frigate/stats.py b/frigate/stats.py
index 1ceb5f30d..c9b31bcc1 100644
--- a/frigate/stats.py
+++ b/frigate/stats.py
@@ -46,6 +46,7 @@ def stats_init(
config: FrigateConfig,
camera_metrics: dict[str, CameraMetricsTypes],
detectors: dict[str, ObjectDetectProcess],
+ processes: dict[str, int],
) -> StatsTrackingTypes:
stats_tracking: StatsTrackingTypes = {
"camera_metrics": camera_metrics,
@@ -53,6 +54,7 @@ def stats_init(
"started": int(time.time()),
"latest_frigate_version": get_latest_version(config),
"last_updated": int(time.time()),
+ "processes": processes,
}
return stats_tracking
@@ -260,6 +262,12 @@ def stats_snapshot(
"mount_type": get_fs_type(path),
}
+ stats["processes"] = {}
+ for name, pid in stats_tracking["processes"].items():
+ stats["processes"][name] = {
+ "pid": pid,
+ }
+
return stats
diff --git a/frigate/types.py b/frigate/types.py
index 9da4027c9..3cc401ebb 100644
--- a/frigate/types.py
+++ b/frigate/types.py
@@ -34,3 +34,4 @@ class StatsTrackingTypes(TypedDict):
started: int
latest_frigate_version: str
last_updated: int
+ processes: dict[str, int]
diff --git a/frigate/util.py b/frigate/util.py
index b26e28c9f..51d619005 100755
--- a/frigate/util.py
+++ b/frigate/util.py
@@ -799,36 +799,46 @@ def get_cpu_stats() -> dict[str, dict]:
docker_memlimit = get_docker_memlimit_bytes() / 1024
total_mem = os.sysconf("SC_PAGE_SIZE") * os.sysconf("SC_PHYS_PAGES") / 1024
- for pid in os.listdir("/proc"):
- if pid.isdigit():
- try:
- with open(f"/proc/{pid}/stat", "r") as f:
- stats = f.readline().split()
- utime = int(stats[13])
- stime = int(stats[14])
- cpu_usage = round((utime + stime) / os.sysconf("SC_CLK_TCK"))
+ for process in psutil.process_iter(["pid", "name", "cpu_percent"]):
+ pid = process.info["pid"]
+ try:
+ cpu_percent = process.info["cpu_percent"]
- with open(f"/proc/{pid}/statm", "r") as f:
- mem_stats = f.readline().split()
- mem_res = int(mem_stats[1]) * os.sysconf("SC_PAGE_SIZE") / 1024
+ with open(f"/proc/{pid}/stat", "r") as f:
+ stats = f.readline().split()
+ utime = int(stats[13])
+ stime = int(stats[14])
+ starttime = int(stats[21])
- if docker_memlimit > 0:
- mem_pct = round((mem_res / docker_memlimit) * 100, 1)
- else:
- mem_pct = round((mem_res / total_mem) * 100, 1)
+ with open("/proc/uptime") as f:
+ system_uptime_sec = int(float(f.read().split()[0]))
- idx = pid
- if stats[1] == "(go2rtc)":
- idx = "go2rtc"
- if stats[1].startswith("(frigate.r"):
- idx = "recording"
+ clk_tck = os.sysconf(os.sysconf_names["SC_CLK_TCK"])
- usages[idx] = {
- "cpu": str(round(cpu_usage, 2)),
- "mem": f"{mem_pct}",
- }
- except:
- continue
+ process_utime_sec = utime // clk_tck
+ process_stime_sec = stime // clk_tck
+ process_starttime_sec = starttime // clk_tck
+
+ process_elapsed_sec = system_uptime_sec - process_starttime_sec
+ process_usage_sec = process_utime_sec + process_stime_sec
+ cpu_average_usage = process_usage_sec * 100 // process_elapsed_sec
+
+ with open(f"/proc/{pid}/statm", "r") as f:
+ mem_stats = f.readline().split()
+ mem_res = int(mem_stats[1]) * os.sysconf("SC_PAGE_SIZE") / 1024
+
+ if docker_memlimit > 0:
+ mem_pct = round((mem_res / docker_memlimit) * 100, 1)
+ else:
+ mem_pct = round((mem_res / total_mem) * 100, 1)
+
+ usages[pid] = {
+ "cpu": str(cpu_percent),
+ "cpu_average": str(round(cpu_average_usage, 2)),
+ "mem": f"{mem_pct}",
+ }
+ except:
+ continue
return usages
diff --git a/web/src/routes/System.jsx b/web/src/routes/System.jsx
index 0320e237b..b6e4d3c9d 100644
--- a/web/src/routes/System.jsx
+++ b/web/src/routes/System.jsx
@@ -29,12 +29,14 @@ export default function System() {
detectors,
service = {},
detection_fps: _,
+ processes,
...cameras
} = stats || initialStats || emptyObject;
const detectorNames = Object.keys(detectors || emptyObject);
const gpuNames = Object.keys(gpu_usages || emptyObject);
const cameraNames = Object.keys(cameras || emptyObject);
+ const processesNames = Object.keys(processes || emptyObject);
const onHandleFfprobe = async (camera, e) => {
if (e) {
@@ -347,7 +349,7 @@ export default function System() {
P-ID | CPU % | +Avg CPU % | Memory % |
---|---|---|---|
{cpu_usages[process]?.['cpu'] || '- '}% | -{cpu_usages[process]?.['mem'] || '- '}% | +||
{processes[process]['pid'] || '- '} | +{cpu_usages[processes[process]['pid']]?.['cpu'] || '- '}% | +{cpu_usages[processes[process]['pid']]?.['cpu_average'] || '- '}% | +{cpu_usages[processes[process]['pid']]?.['mem'] || '- '}% |