WIP stage redesign

This commit is contained in:
Rodrigo Arias 2020-10-09 15:55:37 +02:00
parent 654e243735
commit a576be8031
14 changed files with 378 additions and 82 deletions

View File

@ -0,0 +1,74 @@
{
stdenv
, nixpkgs
, pkgs
, stages
, machineConf
}:
with stdenv.lib;
let
bsc = pkgs.bsc;
w = runWrappers;
in
{
/* Returns the path of the executable of a stage */
stageProgram = stage:
if stage ? programPath
then "${stage}${stage.programPath}"
else "${stage}";
/* Takes a list of units and builds an experiment, after executing the
trebuchet and the isolate stages. Returns the trebuchet stage. */
buildExperiment = {units, conf, ...}: stage.trebuchet {
inherit (machineConf) nixPrefix;
nextStage = stage.isolate {
inherit (machineConf) nixPrefix;
nextStage = stage.experiment {
inherit units;
}
}
};
sbatch = {nextStage, conf, ...}: with conf; w.sbatch (
# Allow a user to define a custom reservation for the job in MareNostrum4,
# by setting the garlic.sbatch.reservation attribute in the
# ~/.config/nixpkgs/config.nix file. If the attribute is not set, no
# reservation is used. The user reservation may be overwritten by the
# experiment, if the reservation is set like with nodes or ntasksPerNode.
optionalAttrs (pkgs.config ? garlic.sbatch.reservation) {
inherit (pkgs.config.garlic.sbatch) reservation;
} // {
exclusive = true;
time = "02:00:00";
qos = "debug";
jobName = "nbody-tampi";
inherit nextStage nixPrefix nodes ntasksPerNode;
}
);
control = {nextStage, conf, ...}: stages.control {
inherit (conf) loops;
inherit nextStage;
};
srun = {nextStage, conf, ...}: stages.srun {
inherit (conf) nixPrefix cpuBind;
inherit nextStage;
};
isolate = {nextStage, conf, ...}: stages.isolate {
clusterName = machineConf.name;
inherit (conf) nixPrefix;
inherit nextStage;
};
stdStages = [
sbatch
isolate
control
srun
isolate
];
}

75
garlic/exp/nbody/test.nix Normal file
View File

@ -0,0 +1,75 @@
{
stdenv
, stdexp
, pkgs
, targetMachine
, stages
}:
with stdenv.lib;
let
bsc = pkgs.bsc;
# Configurations for each unit (using the cartesian product)
confUnit = with bsc; {
blocksize = [ 1024 2048 ];
};
# Configuration for the complete experiment
confExperiment = with bsc; {
# nbody options
particles = 1024 * 4;
timesteps = 10;
cc = icc;
mpi = impi;
gitBranch = "garlic/mpi+send";
# Repeat the execution of each unit 30 times
loops = 30;
# Resources
ntasksPerNode = 2;
nodes = 1;
cpuBind = "sockets,verbose";
};
confMachine = targetMachine.config;
# Compute the array of configurations
configs = stdexp.buildConfigs {
var = confUnit;
fixed = confMachine // confExperiment;
};
exec = {nextStage, conf, ...}: with conf; stages.exec {
inherit nextStage;
argv = [ "-t" timesteps "-p" particles ];
env = "";
};
# We may be able to use overlays by invoking the fix function directly, but we
# have to get the definition of the bsc packages and the garlic ones as
# overlays.
program = {nextStage, conf, ...}: with conf;
let
# We set the mpi implementation to the one specified in the conf, so all
# packages in bsc will use that one.
customPkgs = stdexp.genPkgs (self: super: {
bsc = super.bsc // { mpi = conf.mpi; };
});
in
customPkgs.garlic.nbody.override {
inherit cc blocksize mpi gitBranch;
};
# Generate the experimental units
units = map (c: stages.unit {
conf = c;
stages = stdexp.stdStages ++ [ exec program ];
}) configs;
in
elemAt units 0
#buildExperiment units

84
garlic/exp/stdexp.nix Normal file
View File

@ -0,0 +1,84 @@
{
stdenv
, config
, stages
, targetMachine
, garlicTools
}:
with stdenv.lib;
with garlicTools;
let
machineConf = targetMachine.config;
in
rec {
/* Takes a list of units and builds an experiment, after executing the
trebuchet and the isolate stages. Returns the trebuchet stage. */
buildExperiment = {units, conf, ...}: stage.trebuchet {
inherit (machineConf) nixPrefix;
nextStage = stage.isolate {
inherit (machineConf) nixPrefix;
nextStage = stage.experiment {
inherit units;
};
};
};
/* Given an attrset of lists `var` and an attrset `fixed`, computes the
cartesian product of all combinations of `var` and prepends `fixed`
to each. */
buildConfigs = {fixed, var}:
map (c: fixed // c) (genConfigs var);
sbatch = {nextStage, conf, ...}: with conf; stages.sbatch (
# Allow a user to define a custom reservation for the job in MareNostrum4,
# by setting the garlic.sbatch.reservation attribute in the
# ~/.config/nixpkgs/config.nix file. If the attribute is not set, no
# reservation is used. The user reservation may be overwritten by the
# experiment, if the reservation is set like with nodes or ntasksPerNode.
optionalAttrs (config ? garlic.sbatch.reservation) {
inherit (config.garlic.sbatch) reservation;
} // {
exclusive = true;
time = "02:00:00";
qos = "debug";
jobName = "nbody-tampi";
inherit nextStage nixPrefix nodes ntasksPerNode;
}
);
control = {nextStage, conf, ...}: stages.control {
inherit (conf) loops;
inherit nextStage;
};
srun = {nextStage, conf, ...}: stages.srun {
inherit (conf) nixPrefix cpuBind;
inherit nextStage;
};
isolate = {nextStage, conf, ...}: stages.isolate {
clusterName = machineConf.name;
inherit (conf) nixPrefix;
inherit nextStage;
};
stdStages = [
sbatch
isolate
control
srun
isolate
];
# FIXME: Remove this hack and allow custom nixpkgs
bscOverlay = import ../../overlay.nix;
nixpkgs = import <nixpkgs>;
genPkgs = newOverlay: nixpkgs {
overlays = [
bscOverlay
newOverlay
];
};
}

17
garlic/machines.nix Normal file
View File

@ -0,0 +1,17 @@
{
stdenv
}:
{
# MareNostrum 4 configuration
mn4 = {
config = {
name = "mn4";
nixPrefix = "/gpfs/projects/bsc15/nix";
cachelineBytes = 64;
march = "skylake-avx512";
mtune = "skylake-avx512";
};
# TODO: Add the specific details for SLURM and the interconection here
};
}

View File

@ -1,30 +0,0 @@
{
stdenv
, bash
}:
{
program
, env ? ""
# bash array as string, example: argv=''(-f "file with spaces" -t 10)''
, argv ? "()"
}:
stdenv.mkDerivation {
name = "argv";
preferLocalBuild = true;
phases = [ "installPhase" ];
installPhase = ''
cat > $out <<EOF
#!${bash}/bin/bash --norc
# Requires /nix to use bash
${env}
argv=${argv}
exec ${program} \''${argv[@]}
EOF
chmod +x $out
'';
}

View File

@ -1,12 +1,15 @@
{ {
stdenv stdenv
, garlicTools
}: }:
{ {
program nextStage
, loops ? 30 , loops ? 30
}: }:
with garlicTools;
stdenv.mkDerivation { stdenv.mkDerivation {
name = "control"; name = "control";
preferLocalBuild = true; preferLocalBuild = true;
@ -16,7 +19,7 @@ stdenv.mkDerivation {
cat > $out <<EOF cat > $out <<EOF
#!/bin/sh #!/bin/sh
for n in \$(seq 1 ${toString loops}); do for n in \$(seq 1 ${toString loops}); do
${program} ${stageProgram nextStage}
done done
EOF EOF
chmod +x $out chmod +x $out

31
garlic/stages/exec.nix Normal file
View File

@ -0,0 +1,31 @@
{
stdenv
, garlicTools
}:
{
nextStage
, env ? ""
, argv ? []
}:
with builtins;
with garlicTools;
let
argvString = concatStringsSep " " (map (e: toString e) argv);
in
stdenv.mkDerivation {
name = "exec";
preferLocalBuild = true;
phases = [ "installPhase" ];
installPhase = ''
cat > $out <<EOF
#!/bin/sh
${env}
exec ${stageProgram nextStage} ${argvString}
EOF
chmod +x $out
'';
}

View File

@ -1,9 +1,10 @@
{ {
stdenv stdenv
, nixPrefix ? ""
}: }:
{
units: units:
}
with stdenv.lib; with stdenv.lib;

View File

@ -3,15 +3,17 @@
, nixtools , nixtools
, busybox , busybox
, strace , strace
, garlicTools
}: }:
{ {
program nextStage
, stage
, nixPrefix , nixPrefix
, clusterName , clusterName
}: }:
with garlicTools;
stdenv.mkDerivation { stdenv.mkDerivation {
name = "isolate"; name = "isolate";
preferLocalBuild = true; preferLocalBuild = true;
@ -23,8 +25,9 @@ stdenv.mkDerivation {
src = ./.; src = ./.;
dontPatchShebangs = true; dontPatchShebangs = true;
programPath = "/bin/stage1"; programPath = "/bin/stage1";
inherit program nixPrefix clusterName nixtools busybox; inherit nixPrefix clusterName nixtools busybox;
desc = "# $out\n" + (if builtins.hasAttr "desc" stage then stage.desc else ""); program = stageProgram nextStage;
desc = "# $out\n" + (if builtins.hasAttr "desc" nextStage then nextStage.desc else "");
out = "$out"; out = "$out";
installPhase = '' installPhase = ''

View File

@ -2,10 +2,11 @@
stdenv stdenv
, numactl , numactl
, slurm , slurm
, garlicTools
}: }:
{ {
program nextStage
, jobName , jobName
, chdirPrefix ? "." , chdirPrefix ? "."
, nixPrefix ? "" , nixPrefix ? ""
@ -26,6 +27,8 @@
}: }:
with stdenv.lib; with stdenv.lib;
with garlicTools;
let let
sbatchOpt = name: value: optionalString (value!=null) sbatchOpt = name: value: optionalString (value!=null)
@ -69,7 +72,7 @@ stdenv.mkDerivation rec {
+ optionalString (extra!=null) extra + optionalString (extra!=null) extra
+ +
'' ''
exec ${nixPrefix}${program} exec ${nixPrefix}${stageProgram nextStage}
EOF EOF
cat > $out/${name} <<EOF cat > $out/${name} <<EOF

View File

@ -1,23 +1,30 @@
{ {
stdenv stdenv
, slurm , slurm
, garlicTools
}: }:
{ {
program nextStage
, nixPrefix ? "" , cpuBind
, nixPrefix
, srunOptions ? "" , srunOptions ? ""
}: }:
with garlicTools;
stdenv.mkDerivation rec { stdenv.mkDerivation rec {
name = "srun"; name = "srun";
preferLocalBuild = true;
phases = [ "installPhase" ]; phases = [ "installPhase" ];
preferLocalBuild = true;
dontPatchShebangs = true; dontPatchShebangs = true;
installPhase = '' installPhase = ''
cat > $out <<EOF cat > $out <<EOF
#!/bin/sh -ex #!/bin/sh -ex
exec ${slurm}/bin/srun --mpi=pmi2 ${srunOptions} \ exec ${slurm}/bin/srun \
${nixPrefix}${program} --mpi=pmi2 \
--cpu-bind=${cpuBind} \
${srunOptions} \
${nixPrefix}${stageProgram nextStage}
EOF EOF
chmod +x $out chmod +x $out
''; '';

View File

@ -14,8 +14,8 @@ let
dStages = foldr (stageFn: {conf, prevStage, stages}: { dStages = foldr (stageFn: {conf, prevStage, stages}: {
conf = conf; conf = conf;
prevStage = stageFn {stage=prevStage; conf=conf;}; prevStage = stageFn {nextStage=prevStage; conf=conf;};
stages = [ (stageFn {stage=prevStage; conf=conf;}) ] ++ stages; stages = [ (stageFn {nextStage=prevStage; conf=conf;}) ] ++ stages;
}) })
{conf=conf; stages=[]; prevStage=null;} stages; {conf=conf; stages=[]; prevStage=null;} stages;

View File

@ -1,6 +1,10 @@
let {
lib = import <nixpkgs/lib>; stdenv
}:
with stdenv.lib;
let
gen = rec { gen = rec {
# genAttrSets "a" ["hello" "world"] # genAttrSets "a" ["hello" "world"]
# [ { a = "hello"; } { a = "world"; } ] # [ { a = "hello"; } { a = "world"; } ]
@ -16,18 +20,24 @@ let
# mergeConfig [{e=1;}] {name="a"; value=[1 2] # mergeConfig [{e=1;}] {name="a"; value=[1 2]
# [ { a = 1; e = 1; } { a = 2; e = 1; } ] # [ { a = 1; e = 1; } { a = 2; e = 1; } ]
mergeConfig = (arr: new: lib.flatten ( map (x: addAttrSets new.name new.value x) arr)); mergeConfig = (arr: new: flatten ( map (x: addAttrSets new.name new.value x) arr));
# genConfigs {a=[1 2]; b=[3 4];} # genConfigs {a=[1 2]; b=[3 4];}
# [ { a = 1; b = 3; } { a = 1; b = 4; } { a = 2; b = 3; } { a = 2; b = 4; } ] # [ { a = 1; b = 3; } { a = 1; b = 4; } { a = 2; b = 3; } { a = 2; b = 4; } ]
genConfigs = (config: lib.foldl mergeConfig [{}] (attrToList config)); genConfigs = (config: foldl mergeConfig [{}] (attrToList config));
# Generate multiple app versions by override with each config # Generate multiple app versions by override with each config
genApp = (app: configs: map (conf: app.override conf // {conf=conf;}) configs); genApp = (app: configs: map (conf: app.override conf // {conf=conf;}) configs);
# Generate app version from an array of apps # Generate app version from an array of apps
genApps = (apps: configs: genApps = (apps: configs:
lib.flatten (map (app: genApp app configs) apps)); flatten (map (app: genApp app configs) apps));
/* Returns the path of the executable of a stage */
stageProgram = stage:
if stage ? programPath
then "${stage}${stage.programPath}"
else "${stage}";
}; };
in in

View File

@ -140,13 +140,20 @@ let
nixPrefix = "/gpfs/projects/bsc15/nix"; nixPrefix = "/gpfs/projects/bsc15/nix";
}; };
garlicTools = callPackage ./garlic/tools.nix {};
garlic = { garlic = {
# Configuration for the machines
machines = callPackage ./garlic/machines.nix {};
# Use the configuration for the following target machine
targetMachine = self.garlic.machines.mn4;
# Load some helper functions to generate app variants # Load some helper functions to generate app variants
inherit (import ./garlic/gen.nix) genApps genApp genConfigs;
# Override the hardening flags and parallel build by default (TODO) stdexp = callPackage ./garlic/exp/stdexp.nix {
#mkDerivation = callPackage ./garlic/mkDerivation.nix { }; inherit (self.garlic) targetMachine stages;
};
# Apps for Garlic # Apps for Garlic
# heat = callPackage ./garlic/heat { # heat = callPackage ./garlic/heat {
@ -187,18 +194,18 @@ let
gitBranch = "garlic/seq"; gitBranch = "garlic/seq";
}; };
saiph = callPackage ./garlic/saiph { saiph = callPackage ./garlic/saiph/default.nix {
cc = self.bsc.clangOmpss2; cc = self.bsc.clangOmpss2;
}; };
# Execution wrappers # Execution stages
runWrappers = { stages = {
sbatch = callPackage ./garlic/stages/sbatch.nix { }; sbatch = callPackage ./garlic/stages/sbatch.nix { };
srun = callPackage ./garlic/stages/srun.nix { }; srun = callPackage ./garlic/stages/srun.nix { };
launch = callPackage ./garlic/stages/launcher { }; launch = callPackage ./garlic/stages/launcher { };
control = callPackage ./garlic/stages/control.nix { }; control = callPackage ./garlic/stages/control.nix { };
nixsetup = callPackage ./garlic/stages/nix-setup.nix { }; nixsetup = callPackage ./garlic/stages/nix-setup.nix { };
argv = callPackage ./garlic/stages/argv.nix { }; exec = callPackage ./garlic/stages/exec.nix { };
statspy = callPackage ./garlic/stages/statspy.nix { }; statspy = callPackage ./garlic/stages/statspy.nix { };
extrae = callPackage ./garlic/stages/extrae.nix { }; extrae = callPackage ./garlic/stages/extrae.nix { };
stagen = callPackage ./garlic/stages/stagen.nix { }; stagen = callPackage ./garlic/stages/stagen.nix { };
@ -231,7 +238,7 @@ let
nixpkgs = import <nixpkgs>; nixpkgs = import <nixpkgs>;
genApp = self.bsc.garlic.genApp; genApp = self.bsc.garlic.genApp;
genConfigs = self.bsc.garlic.genConfigs; genConfigs = self.bsc.garlic.genConfigs;
runWrappers = self.bsc.garlic.runWrappers; stages = self.bsc.garlic.stages;
}; };
tampi = callPackage ./garlic/exp/nbody/tampi.nix { tampi = callPackage ./garlic/exp/nbody/tampi.nix {
@ -239,7 +246,12 @@ let
nixpkgs = import <nixpkgs>; nixpkgs = import <nixpkgs>;
genApp = self.bsc.garlic.genApp; genApp = self.bsc.garlic.genApp;
genConfigs = self.bsc.garlic.genConfigs; genConfigs = self.bsc.garlic.genConfigs;
runWrappers = self.bsc.garlic.runWrappers; stages = self.bsc.garlic.stages;
};
test = callPackage ./garlic/exp/nbody/test.nix {
pkgs = self // self.bsc.garlic;
inherit (self.garlic) stdexp targetMachine stages;
}; };
# mpi = callPackage ./bsc/garlic/exp/nbody/mpi.nix { }; # mpi = callPackage ./bsc/garlic/exp/nbody/mpi.nix { };
}; };
@ -250,7 +262,7 @@ let
nixpkgs = import <nixpkgs>; nixpkgs = import <nixpkgs>;
genApp = self.bsc.garlic.genApp; genApp = self.bsc.garlic.genApp;
genConfigs = self.bsc.garlic.genConfigs; genConfigs = self.bsc.garlic.genConfigs;
runWrappers = self.bsc.garlic.runWrappers; stages = self.bsc.garlic.stages;
}; };
}; };
@ -261,14 +273,14 @@ let
nixpkgs = import <nixpkgs>; nixpkgs = import <nixpkgs>;
genApp = self.bsc.garlic.genApp; genApp = self.bsc.garlic.genApp;
genConfigs = self.bsc.garlic.genConfigs; genConfigs = self.bsc.garlic.genConfigs;
runWrappers = self.bsc.garlic.runWrappers; stages = self.bsc.garlic.stages;
}; };
hybrid = callPackage ./garlic/exp/creams/ss+hybrid.nix { hybrid = callPackage ./garlic/exp/creams/ss+hybrid.nix {
pkgs = self // self.bsc.garlic; pkgs = self // self.bsc.garlic;
nixpkgs = import <nixpkgs>; nixpkgs = import <nixpkgs>;
genApp = self.bsc.garlic.genApp; genApp = self.bsc.garlic.genApp;
genConfigs = self.bsc.garlic.genConfigs; genConfigs = self.bsc.garlic.genConfigs;
runWrappers = self.bsc.garlic.runWrappers; stages = self.bsc.garlic.stages;
}; };
}; };
}; };
@ -287,12 +299,18 @@ let
nixpkgs = import <nixpkgs>; nixpkgs = import <nixpkgs>;
genApp = self.bsc.garlic.genApp; genApp = self.bsc.garlic.genApp;
genConfigs = self.bsc.garlic.genConfigs; genConfigs = self.bsc.garlic.genConfigs;
runWrappers = self.bsc.garlic.runWrappers; stages = self.bsc.garlic.stages;
}; };
# mpi = callPackage ./bsc/garlic/exp/nbody/mpi.nix { }; # mpi = callPackage ./bsc/garlic/exp/nbody/mpi.nix { };
}; };
}; };
}; };
test = {
exec = callPackage ./test/garlic/exec.nix {
exec = self.bsc.garlic.stages.exec;
};
};
}; };
in in