test_cuda_setup_evaluator.py 4.94 KB
Newer Older
1
import os
2
import pytest
3
4
5
import bitsandbytes as bnb

from typing import List, NamedTuple
6

7
8
9
from bitsandbytes.cuda_setup import (
    CUDA_RUNTIME_LIB,
    evaluate_cuda_setup,
10
11
    determine_cuda_runtime_lib_path,
    extract_candidate_paths,
12
)
13

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
"""
'LD_LIBRARY_PATH': ':/mnt/D/titus/local/cuda-11.1/lib64/'
'CONDA_EXE': '/mnt/D/titus/miniconda/bin/conda'
'LESSCLOSE': '/usr/bin/lesspipe %s %s'
'OLDPWD': '/mnt/D/titus/src'
'CONDA_PREFIX': '/mnt/D/titus/miniconda/envs/8-bit'
'SSH_AUTH_SOCK': '/mnt/D/titus/.ssh/ssh-agent.tim-uw.sock'
'CONDA_PREFIX_1': '/mnt/D/titus/miniconda'
'PWD': '/mnt/D/titus/src/8-bit'
'HOME': '/mnt/D/titus'
'CONDA_PYTHON_EXE': '/mnt/D/titus/miniconda/bin/python'
'CUDA_HOME': '/mnt/D/titus/local/cuda-11.1/'
'TMUX': '/tmp/tmux-1007/default,59286,1'
'XDG_DATA_DIRS': '/usr/local/share:/usr/share:/var/lib/snapd/desktop'
'SSH_TTY': '/dev/pts/0'
'MAIL': '/var/mail/titus'
'SHELL': '/bin/bash'
'DBUS_SESSION_BUS_ADDRESS': 'unix:path=/run/user/1007/bus'
'XDG_RUNTIME_DIR': '/run/user/1007'
'PATH': '/mnt/D/titus/miniconda/envs/8-bit/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/mnt/D/titus/local/cuda-11.1/bin'
'LESSOPEN': '| /usr/bin/lesspipe %s'
'_': '/mnt/D/titus/miniconda/envs/8-bit/bin/python'
# any that include 'CONDA' that are not 'CONDA_PREFIX'

# we search for
'CUDA_HOME': '/mnt/D/titus/local/cuda-11.1/'
"""

42

43
44
45
class InputAndExpectedOutput(NamedTuple):
    input: str
    output: str
46

47
48

HAPPY_PATH__LD_LIB_TEST_PATHS: List[InputAndExpectedOutput] = [
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
    (
        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}",
    ),
69
70
71
72
    (
        f"dir/with/{CUDA_RUNTIME_LIB}:other/dir/libcuda.so",
        f"dir/with/{CUDA_RUNTIME_LIB}",
    ),
73
74
75
]


76
77
@pytest.fixture(params=HAPPY_PATH__LD_LIB_TEST_PATHS)
def happy_path_path_string(tmpdir, request):
78
    for path in extract_candidate_paths(request.param):
79
80
81
82
83
84
        test_dir.mkdir()
        if CUDA_RUNTIME_LIB in path:
            (test_input / CUDA_RUNTIME_LIB).touch()


@pytest.mark.parametrize("test_input, expected", HAPPY_PATH__LD_LIB_TEST_PATHS)
85
def test_determine_cuda_runtime_lib_path__happy_path(
86
    tmp_path, test_input: str, expected: str
87
):
88
    for path in extract_candidate_paths(test_input):
89
90
        path.mkdir()
        (path / CUDA_RUNTIME_LIB).touch()
91
    assert determine_cuda_runtime_lib_path(test_input) == expected
92
93
94
95
96
97
98
99
100


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)
101
def test_determine_cuda_runtime_lib_path__unhappy_path(tmp_path, test_input: str):
102
103
104
    test_input = tmp_path / test_input
    (test_input / CUDA_RUNTIME_LIB).touch()
    with pytest.raises(FileNotFoundError) as err_info:
105
        determine_cuda_runtime_lib_path(test_input)
106
    assert all(match in err_info for match in {"duplicate", CUDA_RUNTIME_LIB})
107
108


109
def test_determine_cuda_runtime_lib_path__non_existent_dir(capsys, tmp_path):
110
    existent_dir = tmp_path / "a/b"
111
    existent_dir.mkdir()
112
    non_existent_dir = tmp_path / "c/d"  # non-existent dir
113
114
    test_input = ":".join([str(existent_dir), str(non_existent_dir)])

115
    determine_cuda_runtime_lib_path(test_input)
116
117
    std_err = capsys.readouterr().err

118
119
    assert all(match in std_err for match in {"WARNING", "non-existent"})

120
121
122

def test_full_system():
    ## this only tests the cuda version and not compute capability
123
124
125

    # if CONDA_PREFIX exists, it has priority before all other env variables
    # but it does not contain the library directly, so we need to look at the a sub-folder
126
127
128
129
130
131
132
133
134
135
136
    version = ""
    if "CONDA_PREFIX" in os.environ:
        ls_output, err = bnb.utils.execute_and_return(
            f'ls -l {os.environ["CONDA_PREFIX"]}/lib/libcudart.so'
        )
        major, minor, revision = (
            ls_output.split(" ")[-1].replace("libcudart.so.", "").split(".")
        )
        version = float(f"{major}.{minor}")

    if version == "" and "LD_LIBRARY_PATH":
137
138
139
140
141
142
143
144
145
146
147
        ld_path = os.environ["LD_LIBRARY_PATH"]
        paths = ld_path.split(":")
        version = ""
        for p in paths:
            if "cuda" in p:
                idx = p.rfind("cuda-")
                version = p[idx + 5 : idx + 5 + 4].replace("/", "")
                version = float(version)
                break

    assert version > 0
148
    binary_name = evaluate_cuda_setup()
149
150
    binary_name = binary_name.replace("libbitsandbytes_cuda", "")
    assert binary_name.startswith(str(version).replace(".", ""))