diff --git a/docker/install_deps.sh b/docker/install_deps.sh index 9a0e80dfe..3443329dd 100755 --- a/docker/install_deps.sh +++ b/docker/install_deps.sh @@ -12,7 +12,8 @@ apt-get -qq install --no-install-recommends -y \ unzip locales tzdata libxml2 xz-utils \ python3-pip \ curl \ - jq + jq \ + nethogs mkdir -p -m 600 /root/.gnupg diff --git a/frigate/stats.py b/frigate/stats.py index 4287dab0c..9ceaa8db3 100644 --- a/frigate/stats.py +++ b/frigate/stats.py @@ -16,7 +16,7 @@ from frigate.const import DRIVER_AMD, DRIVER_ENV_VAR, RECORD_DIR, CLIPS_DIR, CAC from frigate.types import StatsTrackingTypes, CameraMetricsTypes from frigate.util import get_amd_gpu_stats, get_intel_gpu_stats, get_nvidia_gpu_stats from frigate.version import VERSION -from frigate.util import get_cpu_stats +from frigate.util import get_cpu_stats, get_bandwidth_stats from frigate.object_detection import ObjectDetectProcess logger = logging.getLogger(__name__) @@ -101,6 +101,7 @@ def get_processing_stats( [ asyncio.create_task(set_gpu_stats(config, stats, hwaccel_errors)), asyncio.create_task(set_cpu_stats(stats)), + asyncio.create_task(set_bandwidth_stats(stats)), ] ) @@ -117,6 +118,12 @@ async def set_cpu_stats(all_stats: dict[str, Any]) -> None: if cpu_stats: all_stats["cpu_usages"] = cpu_stats +async def set_bandwidth_stats(all_stats: dict[str, Any]) -> None: + """Set cpu usage from top.""" + bandwidth_stats = get_bandwidth_stats() + + if bandwidth_stats: + all_stats["bandwidth_usages"] = bandwidth_stats async def set_gpu_stats( config: FrigateConfig, all_stats: dict[str, Any], hwaccel_errors: list[str] diff --git a/frigate/util.py b/frigate/util.py index d98cee106..f0605335d 100755 --- a/frigate/util.py +++ b/frigate/util.py @@ -843,6 +843,32 @@ def get_cpu_stats() -> dict[str, dict]: return usages +def get_bandwidth_stats() -> dict[str, dict]: + """Get bandwidth usages for each ffmpeg process id""" + usages = {} + top_command = ["nethogs", "-t", "-v0", "-c5", "-d1"] + + p = sp.run( + top_command, + encoding="ascii", + capture_output=True, + ) + + if p.returncode != 0: + return usages + else: + lines = p.stdout.split("\n") + for line in lines: + stats = list(filter(lambda a: a != "", line.strip().split("\t"))) + try: + if re.search('^ffmpeg/([0-9]+)/', stats[0]): + process = stats[0].split("/") + usages[process[1]] = { + "bandwidth": round(float(stats[2]), 1), + } + except: + continue + return usages def get_amd_gpu_stats() -> dict[str, str]: """Get stats using radeontop.""" diff --git a/web/src/routes/System.jsx b/web/src/routes/System.jsx index 7ec238596..922e07a30 100644 --- a/web/src/routes/System.jsx +++ b/web/src/routes/System.jsx @@ -343,6 +343,7 @@ export default function System() { FPS CPU % Memory % + Bandwidth KB/s @@ -352,6 +353,7 @@ export default function System() { {cameras[camera]['camera_fps'] || '- '} {cpu_usages[cameras[camera]['ffmpeg_pid']]?.['cpu'] || '- '}% {cpu_usages[cameras[camera]['ffmpeg_pid']]?.['mem'] || '- '}% + {bandwidth_usages[cameras[camera]['ffmpeg_pid']]?.['bandwidth'] || '- '}KB/s Capture @@ -359,6 +361,7 @@ export default function System() { {cameras[camera]['process_fps'] || '- '} {cpu_usages[cameras[camera]['capture_pid']]?.['cpu'] || '- '}% {cpu_usages[cameras[camera]['capture_pid']]?.['mem'] || '- '}% + - Detect @@ -379,6 +382,7 @@ export default function System() { {cpu_usages[cameras[camera]['pid']]?.['cpu'] || '- '}% {cpu_usages[cameras[camera]['pid']]?.['mem'] || '- '}% + -