Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions doc/src/release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ The subcommands `show directories`, `show jobs`, and `show status` now report

* Writing tabular output with no rows now results in the output `No matches.`.
* Build executables on Ubuntu 22.04.
* Report an error when the workflow requests 0 processes, GPUs, or threads.

## 0.4.0 (2024-12-06)

Expand Down
14 changes: 7 additions & 7 deletions doc/src/workflow/action/resources.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,16 @@ When omitted, `processes` defaults to `per_submission = 1`.

## threads_per_process

`action.resources.threads_per_process`: **integer** - The number of CPU threads your
action utilizes per process. When omitted, **row** does not make any specific request
for threads from the scheduler. Most schedulers default to 1 thread per process in this
case.
`action.resources.threads_per_process`: **positive integer** - The number of CPU threads
your action utilizes per process. When omitted, **row** does not make any specific
request for threads from the scheduler. Most schedulers default to 1 thread per process
in this case.

## gpus_per_process

`action.resources.gpus_per_process`: **integer** - The number of GPUs your action
utilizes per process. When omitted, **row** does not make any specific request for GPUs
from the scheduler. Most schedulers default to 0 GPUs per process in this case.
`action.resources.gpus_per_process`: **positive integer** - The number of GPUs your
action utilizes per process. When omitted, **row** does not make any specific request
for GPUs from the scheduler. Most schedulers default to 0 GPUs per process in this case.

## walltime

Expand Down
14 changes: 11 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,6 @@ pub enum Error {
#[error("Previous action '{0}' not found in action '{1}'.")]
PreviousActionNotFound(String, String),

#[error("Define 'processes' or 'processes_per_directory', not both in action '{0}'.")]
DuplicateProcesses(String),

#[error("Use '{{directory}}' or '{{directories}}', not both in the command of action '{0}'.")]
ActionContainsMultipleTemplates(String),

Expand Down Expand Up @@ -148,6 +145,17 @@ pub enum Error {
#[error("Unable to parse template '{1}' for action '{0}'.")]
InvalidTemplate(String, String),

#[error("Action '{0}' must request more than 0 processes or omit `resources.processes`.")]
ZeroProcesses(String),

#[error(
"Action '{0}' must request more than 0 threads or omit `resources.threads_per_process`."
)]
ZeroThreads(String),

#[error("Action '{0}' must request more than 0 GPUs or omit `resources.gpus_per_process`.")]
ZeroGpus(String),

// submission errors
#[error("Error encountered while executing action '{0}': {1}.")]
ExecuteAction(String, String),
Expand Down
114 changes: 114 additions & 0 deletions src/workflow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,24 @@ impl Workflow {
warn!("The JSON pointer '{pointer}' does not appear valid. Did you mean '/{pointer}'?");
}
}

// Users must request more than 0 resources, or omit the relevant key to request none.
if matches!(action.resources.processes, Some(Processes::PerDirectory(0)))
|| matches!(
action.resources.processes,
Some(Processes::PerSubmission(0))
)
{
return Err(Error::ZeroProcesses(action.name().into()));
}

if action.resources.threads_per_process == Some(0) {
return Err(Error::ZeroThreads(action.name().into()));
}

if action.resources.gpus_per_process == Some(0) {
return Err(Error::ZeroGpus(action.name().into()));
}
}

for action in &self.action {
Expand Down Expand Up @@ -1187,6 +1205,102 @@ processes.per_directory = 2
);
}

#[test]
#[parallel]
fn zero_processes_submission() {
let temp = TempDir::new().unwrap();
let workflow = r#"
[[action]]
name = "b"
command = "c"
[action.resources]
processes.per_submission = 0
"#;
let result = Workflow::open_str(temp.path(), workflow);
assert!(
matches!(result, Err(Error::ZeroProcesses(..))),
"Expected zero processes error, but got {result:?}"
);

let err = result.unwrap_err().to_string();
assert!(
err.contains("must request more than 0 processes"),
"Expected 'must request more than 0 processes', got {err:?}"
);
}

#[test]
#[parallel]
fn zero_processes_directory() {
let temp = TempDir::new().unwrap();
let workflow = r#"
[[action]]
name = "b"
command = "c"
[action.resources]
processes.per_directory = 0
"#;
let result = Workflow::open_str(temp.path(), workflow);
assert!(
matches!(result, Err(Error::ZeroProcesses(..))),
"Expected zero processes error, but got {result:?}"
);

let err = result.unwrap_err().to_string();
assert!(
err.contains("must request more than 0 processes"),
"Expected 'must request more than 0 processes', got {err:?}"
);
}

#[test]
#[parallel]
fn zero_threads() {
let temp = TempDir::new().unwrap();
let workflow = r#"
[[action]]
name = "b"
command = "c"
[action.resources]
threads_per_process = 0
"#;
let result = Workflow::open_str(temp.path(), workflow);
assert!(
matches!(result, Err(Error::ZeroThreads(..))),
"Expected zero threads error, but got {result:?}"
);

let err = result.unwrap_err().to_string();
assert!(
err.contains("must request more than 0 threads"),
"Expected 'must request more than 0 threads', got {err:?}"
);
}

#[test]
#[parallel]
fn zero_gpus() {
let temp = TempDir::new().unwrap();
let workflow = r#"
[[action]]
name = "b"
command = "c"
[action.resources]
gpus_per_process = 0
"#;
let result = Workflow::open_str(temp.path(), workflow);
assert!(
matches!(result, Err(Error::ZeroGpus(..))),
"Expected zero GPUs error, but got {result:?}"
);

let err = result.unwrap_err().to_string();
assert!(
err.contains("must request more than 0 GPUs"),
"Expected 'must request more than 0 GPUs', got {err:?}"
);
}

#[test]
#[parallel]
fn walltime_duplicate() {
Expand Down