Repository navigation
CUDA: Add CUDA 11.8 / Hopper support and required fixes - #8579
Conversation
The logic for determining the supported compute capabilities was completely wrong, and needed updating in a complicated way for each new toolkit. This replaces the incorrect logic with a simpler mechanism: - We have a list of compute capabilities that we're aware of. - We have the minimum and maximum supported CC for each toolkit. - We generate the list of supported CCs as the range of known CCs within the min/max for the current toolkit. For unknown toolkits, all we can do is assume that it supports all the toolkits that we know about that aren't deprecated upstream (i.e. those from 5.3 onwards). This should be much easier to update - for each new toolkit, we just add a new entry in the mapping from toolkit versions to min/max supported CC versions. If we drop support for a toolkit, we can just delete it from the mapping.
The NVVM IR version for IR given to NVVM should always match the version that it supports - some versions of NVVM can reject IR where the version doesn't match. When the version isn't specified, it is implicitly 1.0, which is why this commit mostly consists of additions that add the IR version to modules.
|
gpuci run tests |
stuartarchibald
left a comment
There was a problem hiding this comment.
Thanks for the patch. This largely looks good, just a few queries to resolve inline. Thanks again!
| (9, 0) | ||
| ) | ||
|
|
||
| # Maps CTK version -> (min supported cc, max supported cc) |
There was a problem hiding this comment.
Are the bounds inclusive/exclusive, should this be clarified?
| def get_supported_ccs(): | ||
| # Attempt to return cached list |
There was a problem hiding this comment.
If there's an in-process cache need, should something like functools.cache be used opposed to module globals?
There was a problem hiding this comment.
That would be way better than the current bodge!
There was a problem hiding this comment.
Actually it doesn't even need to be cached, this just makes no sense. The supported CCs is a property of the NVVM version, so I'm going to just make supported_ccs a property of the NVVM instance, because that just makes more sense anyway (and implicitly "caches" the values too because it's a singleton).
I think there could be an argument for the logic in get_supported_ccs() and its callees to be part of the NVVM class, but I think that functionality will also be common with NVPTX so I don't want to hoist the code into NVVM for now.
| if cudart_version < (11, 0): | ||
| _supported_cc = () | ||
| ctk_ver = f"{cudart_version[0]}.{cudart_version[1]}" | ||
| unsupported_ver = (f"CUDA Toolkit {ctk_ver} is unsupported by Numba - " | ||
| "11.0 is the minimum required version.") |
There was a problem hiding this comment.
Should the minimum version be specified as a constant somewhere (maybe a module global, or perhaps even all this encoding of supported CCs etc ought to go into it's own module or YAML file?) and then code be updated in terms of that constant?
There was a problem hiding this comment.
I think instead of hardcoding the minimum CTK required, it can be derived from the dict of supported CCs, then it doesn't need to be stored separately anywhere. Additionally, I'm going to use NUMBA_CUDA_DEFAULT_PTX_CC for the default minimum for unrecognised toolkits instead of hardcoding (5, 3) above. This will be more robust in that a constant doesn't need updating in two places, and if there's some future toolkit that doesn't even support 5.3, the user can workaround it by setting the environment variable NUMBA_CUDA_DEFAULT_PTX_CC=6.1 (or whatever) to match the minimum for their toolkit.
The CC support matrix for NVPTX will differ, so I think keeping this encoding of supported CCs in nvvm.py is logical, and keeps complexity to a minimum instead of adding additional logic / dependencies.
| versions = NVVM().get_ir_version() | ||
| metadata = metadata_nvvm70 % versions |
There was a problem hiding this comment.
Perhaps update to use .format() or an f-string?
There was a problem hiding this comment.
I decided against that because it makes the IR less legible due to the presence of { and }.
| m = ir.Module("test_nvvm_from_llvm") | ||
| m.triple = 'nvptx64-nvidia-cuda' | ||
| nvvm.add_ir_version(m) |
There was a problem hiding this comment.
Is this 3 line "setup" for a CUDA-target-LLVM-module sufficiently common to make it worth creating a utility function? The main concern here is that the m.triple specification is likely always necessary whereas the nvvm.add_ir_version(m) appears not to be? I suppose the underlying question is "what is the need driving the addition of the add_ir_version()" call?
There was a problem hiding this comment.
This does happen for new modules created by the JITCUDACodegen, but I didn't use that here because it's part of the compiler / "cudapy", rather than the driver, which is under test in these cases.
It makes more logical sense to keep them on the NVVM instance as a property instead.
The minimum toolkit version can be derived from the support matrix, and the minimum CC for unrecognised toolkits can be derived from `config.CUDA_DEFAULT_PTX_CC`, which can also be overridden by the user if necessary - for example, if a user has a toolkit that in future has dropped even support for 5.3.
|
gpuci run tests |
|
@stuartarchibald Many thanks for the review - I've addressed / responded to all comments. |
stuartarchibald
left a comment
There was a problem hiding this comment.
@gmarkall Thanks for the fixes! I agree with the comments you left in response to review, thanks for answering/addressing them.
|
Buildfarm ID: |
|
Any news on the buildfarm? |
|
@gmarkall @stuartarchibald apologies again for the delay here. Some hardware on the buildfram had to be replaced, hence the delay here. I have scheduled a fresh run for this PR at:
|
With #8636 merged to |
See individual commit messages for full descriptions. The required fixes consist of:
main.