#!/bin/bash # Submit jobs to gpuq workers. # # gpuq_submit.sh [...] # pin to a worker # gpuq_submit.sh --class [...] # pick idlest in class # gpuq_submit.sh --status # # Class rosters live in the bucket: gpuq/_classes/.txt (one worker id # per line). Scheduling: prefer workers with 0 pending AND <15% GPU util # (from the node heartbeat); tie-break by fewest pending, then random. set -eu if [ "$1" = "--status" ]; then echo "== pending ==" rclone lsf -R jspace:jspace/gpuq --include "pending/*.sh" 2>/dev/null echo "== done (last 20) ==" rclone lsl -R jspace:jspace/gpuq --include "done/*.sh" 2>/dev/null | sort -k2,3 | tail -20 exit 0 fi pick_worker() { # $1 = class local best="" best_score=999999 for w in $(rclone cat "jspace:jspace/gpuq/_classes/$1.txt" 2>/dev/null); do local node=${w%-gpu*} gpu=${w##*-gpu} local pend util score pend=$(rclone lsf "jspace:jspace/gpuq/$w/pending/" --include "*.sh" 2>/dev/null | wc -l) util=$(rclone cat "jspace:jspace/gpuq/_health/$node.txt" 2>/dev/null \ | grep -E "^$gpu, " | head -1 | awk -F', ' '{print $2}' | tr -dc 0-9) util=${util:-100} score=$((pend * 100 + util)) if [ "$score" -lt "$best_score" ]; then best=$w; best_score=$score; fi done echo "$best" } if [ "$1" = "--class" ]; then CLASS=$2; shift 2 for f in "$@"; do rclone copy "$f" "jspace:jspace/gpuq/_class-pending/$CLASS/" -q echo "queued $(basename $f) -> class $CLASS (dispatcher assigns on idle)" done exit 0 fi ID=$1; shift for f in "$@"; do rclone copy "$f" "jspace:jspace/gpuq/$ID/pending/" -q echo "queued $(basename $f) -> $ID" done