Skip to content

Commit

Permalink
Multiple nvidia GPU support and ffmpeg error catching (#6)
Browse files Browse the repository at this point in the history
* Multiple nvidia GPU support and ffmpeg error catching
  • Loading branch information
Proryanator authored Feb 23, 2023
1 parent 702292d commit b5b4cb7
Show file tree
Hide file tree
Showing 15 changed files with 284 additions and 18 deletions.
129 changes: 128 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ members = [
"ffmpeg",
"permutation",
"permutor-cli",
"cli"
"cli",
"gpus"
]
17 changes: 16 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ resolutions and framerates).
A nice cross-platform tool to test your SSD's sequential read speeds: <a href='https://www.jazzdiskbench.com/'>Jazz Disk
Bench</a>

Note: the tool _does_ support selecting a specific GPU in your system if you have more than one, but you may experience
PCI bottlenecking for GPU's not in the primary slot.

### Important notes about your system

- do make sure your SSD drive in Windows does _not_ have drive compression enabled. This can severely affect your
Expand Down Expand Up @@ -88,7 +91,8 @@ Assuming you have followed the [Installation Setup Requirements](#installation--
benchmark is as simple as:

1) Opening the **benchmark** executable as you would any other program (double-click)
2) Follow the on-screen instructions: select your encoder, and whether to run it on all resolutions or just a specific
2) Follow the on-screen instructions: select your GPU (if you have more than 1, otherwise it auto-selects your only
card), select your encoder, and whether to run it on all resolutions or just a specific
one
3) Wait for the benchmark to finish, which should not take that long

Expand Down Expand Up @@ -195,6 +199,17 @@ stop permuting once it gets to `50Mb/s` because we know that's the point where y
H264_NVENC, and any higher amount of bitrate does not significantly improve quality and can actually reduce encoder
performance.

### Running on a specific GPU in a multi-GPU system

By default, the **permutor-cli** tool will run against the first GPU in your system that it sees.

Much like how the benchmark tool allows for you to select what GPU to run on, the **permutor-cli** tool does this as
well.
With this tool it's as simple as providing the `-gpu 0` option, where 0 in this case would run against your first GPU.

Note: if you are not sure which GPU is considered in the first slot, open the **benchmark** and it'll list the order of
your cards for you.

## Applying your Findings

If you have not heard of the game streaming tools Moonlight or Sunshine mentioned below, a quick
Expand Down
3 changes: 2 additions & 1 deletion benchmark/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ environment = { path = "../environment" }
permutation = { path = "../permutation" }
engine = { path = "../engine" }
ffmpeg = { path = "../ffmpeg" }
cli = { path = "../cli" }
cli = { path = "../cli" }
gpus = { path = "../gpus" }
4 changes: 4 additions & 0 deletions benchmark/src/benchmark_cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ pub struct BenchmarkCli {
/// logs useful information to help troubleshooting
#[arg(short, long)]
pub verbose: bool,
/// the GPU you wish to run the encode on; defaults to the first/only GPU found in your system
#[arg(short, long, default_value = "0")]
pub gpu: u8,
was_ui_opened: bool,
}

Expand All @@ -32,6 +35,7 @@ impl BenchmarkCli {
encoder: String::from(""),
source_file: String::from(""),
verbose: false,
gpu: 0,
was_ui_opened: false,
};
}
Expand Down
35 changes: 32 additions & 3 deletions benchmark/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use engine::benchmark_engine::BenchmarkEngine;
use engine::h264_hevc_nvenc::Nvenc;
use engine::permute::Permute;
use ffmpeg::metadata::MetaData;
use gpus::get_gpus;
use permutation::permutation::Permutation;

use crate::benchmark_cli::BenchmarkCli;
Expand All @@ -24,11 +25,15 @@ fn main() {
fig_title(String::from("Encoder-Benchmark"), String::from(small_font));
let mut cli = BenchmarkCli::new();

// check how many Nvidia GPU's there are
// eventually will add support for checking AMD/Intel GPU's too
let gpus = get_gpus();

// if no args were provided, they will be prompted from the user
// this works for both cli running as well as just clicking the executable
let args: Vec<String> = env::args().collect();
if args.len() == 1 {
read_user_input(&mut cli);
read_user_input(&mut cli, gpus);
cli.set_ui_opened();
} else {
cli = BenchmarkCli::parse();
Expand All @@ -38,7 +43,7 @@ fn main() {

let input_files = get_input_files(cli.source_file);
let mut engine = BenchmarkEngine::new();
let nvenc = Nvenc::new(cli.encoder == "hevc_nvenc");
let nvenc = Nvenc::new(cli.encoder == "hevc_nvenc", cli.gpu);

// prepare permutations for the engine to run over
for input in input_files {
Expand All @@ -55,7 +60,31 @@ fn main() {
pause();
}

fn read_user_input(cli: &mut BenchmarkCli) {
fn read_user_input(cli: &mut BenchmarkCli, gpus: Vec<String>) {
// if more than 1 GPU is identified, ask for the user to choose which one
if gpus.len() > 1 {
loop {
let str_vec = gpus.iter().map(|s| &**s).collect();
print_options(str_vec);
print!("Choose GPU [0-{}]: ", gpus.len() - 1);
let input: String = read!("{}");

if !is_numeric(&input) {
println!("Invalid input, try again...")
} else {
let value: u8 = input.parse().unwrap();

if value as usize >= gpus.len() {
println!("Invalid input, try again...");
} else {
cli.gpu = value;
println!();
break;
}
}
}
}

loop {
print_options(get_supported_encoders().to_vec());
print!("Choose encoder [0-{}]: ", get_supported_encoders().len() - 1);
Expand Down
3 changes: 2 additions & 1 deletion engine/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ ctrlc = "3.2.4"
indicatif = "0.17.2"
stoppable_thread = "0.2.1"
permutation = { path = "../permutation" }
ffmpeg = { path = "../ffmpeg" }
ffmpeg = { path = "../ffmpeg" }
cli = { path = "../cli" }
12 changes: 11 additions & 1 deletion engine/src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use compound_duration::format_dhms;
use crossbeam_channel::Receiver;
use ctrlc::Error;

use cli::cli_util::error_with_ack;
use ffmpeg::args::FfmpegArgs;
use ffmpeg::metadata::MetaData;
use permutation::permutation::Permutation;
Expand All @@ -27,6 +28,12 @@ pub fn run_encode(mut p: Permutation, ctrl_channel: &Result<Receiver<()>, Error>
// not sure what to do about these results here
let mut trial_result = run_overload_benchmark(&metadata, &ffmpeg_args, p.verbose, p.detect_overload, &ctrl_channel);

// this should be a hard-stop for the program here
// perhaps abstract this method out
if trial_result.ffmpeg_error {
error_with_ack(true);
}

result.was_overloaded = trial_result.was_overloaded;
result.encode_time = encode_start_time.elapsed().unwrap().as_secs();

Expand Down Expand Up @@ -83,7 +90,10 @@ fn run_overload_benchmark(metadata: &MetaData, ffmpeg_args: &FfmpegArgs, verbose

let trial_result = progressbar::watch_encode_progress(metadata.frames, detect_overload, metadata.fps, verbose, ffmpeg_args.stats_period, ctrl_channel);

if trial_result.was_overloaded && !was_ctrl_c_received(&ctrl_channel) {
if trial_result.ffmpeg_error && !was_ctrl_c_received(&ctrl_channel) {
let _ = child.kill();
println!("Ffmpeg encountered an error when attempting to run, double-check that your environment is setup correctly. If so, open an issue in github!");
} else if trial_result.was_overloaded && !was_ctrl_c_received(&ctrl_channel) {
let _ = child.kill();
println!("Encoder was overloaded and could not encode the video file in realtime, stopping...");
}
Expand Down
Loading

0 comments on commit b5b4cb7

Please sign in to comment.