1
0
mirror of https://github.com/Kitware/CMake.git synced 2025-10-15 03:48:02 +08:00

CUDA: More exhaustive checks to determine when to do device linking

Previously CMake used fairly naive logic to determine when to do
device linking which caused unnecessary device linking to occur
frequently. We now use a more exhaustive algorithm to determine
when we have a need for device linking.

Fixes: #19238
This commit is contained in:
Robert Maynard
2019-05-09 09:13:39 -04:00
parent 3205c7c950
commit 81b4d10d8f
7 changed files with 112 additions and 107 deletions

View File

@@ -3,14 +3,20 @@
#include "cmLinkLineDeviceComputer.h" #include "cmLinkLineDeviceComputer.h"
#include <algorithm>
#include <set> #include <set>
#include <sstream> #include <sstream>
#include <utility> #include <utility>
#include <vector>
#include "cmAlgorithms.h" #include "cmAlgorithms.h"
#include "cmComputeLinkInformation.h" #include "cmComputeLinkInformation.h"
#include "cmGeneratorTarget.h" #include "cmGeneratorTarget.h"
#include "cmLocalGenerator.h"
#include "cmStateDirectory.h"
#include "cmStateSnapshot.h"
#include "cmStateTypes.h" #include "cmStateTypes.h"
#include "cmSystemTools.h"
class cmOutputConverter; class cmOutputConverter;
@@ -40,6 +46,27 @@ static bool cmLinkItemValidForDevice(std::string const& item)
cmHasLiteralPrefix(item, "--library")); cmHasLiteralPrefix(item, "--library"));
} }
bool cmLinkLineDeviceComputer::ComputeRequiresDeviceLinking(
cmComputeLinkInformation& cli)
{
// Determine if this item might requires device linking.
// For this we only consider targets
typedef cmComputeLinkInformation::ItemVector ItemVector;
ItemVector const& items = cli.GetItems();
std::string config = cli.GetConfig();
for (auto const& item : items) {
if (item.Target &&
item.Target->GetType() == cmStateEnums::STATIC_LIBRARY) {
if ((!item.Target->GetPropertyAsBool("CUDA_RESOLVE_DEVICE_SYMBOLS")) &&
item.Target->GetPropertyAsBool("CUDA_SEPARABLE_COMPILATION")) {
// this dependency requires us to device link it
return true;
}
}
}
return false;
}
std::string cmLinkLineDeviceComputer::ComputeLinkLibraries( std::string cmLinkLineDeviceComputer::ComputeLinkLibraries(
cmComputeLinkInformation& cli, std::string const& stdLibString) cmComputeLinkInformation& cli, std::string const& stdLibString)
{ {
@@ -62,17 +89,12 @@ std::string cmLinkLineDeviceComputer::ComputeLinkLibraries(
} }
if (item.Target) { if (item.Target) {
bool skip = false; bool skip = true;
switch (item.Target->GetType()) { if (item.Target->GetType() == cmStateEnums::STATIC_LIBRARY) {
case cmStateEnums::MODULE_LIBRARY: if ((!item.Target->GetPropertyAsBool("CUDA_RESOLVE_DEVICE_SYMBOLS")) &&
case cmStateEnums::INTERFACE_LIBRARY: item.Target->GetPropertyAsBool("CUDA_SEPARABLE_COMPILATION")) {
skip = true; skip = false;
break; }
case cmStateEnums::STATIC_LIBRARY:
skip = item.Target->GetPropertyAsBool("CUDA_RESOLVE_DEVICE_SYMBOLS");
break;
default:
break;
} }
if (skip) { if (skip) {
continue; continue;
@@ -116,3 +138,56 @@ std::string cmLinkLineDeviceComputer::GetLinkerLanguage(cmGeneratorTarget*,
{ {
return "CUDA"; return "CUDA";
} }
bool requireDeviceLinking(cmGeneratorTarget& target, cmLocalGenerator& lg,
const std::string& config)
{
if (target.GetType() == cmStateEnums::OBJECT_LIBRARY) {
return false;
}
if (const char* resolveDeviceSymbols =
target.GetProperty("CUDA_RESOLVE_DEVICE_SYMBOLS")) {
// If CUDA_RESOLVE_DEVICE_SYMBOLS has been explicitly set we need
// to honor the value no matter what it is.
return cmSystemTools::IsOn(resolveDeviceSymbols);
}
if (const char* separableCompilation =
target.GetProperty("CUDA_SEPARABLE_COMPILATION")) {
if (cmSystemTools::IsOn(separableCompilation)) {
bool doDeviceLinking = false;
switch (target.GetType()) {
case cmStateEnums::SHARED_LIBRARY:
case cmStateEnums::MODULE_LIBRARY:
case cmStateEnums::EXECUTABLE:
doDeviceLinking = true;
break;
default:
break;
}
return doDeviceLinking;
}
}
// Determine if we have any dependencies that require
// us to do a device link step
const std::string cuda_lang("CUDA");
cmGeneratorTarget::LinkClosure const* closure =
target.GetLinkClosure(config);
bool closureHasCUDA =
(std::find(closure->Languages.begin(), closure->Languages.end(),
cuda_lang) != closure->Languages.end());
if (closureHasCUDA) {
cmComputeLinkInformation* pcli = target.GetLinkInformation(config);
if (pcli) {
cmLinkLineDeviceComputer deviceLinkComputer(
&lg, lg.GetStateSnapshot().GetDirectory());
return deviceLinkComputer.ComputeRequiresDeviceLinking(*pcli);
}
return true;
}
return false;
}

View File

@@ -12,6 +12,7 @@
class cmComputeLinkInformation; class cmComputeLinkInformation;
class cmGeneratorTarget; class cmGeneratorTarget;
class cmLocalGenerator;
class cmOutputConverter; class cmOutputConverter;
class cmStateDirectory; class cmStateDirectory;
@@ -26,6 +27,8 @@ public:
cmLinkLineDeviceComputer& operator=(cmLinkLineDeviceComputer const&) = cmLinkLineDeviceComputer& operator=(cmLinkLineDeviceComputer const&) =
delete; delete;
bool ComputeRequiresDeviceLinking(cmComputeLinkInformation& cli);
std::string ComputeLinkLibraries(cmComputeLinkInformation& cli, std::string ComputeLinkLibraries(cmComputeLinkInformation& cli,
std::string const& stdLibString) override; std::string const& stdLibString) override;
@@ -33,4 +36,7 @@ public:
std::string const& config) override; std::string const& config) override;
}; };
bool requireDeviceLinking(cmGeneratorTarget& target, cmLocalGenerator& lg,
const std::string& config);
#endif #endif

View File

@@ -2,7 +2,6 @@
file Copyright.txt or https://cmake.org/licensing for details. */ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmMakefileExecutableTargetGenerator.h" #include "cmMakefileExecutableTargetGenerator.h"
#include <algorithm>
#include <memory> // IWYU pragma: keep #include <memory> // IWYU pragma: keep
#include <set> #include <set>
#include <sstream> #include <sstream>
@@ -87,20 +86,9 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule(
return; return;
} }
const std::string cuda_lang("CUDA"); bool requiresDeviceLinking = requireDeviceLinking(
cmGeneratorTarget::LinkClosure const* closure = *this->GeneratorTarget, *this->LocalGenerator, this->ConfigName);
this->GeneratorTarget->GetLinkClosure(this->ConfigName); if (!requiresDeviceLinking) {
const bool hasCUDA =
(std::find(closure->Languages.begin(), closure->Languages.end(),
cuda_lang) != closure->Languages.end());
bool doDeviceLinking = true;
if (const char* resolveDeviceSymbols =
this->GeneratorTarget->GetProperty("CUDA_RESOLVE_DEVICE_SYMBOLS")) {
doDeviceLinking = cmSystemTools::IsOn(resolveDeviceSymbols);
}
if (!hasCUDA || !doDeviceLinking) {
return; return;
} }

View File

@@ -2,7 +2,6 @@
file Copyright.txt or https://cmake.org/licensing for details. */ file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmMakefileLibraryTargetGenerator.h" #include "cmMakefileLibraryTargetGenerator.h"
#include <algorithm>
#include <memory> // IWYU pragma: keep #include <memory> // IWYU pragma: keep
#include <set> #include <set>
#include <sstream> #include <sstream>
@@ -124,20 +123,10 @@ void cmMakefileLibraryTargetGenerator::WriteObjectLibraryRules()
void cmMakefileLibraryTargetGenerator::WriteStaticLibraryRules() void cmMakefileLibraryTargetGenerator::WriteStaticLibraryRules()
{ {
const std::string cuda_lang("CUDA");
cmGeneratorTarget::LinkClosure const* closure =
this->GeneratorTarget->GetLinkClosure(this->ConfigName);
const bool hasCUDA = bool requiresDeviceLinking = requireDeviceLinking(
(std::find(closure->Languages.begin(), closure->Languages.end(), *this->GeneratorTarget, *this->LocalGenerator, this->ConfigName);
cuda_lang) != closure->Languages.end()); if (requiresDeviceLinking) {
bool doDeviceLinking = false;
if (const char* resolveDeviceSymbols =
this->GeneratorTarget->GetProperty("CUDA_RESOLVE_DEVICE_SYMBOLS")) {
doDeviceLinking = cmSystemTools::IsOn(resolveDeviceSymbols);
}
if (hasCUDA && doDeviceLinking) {
std::string linkRuleVar = "CMAKE_CUDA_DEVICE_LINK_LIBRARY"; std::string linkRuleVar = "CMAKE_CUDA_DEVICE_LINK_LIBRARY";
this->WriteDeviceLibraryRules(linkRuleVar, false); this->WriteDeviceLibraryRules(linkRuleVar, false);
} }
@@ -163,19 +152,9 @@ void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules(bool relink)
} }
if (!relink) { if (!relink) {
const std::string cuda_lang("CUDA"); bool requiresDeviceLinking = requireDeviceLinking(
cmGeneratorTarget::LinkClosure const* closure = *this->GeneratorTarget, *this->LocalGenerator, this->ConfigName);
this->GeneratorTarget->GetLinkClosure(this->ConfigName); if (requiresDeviceLinking) {
const bool hasCUDA =
(std::find(closure->Languages.begin(), closure->Languages.end(),
cuda_lang) != closure->Languages.end());
bool doDeviceLinking = true;
if (const char* resolveDeviceSymbols =
this->GeneratorTarget->GetProperty("CUDA_RESOLVE_DEVICE_SYMBOLS")) {
doDeviceLinking = cmSystemTools::IsOn(resolveDeviceSymbols);
}
if (hasCUDA && doDeviceLinking) {
std::string linkRuleVar = "CMAKE_CUDA_DEVICE_LINK_LIBRARY"; std::string linkRuleVar = "CMAKE_CUDA_DEVICE_LINK_LIBRARY";
this->WriteDeviceLibraryRules(linkRuleVar, relink); this->WriteDeviceLibraryRules(linkRuleVar, relink);
} }
@@ -209,19 +188,9 @@ void cmMakefileLibraryTargetGenerator::WriteModuleLibraryRules(bool relink)
{ {
if (!relink) { if (!relink) {
const std::string cuda_lang("CUDA"); bool requiresDeviceLinking = requireDeviceLinking(
cmGeneratorTarget::LinkClosure const* closure = *this->GeneratorTarget, *this->LocalGenerator, this->ConfigName);
this->GeneratorTarget->GetLinkClosure(this->ConfigName); if (requiresDeviceLinking) {
const bool hasCUDA =
(std::find(closure->Languages.begin(), closure->Languages.end(),
cuda_lang) != closure->Languages.end());
bool doDeviceLinking = true;
if (const char* resolveDeviceSymbols =
this->GeneratorTarget->GetProperty("CUDA_RESOLVE_DEVICE_SYMBOLS")) {
doDeviceLinking = cmSystemTools::IsOn(resolveDeviceSymbols);
}
if (hasCUDA && doDeviceLinking) {
std::string linkRuleVar = "CMAKE_CUDA_DEVICE_LINK_LIBRARY"; std::string linkRuleVar = "CMAKE_CUDA_DEVICE_LINK_LIBRARY";
this->WriteDeviceLibraryRules(linkRuleVar, relink); this->WriteDeviceLibraryRules(linkRuleVar, relink);
} }

View File

@@ -18,6 +18,7 @@
#include "cmGeneratorTarget.h" #include "cmGeneratorTarget.h"
#include "cmGlobalNinjaGenerator.h" #include "cmGlobalNinjaGenerator.h"
#include "cmLinkLineComputer.h" #include "cmLinkLineComputer.h"
#include "cmLinkLineDeviceComputer.h"
#include "cmLocalGenerator.h" #include "cmLocalGenerator.h"
#include "cmLocalNinjaGenerator.h" #include "cmLocalNinjaGenerator.h"
#include "cmMakefile.h" #include "cmMakefile.h"
@@ -571,32 +572,9 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement()
cmGeneratorTarget& genTarget = *this->GetGeneratorTarget(); cmGeneratorTarget& genTarget = *this->GetGeneratorTarget();
// determine if we need to do any device linking for this target bool requiresDeviceLinking = requireDeviceLinking(
const std::string cuda_lang("CUDA"); *this->GeneratorTarget, *this->GetLocalGenerator(), this->ConfigName);
cmGeneratorTarget::LinkClosure const* closure = if (!requiresDeviceLinking) {
genTarget.GetLinkClosure(this->GetConfigName());
const bool hasCUDA =
(std::find(closure->Languages.begin(), closure->Languages.end(),
cuda_lang) != closure->Languages.end());
bool doDeviceLinking = false;
if (const char* resolveDeviceSymbols =
genTarget.GetProperty("CUDA_RESOLVE_DEVICE_SYMBOLS")) {
doDeviceLinking = cmSystemTools::IsOn(resolveDeviceSymbols);
} else {
switch (genTarget.GetType()) {
case cmStateEnums::SHARED_LIBRARY:
case cmStateEnums::MODULE_LIBRARY:
case cmStateEnums::EXECUTABLE:
doDeviceLinking = true;
break;
default:
break;
}
}
if (!(doDeviceLinking && hasCUDA)) {
return; return;
} }

View File

@@ -10,6 +10,7 @@
#include "cmGeneratorExpression.h" #include "cmGeneratorExpression.h"
#include "cmGeneratorTarget.h" #include "cmGeneratorTarget.h"
#include "cmGlobalVisualStudio10Generator.h" #include "cmGlobalVisualStudio10Generator.h"
#include "cmLinkLineDeviceComputer.h"
#include "cmLocalVisualStudio10Generator.h" #include "cmLocalVisualStudio10Generator.h"
#include "cmMakefile.h" #include "cmMakefile.h"
#include "cmSourceFile.h" #include "cmSourceFile.h"
@@ -3007,21 +3008,8 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaLinkOptions(
Options& cudaLinkOptions = *pOptions; Options& cudaLinkOptions = *pOptions;
// Determine if we need to do a device link // Determine if we need to do a device link
bool doDeviceLinking = false; bool doDeviceLinking = requireDeviceLinking(
if (const char* resolveDeviceSymbols = *this->GeneratorTarget, *this->LocalGenerator, configName);
this->GeneratorTarget->GetProperty("CUDA_RESOLVE_DEVICE_SYMBOLS")) {
doDeviceLinking = cmSystemTools::IsOn(resolveDeviceSymbols);
} else {
switch (this->GeneratorTarget->GetType()) {
case cmStateEnums::SHARED_LIBRARY:
case cmStateEnums::MODULE_LIBRARY:
case cmStateEnums::EXECUTABLE:
doDeviceLinking = true;
break;
default:
break;
}
}
cudaLinkOptions.AddFlag("PerformDeviceLink", cudaLinkOptions.AddFlag("PerformDeviceLink",
doDeviceLinking ? "true" : "false"); doDeviceLinking ? "true" : "false");

View File

@@ -359,6 +359,7 @@ CMAKE_CXX_SOURCES="\
cmLinkDirectoriesCommand \ cmLinkDirectoriesCommand \
cmLinkItem \ cmLinkItem \
cmLinkLineComputer \ cmLinkLineComputer \
cmLinkLineDeviceComputer \
cmListCommand \ cmListCommand \
cmListFileCache \ cmListFileCache \
cmLocalCommonGenerator \ cmLocalCommonGenerator \