igneum/infra/cloud-devnet/experiments/hop.sh
igneum-labs d8dc8c6ba3 infra: cloud devnet (20 nodes), rented GPU bench and seed node scripts; plans for both
infra/cloud-devnet: hcloud (doctl variant) create, builder-VM provision from a git-archive source tarball,
systemd units for igneumd --devnet-suffix with a sparse --addpeer mesh and a CPU trickle miner per node,
stdlib wRPC client, experiments (latency, partition, hop, collect, observer hookup), README with the command
sequence and the Hetzner API prices of 3 Oct 2026.
infra/gpu-bench: RunPod image recipes (CUDA 12.8, ROCm), bundle, run.sh (vectors gate, 10-min raw, sweep,
inline shortcut ratio, nvcc/NVRTC/OpenCL recompile timings, results row, intake upload), bench-log template.
infra/seed-nodes: create-seed (persistent IPv4, firewall), provision on the VM, health check, addPeer from the
Mac over grpcurl, seeds.txt; igneum-seed-1 created at 188.245.5.161 (Hetzner cx23, fsn1).
docs/plans/cloud-devnet.md and docs/plans/seed-nodes.md.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 22:01:50 +00:00

50 lines
2.4 KiB
Bash
Executable file

#!/usr/bin/env bash
# Experiment 1c: hash-rate steps for the difficulty controller (spec 02 section 2.3; the dual-lane rule is on the
# `difficulty` worktree, NODE_SRC=vendor/igneum-node-diff when building; on master it exercises Kaspa's sampled DAA).
# ./experiments/hop.sh "<schedule>"
# schedule = phases separated by ";", phase = <selector>:<threads>:<seconds>
# selector: all | half (odd indices) | odd | even | region:<name> | <from>-<to> (indices)
# threads: miner threads on the selected nodes (0 stops the miner); unselected nodes keep their setting
# Default schedule (about 75 min): steady, 4x step up on half the nodes, back down, one region off, back:
# all:1:900;half:4:900;all:1:900;region:hel1:0:600;all:1:900
# Every phase change is logged to results/<date>/hop.log (ts_ms, selector, threads); collect.sh and analyze.py hop
# line the difficulty samples up against it.
. "$(dirname "$0")/../lib/common.sh"
require_nodes
schedule="${1:-all:1:900;half:4:900;all:1:900;region:hel1:0:600;all:1:900}"
out="$(results_dir_for)"; logf="$out/hop.log"
select_nodes() {
case "$1" in
all) node_names ;;
half|odd) awk -F'\t' '$2 % 2 == 1 { print $1 }' "$NODES_FILE" ;;
even) awk -F'\t' '$2 % 2 == 0 { print $1 }' "$NODES_FILE" ;;
region:*) nodes_in_region "${1#region:}" ;;
*-*) awk -F'\t' -v a="${1%-*}" -v b="${1#*-}" '$2 >= a && $2 <= b { print $1 }' "$NODES_FILE" ;;
*) die "bad selector $1" ;;
esac
}
set_threads() { # node threads
local ip; ip=$(node_ip "$1")
if [ "$2" = 0 ]; then
nssh "$ip" "systemctl stop igneum-miner"
else
nssh "$ip" "sed -i 's/^MINER_THREADS=.*/MINER_THREADS=$2/' /etc/igneum/node.env && systemctl restart igneum-miner"
fi
}
log "schedule: $schedule"
IFS=';' read -r -a phases <<< "$schedule"
for ph in "${phases[@]}"; do
sel="${ph%%:*}"; rest="${ph#*:}"
if [ "$sel" = region ]; then sel="region:${rest%%:*}"; rest="${rest#*:}"; fi
threads="${rest%%:*}"; secs="${rest#*:}"
nodes=$(select_nodes "$sel")
log "phase: $sel -> $threads thread(s) for $secs s ($(printf '%s\n' "$nodes" | wc -l | tr -d ' ') nodes)"
for n in $nodes; do set_threads "$n" "$threads" & done; wait
printf '%s\t%s\t%s\t%s\n' "$(date +%s)000" "$sel" "$threads" "$secs" >> "$logf"
sleep "$secs"
done
printf '%s\tend\t-\t-\n' "$(date +%s)000" >> "$logf"
log "done; phases in $logf. Pull the samples with ./experiments/collect.sh and read results/<date>/hop.md"