Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sbatch options #18

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from
Draft
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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Maven projects
/computation-mpi/target/
/computation-slurm/target/
/computation-slurm-tests/target/
/computation-slurm-test/target/
/distribution-hpc/target/
/target

Expand Down

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion computation-slurm-test/src/test/resources/myapps/myecho.sh
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
#!/bin/sh
echo $1 > $2
if [ $1 = "oddIn3" ]; then
echoooo
else
echo $1 > $2
fi
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,16 @@ static String commandToString(String program, Collection<String> args) {
requireNonNull(program);
requireNonNull(args);

String argStr = args.stream().collect(getWrapperAndJoiner());
return program + " " + argStr;
return program + " " + commandArgsToString(args);
}

/**
* Generates a command's argu string, with each argument wrapped with quotes.
* @param args
* @return the argu's string
*/
static String commandArgsToString(Collection<String> args) {
requireNonNull(args);
return args.stream().collect(getWrapperAndJoiner());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public void run() {
commandRunner.execute("rm " + flagDir + "/" + line);
// cancel following jobs(which depends on this job) if there are errors
if (line.startsWith("myerror_")) {
taskStore.getCompletableFuture(workingDirName).cancel(true);
taskStore.getCompletableFuture(workingDirName).cancelBySlurm(new SlurmException("An error job found"));
} else if (line.startsWith("mydone_")) {
String id = line.substring(lastIdx + 1);
taskStore.untracing(Long.parseLong(id));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,129 +6,142 @@
*/
package com.powsybl.computation.slurm;

import com.google.common.base.Preconditions;

import javax.annotation.Nullable;
import java.nio.file.Path;
import java.util.*;
import java.util.stream.Collectors;

/**
* Builds an {@link SbatchCmd}, used to submit script execution to Slurm.
* This class contains two map and one set for three types of arguments in sbatch.
* @see <a href="https://slurm.schedmd.com/sbatch.html">Sbatch</a>
*
* @author Yichen Tang <yichen.tang at rte-france.com>
*/
class SbatchCmdBuilder {
class SbatchArguments {

private static final String DATETIME_FORMATTER = "`date -d \"%d seconds\" \"+%%Y-%%m-%%dT%%H:%%M:%%S\"`";
private static final String PRECEDENT = "#SBATCH ";
private static final String DENPENDENCY_OPT = "dependency";

private final Map<String, String> sbatchArgsByName = new HashMap<>();
private final Map<Character, String> sbatchArgsByCharacter = new HashMap<>();
private final TreeSet<String> sbatchOptions = new TreeSet<>();
private String script;

SbatchCmdBuilder jobName(String jobName) {
SbatchArguments() {
killOnInvalidDep();
}

SbatchArguments jobName(String jobName) {
sbatchArgsByName.put("job-name", jobName);
return this;
}

SbatchCmdBuilder array(int i) {
if (i < 0) {
/**
*
* @param i if equals 1, --array would not be set. If negative, exception would be thrown.
* @return this builder
*/
SbatchArguments array(int i) {
if (i <= 0) {
throw new IllegalArgumentException(i + " is not validate for array.");
}
if (i == 1) {
sbatchArgsByName.put("array", Integer.toString(0));
}
if (i != 1) {
if (i > 1) {
sbatchArgsByName.put("array", "0-" + (i - 1));
}
return this;
}

SbatchCmdBuilder aftercorr(List<Long> jobIds) {
SbatchArguments aftercorr(List<Long> jobIds) {
Objects.requireNonNull(jobIds);
if (!jobIds.isEmpty()) {
String coll = jobIds.stream().map(Object::toString).collect(Collectors.joining(":", "aftercorr:", ""));
sbatchArgsByName.put("dependency", coll);
sbatchArgsByName.put(DENPENDENCY_OPT, coll);
}
return this;
}

SbatchCmdBuilder nodes(int i) {
SbatchArguments aftercorr(@Nullable Long preMasterJob) {
if (preMasterJob != null) {
sbatchArgsByName.put(DENPENDENCY_OPT, "aftercorr:" + preMasterJob);
}
return this;
}

SbatchArguments afternotok(Long lastMasterJob) {
if (lastMasterJob != null) {
sbatchArgsByName.put(DENPENDENCY_OPT, "afternotok:" + lastMasterJob);
}
return this;
}

SbatchArguments nodes(int i) {
if (i < 1) {
throw new IllegalArgumentException(i + " is not validate for nodes.");
}
sbatchArgsByName.put("nodes", Integer.toString(i));
return this;
}

SbatchCmdBuilder ntasks(int i) {
SbatchArguments ntasks(int i) {
if (i < 1) {
throw new IllegalArgumentException(i + " is not validate for ntasks.");
}
sbatchArgsByName.put("ntasks", Integer.toString(i));
return this;
}

SbatchCmdBuilder tasksPerNode(int i) {
SbatchArguments tasksPerNode(int i) {
if (i < 1) {
throw new IllegalArgumentException(i + " is not validate for tasksPerNode.");
}
sbatchArgsByName.put("ntasks-per-node", Integer.toString(i));
return this;
}

SbatchCmdBuilder cpusPerTask(int i) {
SbatchArguments cpusPerTask(int i) {
sbatchArgsByName.put("cpus-per-task", Integer.toString(i));
return this;
}

SbatchCmdBuilder error(String pattern) {
// TODO test
SbatchArguments error(String pattern) {
Objects.requireNonNull(pattern);
sbatchArgsByName.put("error", pattern);
return this;
}

SbatchCmdBuilder output(String pattern) {
SbatchArguments output(String pattern) {
Objects.requireNonNull(pattern);
sbatchArgsByName.put("output", pattern);
return this;
}

SbatchCmdBuilder partition(String partition) {
SbatchArguments partition(String partition) {
Objects.requireNonNull(partition);
sbatchArgsByName.put("partition", partition);
return this;
}

SbatchCmdBuilder oversubscribe() {
SbatchArguments oversubscribe() {
sbatchOptions.add("oversubscribe");
return this;
}

SbatchCmdBuilder script(String name) {
this.script = Objects.requireNonNull(name);
private SbatchArguments killOnInvalidDep() {
sbatchArgsByName.put("kill-on-invalid-dep", "yes");
return this;
}

SbatchCmdBuilder workDir(Path dir) {
SbatchArguments workDir(Path dir) {
Objects.requireNonNull(dir);
sbatchArgsByCharacter.put('D', dir.toAbsolutePath().toString());
return this;
}

SbatchCmdBuilder timeout(@Nullable String duration) {
SbatchArguments timeout(@Nullable String duration) {
sbatchArgsByName.put("time", checkTimeout(duration));
return this;
}

SbatchCmdBuilder deadline(long seconds) {
Preconditions.checkArgument(seconds > 0, "Invalid seconds({}) for deadline: must be 1 or greater", seconds);
sbatchArgsByName.put("deadline", String.format(DATETIME_FORMATTER, seconds));
return this;
}

private static String checkTimeout(@Nullable String duration) {
if (duration == null) {
return "UNLIMITED";
Expand All @@ -137,20 +150,18 @@ private static String checkTimeout(@Nullable String duration) {
return duration;
}

SbatchCmdBuilder qos(String qos) {
SbatchArguments qos(String qos) {
Objects.requireNonNull(qos);
sbatchArgsByName.put("qos", qos);
return this;
}

SbatchCmd build() {
validate();
return new SbatchCmd(sbatchArgsByName, sbatchArgsByCharacter, sbatchOptions, script);
List<String> toScript() {
List<String> list = new ArrayList<>();
sbatchArgsByCharacter.forEach((k, v) -> list.add(PRECEDENT + "-" + k + " " + v));
sbatchArgsByName.forEach((k, v) -> list.add(PRECEDENT + "--" + k + "=" + v));
sbatchOptions.forEach(o -> list.add(PRECEDENT + "--" + o));
return list;
}

private void validate() {
if (null == script) {
throw new SlurmException("Script is null in cmd");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,34 @@
*/
package com.powsybl.computation.slurm;

import java.util.Map;
import com.google.common.base.Preconditions;

import java.util.Objects;
import java.util.TreeSet;

/**
* A submission command to Slurm: sbatch options scriptName.
* A submission command to Slurm: sbatch [--deadline] scriptName.
*
* Sbatch scripts will be submitted using that kind of command.
*
* @author Yichen Tang <yichen.tang at rte-france.com>
*/
class SbatchCmd extends AbstractSlurmCmd<SbatchCmdResult> {

private static final String SBATCH = "sbatch";

private final Map<String, String> argsByName;
private final Map<Character, String> argsByChar;

private final TreeSet<String> options;
private static final String SBATCH = "sbatch ";
private static final String DATETIME_FORMATTER = "--deadline=`date -d \"%d seconds\" \"+%%Y-%%m-%%dT%%H:%%M:%%S\"` ";

private final String scriptName;

private String cmd;
private long deadLine = 0;

SbatchCmd(Map<String, String> argsByName, Map<Character, String> argsByChar, TreeSet<String> options, String scriptName) {
this.argsByName = Objects.requireNonNull(argsByName);
this.argsByChar = Objects.requireNonNull(argsByChar);
SbatchCmd(String scriptName) {
this.scriptName = Objects.requireNonNull(scriptName);
this.options = Objects.requireNonNull(options);
}

SbatchCmd deadLine(long seconds) {
Preconditions.checkArgument(seconds > 0, "Invalid seconds({}) for deadline: must be 1 or greater", seconds);
deadLine = seconds;
return this;
}

SbatchCmdResult send(CommandExecutor commandExecutor) throws SlurmCmdNonZeroException {
Expand All @@ -44,24 +43,10 @@ SbatchCmdResult send(CommandExecutor commandExecutor) throws SlurmCmdNonZeroExce

@Override
public String toString() {
if (cmd == null) {
StringBuilder sb = new StringBuilder();
sb.append(SBATCH);
argsByChar.forEach((c, v) -> {
sb.append(" -").append(c);
sb.append(" ").append(v);
});
argsByName.forEach((k, v) -> {
sb.append(" --").append(k);
sb.append("=").append(v);
});
options.forEach(opt -> {
sb.append(" --");
sb.append(opt);
});
sb.append(" ").append(scriptName);
cmd = sb.toString();
StringBuilder sb = new StringBuilder().append(SBATCH);
if (deadLine > 0) {
sb.append(String.format(DATETIME_FORMATTER, deadLine));
}
return cmd;
return sb.append(scriptName).toString();
}
}
Loading