Skip to content

Commit ddf3e54

Browse files
authored
Added benchmark chart to README.md (#315)
1 parent ae52b29 commit ddf3e54

File tree

4 files changed

+141
-0
lines changed

4 files changed

+141
-0
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,12 @@ The instructions below assume you're on Linux.
118118
pip install torchcodec
119119
```
120120

121+
## Benchmark Results
122+
123+
The following was generated by running [our benchmark script](./benchmarks/decoders/generate_readme_chart.py) on a lightly loaded 22-core machine.
124+
125+
![benchmark_results](./benchmarks/decoders/benchmark_readme_chart.png)
126+
121127
## Planned future work
122128

123129
We are actively working on the following features:

benchmarks/decoders/benchmark_decoders_library.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import abc
22
import json
33
import os
4+
import subprocess
45
import timeit
6+
from concurrent.futures import ThreadPoolExecutor
7+
from itertools import product
58

69
import matplotlib.pyplot as plt
710
import numpy as np
@@ -299,6 +302,53 @@ def create_torchcodec_decoder_from_file(video_file):
299302
return video_decoder
300303

301304

305+
def generate_video(command):
306+
print(command)
307+
print(" ".join(command))
308+
subprocess.check_call(command)
309+
310+
311+
def generate_videos(
312+
resolutions,
313+
encodings,
314+
fpses,
315+
gop_sizes,
316+
durations,
317+
pix_fmts,
318+
ffmpeg_cli,
319+
output_dir,
320+
):
321+
executor = ThreadPoolExecutor(max_workers=20)
322+
video_count = 0
323+
324+
for resolution, duration, fps, gop_size, encoding, pix_fmt in product(
325+
resolutions, durations, fpses, gop_sizes, encodings, pix_fmts
326+
):
327+
outfile = f"{output_dir}/{resolution}_{duration}s_{fps}fps_{gop_size}gop_{encoding}_{pix_fmt}.mp4"
328+
command = [
329+
ffmpeg_cli,
330+
"-y",
331+
"-f",
332+
"lavfi",
333+
"-i",
334+
f"color=c=blue:s={resolution}:d={duration}",
335+
"-c:v",
336+
encoding,
337+
"-r",
338+
f"{fps}",
339+
"-g",
340+
f"{gop_size}",
341+
"-pix_fmt",
342+
pix_fmt,
343+
outfile,
344+
]
345+
executor.submit(generate_video, command)
346+
video_count += 1
347+
348+
executor.shutdown(wait=True)
349+
print(f"Generated {video_count} videos")
350+
351+
302352
def plot_data(df_data, plot_path):
303353
# Creating the DataFrame
304354
df = pd.DataFrame(df_data)
55.3 KB
Loading
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# Copyright (c) Meta Platforms, Inc. and affiliates.
2+
# All rights reserved.
3+
#
4+
# This source code is licensed under the BSD-style license found in the
5+
# LICENSE file in the root directory of this source tree.
6+
7+
import glob
8+
import importlib.resources
9+
import os
10+
import shutil
11+
from pathlib import Path
12+
13+
from benchmark_decoders_library import (
14+
generate_videos,
15+
plot_data,
16+
run_benchmarks,
17+
TorchAudioDecoder,
18+
TorchcodecNonCompiledWithOptions,
19+
TVNewAPIDecoderWithBackend,
20+
)
21+
22+
23+
def in_fbcode() -> bool:
24+
return "FB_PAR_RUNTIME_FILES" in os.environ
25+
26+
27+
def get_test_resource_path(filename: str) -> str:
28+
if in_fbcode():
29+
resource = importlib.resources.files(__package__).joinpath(filename)
30+
with importlib.resources.as_file(resource) as path:
31+
return os.fspath(path)
32+
33+
return str(Path(__file__).parent / f"../../test/resources/{filename}")
34+
35+
36+
def main() -> None:
37+
"""Benchmarks the performance of a few video decoders on synthetic videos"""
38+
39+
resolutions = ["640x480"]
40+
encodings = ["libx264"]
41+
fpses = [30]
42+
gop_sizes = [600]
43+
durations = [10]
44+
pix_fmts = ["yuv420p"]
45+
ffmpeg_path = "/usr/local/bin/ffmpeg"
46+
videos_path = "/tmp/videos"
47+
shutil.rmtree(videos_path)
48+
os.makedirs(videos_path)
49+
generate_videos(
50+
resolutions,
51+
encodings,
52+
fpses,
53+
gop_sizes,
54+
durations,
55+
pix_fmts,
56+
ffmpeg_path,
57+
videos_path,
58+
)
59+
video_paths = glob.glob(f"{videos_path}/*.mp4")
60+
61+
decoder_dict = {}
62+
decoder_dict["TorchCodec"] = TorchcodecNonCompiledWithOptions()
63+
decoder_dict["TorchCodec[num_threads=1]"] = TorchcodecNonCompiledWithOptions(
64+
num_threads=1
65+
)
66+
decoder_dict["TorchVision[backend=VideoReader]"] = TVNewAPIDecoderWithBackend(
67+
"video_reader"
68+
)
69+
decoder_dict["TorchAudio"] = TorchAudioDecoder()
70+
71+
output_png = Path(__file__).parent / "benchmark_readme_chart.png"
72+
# These are the number of uniform seeks we do in the seek+decode benchmark.
73+
num_uniform_samples = 10
74+
df_data = run_benchmarks(
75+
decoder_dict,
76+
video_paths,
77+
num_uniform_samples,
78+
10,
79+
False,
80+
)
81+
plot_data(df_data, output_png)
82+
83+
84+
if __name__ == "__main__":
85+
main()

0 commit comments

Comments
 (0)