Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
OpenDAS
bitsandbytes
Commits
dd50382b
Commit
dd50382b
authored
Jul 31, 2022
by
Tim Dettmers
Browse files
Full evaluate_cuda setup with integration test.
parent
5d90b38c
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
123 additions
and
13 deletions
+123
-13
bitsandbytes/cextension.py
bitsandbytes/cextension.py
+26
-1
bitsandbytes/cuda_setup.py
bitsandbytes/cuda_setup.py
+77
-7
install_cuda.sh
install_cuda.sh
+0
-5
tests/test_cuda_setup_evaluator.py
tests/test_cuda_setup_evaluator.py
+20
-0
No files found.
bitsandbytes/cextension.py
View file @
dd50382b
import
ctypes
as
ct
import
ctypes
as
ct
import
os
import
os
from
warnings
import
warn
from
warnings
import
warn
from
bitsandbytes.cuda_setup
import
evaluate_cuda_setup
lib
=
ct
.
cdll
.
LoadLibrary
(
os
.
path
.
dirname
(
__file__
)
+
'/libbitsandbytes.so'
)
class
CUDALibrary_Singleton
(
object
):
_instance
=
None
def
__init__
(
self
):
raise
RuntimeError
(
'Call get_instance() instead'
)
def
initialize
(
self
):
self
.
context
=
{}
binary_name
=
evaluate_cuda_setup
()
if
not
os
.
path
.
exists
(
os
.
path
.
dirname
(
__file__
)
+
f
'/
{
binary_name
}
'
):
print
(
f
'TODO: compile library for specific version:
{
binary_name
}
'
)
print
(
'defaulting to libbitsandbytes.so'
)
self
.
lib
=
ct
.
cdll
.
LoadLibrary
(
os
.
path
.
dirname
(
__file__
)
+
'/libbitsandbytes.so'
)
else
:
self
.
lib
=
ct
.
cdll
.
LoadLibrary
(
os
.
path
.
dirname
(
__file__
)
+
f
'/
{
binary_name
}
'
)
@
classmethod
def
get_instance
(
cls
):
if
cls
.
_instance
is
None
:
cls
.
_instance
=
cls
.
__new__
(
cls
)
cls
.
_instance
.
initialize
()
return
cls
.
_instance
lib
=
CUDALibrary_Singleton
.
get_instance
().
lib
try
:
try
:
lib
.
cadam32bit_g32
lib
.
cadam32bit_g32
lib
.
get_context
.
restype
=
ct
.
c_void_p
lib
.
get_context
.
restype
=
ct
.
c_void_p
...
...
bitsandbytes/cuda_setup.py
View file @
dd50382b
...
@@ -23,6 +23,58 @@ from pathlib import Path
...
@@ -23,6 +23,58 @@ from pathlib import Path
from
typing
import
Set
,
Union
from
typing
import
Set
,
Union
from
.utils
import
warn_of_missing_prerequisite
,
print_err
from
.utils
import
warn_of_missing_prerequisite
,
print_err
import
ctypes
import
shlex
import
subprocess
def
execute_and_return
(
strCMD
):
proc
=
subprocess
.
Popen
(
shlex
.
split
(
strCMD
),
stdout
=
subprocess
.
PIPE
,
stderr
=
subprocess
.
PIPE
)
out
,
err
=
proc
.
communicate
()
out
,
err
=
out
.
decode
(
"UTF-8"
).
strip
(),
err
.
decode
(
"UTF-8"
).
strip
()
return
out
,
err
def
check_cuda_result
(
cuda
,
result_val
):
if
result_val
!=
0
:
cuda
.
cuGetErrorString
(
result_val
,
ctypes
.
byref
(
error_str
))
print
(
f
"Count not initialize CUDA - failure!"
)
raise
Exception
(
'CUDA excepion!'
)
return
result_val
# taken from https://gist.github.com/f0k/63a664160d016a491b2cbea15913d549
def
get_compute_capability
():
libnames
=
(
'libcuda.so'
,
'libcuda.dylib'
,
'cuda.dll'
)
for
libname
in
libnames
:
try
:
cuda
=
ctypes
.
CDLL
(
libname
)
except
OSError
:
continue
else
:
break
else
:
raise
OSError
(
"could not load any of: "
+
' '
.
join
(
libnames
))
nGpus
=
ctypes
.
c_int
()
cc_major
=
ctypes
.
c_int
()
cc_minor
=
ctypes
.
c_int
()
result
=
ctypes
.
c_int
()
device
=
ctypes
.
c_int
()
context
=
ctypes
.
c_void_p
()
error_str
=
ctypes
.
c_char_p
()
result
=
check_cuda_result
(
cuda
,
cuda
.
cuInit
(
0
))
result
=
check_cuda_result
(
cuda
,
cuda
.
cuDeviceGetCount
(
ctypes
.
byref
(
nGpus
)))
ccs
=
[]
for
i
in
range
(
nGpus
.
value
):
result
=
check_cuda_result
(
cuda
,
cuda
.
cuDeviceGet
(
ctypes
.
byref
(
device
),
i
))
result
=
check_cuda_result
(
cuda
,
cuda
.
cuDeviceComputeCapability
(
ctypes
.
byref
(
cc_major
),
ctypes
.
byref
(
cc_minor
),
device
))
ccs
.
append
(
f
'
{
cc_major
.
value
}
.
{
cc_minor
.
value
}
'
)
#TODO: handle different compute capabilities; for now, take the max
ccs
.
sort
()
return
ccs
[
-
1
]
CUDA_RUNTIME_LIB
:
str
=
"libcudart.so"
CUDA_RUNTIME_LIB
:
str
=
"libcudart.so"
...
@@ -72,12 +124,30 @@ def get_cuda_runtime_lib_path(
...
@@ -72,12 +124,30 @@ def get_cuda_runtime_lib_path(
raise
FileNotFoundError
(
err_msg
)
raise
FileNotFoundError
(
err_msg
)
single_cuda_runtime_lib_dir
=
next
(
iter
(
cuda_runtime_libs
))
single_cuda_runtime_lib_dir
=
next
(
iter
(
cuda_runtime_libs
))
return
ld_library_paths
return
single_cuda_runtime_lib_dir
def
evaluate_cuda_setup
():
def
evaluate_cuda_setup
():
# - if paths faulty, return meaningful error
cuda_path
=
get_cuda_runtime_lib_path
()
# - else:
cc
=
get_compute_capability
()
# - determine CUDA version
binary_name
=
'libbitsandbytes_cpu.so'
# - determine capabilities
# - based on that set the default path
has_gpu
=
cc
!=
''
pass
if
not
has_gpu
:
print
(
'WARNING: No GPU detected! Check our CUDA paths. Processding to load CPU-only library...'
)
return
binary_name
has_cublaslt
=
cc
in
[
'7.5'
,
'8.0'
,
'8.6'
]
# TODO:
# (1) Model missing cases (no CUDA installed by CUDA driver (nvidia-smi accessible)
# (2) Multiple CUDA versions installed
cuda_home
=
str
(
Path
(
cuda_path
).
parent
.
parent
)
ls_output
,
err
=
execute_and_return
(
f
'
{
cuda_home
}
/bin/nvcc --version'
)
cuda_version
=
ls_output
.
split
(
'
\n
'
)[
3
].
split
(
','
)[
-
1
].
strip
().
lower
().
replace
(
'v'
,
''
)
major
,
minor
,
revision
=
cuda_version
.
split
(
'.'
)
cuda_version_string
=
f
'
{
major
}{
minor
}
'
binary_name
=
f
'libbitsandbytes_cuda
{
cuda_version_string
}
_
{
(
"cublaslt"
if
has_cublaslt
else
""
)
}
.so'
return
binary_name
install_cuda.sh
deleted
100644 → 0
View file @
5d90b38c
wget https://developer.download.nvidia.com/compute/cuda/11.1.1/local_installers/cuda_11.1.1_455.32.00_linux.run
bash cuda_11.1.1_455.32.00_linux.run
--no-drm
--no-man-page
--override
--installpath
=
~/local
--librarypath
=
~/local/lib
--toolkitpath
=
~/local/cuda-11.1/
--toolkit
--silent
echo
"export LD_LIBRARY_PATH=
$LD_LIBRARY_PATH
:~/local/cuda-11.1/lib64/"
>>
~/.bashrc
echo
"export PATH=
$PATH
:~/local/cuda-11.1/bin/"
>>
~/.bashrc
source
~/.bashrc
tests/test_cuda_setup_evaluator.py
View file @
dd50382b
import
pytest
import
pytest
import
os
from
typing
import
List
from
typing
import
List
...
@@ -16,6 +17,7 @@ HAPPY_PATH__LD_LIB_TEST_PATHS: List[tuple[str,str]] = [
...
@@ -16,6 +17,7 @@ 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
}
"
),
(
f
"dir/with/
{
CUDA_RUNTIME_LIB
}
:some/other/dir"
,
f
"dir/with/
{
CUDA_RUNTIME_LIB
}
"
),
(
f
"dir/with/
{
CUDA_RUNTIME_LIB
}
:other/dir/libcuda.so"
,
f
"dir/with/
{
CUDA_RUNTIME_LIB
}
"
),
]
]
...
@@ -64,3 +66,21 @@ def test_get_cuda_runtime_lib_path__non_existent_dir(capsys, tmp_path):
...
@@ -64,3 +66,21 @@ def test_get_cuda_runtime_lib_path__non_existent_dir(capsys, tmp_path):
match
in
std_err
match
in
std_err
for
match
in
{
"WARNING"
,
"non-existent"
}
for
match
in
{
"WARNING"
,
"non-existent"
}
)
)
def
test_full_system
():
## this only tests the cuda version and not compute capability
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
binary_name
=
evaluate_cuda_setup
()
binary_name
=
binary_name
.
replace
(
'libbitsandbytes_cuda'
,
''
)
assert
binary_name
.
startswith
(
str
(
version
).
replace
(
'.'
,
''
))
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment