fix(install,studio): address review round 5 (3 real of 10; 5 PS-5.1 claims disproven on hardware)
Real fixes:
- uninstall.ps1: scope the WSL process kill to argv referencing
/root/.unsloth/ (the fallback's install dir, which its Studio server,
llama-server, and build runner all reference) instead of the bare
'[l]lama-server' / '[u]nsloth_studio' name patterns -- uninstalling the
Windows shim must not kill a user's own unrelated llama.cpp server or a
/home Studio in a probed distro. Proven live: the path pattern matched
exactly the three fallback processes while a planted /tmp/llama-server
decoy matched the old pattern and not the new one. The backslash in
'/root/\.unslot[h]/' keeps the pattern from matching the cleanup
command's own argv.
- install.ps1: bridge UNSLOTH_LLAMA_TAG / UNSLOTH_LLAMA_PR into the
background CUDA-build runner -- the provisioner honors both pins, but
Windows env vars don't cross into WSL on their own, so a user's pin was
silently ignored by the deferred build. (Deliberately NOT forwarded into
the inner install.sh env: setup.sh skips its deferral when a PR pin is
visible there, which would CPU-build the pin in the foreground.)
- kernels/flex_attention.py: make _flex_is_dgx_spark() CUDA-free
(nvidia-smi device names, mirroring _is_dgx_spark_no_cuda_init) -- it
runs at module import and called torch.cuda.get_device_name(), which
initializes the CUDA allocator before patch_dgx_spark_memory_config()
can set PYTORCH_CUDA_ALLOC_CONF on exactly the Spark hosts it targets
(reachable via vision.py importing ..kernels before ._utils). Verified
on the N1X: detects the machine with torch.cuda.is_initialized() still
False.
- _utils.py: the TrainingArguments __post_init__ wrapper now forwards
*args/**kwargs (robustness against future InitVar signatures).
Disproven on hardware (no change): the five "high" PS-5.1 claims --
String.TrimEnd('\', '/') with multiple char args binds fine to
params char[] (verified on PS 5.1.28000.1737, and the uninstaller's PATH
cleanup using exactly that code ran successfully this same day), and
[Text.Encoding] resolves via the System namespace prefix (the background
build dispatch using it has run in every install this week). The worker
"_sp possibly undefined" claim is false: `import subprocess as _sp` is at
worker.py line 25.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
ccd5b30b7e
commit
5c2aefc6d1
4 changed files with 32 additions and 14 deletions
|
|
@ -1808,7 +1808,13 @@ shell.Run cmd, 0, False
|
|||
# pass only space-free args, avoiding Start-Process mis-splitting `bash -lc <str>`.
|
||||
$_pathLine = 'export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/lib/wsl/lib:$PATH"' + "`n"
|
||||
$_jobsLine = if ($env:UNSLOTH_LLAMA_BUILD_JOBS) { "export UNSLOTH_LLAMA_BUILD_JOBS=$($env:UNSLOTH_LLAMA_BUILD_JOBS)`n" } else { "" }
|
||||
$_runner = "#!/usr/bin/env bash`n" + $_pathLine + $_jobsLine + "exec bash /root/.unsloth/provision_llama_cuda.sh > /root/.unsloth/llama_cuda_build.log 2>&1`n"
|
||||
# Bridge llama.cpp pins into WSL: the provisioner honors UNSLOTH_LLAMA_TAG /
|
||||
# UNSLOTH_LLAMA_PR, but Windows env vars don't cross into WSL on their own --
|
||||
# without these exports a user's pin would be silently ignored by the
|
||||
# deferred background build. sh-single-quoted (tags/PRs are simple tokens).
|
||||
$_tagLine = if ($env:UNSLOTH_LLAMA_TAG) { "export UNSLOTH_LLAMA_TAG='$($env:UNSLOTH_LLAMA_TAG)'`n" } else { "" }
|
||||
$_prLine = if ($env:UNSLOTH_LLAMA_PR) { "export UNSLOTH_LLAMA_PR='$($env:UNSLOTH_LLAMA_PR)'`n" } else { "" }
|
||||
$_runner = "#!/usr/bin/env bash`n" + $_pathLine + $_jobsLine + $_tagLine + $_prLine + "exec bash /root/.unsloth/provision_llama_cuda.sh > /root/.unsloth/llama_cuda_build.log 2>&1`n"
|
||||
$_runnerB64 = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($_runner))
|
||||
$_fetchCmd = 'mkdir -p /root/.unsloth; if curl -fsSL "' + $_llamaUrl + '" -o /root/.unsloth/provision_llama_cuda.sh && [ -s /root/.unsloth/provision_llama_cuda.sh ]; then chmod +x /root/.unsloth/provision_llama_cuda.sh; echo ' + $_runnerB64 + ' | base64 -d > /root/.unsloth/run_llama_build.sh; chmod +x /root/.unsloth/run_llama_build.sh; echo PROV_FETCHED; else echo PROV_NOSCRIPT; fi'
|
||||
$_fetchOut = & wsl.exe -d $distro --cd /root -u root -- bash -lc $_fetchCmd 2>$null
|
||||
|
|
|
|||
|
|
@ -390,13 +390,17 @@ function Uninstall-UnslothStudio {
|
|||
# /root/.local/bin/unsloth symlink (its target under /root/.unsloth is gone but the link still
|
||||
# resolves on PATH). Scope STRICTLY to /root: the WoA fallback installs there (wsl -u root), so
|
||||
# touching /home/*/.unsloth would erase an unrelated WSL user's own Unsloth/cache that this
|
||||
# installer never created. pkill patterns use the [x]-regex self-exclusion trick: '[u]nsloth_studio'
|
||||
# keeps the shell's own argv from matching while real processes still match. Same for '[l]lama-server'.
|
||||
# installer never created.
|
||||
# The port-8888 kill is gated on an Unsloth install actually existing in the
|
||||
# distro (checked BEFORE the rm deletes the marker): a probed distro with an
|
||||
# unrelated listener on 8888 (Jupyter etc.) must not lose it. The pkills are
|
||||
# already Unsloth-specific, so they stay unconditional.
|
||||
$_clean = '_had=0; if [ -d /root/.unsloth ] || [ -L /root/.local/bin/unsloth ]; then _had=1; fi; rm -rf /root/.unsloth /root/llama-cuda /root/provision_llama_cuda.sh /root/llama_cuda_build.log 2>/dev/null; rm -f /root/.local/bin/unsloth 2>/dev/null; if [ $_had -eq 1 ]; then fuser -k 8888/tcp 2>/dev/null; fi; pkill -9 -f ''[u]nsloth_studio'' 2>/dev/null; pkill -9 -f ''[l]lama-server'' 2>/dev/null; true'
|
||||
# unrelated listener on 8888 (Jupyter etc.) must not lose it. The process kill is
|
||||
# scoped to argv referencing /root/.unsloth/ -- the fallback's install dir, which
|
||||
# its Studio server, llama-server, and build runner all reference -- instead of
|
||||
# bare name patterns that would also kill a user's own unrelated llama-server or
|
||||
# a /home Studio in that distro. The backslash in '/root/\.unslot[h]/' keeps the
|
||||
# pattern from matching this command's own argv (whose literal text contains the
|
||||
# escaped form, not the resolved path) -- same idea as the [x]-bracket trick.
|
||||
$_clean = '_had=0; if [ -d /root/.unsloth ] || [ -L /root/.local/bin/unsloth ]; then _had=1; fi; rm -rf /root/.unsloth /root/llama-cuda /root/provision_llama_cuda.sh /root/llama_cuda_build.log 2>/dev/null; rm -f /root/.local/bin/unsloth 2>/dev/null; if [ $_had -eq 1 ]; then fuser -k 8888/tcp 2>/dev/null; fi; pkill -9 -f ''/root/\.unslot[h]/'' 2>/dev/null; true'
|
||||
$_cands = @('', 'Ubuntu', 'Ubuntu-24.04', 'Ubuntu-22.04', 'Debian')
|
||||
if ($_recordedDistro) { $_cands = @($_recordedDistro) + $_cands }
|
||||
if ($env:UNSLOTH_WSL_DISTRO) { $_cands = @($env:UNSLOTH_WSL_DISTRO) + $_cands }
|
||||
|
|
|
|||
|
|
@ -27,8 +27,12 @@ torch_compile_options = {
|
|||
|
||||
|
||||
def _flex_is_dgx_spark():
|
||||
# Inlined copy of _utils.is_dgx_spark() to avoid a circular import.
|
||||
# Spark = aarch64 + NVIDIA CUDA + a Spark device-name token.
|
||||
# Inlined CUDA-free copy of _utils._is_dgx_spark_no_cuda_init() (kept local to
|
||||
# avoid a circular import). Spark = aarch64 + a Spark device name via nvidia-smi.
|
||||
# Must NOT touch torch.cuda: this runs at module import, and vision.py imports
|
||||
# ..kernels before ._utils -- a device-name query here would initialize the CUDA
|
||||
# allocator before patch_dgx_spark_memory_config() can set PYTORCH_CUDA_ALLOC_CONF
|
||||
# on the very Spark hosts this check targets.
|
||||
_force = os.environ.get("UNSLOTH_FORCE_DGX_SPARK")
|
||||
if _force == "1":
|
||||
return True
|
||||
|
|
@ -39,11 +43,13 @@ def _flex_is_dgx_spark():
|
|||
|
||||
if platform.machine().lower() not in ("aarch64", "arm64"):
|
||||
return False
|
||||
if not (hasattr(torch, "cuda") and torch.cuda.is_available()):
|
||||
return False
|
||||
names = " ".join(
|
||||
str(torch.cuda.get_device_name(i)).upper() for i in range(torch.cuda.device_count())
|
||||
import subprocess
|
||||
|
||||
out = subprocess.run(
|
||||
["nvidia-smi", "--query-gpu=name", "--format=csv,noheader"],
|
||||
capture_output = True, text = True, timeout = 5,
|
||||
)
|
||||
names = (out.stdout or "").upper()
|
||||
return any(t in names for t in ("GB10", "JMJWOA", "N1X", "DGX SPARK", "GB110"))
|
||||
except Exception:
|
||||
return False
|
||||
|
|
|
|||
|
|
@ -1177,8 +1177,10 @@ def patch_dgx_spark_dataloader_defaults():
|
|||
return
|
||||
_orig_post_init = Base.__post_init__
|
||||
|
||||
def __post_init__(self):
|
||||
_orig_post_init(self)
|
||||
# Forward *args/**kwargs so a future TrainingArguments (or a subclass) that
|
||||
# adds InitVar parameters to __post_init__ keeps working through the wrapper.
|
||||
def __post_init__(self, *args, **kwargs):
|
||||
_orig_post_init(self, *args, **kwargs)
|
||||
if getattr(self, "dataloader_pin_memory", None) is True:
|
||||
self.dataloader_pin_memory = False
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue