Relax CuDNN version requirements because CuDNN is backwards compatible within

a major release starting with CuDNN 7.0

PiperOrigin-RevId: 190869028
This commit is contained in:
Smit Hinsu 2018-03-28 18:26:46 -07:00 committed by TensorFlower Gardener
parent 17dfe3ed7d
commit 59a1255354
5 changed files with 233 additions and 28 deletions

View File

@ -56,7 +56,10 @@ cc_library(
[
"cuda/*.cc",
],
exclude = ["cuda/cuda_platform_id.cc"],
exclude = [
"cuda/*_test.cc",
"cuda/cuda_platform_id.cc",
],
),
),
copts = select({
@ -72,6 +75,7 @@ cc_library(
":stream_executor",
"//tensorflow/core:lib",
"//tensorflow/core/kernels:ops_util",
"@com_google_absl//absl/strings",
"@local_config_cuda//cuda:cuda_headers",
] + if_cuda_is_configured([
"//tensorflow/core:cuda",

View File

@ -18,7 +18,9 @@ limitations under the License.
#include <functional>
#include <memory>
#include "absl/strings/str_cat.h"
#include "third_party/eigen3/Eigen/Core"
#include "tensorflow/core/lib/core/errors.h"
#include "tensorflow/core/util/env_var.h"
#include "tensorflow/stream_executor/cuda/cuda_activation.h"
#include "tensorflow/stream_executor/cuda/cuda_diagnostics.h"
@ -27,6 +29,7 @@ limitations under the License.
#include "tensorflow/stream_executor/cuda/cuda_platform_id.h"
#include "tensorflow/stream_executor/cuda/cuda_stream.h"
#include "tensorflow/stream_executor/cuda/cuda_timer.h"
#include "tensorflow/stream_executor/cuda/cudnn_version.h"
#include "tensorflow/stream_executor/dnn.h"
#include "tensorflow/stream_executor/lib/env.h"
#include "tensorflow/stream_executor/lib/error.h"
@ -55,15 +58,6 @@ NarrowT CheckedNarrowing(const WideT& wide) {
return narrow;
}
// Returns the "Compatibility" version number from the CuDNN version number.
// This is the number that tries to indicate ABI compatibility.
//
// For example, if cudnn_version is 5107, the compatibility version
// number will be 5100.
size_t cudnnCompatibilityVersion(size_t cudnn_version) {
return (cudnn_version / 100) * 100;
}
} // namespace
namespace perftools {
@ -109,6 +103,22 @@ string ToString(cudnnStatus_t status) {
}
}
#if CUDNN_VERSION >= 6000
string ToString(libraryPropertyType type) {
switch (type) {
case MAJOR_VERSION:
return "MAJOR_VERSION";
case MINOR_VERSION:
return "MINOR_VERSION";
case PATCH_LEVEL:
return "PATCH_LEVEL";
default:
return absl::StrCat(
"<unknown libraryPropertyType: ", static_cast<int>(type), ">");
}
}
#endif
template <typename T>
cudnnDataType_t GetCudnnDataType();
@ -360,6 +370,34 @@ cudnnConvolutionBwdFilterAlgo_t ToConvBackwardFilterAlgo(
}
}
#if CUDNN_VERSION >= 6000
port::Status GetCudnnProperty(libraryPropertyType type, int* value) {
cudnnStatus_t status = cudnnGetProperty(type, value);
if (status != CUDNN_STATUS_SUCCESS) {
const string error =
absl::StrCat("cudnnGetProperty failed for type: ", ToString(type),
" with status: ", ToString(status));
LOG(ERROR) << error;
return port::Status{port::error::INTERNAL, error};
}
return port::Status::OK();
}
#endif
port::Status GetLoadedCudnnVersion(CudnnVersion* version) {
#if CUDNN_VERSION >= 6000
TF_RETURN_IF_ERROR(GetCudnnProperty(MAJOR_VERSION, &version->major_version));
TF_RETURN_IF_ERROR(GetCudnnProperty(MINOR_VERSION, &version->minor_version));
TF_RETURN_IF_ERROR(GetCudnnProperty(PATCH_LEVEL, &version->patch_level));
#else
size_t loaded_version = ::cudnnGetVersion();
version->major_version = loaded_version / 1000;
version->minor_version = (loaded_version / 100) % 10;
version->patch_level = loaded_version % 100;
#endif
return port::Status::OK();
}
} // namespace
CudnnSupport::CudnnSupport(CUDAExecutor* parent)
@ -376,24 +414,19 @@ port::Status CudnnSupport::Init() {
auto status = wrap::cudnnCreate(
parent_, reinterpret_cast<cudnnHandle_t*>(&dnn_handle_));
if (status == CUDNN_STATUS_SUCCESS) {
// Check whether loaded version of CuDNN matches what the source
// was built with.
size_t loaded_version = ::cudnnGetVersion();
size_t loaded_compat_version = cudnnCompatibilityVersion(loaded_version);
size_t compiled_compat_version = cudnnCompatibilityVersion(CUDNN_VERSION);
bool library_loaded_matches_source =
(loaded_compat_version == compiled_compat_version);
if (!library_loaded_matches_source) {
const string error =
port::StrCat("Loaded runtime CuDNN library: ", loaded_version,
" (compatibility version ", loaded_compat_version,
") but source was compiled with ", CUDNN_VERSION,
" (compatibility version ", compiled_compat_version,
"). If using a binary install, upgrade your CuDNN "
"library to match. If building from sources, "
"make sure the library loaded at runtime matches a "
"compatible version specified during compile "
"configuration.");
CudnnVersion source_version(CUDNN_MAJOR, CUDNN_MINOR, CUDNN_PATCHLEVEL);
CudnnVersion loaded_version;
TF_RETURN_IF_ERROR(GetLoadedCudnnVersion(&loaded_version));
if (!IsSourceCompatibleWithCudnnLibrary(source_version, loaded_version)) {
const tensorflow::string error = absl::StrCat(
"Loaded runtime CuDNN library: ", loaded_version.ToString(),
" but source was compiled with: ", source_version.ToString(),
". CuDNN library major and minor version needs to match or have "
"higher minor version in case of CuDNN 7.0 or later version. If "
"using a binary install, upgrade your CuDNN library. If building "
"from sources, make sure the library loaded at runtime is compatible "
"with the version specified during compile configuration.");
LOG(ERROR) << error;
return port::Status{port::error::INTERNAL, error};
}

View File

@ -0,0 +1,42 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/stream_executor/cuda/cudnn_version.h"
namespace perftools {
namespace gputools {
namespace cuda {
bool IsSourceCompatibleWithCudnnLibrary(CudnnVersion source_version,
CudnnVersion loaded_version) {
// Major version is neither forward or backward compatible and therefore major
// versions needs to match between source and library.
//
// Minor version is backward-compatible beginning with CuDNN 7 and therefore
// minor version of library needs to be same or higher.
//
// Patch releases are always forward and backward compatible and therefore
// need not match.
if (loaded_version.major_version != source_version.major_version) {
return false;
}
return ((loaded_version.minor_version == source_version.minor_version) ||
(source_version.major_version >= 7 &&
loaded_version.minor_version >= source_version.minor_version));
}
} // namespace cuda
} // namespace gputools
} // namespace perftools

View File

@ -0,0 +1,51 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#ifndef TENSORFLOW_STREAM_EXECUTOR_CUDA_CUDNN_VERSION_H_
#define TENSORFLOW_STREAM_EXECUTOR_CUDA_CUDNN_VERSION_H_
#include <string>
#include "absl/strings/str_join.h"
namespace perftools {
namespace gputools {
namespace cuda {
struct CudnnVersion {
CudnnVersion() = default;
CudnnVersion(int major, int minor, int patch)
: major_version(major), minor_version(minor), patch_level(patch) {}
std::string ToString() const {
return absl::StrJoin({major_version, minor_version, patch_level}, ".");
}
int major_version;
int minor_version;
int patch_level;
};
// Returns true if the given source CuDNN version is compatible with the given
// loaded version.
bool IsSourceCompatibleWithCudnnLibrary(CudnnVersion source_version,
CudnnVersion loaded_version);
} // namespace cuda
} // namespace gputools
} // namespace perftools
#endif // TENSORFLOW_STREAM_EXECUTOR_CUDA_CUDNN_VERSION_H_

View File

@ -0,0 +1,75 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/stream_executor/cuda/cudnn_version.h"
#include "testing/base/public/gunit.h"
#include "tensorflow/core/platform/test.h"
namespace perftools {
namespace gputools {
namespace cuda {
namespace {
TEST(CuDNNVersion, ToString) {
CudnnVersion version(7, 0, 12);
EXPECT_EQ(version.ToString(), "7.0.12");
}
TEST(IsSourceCompatibleWithCudnnLibraryTest, Basic) {
// Returns true if both major and minor versions are matching and even if the
// patch versions are not matching.
EXPECT_TRUE(IsSourceCompatibleWithCudnnLibrary(
/*source_version=*/CudnnVersion(7, 0, 12),
/*loaded_version=*/CudnnVersion(7, 0, 14)));
EXPECT_TRUE(IsSourceCompatibleWithCudnnLibrary(
/*source_version=*/CudnnVersion(6, 1, 14),
/*loaded_version=*/CudnnVersion(6, 1, 00)));
// Returns false if major versions are not matching as they are neither
// forward or backward compatible.
EXPECT_FALSE(IsSourceCompatibleWithCudnnLibrary(
/*source_version=*/CudnnVersion(7, 0, 12),
/*loaded_version=*/CudnnVersion(6, 1, 14)));
EXPECT_FALSE(IsSourceCompatibleWithCudnnLibrary(
/*source_version=*/CudnnVersion(8, 1, 15),
/*loaded_version=*/CudnnVersion(7, 0, 14)));
// Returns true if the loaded version is equal or higher because minor version
// are backward compatible with CuDNN version 7.
EXPECT_TRUE(IsSourceCompatibleWithCudnnLibrary(
/*source_version=*/CudnnVersion(7, 0, 14),
/*loaded_version=*/CudnnVersion(7, 1, 14)));
EXPECT_TRUE(IsSourceCompatibleWithCudnnLibrary(
/*source_version=*/CudnnVersion(7, 0, 14),
/*loaded_version=*/CudnnVersion(7, 1, 15)));
EXPECT_FALSE(IsSourceCompatibleWithCudnnLibrary(
/*source_version=*/CudnnVersion(7, 1, 15),
/*loaded_version=*/CudnnVersion(7, 0, 14)));
// Returns false if minor versions are not matching for version 6. Before
// version 7, minor versions are also neither forward or backward compatible.
EXPECT_FALSE(IsSourceCompatibleWithCudnnLibrary(
/*source_version=*/CudnnVersion(6, 0, 14),
/*loaded_version=*/CudnnVersion(6, 1, 15)));
EXPECT_FALSE(IsSourceCompatibleWithCudnnLibrary(
/*source_version=*/CudnnVersion(6, 1, 14),
/*loaded_version=*/CudnnVersion(6, 0, 14)));
}
} // namespace
} // namespace cuda
} // namespace gputools
} // namespace perftools