diff --git a/garlic/exp/ifsker/nodes-or-sockets-mpi.nix b/garlic/exp/ifsker/nodes-or-sockets-mpi.nix new file mode 100644 index 0000000000000000000000000000000000000000..51d208b9e3a12bb8cd9cccda137e7b65c836ff97 --- /dev/null +++ b/garlic/exp/ifsker/nodes-or-sockets-mpi.nix @@ -0,0 +1,76 @@ +{ + stdenv +, stdexp +, bsc +, targetMachine +, stages +, garlicTools +, numactl +}: + +with stdenv.lib; +with garlicTools; + +let + # Initial variable configuration + varConf = with bsc; { + nproma = [ 8 16 32 ]; + gitBranch = [ "garlic/tampi+isend+oss+task" ]; + attachToSocket = [ true false ]; + numactl = [ true false ]; + }; + + # Generate the complete configuration for each unit + genConf = c: targetMachine.config // rec { + hw = targetMachine.config.hw; + inputfile = "data/ifs_input_256"; + timesteps = 20; + nproma = c.nproma; + gitBranch = c.gitBranch; + socketAtt = c.attachToSocket; + useNumact = c.numactl; + + expName = "ifsker-conf"; + attachName = if (socketAtt) then "PerSocket" else "PerNode"; + numaName = if (useNumact) then "True" else "False"; + unitName = expName + + "-${toString gitBranch}" + + "-nproma${toString nproma}" + + "-ranks${toString attachName}" + + "-useNuma${toString numaName}"; + + loops = 10; + + qos = "bsc_cs"; + ntasksPerNode = if (socketAtt) then 2 else 1; + nodes = 4; + time = "04:00:00"; + cpusPerTask = if (socketAtt) then hw.cpusPerSocket else 2*hw.cpusPerSocket; + jobName = unitName; + }; + + # Compute the array of configurations + configs = stdexp.buildConfigs { + inherit varConf genConf; + }; + + exec = {nextStage, conf, ...}: stages.exec ({ + inherit nextStage; + argv = [ "-t" conf.timesteps "-i ${nextStage}/etc/data/ifs_input_256" "-p" conf.nproma ]; + + # The next stage is the program + env = '' + export NANOS6_CONFIG="${nextStage}/etc/nanos6.toml" + ''; + } // optionalAttrs (conf.useNumact) { + program = "${numactl}/bin/numactl --interleave=all ${stageProgram nextStage}"; + }); + + program = {nextStage, conf, ...}: with conf; bsc.garlic.apps.ifsker.override { + inherit (conf) gitBranch; + }; + + pipeline = stdexp.stdPipeline ++ [ exec program ]; + +in + stdexp.genExperiment { inherit configs pipeline; } diff --git a/garlic/exp/ifsker/nproma.nix b/garlic/exp/ifsker/nproma.nix new file mode 100644 index 0000000000000000000000000000000000000000..ad06f4a43acc8854b7448d5f054c96fc16d92edd --- /dev/null +++ b/garlic/exp/ifsker/nproma.nix @@ -0,0 +1,66 @@ +{ + stdenv +, stdexp +, bsc +, targetMachine +, stages +, garlicTools +}: + +with stdenv.lib; +with garlicTools; + +let + # Initial variable configuration + varConf = { + nproma = [ 1 2 4 8 16 32 64 128 256 512 ]; + gitBranch = [ + "garlic/mpi+isend+oss+fork" + "garlic/mpi+isend+oss+task" + "garlic/tampi+send+oss+task" + "garlic/tampi+isend+oss+task" + ]; + }; + + # Generate the complete configuration for each unit + genConf = c: targetMachine.config // rec { + hw = targetMachine.config.hw; + inputfile = "data/ifs_input_256"; + timesteps = 20; + nproma = c.nproma; + gitBranch = c.gitBranch; + + expName = "ifsker-nproma"; + unitName = expName + "-nproma${toString nproma}"; + loops = 10; + qos = "bsc_cs"; + ntasksPerNode = 2; + nodes = 1; + time = "02:00:00"; + cpusPerTask = hw.cpusPerSocket; + jobName = unitName; + }; + + # Compute the array of configurations + configs = stdexp.buildConfigs { + inherit varConf genConf; + }; + + exec = {nextStage, conf, ...}: stages.exec { + inherit nextStage; + argv = [ "-t" conf.timesteps "-i ${nextStage}/etc/data/ifs_input_256" "-p" conf.nproma ]; + + # The next stage is the program + env = '' + export NANOS6_CONFIG="${nextStage}/etc/nanos6.toml" + ''; + }; + + program = {nextStage, conf, ...}: with conf; bsc.garlic.apps.ifsker.override { + inherit (conf) gitBranch; + }; + + pipeline = stdexp.stdPipeline ++ [ exec program ]; + +in + stdexp.genExperiment { inherit configs pipeline; } diff --git a/garlic/exp/ifsker/strong-scaling-mpi.nix b/garlic/exp/ifsker/strong-scaling-mpi.nix new file mode 100644 index 0000000000000000000000000000000000000000..ae047ce67dd296769391c08f6f892affd6d26361 --- /dev/null +++ b/garlic/exp/ifsker/strong-scaling-mpi.nix @@ -0,0 +1,71 @@ +{ + stdenv +, stdexp +, bsc +, targetMachine +, stages +, garlicTools +}: + +with stdenv.lib; +with garlicTools; + +let + # Initial variable configuration + varConf = with bsc; { + nproma = [ 16 ]; + nodes = [ 1 2 4 8 16 ]; + gitBranch = [ + "garlic/mpi+isend+oss+fork" + "garlic/mpi+isend+oss+task" + "garlic/tampi+send+oss+task" + "garlic/tampi+isend+oss+task" + ]; + }; + + # Generate the complete configuration for each unit + genConf = c: targetMachine.config // rec { + hw = targetMachine.config.hw; + inputfile = "data/ifs_input_256"; + timesteps = 20; + nproma = c.nproma; + numNodes = c.nodes; + gitBranch = c.gitBranch; + + expName = "ifsker-scaling"; + unitName = expName + "-${toString gitBranch}" + "-nodes${toString numNodes}"; + + loops = 10; + + nodes = numNodes; + qos = "bsc_cs"; + ntasksPerNode = 2; + time = "04:00:00"; + cpusPerTask = hw.cpusPerSocket; + jobName = unitName; + }; + + # Compute the array of configurations + configs = stdexp.buildConfigs { + inherit varConf genConf; + }; + + exec = {nextStage, conf, ...}: stages.exec { + inherit nextStage; + argv = [ "-t" conf.timesteps "-i ${nextStage}/etc/data/ifs_input_256" "-p" conf.nproma ]; + + # The next stage is the program + env = '' + export NANOS6_CONFIG="${nextStage}/etc/nanos6.toml" + ''; + }; + + program = {nextStage, conf, ...}: with conf; bsc.garlic.apps.ifsker.override { + inherit (conf) gitBranch; + }; + + pipeline = stdexp.stdPipeline ++ [ exec program ]; + +in + + stdexp.genExperiment { inherit configs pipeline; } diff --git a/garlic/exp/index.nix b/garlic/exp/index.nix index d467881b11fe837df27c08d1e8b3223613615aff..3539bdd577340a282248ff40292903c6a7618471 100644 --- a/garlic/exp/index.nix +++ b/garlic/exp/index.nix @@ -43,6 +43,12 @@ ctf = granularity.override { enableCTF = true; }; }; + ifsker = rec { + nproma = callPackage ./ifsker/nproma.nix { }; + nodesorsockets = callPackage ./ifsker/nodes-or-sockets-mpi.nix { }; + scaling = callPackage ./ifsker/strong-scaling-mpi.nix { }; + }; + bigsort = rec { genseq = callPackage ./bigsort/genseq.nix { n = toString (1024 * 1024 * 1024 / 8); # 1 GB input size diff --git a/garlic/fig/ifsker/nodes-or-sockets.R b/garlic/fig/ifsker/nodes-or-sockets.R new file mode 100644 index 0000000000000000000000000000000000000000..02361a9dd6210805b251734eadbb14dfc29c38ea --- /dev/null +++ b/garlic/fig/ifsker/nodes-or-sockets.R @@ -0,0 +1,168 @@ +library(ggplot2) +library(dplyr, warn.conflicts = FALSE) +library(scales) +library(jsonlite) +library(viridis, warn.conflicts = FALSE) + +# Load the arguments (argv) +args = commandArgs(trailingOnly=TRUE) +if (length(args)>0) { input_file = args[1] } else { input_file = "input" } + +dfNuma = jsonlite::stream_in(file(input_file), verbose=FALSE) %>% + jsonlite::flatten() %>% + select(config.nproma, config.gitBranch, config.socketAtt, config.useNumact, unit, time) %>% + rename(nproma=config.nproma, branch=config.gitBranch, attachment=config.socketAtt, usenuma=config.useNumact) %>% + + mutate(nproma = as.factor(nproma)) %>% + mutate(branch = as.factor(branch)) %>% + mutate(attachment = as.factor(attachment)) %>% + mutate(usenuma = as.factor(usenuma)) %>% + mutate(unit = as.factor(unit)) %>% + + group_by(unit) %>% + + mutate(median.time = median(time)) %>% + mutate(normalized.time = time / median.time - 1) %>% + mutate(log.median.time = log(median.time)) %>% + + filter(usenuma == TRUE) %>% + + ungroup() + +dfNonuma = jsonlite::stream_in(file(input_file), verbose=FALSE) %>% + jsonlite::flatten() %>% + select(config.nproma, config.gitBranch, config.socketAtt, config.useNumact, unit, time) %>% + rename(nproma=config.nproma, branch=config.gitBranch, attachment=config.socketAtt, usenuma=config.useNumact) %>% + + mutate(nproma = as.factor(nproma)) %>% + mutate(branch = as.factor(branch)) %>% + mutate(attachment = as.factor(attachment)) %>% + mutate(usenuma = as.factor(usenuma)) %>% + mutate(unit = as.factor(unit)) %>% + + group_by(unit) %>% + + mutate(median.time = median(time)) %>% + mutate(normalized.time = time / median.time - 1) %>% + mutate(log.median.time = log(median.time)) %>% + + filter(usenuma == FALSE) %>% + + ungroup() + +dpi = 300 +h = 5 +w = 8 + + +# --------------------------------------------------------------------- + +p = ggplot(dfNuma, aes(x=nproma, y=median.time, color=attachment)) + + geom_point() + + geom_line(aes(group=attachment)) + + theme_bw() + + labs(x="Nproma", y="Median time (s)", title="IFSKer Granularity (tampi+isend+oss+task | numactl ON | 4 Nodes): Median Time", + subtitle=input_file, color="Rank Attachment") + + theme(plot.subtitle=element_text(size=5)) + + theme(legend.position="bottom") + + scale_color_manual(labels = c("RanksPerNode", "RanksPerSocket"), values=c("blue", "red")) + +ggsave("median-numactl.time.png", plot=p, width=w, height=h, dpi=dpi) +ggsave("median-numactl.time.pdf", plot=p, width=w, height=h, dpi=dpi) + +p = ggplot(dfNonuma, aes(x=nproma, y=median.time, color=attachment)) + + geom_point() + + geom_line(aes(group=attachment)) + + theme_bw() + + labs(x="Nproma", y="Median time (s)", title="IFSKer Granularity (tampi+isend+oss+task | numactl OFF | 4 Nodes): Median Time", + subtitle=input_file, color="Rank Attachment") + + theme(plot.subtitle=element_text(size=5)) + + theme(legend.position="bottom") + + scale_color_manual(labels = c("RanksPerNode", "RanksPerSocket"), values=c("blue", "red")) + +ggsave("median.time.png", plot=p, width=w, height=h, dpi=dpi) +ggsave("median.time.pdf", plot=p, width=w, height=h, dpi=dpi) +# --------------------------------------------------------------------- + +p = ggplot(dfNuma, aes(x=nproma, y=normalized.time, color=attachment)) + + geom_boxplot() + + geom_hline(yintercept=c(-0.01, 0.01), linetype="dashed", color="red") + + facet_wrap(~ attachment) + + theme_bw() + + labs(x="Nproma", y="Normalized Time", title="IFSKer Granularity (tampi+isend+oss+task | numactl ON | 4 Nodes): Normalized Time", + subtitle=input_file, color="Rank Attachment") + + theme(plot.subtitle=element_text(size=5)) + + theme(legend.position="bottom") + + scale_color_manual(labels = c("RanksPerNode", "RanksPerSocket"), values=c("blue", "red")) + +ggsave("normalized-numactl.time.png", plot=p, width=w, height=h, dpi=dpi) +ggsave("normalized-numactl.time.pdf", plot=p, width=w, height=h, dpi=dpi) + +p = ggplot(dfNonuma, aes(x=nproma, y=normalized.time, color=attachment)) + + geom_boxplot() + + geom_hline(yintercept=c(-0.01, 0.01), linetype="dashed", color="red") + + facet_wrap(~ attachment) + + theme_bw() + + labs(x="Nproma", y="Normalized Time", title="IFSKer Granularity (tampi+isend+oss+task | 4 Nodes): Normalized Time", + subtitle=input_file, color="Rank Attachment") + + theme(plot.subtitle=element_text(size=5)) + + theme(legend.position="bottom") + + scale_color_manual(labels = c("RanksPerNode", "RanksPerSocket"), values=c("blue", "red")) + +ggsave("normalized.time.png", plot=p, width=w, height=h, dpi=dpi) +ggsave("normalized.time.pdf", plot=p, width=w, height=h, dpi=dpi) +# --------------------------------------------------------------------- + +p = ggplot(dfNuma, aes(x=nproma, y=time, color=attachment)) + + geom_point(shape=21, size=3) + + theme_bw() + + labs(x="Nproma", y="Time (s)", title="IFSKer Granularity (tampi+isend+oss+task | numactl ON | 4 Nodes): Time", + subtitle=input_file, color="Rank Attachment") + + theme(plot.subtitle=element_text(size=5)) + + theme(legend.position="bottom") + + scale_color_manual(labels = c("RanksPerNode", "RanksPerSocket"), values=c("blue", "red")) + +ggsave("time-numactl.png", plot=p, width=w, height=h, dpi=dpi) +ggsave("time-numactl.pdf", plot=p, width=w, height=h, dpi=dpi) + +p = ggplot(dfNonuma, aes(x=nproma, y=time, color=attachment)) + + geom_point(shape=21, size=3) + + theme_bw() + + labs(x="Nproma", y="Time (s)", title="IFSKer Granularity (tampi+isend+oss+task | 4 Nodes): Time", + subtitle=input_file, color="Rank Attachment") + + theme(plot.subtitle=element_text(size=5)) + + theme(legend.position="bottom") + + scale_color_manual(labels = c("RanksPerNode", "RanksPerSocket"), values=c("blue", "red")) + + +ggsave("time.png", plot=p, width=w, height=h, dpi=dpi) +ggsave("time.pdf", plot=p, width=w, height=h, dpi=dpi) +# --------------------------------------------------------------------- + +p = ggplot(dfNuma, aes(x=nproma, y=attachment, fill=median.time)) + + geom_raster() + + scale_fill_viridis(option="plasma") + + coord_fixed() + + theme_bw() + + labs(x="Nproma", y="Attachment", title="IFSKer Granularity (tampi+isend+oss+task | numactl ON | 4 Nodes): Time", + subtitle=input_file, color = "Rank Attachment") + + theme(plot.subtitle=element_text(size=5)) + + theme(legend.position="bottom") + + scale_color_manual(labels = c("RanksPerNode", "RanksPerSocket"), values=c("blue", "red")) + +ggsave("time-numactl.heatmap.png", plot=p, width=w, height=h, dpi=dpi) +ggsave("time-numactl.heatmap.pdf", plot=p, width=w, height=h, dpi=dpi) + +p = ggplot(dfNonuma, aes(x=nproma, y=attachment, fill=median.time)) + + geom_raster() + + scale_fill_viridis(option="plasma") + + coord_fixed() + + theme_bw() + + labs(x="Nproma", y="Attachment", title="IFSKer Granularity (tampi+isend+oss+task | 4 Nodes): Time", + subtitle=input_file, color = "Rank Attachment") + + theme(plot.subtitle=element_text(size=5)) + + theme(legend.position="bottom") + + scale_color_manual(labels = c("RanksPerNode", "RanksPerSocket"), values=c("blue", "red")) + +ggsave("time.heatmap.png", plot=p, width=w, height=h, dpi=dpi) +ggsave("time.heatmap.pdf", plot=p, width=w, height=h, dpi=dpi) diff --git a/garlic/fig/ifsker/nproma.R b/garlic/fig/ifsker/nproma.R new file mode 100644 index 0000000000000000000000000000000000000000..4728a55d3db1d8bd81d6da94da87f5b66a47f7ec --- /dev/null +++ b/garlic/fig/ifsker/nproma.R @@ -0,0 +1,92 @@ +library(ggplot2) +library(dplyr, warn.conflicts = FALSE) +library(scales) +library(jsonlite) +library(viridis, warn.conflicts = FALSE) + +# Load the arguments (argv) +args = commandArgs(trailingOnly=TRUE) +if (length(args)>0) { input_file = args[1] } else { input_file = "input" } + +df = jsonlite::stream_in(file(input_file), verbose=FALSE) %>% + jsonlite::flatten() %>% + select(config.nproma, config.gitBranch, unit, time) %>% + rename(nproma=config.nproma, branch=config.gitBranch) %>% + + mutate(nproma = as.factor(nproma)) %>% + mutate(branch = as.factor(branch)) %>% + mutate(unit = as.factor(unit)) %>% + + group_by(unit) %>% + + mutate(median.time = median(time)) %>% + mutate(normalized.time = time / median.time - 1) %>% + mutate(log.median.time = log(median.time)) %>% + + ungroup() + +dpi = 300 +h = 5 +w = 8 + +# --------------------------------------------------------------------- + +p = ggplot(df, aes(x=nproma, y=median.time, color=branch)) + + geom_point() + + geom_line(aes(group=branch)) + + theme_bw() + + labs(x="Nproma", y="Median time (s)", title="IFSKer Granularity: Median Time", + subtitle=input_file) + + theme(plot.subtitle=element_text(size=5)) + + theme(legend.position="bottom") + + theme(legend.text = element_text(size=7)) + +ggsave("median.time.png", plot=p, width=w, height=h, dpi=dpi) +ggsave("median.time.pdf", plot=p, width=w, height=h, dpi=dpi) + +# --------------------------------------------------------------------- + +p = ggplot(df, aes(x=nproma, y=normalized.time, color=branch)) + + geom_boxplot() + + geom_hline(yintercept=c(-0.01, 0.01), linetype="dashed", color="red") + + facet_wrap(~ branch) + + theme_bw() + + labs(x="Nproma", y="Normalized Time", title="IFSKer Granularity: Normalized Time", + subtitle=input_file) + + theme(plot.subtitle=element_text(size=5)) + + theme(legend.position="bottom") + + theme(legend.text = element_text(size=7)) + +ggsave("normalized.time.png", plot=p, width=w, height=h, dpi=dpi) +ggsave("normalized.time.pdf", plot=p, width=w, height=h, dpi=dpi) + +# --------------------------------------------------------------------- + +p = ggplot(df, aes(x=nproma, y=time, color=branch)) + + geom_point(shape=21, size=3) + + theme_bw() + + labs(x="Nproma", y="Time (s)", title="IFSKer Granularity: Time", + subtitle=input_file) + + theme(plot.subtitle=element_text(size=5)) + + theme(legend.position="bottom") + + theme(legend.text = element_text(size=7)) + +ggsave("time.png", plot=p, width=w, height=h, dpi=dpi) +ggsave("time.pdf", plot=p, width=w, height=h, dpi=dpi) + + +# --------------------------------------------------------------------- + +p = ggplot(df, aes(x=nproma, y=branch, fill=median.time)) + + geom_raster() + + scale_fill_viridis(option="plasma") + + coord_fixed() + + theme_bw() + + labs(x="Nproma", y="Branch", title="IFSKer Granularity: Time", + subtitle=input_file) + + theme(plot.subtitle=element_text(size=5)) + + theme(legend.position="bottom") + + theme(legend.text = element_text(size=7)) + +ggsave("time.heatmap.png", plot=p, width=w, height=h, dpi=dpi) +ggsave("time.heatmap.pdf", plot=p, width=w, height=h, dpi=dpi) diff --git a/garlic/fig/ifsker/scaling.R b/garlic/fig/ifsker/scaling.R new file mode 100644 index 0000000000000000000000000000000000000000..9df77d5beeeab2b76345965a657c3b84b277400e --- /dev/null +++ b/garlic/fig/ifsker/scaling.R @@ -0,0 +1,93 @@ +library(ggplot2) +library(dplyr, warn.conflicts = FALSE) +library(scales) +library(jsonlite) +library(viridis, warn.conflicts = FALSE) + +# Load the arguments (argv) +args = commandArgs(trailingOnly=TRUE) +if (length(args)>0) { input_file = args[1] } else { input_file = "input" } + +df = jsonlite::stream_in(file(input_file), verbose=FALSE) %>% + jsonlite::flatten() %>% + select(config.nproma, config.gitBranch, config.numNodes, unit, time) %>% + rename(nodes = config.numNodes, nproma=config.nproma, branch=config.gitBranch) %>% + + mutate(nproma = as.factor(nproma)) %>% + mutate(nodes = as.factor(nodes)) %>% + mutate(branch = as.factor(branch)) %>% + mutate(unit = as.factor(unit)) %>% + + group_by(unit) %>% + + mutate(median.time = median(time)) %>% + mutate(normalized.time = time / median.time - 1) %>% + mutate(log.median.time = log(median.time)) %>% + + ungroup() + +dpi = 300 +h = 5 +w = 8 + +# --------------------------------------------------------------------- + +p = ggplot(df, aes(x=nodes, y=median.time, color=branch)) + + geom_point() + + geom_line(aes(group=branch)) + + theme_bw() + + labs(x="Nodes", y="Median time (s)", title="IFSKer Scaling: Median Time", + subtitle=input_file) + + theme(plot.subtitle=element_text(size=5)) + + theme(legend.position="bottom") + + theme(legend.text = element_text(size=7)) + +ggsave("median.time.png", plot=p, width=w, height=h, dpi=dpi) +ggsave("median.time.pdf", plot=p, width=w, height=h, dpi=dpi) + +# --------------------------------------------------------------------- + +p = ggplot(df, aes(x=nodes, y=normalized.time, color=branch)) + + geom_boxplot() + + geom_hline(yintercept=c(-0.01, 0.01), linetype="dashed", color="red") + + facet_wrap(~ branch) + + theme_bw() + + labs(x="Nodes", y="Normalized time (s)", title="IFSKer Scaling: Normalized Time", + subtitle=input_file) + + theme(plot.subtitle=element_text(size=5)) + + theme(legend.position="bottom") + + theme(legend.text = element_text(size=7)) + +ggsave("normalized.time.png", plot=p, width=w, height=h, dpi=dpi) +ggsave("normalized.time.pdf", plot=p, width=w, height=h, dpi=dpi) + +# --------------------------------------------------------------------- + +p = ggplot(df, aes(x=nodes, y=time, color=branch)) + + geom_point(shape=21, size=3) + + theme_bw() + + labs(x="Nodes", y="Time (s)", title="IFSKer Scaling: Time", + subtitle=input_file) + + theme(plot.subtitle=element_text(size=5)) + + theme(legend.position="bottom") + + theme(legend.text = element_text(size=7)) + +ggsave("time.png", plot=p, width=w, height=h, dpi=dpi) +ggsave("time.pdf", plot=p, width=w, height=h, dpi=dpi) + + +# --------------------------------------------------------------------- + +p = ggplot(df, aes(x=nodes, y=branch, fill=median.time)) + + geom_raster() + + scale_fill_viridis(option="plasma") + + coord_fixed() + + theme_bw() + + labs(x="Nodes", y="Branch", title="IFSKer Scaling: Time", + subtitle=input_file) + + theme(plot.subtitle=element_text(size=5)) + + theme(legend.position="bottom") + + theme(legend.text = element_text(size=7)) + +ggsave("time.heatmap.png", plot=p, width=w, height=h, dpi=dpi) +ggsave("time.heatmap.pdf", plot=p, width=w, height=h, dpi=dpi) diff --git a/garlic/fig/index.nix b/garlic/fig/index.nix index 6f6ff4b527520130149ecad663536e4307eea504..5a47c6aef51d61971e560897866b58e42263e6a5 100644 --- a/garlic/fig/index.nix +++ b/garlic/fig/index.nix @@ -35,6 +35,12 @@ in numa = stdPlot ./nbody/numa.R [ numa ]; }; + ifsker = with exp.ifsker; { + nproma = stdPlot ./ifsker/nproma.R [ nproma ]; + nodesorsockets = stdPlot ./ifsker/nodes-or-sockets.R [ nodesorsockets ]; + scaling = stdPlot ./ifsker/scaling.R [ scaling ]; + }; + hpcg = with exp.hpcg; { ss = stdPlot ./hpcg/ss.R [ ss ]; ws = stdPlot ./hpcg/ws.R [ ws ];