Skip to content
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
550cc8c
added bert as a test inference benchmark
McLavish Oct 30, 2025
f9c3817
hotfix to enable gpu capabilities
McLavish Nov 3, 2025
0f93b66
added pre-commit hooks for linting and formatting
McLavish Nov 4, 2025
b965d7b
linting and formatting setting for whoever uses vscode + black + flak…
McLavish Nov 4, 2025
e9916db
reformatted local file so it passes linting/format
McLavish Nov 4, 2025
2b75311
Merge branch 'development' into feature/bert-inference
McLavish Nov 4, 2025
813af03
bert now uses gpu
McLavish Nov 4, 2025
3a96f04
changed data repo to be OUR forked data repo
McLavish Nov 4, 2025
d4d5d30
change data loading path to own forked repo
Russellpang Nov 5, 2025
1b7deb7
change data loading path to own forked repo
Russellpang Nov 5, 2025
668652c
update benchmark function
Russellpang Nov 5, 2025
aae1023
fix: replaced onnxruntime requirement from CPU to GPU. now it actuall…
McLavish Nov 5, 2025
25fd1d9
circleci mypy fix?
McLavish Nov 5, 2025
c478c91
Merge pull request #2 from McLavish/feature/bert-inference
McLavish Nov 5, 2025
d6c4227
benchmarks is now flake8/black compliant. pre-commit hooks also check…
McLavish Nov 5, 2025
27b14d6
add linalg benchmarks
Russellpang Nov 5, 2025
ace2335
add linalg benchmarks
Russellpang Nov 5, 2025
ad3023d
changed CI/CD to run linting on the benchmarks folder ONLY. disabled …
McLavish Nov 5, 2025
52f30c0
fix typo
Russellpang Nov 6, 2025
4efff4d
update code
Russellpang Nov 6, 2025
f8577e7
Create .gitkeep
JessieeeNotLi Nov 6, 2025
dfaa14a
watermarking GPU benchmark files
JessieeeNotLi Nov 6, 2025
7f4f6c9
added run benchmark script
JessieeeNotLi Nov 6, 2025
1653b7c
Add usage instructions to read.me
JessieeeNotLi Nov 6, 2025
f5e7ab7
watermarking_readme.md
JessieeeNotLi Nov 6, 2025
aa3483f
Update NVENC benchmark instructions in README
JessieeeNotLi Nov 6, 2025
adf54a5
migrated from CircleCI to Github Actions
McLavish Nov 6, 2025
67772e2
fixed workflow directory
McLavish Nov 6, 2025
8f02b66
pip dependencies take too long
McLavish Nov 6, 2025
ae61e4b
Merge pull request #8 from McLavish/hotfix/code-quality-on-benchmarks
McLavish Nov 6, 2025
e06985c
new benchmark data
McLavish Nov 10, 2025
037f6c3
Bring folder from other-branch
Nov 12, 2025
377d949
update code
Nov 12, 2025
8dd8a6e
modify code and requirements
Nov 12, 2025
fa7e76e
Create .gitkeep
JessieeeNotLi Nov 12, 2025
51713f4
Add Dockerfile for NVENC-enabled FFmpeg image
JessieeeNotLi Nov 12, 2025
e0cfbdc
Add run script for video watermarking benchmark
JessieeeNotLi Nov 12, 2025
de15075
unfinished new fuc
Russellpang Nov 12, 2025
f534a53
Add files via upload
JessieeeNotLi Nov 12, 2025
3006879
add new functions
Russellpang Nov 12, 2025
7057465
Update run.sh
JessieeeNotLi Nov 12, 2025
44c8bcb
Update run.sh
JessieeeNotLi Nov 12, 2025
e53cfde
added gpu benchmark, and test results on CPU:wq
Nov 12, 2025
d224ddc
add new functions
Russellpang Nov 13, 2025
921f321
added recommender benchmark
McLavish Nov 13, 2025
dd840d1
Merge branch 'development' into feature/russell
YuxuanLiu-kayla Nov 13, 2025
4fca4aa
changed data submodule to use ssh and not https
McLavish Nov 13, 2025
26dfcf4
add channel_flow, compute, fft, and resnet of jax_npbench
down-street Nov 15, 2025
fad77da
reset the config
down-street Nov 15, 2025
e995e6a
Merge pull request #13 from McLavish/jiahao/npbenchs
down-street Nov 15, 2025
7e0d13f
microbenchmark example
Nov 16, 2025
942f5a1
Remove SSH public key from eval command
Russellpang Nov 16, 2025
6bc1dd7
Remove local_deployment.json configuration
Russellpang Nov 16, 2025
460ea1f
Delete out_storage.json configuration file
Russellpang Nov 16, 2025
de41ab6
Remove SSH private key from eval command
Russellpang Nov 16, 2025
ded520f
remove garbage
Nov 16, 2025
5c85980
test
Russellpang Nov 17, 2025
c5782dd
test
Russellpang Nov 17, 2025
2b52ced
test
Russellpang Nov 17, 2025
e5cb20c
Merge branch 'development' into feature/russell
Russellpang Nov 17, 2025
6488d6d
remove unnecessay files
Russellpang Nov 17, 2025
55c4ac4
fuck you
Russellpang Nov 17, 2025
b97b7a5
Refactor argument parsing for cleaner syntax
Russellpang Nov 17, 2025
1998b6b
Change 'reps' to 'iters' in jacobi2d function
Russellpang Nov 17, 2025
2cbd768
Delete benchmarks/000.microbenchmarks/050.matmul directory
Russellpang Nov 17, 2025
074d4b7
Merge pull request #6 from McLavish/feature/russell
McLavish Nov 17, 2025
efced9c
Revert "changed data submodule to use ssh and not https"
McLavish Nov 17, 2025
bc48b5e
fix: missing config.json
McLavish Nov 17, 2025
e154ba0
Merge branch 'development' into feature/inference-recommender
McLavish Nov 17, 2025
d9ed506
Merge pull request #11 from McLavish/feature/inference-recommender
McLavish Nov 17, 2025
703a05d
adapted watermarking benchmark to sebs structure
JessieeeNotLi Nov 23, 2025
f5093a8
Merge branch 'development' into jessie/video_watermarking
JessieeeNotLi Nov 23, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

15 changes: 15 additions & 0 deletions benchmarks/200.multimedia/225.video-watermarking-gpu/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# NVENC-enabled FFmpeg base image
FROM jrottenberg/ffmpeg:6.1-nvidia

# Python for gpu_bench.py
RUN apt-get update && apt-get install -y --no-install-recommends \
python3 python3-pip python3-venv ca-certificates && \
rm -rf /var/lib/apt/lists/*

WORKDIR /app
COPY gpu_bench.py /app/gpu_bench.py
COPY run.sh /app/run.sh
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify COPY source paths match actual file locations.

The Dockerfile copies gpu_bench.py and run.sh from the build context root (lines 10-11), but based on the PR summary, gpu_bench.py is located in watermarking_bench/ directory. Confirm whether:

  • The build context is correctly structured and paths should be watermarking_bench/gpu_bench.py
  • These files are actually at the repository root
  • Or the docker build is invoked from a non-standard location

🏁 Script executed:

#!/bin/bash
# Description: Verify locations of gpu_bench.py and run.sh relative to Dockerfile

# Find gpu_bench.py
echo "=== Finding gpu_bench.py ==="
find . -name "gpu_bench.py" -type f 2>/dev/null | head -20

# Find run.sh  
echo "=== Finding run.sh in video-watermarking-gpu context ==="
find . -path "*/225.video-watermarking-gpu/run.sh" -type f 2>/dev/null

# Check build context assumptions
echo "=== Checking Dockerfile location ==="
find . -path "*225.video-watermarking-gpu/Dockerfile" -type f 2>/dev/null

Length of output: 284


I need to gather more information to confirm the build context assumptions:Now I need to verify the file details and check the directory structure to understand the exact build setup:Now let me verify the actual content of the files and directory structure to understand the full context:


🏁 Script executed:

#!/bin/bash
# Description: Verify file locations and check gpu_bench.py details

echo "=== Checking gpu_bench.py shebang and location ==="
head -3 ./watermarking_bench/gpu_bench.py

echo ""
echo "=== Checking if watermarking_bench is at repo root ==="
ls -la ./watermarking_bench/ | head -10

echo ""
echo "=== Directory structure around Dockerfile ==="
ls -la ./benchmarks/200.multimedia/225.video-watermarking-gpu/

echo ""
echo "=== Checking if watermarking_bench is inside benchmarks ==="
find ./benchmarks -name "gpu_bench.py" -type f 2>/dev/null

echo ""
echo "=== Checking for any requirements or build configuration ==="
find ./watermarking_bench -name "requirements*.txt" -o -name "setup.py" -o -name "*.md" 2>/dev/null | head -10

Length of output: 1338


Let me check the build documentation and run.sh to understand the intended build context:

Now let me check the build documentation and run.sh to determine the intended build pattern:


🏁 Script executed:

#!/bin/bash
# Description: Check build documentation and run.sh

echo "=== Contents of run.sh ==="
cat ./benchmarks/200.multimedia/225.video-watermarking-gpu/run.sh

echo ""
echo "=== Contents of watermarking_readme.md ==="
cat ./watermarking_bench/watermarking_readme.md

Length of output: 935


Fix COPY source paths to match actual file locations.

The Dockerfile's COPY commands (lines 10-11) assume both files are in the build context root, but they are located elsewhere:

  • gpu_bench.py is at watermarking_bench/gpu_bench.py (not in context root)
  • run.sh is at benchmarks/200.multimedia/225.video-watermarking-gpu/run.sh (not in context root)

Update to:

COPY watermarking_bench/gpu_bench.py /app/gpu_bench.py
COPY benchmarks/200.multimedia/225.video-watermarking-gpu/run.sh /app/run.sh

This assumes docker build is invoked from the repository root with the standard context (.).

🤖 Prompt for AI Agents
In benchmarks/200.multimedia/225.video-watermarking-gpu/Dockerfile around lines
10 to 11, the COPY source paths are incorrect (they assume files live in the
build context root); update the COPY commands to use the actual locations: copy
watermarking_bench/gpu_bench.py to /app/gpu_bench.py and copy
benchmarks/200.multimedia/225.video-watermarking-gpu/run.sh to /app/run.sh,
assuming docker build is run from the repository root (context .).

RUN chmod +x /app/gpu_bench.py /app/run.sh

# default entrypoint lets SeBS simply "docker run" it
ENTRYPOINT ["/app/run.sh"]
293 changes: 293 additions & 0 deletions benchmarks/200.multimedia/225.video-watermarking-gpu/gpu_bench.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,293 @@
#!/usr/bin/env python3
import argparse, datetime, json, os, re, shutil, subprocess, sys, tempfile, csv
from typing import List, Dict, Any, Optional, Tuple

# --- helpers ---------------------------------------------------------------

def which_ffmpeg() -> str:
p = shutil.which("ffmpeg")
if not p:
sys.exit("ffmpeg not found on PATH. Use Docker image with NVENC or install FFmpeg with NVENC.")
return p

def run(cmd: List[str]) -> subprocess.CompletedProcess:
return subprocess.run(cmd, stdin=subprocess.DEVNULL, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)

def has_encoder(ffmpeg: str, enc: str) -> bool:
out = run([ffmpeg, "-hide_banner", "-encoders"]).stdout
return re.search(rf"\b{re.escape(enc)}\b", out) is not None

def has_filter(ffmpeg: str, name: str) -> bool:
out = run([ffmpeg, "-hide_banner", "-filters"]).stdout
return (f" {name} " in out)

def gpu_info() -> Dict[str, Any]:
try:
out = run(["nvidia-smi", "--query-gpu=name,memory.total,driver_version", "--format=csv,noheader,nounits"]).stdout.strip()
name, mem, drv = [x.strip() for x in out.splitlines()[0].split(",")]
return {"name": name, "memory_total_mb": int(mem), "driver_version": drv}
except Exception:
return {"name": None, "memory_total_mb": None, "driver_version": None}

def parse_progress(log: str) -> Dict[str, Any]:
lines = [ln for ln in log.splitlines() if ("fps=" in ln or "speed=" in ln or "frame=" in ln)]
fps = speed = frames = None
if lines:
last = lines[-1]
m = re.search(r"fps=\s*([0-9]+(?:\.[0-9]+)?)", last); fps = float(m.group(1)) if m else None
m = re.search(r"speed=\s*([0-9]+(?:\.[0-9]+)?)x", last); speed = float(m.group(1)) if m else None
m = re.search(r"frame=\s*([0-9]+)", last); frames = int(m.group(1)) if m else None
return {"fps": fps, "speed_x": speed, "frames": frames}

# --- filter planning -------------------------------------------------------

def build_vf_or_complex(
ffmpeg: str,
scale: Optional[str],
wm_path: Optional[str],
overlay: str,
want_gpu_decode: bool
) -> Tuple[List[str], str]:
"""
Returns (ffmpeg_args_for_filters, filter_used_string).

Priority:
- Prefer GPU filters: scale_npp, then scale_cuda, then CPU scale with explicit bridges.
- Prefer overlay_cuda; else CPU overlay with explicit bridges.
- Never place 'format=nv12' *after* 'hwupload_cuda'.
"""
used = []
vf_args: List[str] = []
complex_graph = ""

have_scale_npp = has_filter(ffmpeg, "scale_npp")
have_scale_cuda = has_filter(ffmpeg, "scale_cuda")
have_overlay_cuda= has_filter(ffmpeg, "overlay_cuda")

# No watermark case
if not wm_path:
if scale:
if want_gpu_decode and have_scale_npp:
vf_args = ["-vf", f"scale_npp={scale}"]
used.append("scale_npp")
elif want_gpu_decode and have_scale_cuda:
vf_args = ["-vf", f"scale_cuda={scale}"]
used.append("scale_cuda")
else:
# CPU scale with explicit bridges
# hw frames -> CPU: hwdownload,format=nv12
# CPU scale -> back to GPU: hwupload_cuda
vf_args = ["-vf", f"hwdownload,format=nv12,scale={scale},hwupload_cuda"]
used.append("scale(cpu)+hwdownload+hwupload_cuda")
else:
vf_args = []
return (vf_args, "+".join(used))

# Watermark case
if want_gpu_decode and have_overlay_cuda:
if scale and have_scale_npp:
complex_graph = f"[0:v]scale_npp={scale}[v0];[v0][1:v]overlay_cuda={overlay}[vout]"
used += ["scale_npp","overlay_cuda"]
elif scale and have_scale_cuda:
complex_graph = f"[0:v]scale_cuda={scale}[v0];[v0][1:v]overlay_cuda={overlay}[vout]"
used += ["scale_cuda","overlay_cuda"]
elif scale:
complex_graph = (
f"[0:v]hwdownload,format=nv12,scale={scale},hwupload_cuda[v0];"
f"[v0][1:v]overlay_cuda={overlay}[vout]"
)
used += ["scale(cpu)+hwdownload+hwupload_cuda","overlay_cuda"]
else:
complex_graph = f"[0:v][1:v]overlay_cuda={overlay}[vout]"
used += ["overlay_cuda"]
return (["-filter_complex", complex_graph, "-map", "[vout]"], "+".join(used))

# CPU overlay fallback
if scale and want_gpu_decode and (have_scale_npp or have_scale_cuda):
scaler = "scale_npp" if have_scale_npp else "scale_cuda"
complex_graph = (
f"[0:v]{scaler}={scale}[v0gpu];"
f"[v0gpu]hwdownload,format=nv12[v0cpu];"
f"[v0cpu][1:v]overlay={overlay}[mix];"
f"[mix]hwupload_cuda[vout]"
)
used += [scaler, "hwdownload+overlay(cpu)+hwupload_cuda"]
elif scale:
complex_graph = (
f"[0:v]hwdownload,format=nv12,scale={scale}[v0cpu];"
f"[v0cpu][1:v]overlay={overlay}[mix];"
f"[mix]hwupload_cuda[vout]"
)
used += ["scale(cpu)+overlay(cpu)+hwupload_cuda"]
else:
complex_graph = (
f"[0:v]hwdownload,format=nv12[v0cpu];"
f"[v0cpu][1:v]overlay={overlay}[mix];"
f"[mix]hwupload_cuda[vout]"
)
used += ["overlay(cpu)+hwupload_cuda"]

return (["-filter_complex", complex_graph, "-map", "[vout]"], "+".join(used))

# --- core ------------------------------------------------------------------

def transcode_once(
ffmpeg: str,
inp: str,
outp: str,
codec: str,
bitrate: str,
preset: str,
duration: Optional[float],
scale: Optional[str],
wm_path: Optional[str],
overlay_pos: str,
decode_mode: str = "gpu" # "gpu" or "cpu"
) -> Dict[str, Any]:

if not has_encoder(ffmpeg, codec):
raise RuntimeError(f"encoder '{codec}' not available; check your ffmpeg build (NVENC/AV1).")

want_gpu_decode = (decode_mode == "gpu")

args = [ffmpeg, "-hide_banner", "-y", "-vsync", "0"]

if want_gpu_decode:
# Keep decode on GPU & use CUDA frames. Give NVDEC extra surfaces.
args += ["-hwaccel", "cuda", "-hwaccel_output_format", "cuda", "-extra_hw_frames", "16"]
# Helpful on some builds to make filters pick the right device
args += ["-init_hw_device", "cuda=cuda", "-filter_hw_device", "cuda"]

# inputs
args += ["-i", inp]
if wm_path:
args += ["-loop", "1", "-i", wm_path]

if duration:
args += ["-t", str(duration)]

# Build filters
filt_args, filter_used = build_vf_or_complex(ffmpeg, scale, wm_path, overlay_pos, want_gpu_decode)
args += filt_args

# encoder params
args += ["-c:v", codec, "-b:v", bitrate, "-preset", preset, "-rc", "vbr", "-movflags", "+faststart"]
# audio: copy if present
args += ["-c:a", "copy"]

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Audio copy crashes when watermark is enabled

Whenever build_vf_or_complex needs watermarking it returns -filter_complex … -map [vout] (e.g., Line 73). That mapping drops all audio streams, yet we still force -c:a copy here. ffmpeg then aborts with “Stream specifier ':a' matches no streams,” so every watermark trial fails. Please either keep audio mapped (e.g., append -map 0:a? alongside [vout]) or skip -c:a copy when no audio output is present.

A minimal fix is to extend each filter-complex return to include audio (and keep -c:a copy working):

-        return (["-filter_complex", complex_graph, "-map", "[vout]"], "+".join(used))
+        return ([
+            "-filter_complex", complex_graph,
+            "-map", "[vout]",
+            "-map", "0:a?"
+        ], "+".join(used))

Make the corresponding change for the other watermark branches as well.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In benchmarks/200.multimedia/225.video-watermarking-gpu/gpu_bench.py around
lines 189-191, we always append "-c:a copy" even when build_vf_or_complex
returns a filter_complex that maps only video (e.g., "-map [vout]"), which drops
audio and makes ffmpeg fail with "Stream specifier ':a' matches no streams." Fix
by either (1) modifying the watermarking branches in build_vf_or_complex to
include audio mapping (append "-map 0:a?" alongside the video map so audio is
preserved and "-c:a copy" remains valid) or (2) only append "-c:a copy" when an
audio output map exists (detect if any "-map 0:a" or "-map 0:a?" is present and
skip adding "-c:a" otherwise); apply the same change to all other watermark
branches that return a filter_complex mapping video only.

# Output path
args += [outp]

t0 = datetime.datetime.now()
proc = run(args)
t1 = datetime.datetime.now()
if proc.returncode != 0:
raise RuntimeError("ffmpeg failed:\n" + proc.stdout + f"\n\nARGS:\n{' '.join(args)}")

parsed = parse_progress(proc.stdout)
size = os.path.getsize(outp) if os.path.exists(outp) else 0
return {
"args": args,
"filter_used": filter_used,
"stdout_tail": "\n".join(proc.stdout.splitlines()[-15:]),
"compute_time_us": (t1 - t0) / datetime.timedelta(microseconds=1),
"fps": parsed["fps"],
"speed_x": parsed["speed_x"],
"frames": parsed["frames"],
"output_size_bytes": size
}

def main():
ap = argparse.ArgumentParser(description="GPU NVENC benchmark.")
ap.add_argument("--input", required=True, help="Path to input video")
ap.add_argument("--duration", type=float, default=None, help="Trim to first N seconds")
ap.add_argument("--repeat", type=int, default=1, help="Repeat each trial")
ap.add_argument("--warmup", action="store_true", help="Run one warmup trial (not recorded)")
ap.add_argument("--csv", default=None, help="Optional path to write CSV summary")
ap.add_argument("--watermark", default=None, help="Path to watermark PNG (optional)")
ap.add_argument("--overlay", default="main_w/2-overlay_w/2:main_h/2-overlay_h/2",
help="Overlay position (ffmpeg expr), e.g. '10:10' or 'main_w-overlay_w-10:10'")
ap.add_argument("--decode", choices=["gpu","cpu"], default="gpu",
help="Decode on GPU (default) or CPU.")
ap.add_argument("--trials", nargs="+", default=[
"codec=h264_nvenc,bitrate=5M,preset=p5",
"codec=h264_nvenc,bitrate=12M,preset=p1,scale=1920:1080",
"codec=hevc_nvenc,bitrate=6M,preset=p4",
"codec=av1_nvenc,bitrate=3M,preset=p5"
], help="List like codec=h264_nvenc,bitrate=5M,preset=p5[,scale=WxH]")
args = ap.parse_args()

ffmpeg = which_ffmpeg()
gi = gpu_info()

def parse_trial(s: str) -> Dict[str, str]:
d: Dict[str, str] = {}
for kv in s.split(","):
k, v = kv.split("=", 1)
d[k.strip()] = v.strip()
return d

trial_specs = [parse_trial(s) for s in args.trials]

# optional warmup
if args.warmup:
with tempfile.NamedTemporaryFile(suffix=".mp4", delete=True) as tmp:
_ = transcode_once(ffmpeg, args.input, tmp.name,
trial_specs[0].get("codec","h264_nvenc"),
trial_specs[0].get("bitrate","5M"),
trial_specs[0].get("preset","p5"),
args.duration,
trial_specs[0].get("scale"),
args.watermark,
args.overlay,
args.decode)

results = []
idx = 0
for spec in trial_specs:
for _ in range(args.repeat):
with tempfile.NamedTemporaryFile(suffix=".mp4", delete=False) as tmp:
outp = tmp.name
res = transcode_once(ffmpeg, args.input, outp,
spec.get("codec","h264_nvenc"),
spec.get("bitrate","5M"),
spec.get("preset","p5"),
args.duration,
spec.get("scale"),
args.watermark,
args.overlay,
args.decode)
results.append({
"trial_index": idx,
"codec": spec.get("codec"),
"bitrate": spec.get("bitrate"),
"preset": spec.get("preset"),
"scale_filter": res["filter_used"],
"fps": res["fps"],
"speed_x": res["speed_x"],
"frames": res["frames"],
"compute_time_us": res["compute_time_us"],
"output_size_bytes": res["output_size_bytes"],
"stdout_tail": res["stdout_tail"],
"argv": " ".join(res["args"]),
})
idx += 1
try: os.remove(outp)
except OSError: pass

report = {
"gpu": gi,
"ffmpeg_path": ffmpeg,
"trial_count": len(results),
"results": results
}
print(json.dumps(report, indent=2))

if args.csv and results:
with open(args.csv, "w", newline="") as f:
w = csv.DictWriter(f, fieldnames=list(results[0].keys()))
w.writeheader()
w.writerows(results)

if __name__ == "__main__":
main()
23 changes: 23 additions & 0 deletions benchmarks/200.multimedia/225.video-watermarking-gpu/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/usr/bin/env bash
set -euo pipefail

# Pass through common args; provide sensible defaults
INPUT="${INPUT:-/data/sample.mp4}"
DURATION="${DURATION:-8}"
REPEAT="${REPEAT:-1}"
CSV="${CSV:-/out/results.csv}"
DECODE="${DECODE:-gpu}" # 'gpu' or 'cpu'

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Default decode mode breaks CPU image startup

Line 13 forces DECODE to gpu, so transcode_once always adds -hwaccel cuda (Line 165 in gpu_bench.py). On the CPU image—which by definition has no CUDA devices—ffmpeg fails immediately (No NVDEC device found), making the CPU benchmark unusable unless the caller manually overrides DECODE. Please default to CPU (or auto-detect with nvidia-smi) so the CPU image works out of the box.

Apply this diff to auto-detect the decode mode:

- DECODE="${DECODE:-gpu}"
+if [ -z "${DECODE:-}" ]; then
+  if command -v nvidia-smi >/dev/null 2>&1 && nvidia-smi -L >/dev/null 2>&1; then
+    DECODE="gpu"
+  else
+    DECODE="cpu"
+  fi
+fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
DECODE="${DECODE:-gpu}" # 'gpu' or 'cpu'
if [ -z "${DECODE:-}" ]; then
if command -v nvidia-smi >/dev/null 2>&1 && nvidia-smi -L >/dev/null 2>&1; then
DECODE="gpu"
else
DECODE="cpu"
fi
fi
🤖 Prompt for AI Agents
In benchmarks/200.multimedia/225.video-watermarking-gpu/run.sh around lines
13-14, the script currently forces DECODE="${DECODE:-gpu}" which breaks the CPU
image; change it to default to cpu or auto-detect GPUs: if DECODE is not set,
run a quick check for nvidia-smi (and that it reports at least one GPU) and set
DECODE=gpu only in that case, otherwise set DECODE=cpu; ensure the detection is
robust (check command exists and exit code/output) and leaves an explicit
caller-provided DECODE unchanged.

mkdir -p /out

# If INPUT is missing, let gpu_bench synthesize one
/app/gpu_bench.py \
--input "$INPUT" \
--duration "$DURATION" \
--repeat "$REPEAT" \
--decode "$DECODE" \
--csv "$CSV" \
--trials \
"codec=h264_nvenc,bitrate=5M,preset=p5" \
"codec=h264_nvenc,bitrate=12M,preset=p1,scale=1920:1080" \
"codec=hevc_nvenc,bitrate=6M,preset=p4"
1 change: 1 addition & 0 deletions watermarking_bench/.gitkeep
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

Loading