allegro-buddy 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- allegro_buddy-0.1.0/.github/assets/free.svg +95 -0
- allegro_buddy-0.1.0/.github/assets/queue.svg +85 -0
- allegro_buddy-0.1.0/.github/assets/why.svg +76 -0
- allegro_buddy-0.1.0/.github/workflows/ci.yml +52 -0
- allegro_buddy-0.1.0/.github/workflows/pypi.yml +44 -0
- allegro_buddy-0.1.0/LICENSE +21 -0
- allegro_buddy-0.1.0/PKG-INFO +90 -0
- allegro_buddy-0.1.0/README.md +76 -0
- allegro_buddy-0.1.0/pyproject.toml +60 -0
- allegro_buddy-0.1.0/src/allegro_buddy/__init__.py +5 -0
- allegro_buddy-0.1.0/src/allegro_buddy/__main__.py +4 -0
- allegro_buddy-0.1.0/src/allegro_buddy/cli.py +567 -0
- allegro_buddy-0.1.0/src/allegro_buddy/clusters/allegro.ini +19 -0
- allegro_buddy-0.1.0/src/allegro_buddy/clusters/bhlrn4.ini +20 -0
- allegro_buddy-0.1.0/src/allegro_buddy/core.py +1556 -0
- allegro_buddy-0.1.0/src/allegro_buddy/fit.py +862 -0
- allegro_buddy-0.1.0/src/allegro_buddy/handlers/__init__.py +1 -0
- allegro_buddy-0.1.0/src/allegro_buddy/handlers/config.py +86 -0
- allegro_buddy-0.1.0/src/allegro_buddy/handlers/dev.py +386 -0
- allegro_buddy-0.1.0/src/allegro_buddy/handlers/job.py +68 -0
- allegro_buddy-0.1.0/src/allegro_buddy/handlers/resources.py +777 -0
- allegro_buddy-0.1.0/src/allegro_buddy/handlers/why.py +523 -0
- allegro_buddy-0.1.0/src/allegro_buddy/settings.py +238 -0
- allegro_buddy-0.1.0/tests/conftest.py +125 -0
- allegro_buddy-0.1.0/tests/demo_cluster.py +393 -0
- allegro_buddy-0.1.0/tests/slurm_records.py +142 -0
- allegro_buddy-0.1.0/tests/snapshots/allegro-config-show.txt +23 -0
- allegro_buddy-0.1.0/tests/snapshots/allegro-dev-start.txt +2 -0
- allegro_buddy-0.1.0/tests/snapshots/allegro-dev-status.txt +6 -0
- allegro_buddy-0.1.0/tests/snapshots/allegro-dev-stop.txt +1 -0
- allegro_buddy-0.1.0/tests/snapshots/allegro-error-unknown-job.txt +1 -0
- allegro_buddy-0.1.0/tests/snapshots/allegro-free-a5000.txt +8 -0
- allegro_buddy-0.1.0/tests/snapshots/allegro-free-cpu.txt +8 -0
- allegro_buddy-0.1.0/tests/snapshots/allegro-free-nodes.txt +9 -0
- allegro_buddy-0.1.0/tests/snapshots/allegro-free.txt +13 -0
- allegro_buddy-0.1.0/tests/snapshots/allegro-help.txt +25 -0
- allegro_buddy-0.1.0/tests/snapshots/allegro-info.txt +20 -0
- allegro_buddy-0.1.0/tests/snapshots/allegro-job-history.txt +8 -0
- allegro_buddy-0.1.0/tests/snapshots/allegro-job-output.txt +7 -0
- allegro_buddy-0.1.0/tests/snapshots/allegro-node-cpu.txt +5 -0
- allegro_buddy-0.1.0/tests/snapshots/allegro-node-shared.txt +6 -0
- allegro_buddy-0.1.0/tests/snapshots/allegro-node.txt +6 -0
- allegro_buddy-0.1.0/tests/snapshots/allegro-queue-all.txt +13 -0
- allegro_buddy-0.1.0/tests/snapshots/allegro-queue.txt +8 -0
- allegro_buddy-0.1.0/tests/snapshots/allegro-why-fix-confirm.txt +5 -0
- allegro_buddy-0.1.0/tests/snapshots/allegro-why-fix.txt +4 -0
- allegro_buddy-0.1.0/tests/snapshots/allegro-why-job.txt +8 -0
- allegro_buddy-0.1.0/tests/snapshots/allegro-why-nodes.txt +15 -0
- allegro_buddy-0.1.0/tests/snapshots/allegro-why.txt +10 -0
- allegro_buddy-0.1.0/tests/test_cli.py +770 -0
- allegro_buddy-0.1.0/tests/test_cluster_output.py +435 -0
- allegro_buddy-0.1.0/tests/test_demo_output.py +100 -0
- allegro_buddy-0.1.0/tests/test_dev.py +139 -0
- allegro_buddy-0.1.0/tests/test_fit.py +763 -0
- allegro_buddy-0.1.0/tests/test_gpu.py +443 -0
- allegro_buddy-0.1.0/tests/test_gpu_counts.py +223 -0
- allegro_buddy-0.1.0/tests/test_integration.py +420 -0
- allegro_buddy-0.1.0/tests/test_parsing.py +705 -0
- allegro_buddy-0.1.0/tests/test_queue.py +246 -0
- allegro_buddy-0.1.0/tests/test_slurm.py +496 -0
- allegro_buddy-0.1.0/tests/test_stats.py +296 -0
- allegro_buddy-0.1.0/tests/test_why.py +439 -0
- allegro_buddy-0.1.0/uv.lock +595 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
<svg class="rich-terminal" viewBox="0 0 994 269.6" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<!-- Generated with Rich https://www.textualize.io -->
|
|
3
|
+
<style>
|
|
4
|
+
|
|
5
|
+
@font-face {
|
|
6
|
+
font-family: "Fira Code";
|
|
7
|
+
src: local("FiraCode-Regular"),
|
|
8
|
+
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Regular.woff2") format("woff2"),
|
|
9
|
+
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Regular.woff") format("woff");
|
|
10
|
+
font-style: normal;
|
|
11
|
+
font-weight: 400;
|
|
12
|
+
}
|
|
13
|
+
@font-face {
|
|
14
|
+
font-family: "Fira Code";
|
|
15
|
+
src: local("FiraCode-Bold"),
|
|
16
|
+
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Bold.woff2") format("woff2"),
|
|
17
|
+
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Bold.woff") format("woff");
|
|
18
|
+
font-style: bold;
|
|
19
|
+
font-weight: 700;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.terminal-2014532663-matrix {
|
|
23
|
+
font-family: Fira Code, monospace;
|
|
24
|
+
font-size: 20px;
|
|
25
|
+
line-height: 24.4px;
|
|
26
|
+
font-variant-east-asian: full-width;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.terminal-2014532663-title {
|
|
30
|
+
font-size: 18px;
|
|
31
|
+
font-weight: bold;
|
|
32
|
+
font-family: arial;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.terminal-2014532663-r1 { fill: #c5c8c6;font-weight: bold }
|
|
36
|
+
.terminal-2014532663-r2 { fill: #c5c8c6 }
|
|
37
|
+
.terminal-2014532663-r3 { fill: #98a84b }
|
|
38
|
+
.terminal-2014532663-r4 { fill: #868887 }
|
|
39
|
+
.terminal-2014532663-r5 { fill: #d0b344 }
|
|
40
|
+
.terminal-2014532663-r6 { fill: #608ab1 }
|
|
41
|
+
</style>
|
|
42
|
+
|
|
43
|
+
<defs>
|
|
44
|
+
<clipPath id="terminal-2014532663-clip-terminal">
|
|
45
|
+
<rect x="0" y="0" width="975.0" height="218.6" />
|
|
46
|
+
</clipPath>
|
|
47
|
+
<clipPath id="terminal-2014532663-line-0">
|
|
48
|
+
<rect x="0" y="1.5" width="976" height="24.65"/>
|
|
49
|
+
</clipPath>
|
|
50
|
+
<clipPath id="terminal-2014532663-line-1">
|
|
51
|
+
<rect x="0" y="25.9" width="976" height="24.65"/>
|
|
52
|
+
</clipPath>
|
|
53
|
+
<clipPath id="terminal-2014532663-line-2">
|
|
54
|
+
<rect x="0" y="50.3" width="976" height="24.65"/>
|
|
55
|
+
</clipPath>
|
|
56
|
+
<clipPath id="terminal-2014532663-line-3">
|
|
57
|
+
<rect x="0" y="74.7" width="976" height="24.65"/>
|
|
58
|
+
</clipPath>
|
|
59
|
+
<clipPath id="terminal-2014532663-line-4">
|
|
60
|
+
<rect x="0" y="99.1" width="976" height="24.65"/>
|
|
61
|
+
</clipPath>
|
|
62
|
+
<clipPath id="terminal-2014532663-line-5">
|
|
63
|
+
<rect x="0" y="123.5" width="976" height="24.65"/>
|
|
64
|
+
</clipPath>
|
|
65
|
+
<clipPath id="terminal-2014532663-line-6">
|
|
66
|
+
<rect x="0" y="147.9" width="976" height="24.65"/>
|
|
67
|
+
</clipPath>
|
|
68
|
+
<clipPath id="terminal-2014532663-line-7">
|
|
69
|
+
<rect x="0" y="172.3" width="976" height="24.65"/>
|
|
70
|
+
</clipPath>
|
|
71
|
+
</defs>
|
|
72
|
+
|
|
73
|
+
<rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" x="1" y="1" width="992" height="267.6" rx="8"/><text class="terminal-2014532663-title" fill="#c5c8c6" text-anchor="middle" x="496" y="27">ab free --nodes</text>
|
|
74
|
+
<g transform="translate(26,22)">
|
|
75
|
+
<circle cx="0" cy="0" r="7" fill="#ff5f57"/>
|
|
76
|
+
<circle cx="22" cy="0" r="7" fill="#febc2e"/>
|
|
77
|
+
<circle cx="44" cy="0" r="7" fill="#28c840"/>
|
|
78
|
+
</g>
|
|
79
|
+
|
|
80
|
+
<g transform="translate(9, 41)" clip-path="url(#terminal-2014532663-clip-terminal)">
|
|
81
|
+
|
|
82
|
+
<g class="terminal-2014532663-matrix">
|
|
83
|
+
<text class="terminal-2014532663-r1" x="0" y="20" textLength="756.4" clip-path="url(#terminal-2014532663-line-0)">                          GPU nodes                           </text><text class="terminal-2014532663-r2" x="976" y="20" textLength="12.2" clip-path="url(#terminal-2014532663-line-0)">
|
|
84
|
+
</text><text class="terminal-2014532663-r1" x="0" y="44.4" textLength="73.2" clip-path="url(#terminal-2014532663-line-1)">Node  </text><text class="terminal-2014532663-r1" x="109.8" y="44.4" textLength="109.8" clip-path="url(#terminal-2014532663-line-1)">State    </text><text class="terminal-2014532663-r1" x="256.2" y="44.4" textLength="61" clip-path="url(#terminal-2014532663-line-1)">A5000</text><text class="terminal-2014532663-r1" x="353.8" y="44.4" textLength="85.4" clip-path="url(#terminal-2014532663-line-1)">GTX1080</text><text class="terminal-2014532663-r1" x="475.8" y="44.4" textLength="109.8" clip-path="url(#terminal-2014532663-line-1)">Free CPUs</text><text class="terminal-2014532663-r1" x="622.2" y="44.4" textLength="134.2" clip-path="url(#terminal-2014532663-line-1)">Free memory</text><text class="terminal-2014532663-r2" x="976" y="44.4" textLength="12.2" clip-path="url(#terminal-2014532663-line-1)">
|
|
85
|
+
</text><text class="terminal-2014532663-r2" x="0" y="68.8" textLength="756.4" clip-path="url(#terminal-2014532663-line-2)">──────────────────────────────────────────────────────────────</text><text class="terminal-2014532663-r2" x="976" y="68.8" textLength="12.2" clip-path="url(#terminal-2014532663-line-2)">
|
|
86
|
+
</text><text class="terminal-2014532663-r3" x="0" y="93.2" textLength="73.2" clip-path="url(#terminal-2014532663-line-3)">gpu102</text><text class="terminal-2014532663-r3" x="109.8" y="93.2" textLength="109.8" clip-path="url(#terminal-2014532663-line-3)">IDLE     </text><text class="terminal-2014532663-r3" x="280.6" y="93.2" textLength="12.2" clip-path="url(#terminal-2014532663-line-3)">4</text><text class="terminal-2014532663-r4" x="292.8" y="93.2" textLength="12.2" clip-path="url(#terminal-2014532663-line-3)">/</text><text class="terminal-2014532663-r4" x="305" y="93.2" textLength="12.2" clip-path="url(#terminal-2014532663-line-3)">4</text><text class="terminal-2014532663-r4" x="353.8" y="93.2" textLength="85.4" clip-path="url(#terminal-2014532663-line-3)">      -</text><text class="terminal-2014532663-r3" x="524.6" y="93.2" textLength="24.4" clip-path="url(#terminal-2014532663-line-3)">16</text><text class="terminal-2014532663-r4" x="549" y="93.2" textLength="12.2" clip-path="url(#terminal-2014532663-line-3)">/</text><text class="terminal-2014532663-r4" x="561.2" y="93.2" textLength="24.4" clip-path="url(#terminal-2014532663-line-3)">16</text><text class="terminal-2014532663-r3" x="683.2" y="93.2" textLength="24.4" clip-path="url(#terminal-2014532663-line-3)">90</text><text class="terminal-2014532663-r4" x="707.6" y="93.2" textLength="12.2" clip-path="url(#terminal-2014532663-line-3)">/</text><text class="terminal-2014532663-r4" x="719.8" y="93.2" textLength="24.4" clip-path="url(#terminal-2014532663-line-3)">90</text><text class="terminal-2014532663-r4" x="744.2" y="93.2" textLength="12.2" clip-path="url(#terminal-2014532663-line-3)">G</text><text class="terminal-2014532663-r2" x="976" y="93.2" textLength="12.2" clip-path="url(#terminal-2014532663-line-3)">
|
|
87
|
+
</text><text class="terminal-2014532663-r3" x="0" y="117.6" textLength="73.2" clip-path="url(#terminal-2014532663-line-4)">gpu101</text><text class="terminal-2014532663-r5" x="109.8" y="117.6" textLength="109.8" clip-path="url(#terminal-2014532663-line-4)">MIXED    </text><text class="terminal-2014532663-r5" x="280.6" y="117.6" textLength="12.2" clip-path="url(#terminal-2014532663-line-4)">3</text><text class="terminal-2014532663-r4" x="292.8" y="117.6" textLength="12.2" clip-path="url(#terminal-2014532663-line-4)">/</text><text class="terminal-2014532663-r4" x="305" y="117.6" textLength="12.2" clip-path="url(#terminal-2014532663-line-4)">4</text><text class="terminal-2014532663-r4" x="353.8" y="117.6" textLength="85.4" clip-path="url(#terminal-2014532663-line-4)">      -</text><text class="terminal-2014532663-r3" x="524.6" y="117.6" textLength="24.4" clip-path="url(#terminal-2014532663-line-4)">12</text><text class="terminal-2014532663-r4" x="549" y="117.6" textLength="12.2" clip-path="url(#terminal-2014532663-line-4)">/</text><text class="terminal-2014532663-r4" x="561.2" y="117.6" textLength="24.4" clip-path="url(#terminal-2014532663-line-4)">16</text><text class="terminal-2014532663-r3" x="683.2" y="117.6" textLength="24.4" clip-path="url(#terminal-2014532663-line-4)">90</text><text class="terminal-2014532663-r4" x="707.6" y="117.6" textLength="12.2" clip-path="url(#terminal-2014532663-line-4)">/</text><text class="terminal-2014532663-r4" x="719.8" y="117.6" textLength="24.4" clip-path="url(#terminal-2014532663-line-4)">90</text><text class="terminal-2014532663-r4" x="744.2" y="117.6" textLength="12.2" clip-path="url(#terminal-2014532663-line-4)">G</text><text class="terminal-2014532663-r2" x="976" y="117.6" textLength="12.2" clip-path="url(#terminal-2014532663-line-4)">
|
|
88
|
+
</text><text class="terminal-2014532663-r3" x="0" y="142" textLength="73.2" clip-path="url(#terminal-2014532663-line-5)">gpu201</text><text class="terminal-2014532663-r6" x="109.8" y="142" textLength="109.8" clip-path="url(#terminal-2014532663-line-5)">ALLOCATED</text><text class="terminal-2014532663-r4" x="256.2" y="142" textLength="61" clip-path="url(#terminal-2014532663-line-5)">    -</text><text class="terminal-2014532663-r4" x="402.6" y="142" textLength="12.2" clip-path="url(#terminal-2014532663-line-5)">0</text><text class="terminal-2014532663-r4" x="414.8" y="142" textLength="12.2" clip-path="url(#terminal-2014532663-line-5)">/</text><text class="terminal-2014532663-r4" x="427" y="142" textLength="12.2" clip-path="url(#terminal-2014532663-line-5)">4</text><text class="terminal-2014532663-r4" x="536.8" y="142" textLength="12.2" clip-path="url(#terminal-2014532663-line-5)">0</text><text class="terminal-2014532663-r4" x="549" y="142" textLength="12.2" clip-path="url(#terminal-2014532663-line-5)">/</text><text class="terminal-2014532663-r4" x="561.2" y="142" textLength="24.4" clip-path="url(#terminal-2014532663-line-5)">16</text><text class="terminal-2014532663-r3" x="683.2" y="142" textLength="24.4" clip-path="url(#terminal-2014532663-line-5)">90</text><text class="terminal-2014532663-r4" x="707.6" y="142" textLength="12.2" clip-path="url(#terminal-2014532663-line-5)">/</text><text class="terminal-2014532663-r4" x="719.8" y="142" textLength="24.4" clip-path="url(#terminal-2014532663-line-5)">90</text><text class="terminal-2014532663-r4" x="744.2" y="142" textLength="12.2" clip-path="url(#terminal-2014532663-line-5)">G</text><text class="terminal-2014532663-r2" x="976" y="142" textLength="12.2" clip-path="url(#terminal-2014532663-line-5)">
|
|
89
|
+
</text><text class="terminal-2014532663-r2" x="976" y="166.4" textLength="12.2" clip-path="url(#terminal-2014532663-line-6)">
|
|
90
|
+
</text><text class="terminal-2014532663-r1" x="0" y="190.8" textLength="73.2" clip-path="url(#terminal-2014532663-line-7)">total </text><text class="terminal-2014532663-r3" x="280.6" y="190.8" textLength="12.2" clip-path="url(#terminal-2014532663-line-7)">7</text><text class="terminal-2014532663-r4" x="292.8" y="190.8" textLength="12.2" clip-path="url(#terminal-2014532663-line-7)">/</text><text class="terminal-2014532663-r4" x="305" y="190.8" textLength="12.2" clip-path="url(#terminal-2014532663-line-7)">8</text><text class="terminal-2014532663-r4" x="402.6" y="190.8" textLength="12.2" clip-path="url(#terminal-2014532663-line-7)">0</text><text class="terminal-2014532663-r4" x="414.8" y="190.8" textLength="12.2" clip-path="url(#terminal-2014532663-line-7)">/</text><text class="terminal-2014532663-r4" x="427" y="190.8" textLength="12.2" clip-path="url(#terminal-2014532663-line-7)">4</text><text class="terminal-2014532663-r3" x="524.6" y="190.8" textLength="24.4" clip-path="url(#terminal-2014532663-line-7)">28</text><text class="terminal-2014532663-r4" x="549" y="190.8" textLength="12.2" clip-path="url(#terminal-2014532663-line-7)">/</text><text class="terminal-2014532663-r4" x="561.2" y="190.8" textLength="24.4" clip-path="url(#terminal-2014532663-line-7)">48</text><text class="terminal-2014532663-r3" x="658.8" y="190.8" textLength="36.6" clip-path="url(#terminal-2014532663-line-7)">270</text><text class="terminal-2014532663-r4" x="695.4" y="190.8" textLength="12.2" clip-path="url(#terminal-2014532663-line-7)">/</text><text class="terminal-2014532663-r4" x="707.6" y="190.8" textLength="36.6" clip-path="url(#terminal-2014532663-line-7)">270</text><text class="terminal-2014532663-r4" x="744.2" y="190.8" textLength="12.2" clip-path="url(#terminal-2014532663-line-7)">G</text><text class="terminal-2014532663-r2" x="976" y="190.8" textLength="12.2" clip-path="url(#terminal-2014532663-line-7)">
|
|
91
|
+
</text><text class="terminal-2014532663-r4" x="0" y="215.2" textLength="122" clip-path="url(#terminal-2014532663-line-8)">free/total</text><text class="terminal-2014532663-r2" x="976" y="215.2" textLength="12.2" clip-path="url(#terminal-2014532663-line-8)">
|
|
92
|
+
</text>
|
|
93
|
+
</g>
|
|
94
|
+
</g>
|
|
95
|
+
</svg>
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
<svg class="rich-terminal" viewBox="0 0 1092 196.39999999999998" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<!-- Generated with Rich https://www.textualize.io -->
|
|
3
|
+
<style>
|
|
4
|
+
|
|
5
|
+
@font-face {
|
|
6
|
+
font-family: "Fira Code";
|
|
7
|
+
src: local("FiraCode-Regular"),
|
|
8
|
+
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Regular.woff2") format("woff2"),
|
|
9
|
+
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Regular.woff") format("woff");
|
|
10
|
+
font-style: normal;
|
|
11
|
+
font-weight: 400;
|
|
12
|
+
}
|
|
13
|
+
@font-face {
|
|
14
|
+
font-family: "Fira Code";
|
|
15
|
+
src: local("FiraCode-Bold"),
|
|
16
|
+
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Bold.woff2") format("woff2"),
|
|
17
|
+
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Bold.woff") format("woff");
|
|
18
|
+
font-style: bold;
|
|
19
|
+
font-weight: 700;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.terminal-1079823974-matrix {
|
|
23
|
+
font-family: Fira Code, monospace;
|
|
24
|
+
font-size: 20px;
|
|
25
|
+
line-height: 24.4px;
|
|
26
|
+
font-variant-east-asian: full-width;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.terminal-1079823974-title {
|
|
30
|
+
font-size: 18px;
|
|
31
|
+
font-weight: bold;
|
|
32
|
+
font-family: arial;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.terminal-1079823974-r1 { fill: #c5c8c6;font-weight: bold }
|
|
36
|
+
.terminal-1079823974-r2 { fill: #c5c8c6 }
|
|
37
|
+
.terminal-1079823974-r3 { fill: #68a0b3 }
|
|
38
|
+
.terminal-1079823974-r4 { fill: #98a84b;font-weight: bold }
|
|
39
|
+
.terminal-1079823974-r5 { fill: #98a84b }
|
|
40
|
+
.terminal-1079823974-r6 { fill: #d0b344;font-weight: bold }
|
|
41
|
+
.terminal-1079823974-r7 { fill: #d0b344 }
|
|
42
|
+
.terminal-1079823974-r8 { fill: #868887 }
|
|
43
|
+
</style>
|
|
44
|
+
|
|
45
|
+
<defs>
|
|
46
|
+
<clipPath id="terminal-1079823974-clip-terminal">
|
|
47
|
+
<rect x="0" y="0" width="1072.6" height="145.39999999999998" />
|
|
48
|
+
</clipPath>
|
|
49
|
+
<clipPath id="terminal-1079823974-line-0">
|
|
50
|
+
<rect x="0" y="1.5" width="1073.6" height="24.65"/>
|
|
51
|
+
</clipPath>
|
|
52
|
+
<clipPath id="terminal-1079823974-line-1">
|
|
53
|
+
<rect x="0" y="25.9" width="1073.6" height="24.65"/>
|
|
54
|
+
</clipPath>
|
|
55
|
+
<clipPath id="terminal-1079823974-line-2">
|
|
56
|
+
<rect x="0" y="50.3" width="1073.6" height="24.65"/>
|
|
57
|
+
</clipPath>
|
|
58
|
+
<clipPath id="terminal-1079823974-line-3">
|
|
59
|
+
<rect x="0" y="74.7" width="1073.6" height="24.65"/>
|
|
60
|
+
</clipPath>
|
|
61
|
+
<clipPath id="terminal-1079823974-line-4">
|
|
62
|
+
<rect x="0" y="99.1" width="1073.6" height="24.65"/>
|
|
63
|
+
</clipPath>
|
|
64
|
+
</defs>
|
|
65
|
+
|
|
66
|
+
<rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" x="1" y="1" width="1090" height="194.4" rx="8"/><text class="terminal-1079823974-title" fill="#c5c8c6" text-anchor="middle" x="545" y="27">ab queue</text>
|
|
67
|
+
<g transform="translate(26,22)">
|
|
68
|
+
<circle cx="0" cy="0" r="7" fill="#ff5f57"/>
|
|
69
|
+
<circle cx="22" cy="0" r="7" fill="#febc2e"/>
|
|
70
|
+
<circle cx="44" cy="0" r="7" fill="#28c840"/>
|
|
71
|
+
</g>
|
|
72
|
+
|
|
73
|
+
<g transform="translate(9, 41)" clip-path="url(#terminal-1079823974-clip-terminal)">
|
|
74
|
+
|
|
75
|
+
<g class="terminal-1079823974-matrix">
|
|
76
|
+
<text class="terminal-1079823974-r1" x="0" y="20" textLength="1037" clip-path="url(#terminal-1079823974-line-0)">                                        Queue                                        </text><text class="terminal-1079823974-r2" x="1073.6" y="20" textLength="12.2" clip-path="url(#terminal-1079823974-line-0)">
|
|
77
|
+
</text><text class="terminal-1079823974-r1" x="0" y="44.4" textLength="61" clip-path="url(#terminal-1079823974-line-1)">JobID</text><text class="terminal-1079823974-r1" x="97.6" y="44.4" textLength="61" clip-path="url(#terminal-1079823974-line-1)">Name </text><text class="terminal-1079823974-r1" x="195.2" y="44.4" textLength="85.4" clip-path="url(#terminal-1079823974-line-1)">State  </text><text class="terminal-1079823974-r1" x="317.2" y="44.4" textLength="109.8" clip-path="url(#terminal-1079823974-line-1)">Partition</text><text class="terminal-1079823974-r1" x="463.6" y="44.4" textLength="109.8" clip-path="url(#terminal-1079823974-line-1)">Time left</text><text class="terminal-1079823974-r1" x="610" y="44.4" textLength="97.6" clip-path="url(#terminal-1079823974-line-1)">Start   </text><text class="terminal-1079823974-r1" x="744.2" y="44.4" textLength="292.8" clip-path="url(#terminal-1079823974-line-1)">Node/Reason             </text><text class="terminal-1079823974-r2" x="1073.6" y="44.4" textLength="12.2" clip-path="url(#terminal-1079823974-line-1)">
|
|
78
|
+
</text><text class="terminal-1079823974-r2" x="0" y="68.8" textLength="1037" clip-path="url(#terminal-1079823974-line-2)">─────────────────────────────────────────────────────────────────────────────────────</text><text class="terminal-1079823974-r2" x="1073.6" y="68.8" textLength="12.2" clip-path="url(#terminal-1079823974-line-2)">
|
|
79
|
+
</text><text class="terminal-1079823974-r3" x="0" y="93.2" textLength="61" clip-path="url(#terminal-1079823974-line-3)">64612</text><text class="terminal-1079823974-r2" x="97.6" y="93.2" textLength="61" clip-path="url(#terminal-1079823974-line-3)">train</text><text class="terminal-1079823974-r4" x="195.2" y="93.2" textLength="85.4" clip-path="url(#terminal-1079823974-line-3)">RUNNING</text><text class="terminal-1079823974-r4" x="317.2" y="93.2" textLength="109.8" clip-path="url(#terminal-1079823974-line-3)">gpu      </text><text class="terminal-1079823974-r2" x="463.6" y="93.2" textLength="109.8" clip-path="url(#terminal-1079823974-line-3)">    6h57m</text><text class="terminal-1079823974-r5" x="744.2" y="93.2" textLength="292.8" clip-path="url(#terminal-1079823974-line-3)">gpu081                  </text><text class="terminal-1079823974-r2" x="1073.6" y="93.2" textLength="12.2" clip-path="url(#terminal-1079823974-line-3)">
|
|
80
|
+
</text><text class="terminal-1079823974-r3" x="0" y="117.6" textLength="61" clip-path="url(#terminal-1079823974-line-4)">64613</text><text class="terminal-1079823974-r2" x="97.6" y="117.6" textLength="61" clip-path="url(#terminal-1079823974-line-4)">eval </text><text class="terminal-1079823974-r6" x="195.2" y="117.6" textLength="85.4" clip-path="url(#terminal-1079823974-line-4)">PENDING</text><text class="terminal-1079823974-r4" x="317.2" y="117.6" textLength="109.8" clip-path="url(#terminal-1079823974-line-4)">gpu      </text><text class="terminal-1079823974-r2" x="463.6" y="117.6" textLength="109.8" clip-path="url(#terminal-1079823974-line-4)">       8h</text><text class="terminal-1079823974-r2" x="610" y="117.6" textLength="97.6" clip-path="url(#terminal-1079823974-line-4)">in 2h10m</text><text class="terminal-1079823974-r7" x="744.2" y="117.6" textLength="292.8" clip-path="url(#terminal-1079823974-line-4)">GPU-bound · max 2/4 free</text><text class="terminal-1079823974-r2" x="1073.6" y="117.6" textLength="12.2" clip-path="url(#terminal-1079823974-line-4)">
|
|
81
|
+
</text><text class="terminal-1079823974-r8" x="0" y="142" textLength="671" clip-path="url(#terminal-1079823974-line-5)">ⓘ `ab why` shows what is short and what would start now</text><text class="terminal-1079823974-r2" x="1073.6" y="142" textLength="12.2" clip-path="url(#terminal-1079823974-line-5)">
|
|
82
|
+
</text>
|
|
83
|
+
</g>
|
|
84
|
+
</g>
|
|
85
|
+
</svg>
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
<svg class="rich-terminal" viewBox="0 0 994 147.6" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<!-- Generated with Rich https://www.textualize.io -->
|
|
3
|
+
<style>
|
|
4
|
+
|
|
5
|
+
@font-face {
|
|
6
|
+
font-family: "Fira Code";
|
|
7
|
+
src: local("FiraCode-Regular"),
|
|
8
|
+
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Regular.woff2") format("woff2"),
|
|
9
|
+
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Regular.woff") format("woff");
|
|
10
|
+
font-style: normal;
|
|
11
|
+
font-weight: 400;
|
|
12
|
+
}
|
|
13
|
+
@font-face {
|
|
14
|
+
font-family: "Fira Code";
|
|
15
|
+
src: local("FiraCode-Bold"),
|
|
16
|
+
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff2/FiraCode-Bold.woff2") format("woff2"),
|
|
17
|
+
url("https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/woff/FiraCode-Bold.woff") format("woff");
|
|
18
|
+
font-style: bold;
|
|
19
|
+
font-weight: 700;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.terminal-3157129480-matrix {
|
|
23
|
+
font-family: Fira Code, monospace;
|
|
24
|
+
font-size: 20px;
|
|
25
|
+
line-height: 24.4px;
|
|
26
|
+
font-variant-east-asian: full-width;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.terminal-3157129480-title {
|
|
30
|
+
font-size: 18px;
|
|
31
|
+
font-weight: bold;
|
|
32
|
+
font-family: arial;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.terminal-3157129480-r1 { fill: #68a0b3 }
|
|
36
|
+
.terminal-3157129480-r2 { fill: #c5c8c6 }
|
|
37
|
+
.terminal-3157129480-r3 { fill: #608ab1;font-weight: bold }
|
|
38
|
+
.terminal-3157129480-r4 { fill: #868887 }
|
|
39
|
+
.terminal-3157129480-r5 { fill: #d0b344 }
|
|
40
|
+
.terminal-3157129480-r6 { fill: #98a84b;font-weight: bold }
|
|
41
|
+
.terminal-3157129480-r7 { fill: #68a0b3;font-weight: bold }
|
|
42
|
+
</style>
|
|
43
|
+
|
|
44
|
+
<defs>
|
|
45
|
+
<clipPath id="terminal-3157129480-clip-terminal">
|
|
46
|
+
<rect x="0" y="0" width="975.0" height="96.6" />
|
|
47
|
+
</clipPath>
|
|
48
|
+
<clipPath id="terminal-3157129480-line-0">
|
|
49
|
+
<rect x="0" y="1.5" width="976" height="24.65"/>
|
|
50
|
+
</clipPath>
|
|
51
|
+
<clipPath id="terminal-3157129480-line-1">
|
|
52
|
+
<rect x="0" y="25.9" width="976" height="24.65"/>
|
|
53
|
+
</clipPath>
|
|
54
|
+
<clipPath id="terminal-3157129480-line-2">
|
|
55
|
+
<rect x="0" y="50.3" width="976" height="24.65"/>
|
|
56
|
+
</clipPath>
|
|
57
|
+
</defs>
|
|
58
|
+
|
|
59
|
+
<rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" x="1" y="1" width="992" height="145.6" rx="8"/><text class="terminal-3157129480-title" fill="#c5c8c6" text-anchor="middle" x="496" y="27">ab why 64267</text>
|
|
60
|
+
<g transform="translate(26,22)">
|
|
61
|
+
<circle cx="0" cy="0" r="7" fill="#ff5f57"/>
|
|
62
|
+
<circle cx="22" cy="0" r="7" fill="#febc2e"/>
|
|
63
|
+
<circle cx="44" cy="0" r="7" fill="#28c840"/>
|
|
64
|
+
</g>
|
|
65
|
+
|
|
66
|
+
<g transform="translate(9, 41)" clip-path="url(#terminal-3157129480-clip-terminal)">
|
|
67
|
+
|
|
68
|
+
<g class="terminal-3157129480-matrix">
|
|
69
|
+
<text class="terminal-3157129480-r1" x="0" y="20" textLength="170.8" clip-path="url(#terminal-3157129480-line-0)">64267_[50-142]</text><text class="terminal-3157129480-r3" x="195.2" y="20" textLength="36.6" clip-path="url(#terminal-3157129480-line-0)">big</text><text class="terminal-3157129480-r2" x="231.8" y="20" textLength="158.6" clip-path="url(#terminal-3157129480-line-0)">  4 CPU · 56G</text><text class="terminal-3157129480-r4" x="390.4" y="20" textLength="146.4" clip-path="url(#terminal-3157129480-line-0)">  (93 tasks)</text><text class="terminal-3157129480-r2" x="976" y="20" textLength="12.2" clip-path="url(#terminal-3157129480-line-0)">
|
|
70
|
+
</text><text class="terminal-3157129480-r2" x="0" y="44.4" textLength="170.8" clip-path="url(#terminal-3157129480-line-1)">  waiting for </text><text class="terminal-3157129480-r5" x="170.8" y="44.4" textLength="73.2" clip-path="url(#terminal-3157129480-line-1)">memory</text><text class="terminal-3157129480-r2" x="244" y="44.4" textLength="134.2" clip-path="url(#terminal-3157129480-line-1)"> to free up</text><text class="terminal-3157129480-r2" x="976" y="44.4" textLength="12.2" clip-path="url(#terminal-3157129480-line-1)">
|
|
71
|
+
</text><text class="terminal-3157129480-r6" x="24.4" y="68.8" textLength="195.2" clip-path="url(#terminal-3157129480-line-2)">starts now with </text><text class="terminal-3157129480-r7" x="219.6" y="68.8" textLength="183" clip-path="url(#terminal-3157129480-line-2)">--mem 56G → 32G</text><text class="terminal-3157129480-r2" x="976" y="68.8" textLength="12.2" clip-path="url(#terminal-3157129480-line-2)">
|
|
72
|
+
</text><text class="terminal-3157129480-r4" x="0" y="93.2" textLength="671" clip-path="url(#terminal-3157129480-line-3)">ⓘ `ab why 64267 --fix` changes the job so it starts now</text><text class="terminal-3157129480-r2" x="976" y="93.2" textLength="12.2" clip-path="url(#terminal-3157129480-line-3)">
|
|
73
|
+
</text>
|
|
74
|
+
</g>
|
|
75
|
+
</g>
|
|
76
|
+
</svg>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
paths:
|
|
7
|
+
- 'src/**'
|
|
8
|
+
- 'tests/**'
|
|
9
|
+
- 'pyproject.toml'
|
|
10
|
+
- 'uv.lock'
|
|
11
|
+
- 'scripts/**'
|
|
12
|
+
- '.gitattributes'
|
|
13
|
+
- '.github/workflows/ci.yml'
|
|
14
|
+
pull_request:
|
|
15
|
+
types: [opened, synchronize, reopened, ready_for_review]
|
|
16
|
+
paths:
|
|
17
|
+
- 'src/**'
|
|
18
|
+
- 'tests/**'
|
|
19
|
+
- 'pyproject.toml'
|
|
20
|
+
- 'uv.lock'
|
|
21
|
+
- 'scripts/**'
|
|
22
|
+
- '.gitattributes'
|
|
23
|
+
- '.github/workflows/ci.yml'
|
|
24
|
+
|
|
25
|
+
# A new push to the same branch/PR cancels the run still in progress.
|
|
26
|
+
concurrency:
|
|
27
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
28
|
+
cancel-in-progress: true
|
|
29
|
+
|
|
30
|
+
permissions:
|
|
31
|
+
contents: read
|
|
32
|
+
|
|
33
|
+
jobs:
|
|
34
|
+
test:
|
|
35
|
+
# Draft PRs get no CI; run the checks locally before marking a PR ready.
|
|
36
|
+
if: github.event.pull_request.draft != true
|
|
37
|
+
runs-on: ubuntu-latest
|
|
38
|
+
timeout-minutes: 10
|
|
39
|
+
strategy:
|
|
40
|
+
matrix:
|
|
41
|
+
# Oldest supported and newest only; versions in between add cost, not coverage.
|
|
42
|
+
python: ['3.10', '3.13']
|
|
43
|
+
steps:
|
|
44
|
+
- uses: actions/checkout@v4
|
|
45
|
+
- uses: astral-sh/setup-uv@v6
|
|
46
|
+
with:
|
|
47
|
+
python-version: ${{ matrix.python }}
|
|
48
|
+
enable-cache: true
|
|
49
|
+
- run: uv sync --locked
|
|
50
|
+
- if: matrix.python == '3.10'
|
|
51
|
+
run: uv run ruff check .
|
|
52
|
+
- run: uv run pytest -q
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
name: PyPI
|
|
2
|
+
|
|
3
|
+
# Runs only in the public repo, on the release that release.yml creates there, so
|
|
4
|
+
# the sdist holds only the public snapshot and the PyPI provenance names the public
|
|
5
|
+
# repo. Uses PyPI Trusted Publishing (no token): the PyPI project trusts
|
|
6
|
+
# Grutschus/allegro-buddy, workflow pypi.yml, environment pypi.
|
|
7
|
+
on:
|
|
8
|
+
release:
|
|
9
|
+
types: [published]
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
build:
|
|
16
|
+
if: github.repository == 'Grutschus/allegro-buddy'
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
timeout-minutes: 5
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v4
|
|
21
|
+
- uses: astral-sh/setup-uv@v6
|
|
22
|
+
- run: uv build
|
|
23
|
+
- uses: actions/upload-artifact@v4
|
|
24
|
+
with:
|
|
25
|
+
name: dist
|
|
26
|
+
path: dist/
|
|
27
|
+
|
|
28
|
+
# Separate job so a required reviewer on the pypi environment can download and
|
|
29
|
+
# inspect the dist artifact before approving the upload.
|
|
30
|
+
publish:
|
|
31
|
+
needs: build
|
|
32
|
+
runs-on: ubuntu-latest
|
|
33
|
+
timeout-minutes: 5
|
|
34
|
+
environment:
|
|
35
|
+
name: pypi
|
|
36
|
+
url: https://pypi.org/project/allegro-buddy/
|
|
37
|
+
permissions:
|
|
38
|
+
id-token: write
|
|
39
|
+
steps:
|
|
40
|
+
- uses: actions/download-artifact@v4
|
|
41
|
+
with:
|
|
42
|
+
name: dist
|
|
43
|
+
path: dist/
|
|
44
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Grutschus
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: allegro-buddy
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A friendly Slurm helper, with presets for the Allegro cluster.
|
|
5
|
+
Project-URL: Source, https://github.com/Grutschus/allegro-buddy
|
|
6
|
+
Author: Grutschus
|
|
7
|
+
License: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Requires-Python: >=3.10
|
|
10
|
+
Requires-Dist: click>=8.1.7
|
|
11
|
+
Requires-Dist: rich-click>=1.9
|
|
12
|
+
Requires-Dist: rich>=13.0.0
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
|
|
15
|
+
# allegro-buddy
|
|
16
|
+
|
|
17
|
+
A small Slurm companion for everyday cluster work: what is free, why your job is
|
|
18
|
+
waiting, and a dev node in one command. It reads what it needs from Slurm, so it
|
|
19
|
+
works beyond the Allegro cluster it was born on.
|
|
20
|
+
|
|
21
|
+
<img src="https://raw.githubusercontent.com/Grutschus/allegro-buddy/main/.github/assets/queue.svg" alt="ab queue: your jobs, start estimates and why pending jobs wait">
|
|
22
|
+
|
|
23
|
+
## Install
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
uv tool install allegro-buddy # or: pip install allegro-buddy
|
|
27
|
+
ab completion --install # optional: tab completion
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
This installs two equal commands, `ab` and `allegro-buddy`. Upgrade with
|
|
31
|
+
`uv tool upgrade allegro-buddy`.
|
|
32
|
+
|
|
33
|
+
## Commands
|
|
34
|
+
|
|
35
|
+
| Command | What it does |
|
|
36
|
+
| --- | --- |
|
|
37
|
+
| `ab info` | Partitions you can use, with free CPUs, memory and GPUs |
|
|
38
|
+
| `ab free [--nodes] [-G a5000]` | Free GPUs by type, per partition or per node |
|
|
39
|
+
| `ab q [--all] [-w]` | Your queue, with start estimates and what pending jobs lack |
|
|
40
|
+
| `ab why [JOBID] [--fix]` | Why a job waits, and the one change that starts it now |
|
|
41
|
+
| `ab node [NODE]` | Which jobs use a node's GPUs, CPUs and memory, and for how long |
|
|
42
|
+
| `ab dev start / login / status / stop` | A detached dev allocation; `ab l` logs in |
|
|
43
|
+
| `ab job history / output` | Your finished jobs and their output |
|
|
44
|
+
| `ab config show` | Every setting and where it came from |
|
|
45
|
+
|
|
46
|
+
Every command has `-h`.
|
|
47
|
+
|
|
48
|
+
### Why is my job waiting?
|
|
49
|
+
|
|
50
|
+
<img src="https://raw.githubusercontent.com/Grutschus/allegro-buddy/main/.github/assets/why.svg" alt="ab why: what a pending job waits for and the change that starts it now">
|
|
51
|
+
|
|
52
|
+
`ab why JOBID --fix` applies the suggested change after asking. It only touches
|
|
53
|
+
your own pending jobs and never lowers the GPU count unless you pass `--fix gpus`.
|
|
54
|
+
|
|
55
|
+
### What is free?
|
|
56
|
+
|
|
57
|
+
<img src="https://raw.githubusercontent.com/Grutschus/allegro-buddy/main/.github/assets/free.svg" alt="ab free --nodes: free GPUs, CPUs and memory per node">
|
|
58
|
+
|
|
59
|
+
### Dev nodes
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
ab dev start --gpu 1 --gpu-type a5000 # waits until running, then shows how to log in
|
|
63
|
+
ab l # ssh into it (--srun where SSH is blocked)
|
|
64
|
+
ab dev stop
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Configuration
|
|
68
|
+
|
|
69
|
+
Slurm tells allegro-buddy which partitions have GPUs, which GPU types exist and
|
|
70
|
+
which partition is the default. A config file only fills in the rest, such as
|
|
71
|
+
your own `ab dev start` defaults:
|
|
72
|
+
|
|
73
|
+
```ini
|
|
74
|
+
# ~/.config/allegro-buddy/config.ini
|
|
75
|
+
[dev]
|
|
76
|
+
gpu = 1
|
|
77
|
+
gpu-type = a5000
|
|
78
|
+
cpus = 8
|
|
79
|
+
mem = 32G
|
|
80
|
+
time = 04:00:00
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Values come from, highest first: command-line flags, your user file, a site file
|
|
84
|
+
(`$AB_SITE_CONFIG` or `/etc/allegro-buddy/config.ini`), a shipped cluster preset
|
|
85
|
+
(`allegro`, `bhlrn4`), then Slurm. The preset follows Slurm's `ClusterName`;
|
|
86
|
+
`AB_CLUSTER=none` turns it off. `ab config show` lists every value and its source.
|
|
87
|
+
|
|
88
|
+
## License
|
|
89
|
+
|
|
90
|
+
MIT, see [LICENSE](https://github.com/Grutschus/allegro-buddy/blob/main/LICENSE).
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# allegro-buddy
|
|
2
|
+
|
|
3
|
+
A small Slurm companion for everyday cluster work: what is free, why your job is
|
|
4
|
+
waiting, and a dev node in one command. It reads what it needs from Slurm, so it
|
|
5
|
+
works beyond the Allegro cluster it was born on.
|
|
6
|
+
|
|
7
|
+
<img src="https://raw.githubusercontent.com/Grutschus/allegro-buddy/main/.github/assets/queue.svg" alt="ab queue: your jobs, start estimates and why pending jobs wait">
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
uv tool install allegro-buddy # or: pip install allegro-buddy
|
|
13
|
+
ab completion --install # optional: tab completion
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
This installs two equal commands, `ab` and `allegro-buddy`. Upgrade with
|
|
17
|
+
`uv tool upgrade allegro-buddy`.
|
|
18
|
+
|
|
19
|
+
## Commands
|
|
20
|
+
|
|
21
|
+
| Command | What it does |
|
|
22
|
+
| --- | --- |
|
|
23
|
+
| `ab info` | Partitions you can use, with free CPUs, memory and GPUs |
|
|
24
|
+
| `ab free [--nodes] [-G a5000]` | Free GPUs by type, per partition or per node |
|
|
25
|
+
| `ab q [--all] [-w]` | Your queue, with start estimates and what pending jobs lack |
|
|
26
|
+
| `ab why [JOBID] [--fix]` | Why a job waits, and the one change that starts it now |
|
|
27
|
+
| `ab node [NODE]` | Which jobs use a node's GPUs, CPUs and memory, and for how long |
|
|
28
|
+
| `ab dev start / login / status / stop` | A detached dev allocation; `ab l` logs in |
|
|
29
|
+
| `ab job history / output` | Your finished jobs and their output |
|
|
30
|
+
| `ab config show` | Every setting and where it came from |
|
|
31
|
+
|
|
32
|
+
Every command has `-h`.
|
|
33
|
+
|
|
34
|
+
### Why is my job waiting?
|
|
35
|
+
|
|
36
|
+
<img src="https://raw.githubusercontent.com/Grutschus/allegro-buddy/main/.github/assets/why.svg" alt="ab why: what a pending job waits for and the change that starts it now">
|
|
37
|
+
|
|
38
|
+
`ab why JOBID --fix` applies the suggested change after asking. It only touches
|
|
39
|
+
your own pending jobs and never lowers the GPU count unless you pass `--fix gpus`.
|
|
40
|
+
|
|
41
|
+
### What is free?
|
|
42
|
+
|
|
43
|
+
<img src="https://raw.githubusercontent.com/Grutschus/allegro-buddy/main/.github/assets/free.svg" alt="ab free --nodes: free GPUs, CPUs and memory per node">
|
|
44
|
+
|
|
45
|
+
### Dev nodes
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
ab dev start --gpu 1 --gpu-type a5000 # waits until running, then shows how to log in
|
|
49
|
+
ab l # ssh into it (--srun where SSH is blocked)
|
|
50
|
+
ab dev stop
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Configuration
|
|
54
|
+
|
|
55
|
+
Slurm tells allegro-buddy which partitions have GPUs, which GPU types exist and
|
|
56
|
+
which partition is the default. A config file only fills in the rest, such as
|
|
57
|
+
your own `ab dev start` defaults:
|
|
58
|
+
|
|
59
|
+
```ini
|
|
60
|
+
# ~/.config/allegro-buddy/config.ini
|
|
61
|
+
[dev]
|
|
62
|
+
gpu = 1
|
|
63
|
+
gpu-type = a5000
|
|
64
|
+
cpus = 8
|
|
65
|
+
mem = 32G
|
|
66
|
+
time = 04:00:00
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Values come from, highest first: command-line flags, your user file, a site file
|
|
70
|
+
(`$AB_SITE_CONFIG` or `/etc/allegro-buddy/config.ini`), a shipped cluster preset
|
|
71
|
+
(`allegro`, `bhlrn4`), then Slurm. The preset follows Slurm's `ClusterName`;
|
|
72
|
+
`AB_CLUSTER=none` turns it off. `ab config show` lists every value and its source.
|
|
73
|
+
|
|
74
|
+
## License
|
|
75
|
+
|
|
76
|
+
MIT, see [LICENSE](https://github.com/Grutschus/allegro-buddy/blob/main/LICENSE).
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "allegro-buddy"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "A friendly Slurm helper, with presets for the Allegro cluster."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.10"
|
|
7
|
+
dependencies = [
|
|
8
|
+
"click>=8.1.7",
|
|
9
|
+
"rich>=13.0.0",
|
|
10
|
+
"rich-click>=1.9",
|
|
11
|
+
]
|
|
12
|
+
authors = [{ name = "Grutschus" }]
|
|
13
|
+
license = { text = "MIT" }
|
|
14
|
+
|
|
15
|
+
[project.urls]
|
|
16
|
+
Source = "https://github.com/Grutschus/allegro-buddy"
|
|
17
|
+
|
|
18
|
+
[project.scripts]
|
|
19
|
+
ab = "allegro_buddy.cli:main"
|
|
20
|
+
allegro-buddy = "allegro_buddy.cli:main"
|
|
21
|
+
|
|
22
|
+
[build-system]
|
|
23
|
+
requires = ["hatchling"]
|
|
24
|
+
build-backend = "hatchling.build"
|
|
25
|
+
|
|
26
|
+
[dependency-groups]
|
|
27
|
+
dev = ["pre-commit>=4.0.1", "ruff>=0.6.9", "ty>=0.0.34", "pytest>=8.0", "pytest-mock>=3.14", "pytest-cov>=5.0"]
|
|
28
|
+
|
|
29
|
+
[tool.pytest.ini_options]
|
|
30
|
+
testpaths = ["tests"]
|
|
31
|
+
addopts = "-v"
|
|
32
|
+
markers = [
|
|
33
|
+
"cluster: requires a running Slurm cluster (pass --cluster to enable)",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
[tool.hatch.build.targets.wheel]
|
|
37
|
+
packages = ["src/allegro_buddy"]
|
|
38
|
+
|
|
39
|
+
[tool.ruff]
|
|
40
|
+
line-length = 90
|
|
41
|
+
target-version = "py310"
|
|
42
|
+
|
|
43
|
+
[tool.ruff.format]
|
|
44
|
+
quote-style = "single"
|
|
45
|
+
line-ending = "lf"
|
|
46
|
+
indent-style = "space"
|
|
47
|
+
|
|
48
|
+
[tool.ruff.lint]
|
|
49
|
+
extend-select = ["B", "C4", "COM", "I", "RET", "RUF", "SIM", "TC", "UP"]
|
|
50
|
+
ignore = ["COM812"]
|
|
51
|
+
|
|
52
|
+
[tool.ty.environment]
|
|
53
|
+
python-version = "3.10"
|
|
54
|
+
|
|
55
|
+
[tool.ty.src]
|
|
56
|
+
# scripts/ is private tooling that imports tests via sys.path
|
|
57
|
+
exclude = ["scripts"]
|
|
58
|
+
|
|
59
|
+
[tool.uv]
|
|
60
|
+
default-groups = ["dev"]
|