From 21c9416105c4b090f04e0cbee66ab6d5ac392123 Mon Sep 17 00:00:00 2001 From: ScriptSmith Date: Tue, 24 Sep 2024 14:55:03 +1000 Subject: [PATCH 1/2] Use CommandBox to group commands and example outputs --- src/components/output/CommandBox.js | 65 +++++++++++ src/components/output/CommandBox.stories.js | 38 +++++++ src/components/output/PreformattedBox.js | 4 +- .../guide/Instructions/AccessInstructions.js | 8 +- .../guide/Instructions/ConnectInstructions.js | 6 +- .../guide/Instructions/InstallInstructions.js | 103 ++++++++---------- .../guide/Instructions/RunInstructions.js | 13 +-- .../guide/Instructions/StatusInstructions.js | 76 +++++++------ .../Instructions/TeardownInstructions.js | 8 +- 9 files changed, 211 insertions(+), 110 deletions(-) create mode 100644 src/components/output/CommandBox.js create mode 100644 src/components/output/CommandBox.stories.js diff --git a/src/components/output/CommandBox.js b/src/components/output/CommandBox.js new file mode 100644 index 00000000..f46660a0 --- /dev/null +++ b/src/components/output/CommandBox.js @@ -0,0 +1,65 @@ +import { Box, Heading, useColorModeValue } from "@chakra-ui/react"; + +import PreformattedBox from "./PreformattedBox"; + +function Header({ children }) { + return ( + + {children} + + ); +} + +export default function CommandBox({ command, output, editable }) { + return ( + + +
Command
+ + {command} + +
+ {output && ( + +
Output
+ + {output} + +
+ )} +
+ ); +} diff --git a/src/components/output/CommandBox.stories.js b/src/components/output/CommandBox.stories.js new file mode 100644 index 00000000..13402bf6 --- /dev/null +++ b/src/components/output/CommandBox.stories.js @@ -0,0 +1,38 @@ +import CommandBox from "./CommandBox"; + +export default { + title: "Outputs/CommandBox", + component: CommandBox, +}; + +export const CommandOnly = { + args: { + command: "ls -lah", + }, +}; + +export const CommandAndOutput = { + args: { + command: "ls -lah", + output: "-rw-r--r-- 1 user group 0 Jan 01 00:00 file.txt", + }, +}; + +export const MultilineCommandAndOutput = { + args: { + command: [ + "echo 'Hello, world!' > file.txt", + "ls -lah", + "cat file.txt", + ].join("\n"), + output: `-rw-r--r-- 1 user group 0 Jan 01 00:00 file.txt +Hello, world!`, + }, +}; + +export const Editable = { + args: { + command: "ls -lah", + editable: true, + }, +}; diff --git a/src/components/output/PreformattedBox.js b/src/components/output/PreformattedBox.js index a205f36e..b5b4e242 100644 --- a/src/components/output/PreformattedBox.js +++ b/src/components/output/PreformattedBox.js @@ -17,6 +17,7 @@ export default function PreformattedBox({ type = "input", defaultRows = 10, wrap = true, + contentProps, }) { const [hover, setHover] = useState(false); const [copied, setCopied] = useState(false); @@ -26,7 +27,7 @@ export default function PreformattedBox({ if (type === "input") { bg = useColorModeValue("gray.50", "gray.800"); } else if (type === "output") { - bg = useColorModeValue("gray.300", "gray.700"); + bg = useColorModeValue("gray.200", "gray.700"); } else { bg = useColorModeValue("gray.50", "gray.800"); } @@ -64,6 +65,7 @@ export default function PreformattedBox({ key={text} onSubmit={(e) => setText(e)} sx={wrapStyle} + {...contentProps} > {editable ? ( <> diff --git a/src/components/tool/guide/Instructions/AccessInstructions.js b/src/components/tool/guide/Instructions/AccessInstructions.js index 4b9a84b1..fe8dabbc 100644 --- a/src/components/tool/guide/Instructions/AccessInstructions.js +++ b/src/components/tool/guide/Instructions/AccessInstructions.js @@ -1,6 +1,7 @@ import { Code } from "@chakra-ui/react"; import TextWithLink from "../../../navigation/TextWithLink"; +import CommandBox from "../../../output/CommandBox"; import PreformattedBox from "../../../output/PreformattedBox"; import InstructionHeading from "./components/InstructionHeading"; import InstructionText from "./components/InstructionText"; @@ -30,10 +31,9 @@ export function AccessInstructions({ service, port, node, username }) { )} - - ssh -L {port}:{node || "node"}:{port} {username || "username"} - @lyra.qut.edu.au - + )} Access the tool diff --git a/src/components/tool/guide/Instructions/ConnectInstructions.js b/src/components/tool/guide/Instructions/ConnectInstructions.js index 614c4f0e..727f50a6 100644 --- a/src/components/tool/guide/Instructions/ConnectInstructions.js +++ b/src/components/tool/guide/Instructions/ConnectInstructions.js @@ -1,7 +1,7 @@ import { Box, Code } from "@chakra-ui/react"; import TextWithLink from "../../../navigation/TextWithLink"; -import PreformattedBox from "../../../output/PreformattedBox"; +import CommandBox from "../../../output/CommandBox"; import AlertHelper from "../Config/AlertHelper"; import InstructionHeading from "./components/InstructionHeading"; import InstructionText from "./components/InstructionText"; @@ -87,9 +87,7 @@ function LyraInstructions({ username }) { )} - - ssh {username || "username"}@lyra.qut.edu.au - + ); } diff --git a/src/components/tool/guide/Instructions/InstallInstructions.js b/src/components/tool/guide/Instructions/InstallInstructions.js index 542813d6..32cb4583 100644 --- a/src/components/tool/guide/Instructions/InstallInstructions.js +++ b/src/components/tool/guide/Instructions/InstallInstructions.js @@ -1,7 +1,7 @@ import { Tab, TabList, TabPanel, TabPanels, Tabs } from "@chakra-ui/react"; import TextWithLink from "../../../navigation/TextWithLink"; -import PreformattedBox from "../../../output/PreformattedBox"; +import CommandBox from "../../../output/CommandBox"; import AlertHelper from "../Config/AlertHelper"; import InstructionHeading from "./components/InstructionHeading"; import InstructionText from "./components/InstructionText"; @@ -18,10 +18,9 @@ function SingularityBuildInstructions({ hardware, gpuVendor }) { } } return ( - - singularity build {containerName}{" "} - docker://ghcr.io/eresearchqut/ai-toolbox/hf_pipeline:{containerTag} - + ); } function SingularityRunInstructions({ hardware, gpuVendor, service }) { @@ -42,11 +41,9 @@ function SingularityRunInstructions({ hardware, gpuVendor, service }) { service === "Lyra" ? "/work/ai-toolbox/containers/" : ""; let containerName = singularityContainerName(hardware, gpuVendor); return ( - - singularity run {argsString} - {containerLocation} - {containerName} bash - + ); } @@ -119,25 +116,24 @@ export function InstallInstructions({ Download the latest version of micromamba - - wget - https://raw.githubusercontent.com/mamba-org/micromamba-releases/main/install.sh - + Run the installer and follow the prompts to install micromamba: - - bash install.sh -p ~/micromamba - + Create an alias for micromamba - - {'echo "alias conda=micromamba" >> ~/.bashrc'} - + > ~/.bashrc"} + /> Refresh the shell: - source ~/.bashrc + @@ -148,18 +144,19 @@ export function InstallInstructions({ Download the latest version of miniconda: - - wget - https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh - + Run the installer and follow the prompts to install conda: - - bash Miniconda3-latest-Linux-x86_64.sh - + Refresh the shell: - source ~/.bashrc + @@ -169,26 +166,26 @@ export function InstallInstructions({ Create the conda environment (if it doesn't exist): - conda create --name hf + Create the conda environment: + Activate the conda environment: - conda activate hf + Install the transformers package: - - conda install -c huggingface -c conda-forge transformers - + Install pytorch: - - conda install -c pytorch -c nvidia -c conda-forge pytorch - torchvision torchaudio pytorch-cuda=12.1 - + Install the gradio package: - conda install -c conda-forge gradio + {isWorkstationNotebook && ( <> Install JupyterLab: - - conda install -c conda-forge jupyterlab - + )} @@ -218,15 +215,13 @@ export function InstallInstructions({ <> Python module Source the module script: - - source /etc/profile.d/modules.sh - + Load the python module: - - module load python/3.10.8-gcccore-12.2.0-bare - + Check the python version - python --version + )} @@ -235,17 +230,15 @@ export function InstallInstructions({ Create the virtual environment (if it doesn't exist): - python -m venv hf-venv + Activate the virtual environment: - source hf-venv/bin/activate + Install the base dependencies: - - pip install gradio 'transformers[torch]' - + {isWorkstationNotebook && ( <> Install JupyterLab: - pip install jupyterlab + )} diff --git a/src/components/tool/guide/Instructions/RunInstructions.js b/src/components/tool/guide/Instructions/RunInstructions.js index f438ceb7..cddc3703 100644 --- a/src/components/tool/guide/Instructions/RunInstructions.js +++ b/src/components/tool/guide/Instructions/RunInstructions.js @@ -1,6 +1,7 @@ // TODO: Different operating systems import { Code } from "@chakra-ui/react"; +import CommandBox from "../../../output/CommandBox"; import PreformattedBox from "../../../output/PreformattedBox"; import InstructionHeading from "./components/InstructionHeading"; import InstructionText from "./components/InstructionText"; @@ -14,11 +15,9 @@ export function RunInstructions({ service, tool, task, model, port }) { {tool === "CLI" && ( <> Start the gradio server: - - gradio pipeline {task} --model={model}{" "} - --server-name="0.0.0.0" --server-port={port}{" "} - --device-map="auto" - + )} {tool === "Script" && ( @@ -44,7 +43,7 @@ interface.launch(server_name="0.0.0.0", server_port=PORT) `} Run the script: - python hf_pipeline.py {port} + )} {tool === "Notebook" && ( @@ -54,7 +53,7 @@ interface.launch(server_name="0.0.0.0", server_port=PORT) Run the following command to start the server: - python -m jupyterlab + Open the link to the jupyter server in your browser, and create a new notebook. diff --git a/src/components/tool/guide/Instructions/StatusInstructions.js b/src/components/tool/guide/Instructions/StatusInstructions.js index fa9611c6..3de73a2e 100644 --- a/src/components/tool/guide/Instructions/StatusInstructions.js +++ b/src/components/tool/guide/Instructions/StatusInstructions.js @@ -2,7 +2,7 @@ import { Code, Table, Tbody, Td, Text, Th, Thead, Tr } from "@chakra-ui/react"; import { useState } from "react"; -import PreformattedBox from "../../../output/PreformattedBox"; +import CommandBox from "../../../output/CommandBox"; import InstructionInput from "./InstructionInput"; import InstructionHeading from "./components/InstructionHeading"; import InstructionText from "./components/InstructionText"; @@ -29,17 +29,16 @@ export function LyraStatusInstructions({ jobType, jobName }) { /> Job status - You can check the status of your jobs by running the following - command: + Check the status of your jobs by running the following command: - qstat -xu $USER - - {`pbs: + +${jobIdOrPlaceholder}.pbs username quick job-name -- 1 4 32gb 01:00 Q --`} + /> The job status will be shown in the S column. @@ -106,43 +105,50 @@ Job ID Username Queue Jobname SessID NDS TSK Memory Time S Time Run the following command to see the output files: - {`ls -lh ${jobName}.*`} - - {`-rw------- 1 username default 100 Jan 01 00:00 ${jobName}.e${jobIdOrPlaceholder} --rw------- 1 username default 80 Jan 01 00:00 ${jobName}.o${jobIdOrPlaceholder}`} - + Run the following command to see the output of the job: - {`cat ${jobName}.o${jobIdOrPlaceholder}`} - - {`Hello, world! -PBS Job ${jobIdOrPlaceholder}.pbs -CPU time : 00:00:00 -Wall time : 00:00:01 -Mem usage : 0b`} - + Run the following command to see the error output of the job: - {`cat ${jobName}.e${jobIdOrPlaceholder}`} - {`Data written to stderr`} + Use the following command to get more detailed information about the job, including resource usage. - {`qstat -fx ${jobIdOrPlaceholder}`} - - {`Job Id: ${jobIdOrPlaceholder}.pbs - ... - resources_used.cpupercent = 99 - resources_used.cput = 00:39:22 - resources_used.mem = 5671036kb - resources_used.ncpus = 1 - resources_used.vmem = 2755392kb - resources_used.walltime = 00:40:51 - ...`} - + Observe the resource usage of the job and adjust the requested resources in future job submissions accordingly diff --git a/src/components/tool/guide/Instructions/TeardownInstructions.js b/src/components/tool/guide/Instructions/TeardownInstructions.js index 39b2886b..d02a3c3c 100644 --- a/src/components/tool/guide/Instructions/TeardownInstructions.js +++ b/src/components/tool/guide/Instructions/TeardownInstructions.js @@ -8,7 +8,7 @@ import { useColorModeValue, } from "@chakra-ui/react"; -import PreformattedBox from "../../../output/PreformattedBox"; +import CommandBox from "../../../output/CommandBox"; import InstructionHeading from "./components/InstructionHeading"; import InstructionText from "./components/InstructionText"; @@ -69,12 +69,12 @@ export function TeardownInstructions({ To stop the job early, you need to know your job id. You can either note down your job id when you submit a batch job, or find the job id using the check job status command: - qstat -u $USER + - To stop the job early, run the following: - {`qdel {job_id}`} + To stop the job early, run the following command: + )} Exit the ssh session From 8395056eb122967ec38344e064a253ab7ab895b1 Mon Sep 17 00:00:00 2001 From: ScriptSmith Date: Tue, 24 Sep 2024 14:55:34 +1000 Subject: [PATCH 2/2] Refactoring batch scripts: - Use CommandBox - Use cat >> EOF rather than explaining filesystems & text editors - Remove option to submit batch script through stdin --- .../guide/Instructions/StartInstructions.js | 91 +++++++------------ 1 file changed, 33 insertions(+), 58 deletions(-) diff --git a/src/components/tool/guide/Instructions/StartInstructions.js b/src/components/tool/guide/Instructions/StartInstructions.js index 140cab43..9aaddc66 100644 --- a/src/components/tool/guide/Instructions/StartInstructions.js +++ b/src/components/tool/guide/Instructions/StartInstructions.js @@ -1,9 +1,9 @@ -import { Code, Flex, Kbd, Radio, RadioGroup } from "@chakra-ui/react"; +import { Code } from "@chakra-ui/react"; import { useState } from "react"; import TextWithLink from "../../../navigation/TextWithLink"; -import PreformattedBox from "../../../output/PreformattedBox"; +import CommandBox from "../../../output/CommandBox"; import InstructionInput from "./InstructionInput"; import InstructionHeading from "./components/InstructionHeading"; import InstructionText from "./components/InstructionText"; @@ -63,6 +63,9 @@ export function LyraStartInstructions({ const batchJobScript = [ "#!/bin/bash -l", + `#PBS -N ${jobName}`, + `#PBS -l walltime=${wallTimeStr}`, + `#PBS -l ${resources.join(":")}`, "", "cd $PBS_O_WORKDIR", "", @@ -70,12 +73,12 @@ export function LyraStartInstructions({ 'echo "Data written to stderr" >&2', ]; - const [scriptInput, setScriptInput] = useState("file"); const [scriptPath, setScriptPath] = useState(); - const cmdText = `qsub${jobParameters.join("")} -l walltime=${wallTimeStr} -l ${resources.join( - ":", - )}${jobType === "Batch" && scriptInput === "file" ? " " + (scriptPath || `${jobName}.pbs`) : ""}`; + const cmdText = + jobType === "Interactive" + ? `qsub${jobParameters.join("")} -l walltime=${wallTimeStr} -l ${resources.join(":")}` + : `qsub ${scriptPath || `${jobName}.pbs`}`; return ( <> @@ -84,69 +87,41 @@ export function LyraStartInstructions({ Create the batch job script A job script contains the commands you want to run as part of the - job. - - - Click the example script below to edit it, or copy it into your - preferred text editor. + job. The script will be saved on the Lyra filesystem. + - + Run the following command to create the batch job script: - - {batchJobScript.join("\n")} - + ${jobName}.pbs`, + ...batchJobScript, + "EOF", + "", + ].join("\n")} + /> - You may either: - - - - Save the script as a file on Lyra (eg.{" "} - {jobName}.pbs) - - - Run the command below, then paste the script into the - command's input - - - + Run the following command to confirm the contents of the script: + )} - {jobType === "Batch" && scriptInput === "file" && ( - - )} Schedule a job - In the ssh session, run the following command to schedule the{" "} - {jobType.toLowerCase()} job: + Run the following command to schedule the {jobType.toLowerCase()} job: - {cmdText} - {scriptInput === "stdin" && ( - - Paste the batch job script above into the command's input, then - press Ctrl + D to submit the job. - - )} + ); }