forked from mrq/bitsandbytes-rocm
adding CLI tool for CUDA install debugging - intermediate commit
This commit is contained in:
parent
bd515328d7
commit
5d90b38c4d
3
bitsandbytes/__main__.py
Normal file
3
bitsandbytes/__main__.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
from bitsandbytes.debug_cli import cli
|
||||||
|
|
||||||
|
cli()
|
83
bitsandbytes/cuda_setup.py
Normal file
83
bitsandbytes/cuda_setup.py
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
"""
|
||||||
|
build is dependent on
|
||||||
|
- compute capability
|
||||||
|
- dependent on GPU family
|
||||||
|
- CUDA version
|
||||||
|
- Software:
|
||||||
|
- CPU-only: only CPU quantization functions (no optimizer, no matrix multipl)
|
||||||
|
- CuBLAS-LT: full-build 8-bit optimizer
|
||||||
|
- no CuBLAS-LT: no 8-bit matrix multiplication (`nomatmul`)
|
||||||
|
|
||||||
|
alle Binaries packagen
|
||||||
|
|
||||||
|
evaluation:
|
||||||
|
- if paths faulty, return meaningful error
|
||||||
|
- else:
|
||||||
|
- determine CUDA version
|
||||||
|
- determine capabilities
|
||||||
|
- based on that set the default path
|
||||||
|
"""
|
||||||
|
|
||||||
|
from os import environ as env
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Set, Union
|
||||||
|
from .utils import warn_of_missing_prerequisite, print_err
|
||||||
|
|
||||||
|
|
||||||
|
CUDA_RUNTIME_LIB: str = "libcudart.so"
|
||||||
|
|
||||||
|
def tokenize_paths(paths: str) -> Set[Path]:
|
||||||
|
return {
|
||||||
|
Path(ld_path) for ld_path in paths.split(':')
|
||||||
|
if ld_path
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_cuda_runtime_lib_path(
|
||||||
|
# TODO: replace this with logic for all paths in env vars
|
||||||
|
LD_LIBRARY_PATH: Union[str, None] = env.get("LD_LIBRARY_PATH")
|
||||||
|
) -> Union[Path, None]:
|
||||||
|
""" # TODO: add doc-string
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not LD_LIBRARY_PATH:
|
||||||
|
warn_of_missing_prerequisite(
|
||||||
|
'LD_LIBRARY_PATH is completely missing from environment!'
|
||||||
|
)
|
||||||
|
return None
|
||||||
|
|
||||||
|
ld_library_paths: Set[Path] = tokenize_paths(LD_LIBRARY_PATH)
|
||||||
|
|
||||||
|
non_existent_directories: Set[Path] = {
|
||||||
|
path for path in ld_library_paths
|
||||||
|
if not path.exists()
|
||||||
|
}
|
||||||
|
|
||||||
|
if non_existent_directories:
|
||||||
|
print_err(
|
||||||
|
"WARNING: The following directories listed your path were found to "
|
||||||
|
f"be non-existent: {non_existent_directories}"
|
||||||
|
)
|
||||||
|
|
||||||
|
cuda_runtime_libs: Set[Path] = {
|
||||||
|
path / CUDA_RUNTIME_LIB for path in ld_library_paths
|
||||||
|
if (path / CUDA_RUNTIME_LIB).is_file()
|
||||||
|
} - non_existent_directories
|
||||||
|
|
||||||
|
if len(cuda_runtime_libs) > 1:
|
||||||
|
err_msg = f"Found duplicate {CUDA_RUNTIME_LIB} files: {cuda_runtime_libs}.."
|
||||||
|
raise FileNotFoundError(err_msg)
|
||||||
|
|
||||||
|
elif len(cuda_runtime_libs) < 1:
|
||||||
|
err_msg = f"Did not find {CUDA_RUNTIME_LIB} files: {cuda_runtime_libs}.."
|
||||||
|
raise FileNotFoundError(err_msg)
|
||||||
|
|
||||||
|
single_cuda_runtime_lib_dir = next(iter(cuda_runtime_libs))
|
||||||
|
return ld_library_paths
|
||||||
|
|
||||||
|
def evaluate_cuda_setup():
|
||||||
|
# - if paths faulty, return meaningful error
|
||||||
|
# - else:
|
||||||
|
# - determine CUDA version
|
||||||
|
# - determine capabilities
|
||||||
|
# - based on that set the default path
|
||||||
|
pass
|
27
bitsandbytes/debug_cli.py
Normal file
27
bitsandbytes/debug_cli.py
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import typer
|
||||||
|
|
||||||
|
|
||||||
|
cli = typer.Typer()
|
||||||
|
|
||||||
|
|
||||||
|
@cli.callback()
|
||||||
|
def callback():
|
||||||
|
"""
|
||||||
|
Awesome Portal Gun
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@cli.command()
|
||||||
|
def shoot():
|
||||||
|
"""
|
||||||
|
Shoot the portal gun
|
||||||
|
"""
|
||||||
|
typer.echo("Shooting portal gun")
|
||||||
|
|
||||||
|
|
||||||
|
@cli.command()
|
||||||
|
def load():
|
||||||
|
"""
|
||||||
|
Load the portal gun
|
||||||
|
"""
|
||||||
|
typer.echo("Loading portal gun")
|
7
bitsandbytes/utils.py
Normal file
7
bitsandbytes/utils.py
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import sys
|
||||||
|
|
||||||
|
def print_err(s: str) -> None:
|
||||||
|
print(s, file=sys.stderr)
|
||||||
|
|
||||||
|
def warn_of_missing_prerequisite(s: str) -> None:
|
||||||
|
print_err('WARNING, missing pre-requisite: ' + s)
|
14
environment.yml
Normal file
14
environment.yml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
name: 8-bit
|
||||||
|
channels:
|
||||||
|
- conda-forge
|
||||||
|
dependencies:
|
||||||
|
- python=3.9
|
||||||
|
- pytest
|
||||||
|
- pytorch
|
||||||
|
- torchaudio
|
||||||
|
- torchvision
|
||||||
|
- cudatoolkit=11.1
|
||||||
|
- typer
|
||||||
|
- ca-certificates
|
||||||
|
- certifi
|
||||||
|
- openssl
|
3
setup.py
3
setup.py
|
@ -23,6 +23,9 @@ setup(
|
||||||
keywords="gpu optimizers optimization 8-bit quantization compression",
|
keywords="gpu optimizers optimization 8-bit quantization compression",
|
||||||
url="http://packages.python.org/bitsandbytes",
|
url="http://packages.python.org/bitsandbytes",
|
||||||
packages=find_packages(),
|
packages=find_packages(),
|
||||||
|
entry_points={
|
||||||
|
"console_scripts": ["debug_cuda = bitsandbytes.debug_cli:cli"],
|
||||||
|
},
|
||||||
package_data={'': ['libbitsandbytes.so']},
|
package_data={'': ['libbitsandbytes.so']},
|
||||||
long_description=read('README.md'),
|
long_description=read('README.md'),
|
||||||
long_description_content_type='text/markdown',
|
long_description_content_type='text/markdown',
|
||||||
|
|
66
tests/test_cuda_setup_evaluator.py
Normal file
66
tests/test_cuda_setup_evaluator.py
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
from bitsandbytes.cuda_setup import (
|
||||||
|
CUDA_RUNTIME_LIB,
|
||||||
|
get_cuda_runtime_lib_path,
|
||||||
|
evaluate_cuda_setup,
|
||||||
|
tokenize_paths,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
HAPPY_PATH__LD_LIB_TEST_PATHS: List[tuple[str,str]] = [
|
||||||
|
(f"some/other/dir:dir/with/{CUDA_RUNTIME_LIB}", f"dir/with/{CUDA_RUNTIME_LIB}"),
|
||||||
|
(f":some/other/dir:dir/with/{CUDA_RUNTIME_LIB}", f"dir/with/{CUDA_RUNTIME_LIB}"),
|
||||||
|
(f"some/other/dir:dir/with/{CUDA_RUNTIME_LIB}:", f"dir/with/{CUDA_RUNTIME_LIB}"),
|
||||||
|
(f"some/other/dir::dir/with/{CUDA_RUNTIME_LIB}", f"dir/with/{CUDA_RUNTIME_LIB}"),
|
||||||
|
(f"dir/with/{CUDA_RUNTIME_LIB}:some/other/dir", f"dir/with/{CUDA_RUNTIME_LIB}"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"test_input, expected",
|
||||||
|
HAPPY_PATH__LD_LIB_TEST_PATHS
|
||||||
|
)
|
||||||
|
def test_get_cuda_runtime_lib_path__happy_path(
|
||||||
|
tmp_path, test_input: str, expected: str
|
||||||
|
):
|
||||||
|
for path in tokenize_paths(test_input):
|
||||||
|
assert False == tmp_path / test_input
|
||||||
|
test_dir.mkdir()
|
||||||
|
(test_input / CUDA_RUNTIME_LIB).touch()
|
||||||
|
assert get_cuda_runtime_lib_path(test_input) == expected
|
||||||
|
|
||||||
|
|
||||||
|
UNHAPPY_PATH__LD_LIB_TEST_PATHS = [
|
||||||
|
f"a/b/c/{CUDA_RUNTIME_LIB}:d/e/f/{CUDA_RUNTIME_LIB}",
|
||||||
|
f"a/b/c/{CUDA_RUNTIME_LIB}:d/e/f/{CUDA_RUNTIME_LIB}:g/h/j/{CUDA_RUNTIME_LIB}",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("test_input", UNHAPPY_PATH__LD_LIB_TEST_PATHS)
|
||||||
|
def test_get_cuda_runtime_lib_path__unhappy_path(tmp_path, test_input: str):
|
||||||
|
test_input = tmp_path / test_input
|
||||||
|
(test_input / CUDA_RUNTIME_LIB).touch()
|
||||||
|
with pytest.raises(FileNotFoundError) as err_info:
|
||||||
|
get_cuda_runtime_lib_path(test_input)
|
||||||
|
assert all(
|
||||||
|
match in err_info
|
||||||
|
for match in {"duplicate", CUDA_RUNTIME_LIB}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_cuda_runtime_lib_path__non_existent_dir(capsys, tmp_path):
|
||||||
|
existent_dir = tmp_path / 'a/b'
|
||||||
|
existent_dir.mkdir()
|
||||||
|
non_existent_dir = tmp_path / 'c/d' # non-existent dir
|
||||||
|
test_input = ":".join([str(existent_dir), str(non_existent_dir)])
|
||||||
|
|
||||||
|
get_cuda_runtime_lib_path(test_input)
|
||||||
|
std_err = capsys.readouterr().err
|
||||||
|
|
||||||
|
assert all(
|
||||||
|
match in std_err
|
||||||
|
for match in {"WARNING", "non-existent"}
|
||||||
|
)
|
Loading…
Reference in New Issue
Block a user