-
Notifications
You must be signed in to change notification settings - Fork 6.8k
cuda/cuDNN lib version checking. Force cuDNN v7 usage. #15449
cuda/cuDNN lib version checking. Force cuDNN v7 usage. #15449
Conversation
…nst CUDNN_VERSION < 7000.
Versioning issues were recently discussed in the dev forum: https://lists.apache.org/thread.html/96d4a46a0a3c98ea1f3a3237de713ef5f40967fcb0817d661c18e950@%3Cdev.mxnet.apache.org%3E Although the PR as it stands does not preclude CUDA8, I propose to add STATIC_ASSERT_CUDA_VERSION_GE(9000) given enough consensus. Tagging @ptrendx @KellenSunderland @marcoabreu @larroy |
I propose that this PR be accepted in its fairly minimal form. Once merged, I would then follow-up with a PR with sizeable cleanup/removal of cuda and cudnn code using the mechanisms set up here. I can envision a couple of approaches. The first (which I'm not recommending) I'd call the simple, but dangerous approach. In cuda_utils.h, I'd put the lines:
Then I'd rip out all code dealing with earlier versions in other files that included cuda_utils.h. I'm worried this approach would make it too easy for users to experiment with going back to old versions. Perhaps the code removed involved bug work-arounds for older lib versions. This approach loses information about the support level of the various operator implementations. My preference then is: As we remove old code from a file, and thereby add a minimum version requirement, we add the appropriate STATIC_ASSERT_ macro to the file. Thus the protection travels with the file. No version support information is lost and it would be hard to get in trouble when mixing versions as in:
In the above scenario, if my_favorite_op-inl.h was counting on version protections present in its own-version cuda_utils.h, those may now be different and more lax (i.e. allowing older libs). Best if the STATIC_ASSERT_ statements live in my_favorite_op-inl.h where the version requirement exists. Comments welcome. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM % some symbol visibility comments
src/common/cuda_utils.cc
Outdated
|
||
|
||
// Start-up check that the version of cuda compiled-against matches the linked-against version. | ||
bool CudaVersionChecks() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should this be static or anon ns?
src/common/cuda_utils.cc
Outdated
|
||
// Dynamic initialization here will emit a warning if runtime and compile-time versions mismatch. | ||
// Also if the user has recompiled their source to a version no longer tested by upstream CI. | ||
bool cudnn_version_ok = CuDNNVersionChecks(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
symbol visibility: can be static or anon ns? if you are just forcing static initialization. Also maybe we should start thinking about having a single place to do static initialization on library load.
Also in this case a static object and the version check inside ctor would save the memory for this variable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a partial response to what you're advocating, I've removed the CuDNNVersionChecks() and CudaVersionChecks() functions from the namespace, using instead immediately-invoked function expressions. I like the simplicity of it now, and I don't think the variable memory (8 bytes?) is much of an issue. If you feel otherwise, send me a pointer to an example of the programming pattern you think would be an improvement.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Up to you. I was thinking that using a static object with no members should not use any memory when initialized in global context as your boolean variable but that depends on the implementation. I agree is not a big deal. I was thinking on something like:
struct Initializer {
Initializer() {
// your code here
}
};
static Initializer initializer;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Who calls the version check now? I see a lambda but not where is called.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At the end of each lambda, there's a null argument list '()', turning the lambdas into 'immediately invoked function expressions'.
Thanks for the code snippet- it's pretty similar in effect to what I've got now, so if it's OK with you, I'd prefer to stick with what I've already verified. Actually, my current solution has slightly fewer code lines and less names in the namespace.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure makes sense, thanks.
For my recent "Move STATIC_ASSERT_..." commit, I ended up moving the compile-time check to resource.cc, where the real version dependency is, instead of in rnn.cc, while also simplifying the #if logic. The error message now properly reveals that it's cudnnRestoreDropoutDescriptor() that's missing from cuDNN v6:
@szha Since you introduced the change that included the dependency, maybe you'd like to weigh in? |
@mxnet-label-bot add [CUDA] |
Gentle ping now that the holiday weekend is over. |
Not sure if the timing permits this, but I'd think this might be a useful PR to backport to v1.5 |
src/common/cuda_utils.cc
Outdated
int linkedAgainstCudaVersion = 0; | ||
CUDA_CALL(cudaRuntimeGetVersion(&linkedAgainstCudaVersion)); | ||
if (linkedAgainstCudaVersion != CUDA_VERSION) | ||
LOG(WARNING) << "cuda library mismatch: linked-against version " << linkedAgainstCudaVersion |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just want to make sure I'm understanding this one. If a user runs with CUDA 10.2, but the library was linked against 10.1 would this issue a warning? I tend to do that fairly often, is it against best practices?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So 'yes' there would be a warning if the user built against 10.1, but ran with 10.2. These warnings can be turned off with an environment variable setting MXNET_CUDA_VERSION_CHECKING=0. The idea behind the 'advisory' is that the user may want to rebuild to get the new functionality present in 10.2, or perhaps to avoid work-arounds for any issues of 10.1. It's probably more useful with the CUDNN version checks, where we have far more compile guards based on version minor numbers. Do you feel these warnings would be unwelcome to users?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the question is what can be the issues when linking against a smaller cuda, leaving performance gains on the table? I think you guys are the experts, I was getting some info from here: https://docs.nvidia.com/deploy/cuda-compatibility/#binary-compatibility
Does this warning indicate a real problem or will it confuse users, when there's nothing wrong on running with a newer cuda.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After studying the link supplied by @larroy (thanks!), I need to retract what I said above. Based on a new understanding, I have removed the runtime check of the cuda-runtime library version. The check is unnecessary since (per the link) the major.minor of the cuda runtime must match for the libmxnet.so lib to load. It was instructive for me to do a ldd libmxnet.so
:
libcudart.so.9.2 => /usr/local/cuda/lib64/libcudart.so.9.2 (0x00007f361cc64000)
libcudnn.so.7 => /usr/lib/x86_64-linux-gnu/libcudnn.so.7 (0x00007f35f9cdf000)
libcuda.so.1 => /usr/lib/x86_64-linux-gnu/libcuda.so.1 (0x00007f35f3703000)
Note the extra '.minor' number on libcudart.so. So while a compiled-against cudnn 7.2, might run against a cudnn 7.6, a compiled-against cuda 10.1 won't run against a cuda 10.2. Now, keep in mind we're talking about the cuda runtime
library, so libcudart.so as set up by the toolkit install. Your experience on 10.1 vs. 10.2 @KellenSunderland was probably based on upgrading the driver to a higher version, while leaving the toolkit install the same.
Let me know if the PR is now to your liking. I've left in the test of the cuda runtime version against the threshold MXNET_CI_OLDEST_CUDA_VERSION. The idea is that once we no longer test against a particular cuda version, then bugs will creep in with new PRs. We'd prefer users to not be on the front line of bug finding, so we should encourage them to upgrade.
Back to your original question- there will be no warning for upgrading the driver to a newer version (e.g. 10.2) while leaving the toolkit at 10.1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the clarification, I think your change brings value to align users and what's tested in CI/CD.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the updates and clarification Dick.
// Also if the user has recompiled their source to a version no longer tested by upstream CI. | ||
bool cuda_version_check_performed = []() { | ||
// Don't bother with checks if there are no GPUs visible (e.g. with CUDA_VISIBLE_DEVICES="") | ||
if (dmlc::GetEnv("MXNET_CUDA_VERSION_CHECKING", true) && Context::GetGPUCount() > 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@DickJC123 we have detected an error when running a GPU compiled MXNet in a CPU machine, when building mxnet is loaded to generate the operator bindings. My colleague will fill a ticket about this. Would be great to have your guidance if the underlying cudaGetDeviceCount can run without driver, as the call is failing. Our thinking is that before we were not calling this cuda function on load time. I think a possible solution is to add a function that checks if GPUs are available if the GPU count can't be called without GPUs which is a bit puzzling.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
filed a issue on the same, this is breaking our internal build flows, where our buildfarm does not have GPU enabled machines, the GPU builds are also done on CPU machines, with CUDA installed on them, for build purposes.
This PR addresses two issues:
- rnn.cc of mxnet v1.5 does not compile against cudnn v6. This PR enforces systems that rebuild mxnet to have cudnn v7, and improves the error message for compiling against v6.
- We are accumulating stale code that references no-longer-supported cuda/cudnn versions. This PR provides a means for cleaning out this code.
This PR introduces both runtime and compile-time cuda and cuDNN version checking. The compile time checks are based on new macros: STATIC_ASSERT_CUDNN_VERSION_GE(min_version) and STATIC_ASSERT_CUDA_VERSION_GE(min_version). Example usage:
Before PR:
After PR (given the assumption that we're now requiring cuDNN v7):
Discussion continues in the comments section.
Checklist
Essentials
Please feel free to remove inapplicable items for your PR.
Changes
Comments
This PR improves the compile-time message to a user trying to build MXNet 1.5 against cuDNN v6.
Before PR, only the missing library entrypoint is mentioned:
After the PR, the error mentions the library version issue directly:
This PR provides 2 runtime checks and issues a warning:
- when the compiled-against cuda or cuDNN library version does not match the linked-against version, and
- when the library versions are old w.r.t. the versions tested against by the MXNet CI.
I built the PR against cuda 9 and cuDNN v7.1.4. Running any model will emit the warning:
I then upgraded cuDNN to v7.2.1 without recompiling. The following additional message now appears when running models:
As stated, the user can choose to kill the warning messages with environment variables settings.