mirror of
https://github.com/Kitware/CMake.git
synced 2025-10-14 19:08:07 +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:
@@ -3,14 +3,20 @@
|
||||
|
||||
#include "cmLinkLineDeviceComputer.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "cmAlgorithms.h"
|
||||
#include "cmComputeLinkInformation.h"
|
||||
#include "cmGeneratorTarget.h"
|
||||
#include "cmLocalGenerator.h"
|
||||
#include "cmStateDirectory.h"
|
||||
#include "cmStateSnapshot.h"
|
||||
#include "cmStateTypes.h"
|
||||
#include "cmSystemTools.h"
|
||||
|
||||
class cmOutputConverter;
|
||||
|
||||
@@ -40,6 +46,27 @@ static bool cmLinkItemValidForDevice(std::string const& item)
|
||||
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(
|
||||
cmComputeLinkInformation& cli, std::string const& stdLibString)
|
||||
{
|
||||
@@ -62,17 +89,12 @@ std::string cmLinkLineDeviceComputer::ComputeLinkLibraries(
|
||||
}
|
||||
|
||||
if (item.Target) {
|
||||
bool skip = false;
|
||||
switch (item.Target->GetType()) {
|
||||
case cmStateEnums::MODULE_LIBRARY:
|
||||
case cmStateEnums::INTERFACE_LIBRARY:
|
||||
skip = true;
|
||||
break;
|
||||
case cmStateEnums::STATIC_LIBRARY:
|
||||
skip = item.Target->GetPropertyAsBool("CUDA_RESOLVE_DEVICE_SYMBOLS");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
bool skip = true;
|
||||
if (item.Target->GetType() == cmStateEnums::STATIC_LIBRARY) {
|
||||
if ((!item.Target->GetPropertyAsBool("CUDA_RESOLVE_DEVICE_SYMBOLS")) &&
|
||||
item.Target->GetPropertyAsBool("CUDA_SEPARABLE_COMPILATION")) {
|
||||
skip = false;
|
||||
}
|
||||
}
|
||||
if (skip) {
|
||||
continue;
|
||||
@@ -116,3 +138,56 @@ std::string cmLinkLineDeviceComputer::GetLinkerLanguage(cmGeneratorTarget*,
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@@ -12,6 +12,7 @@
|
||||
|
||||
class cmComputeLinkInformation;
|
||||
class cmGeneratorTarget;
|
||||
class cmLocalGenerator;
|
||||
class cmOutputConverter;
|
||||
class cmStateDirectory;
|
||||
|
||||
@@ -26,6 +27,8 @@ public:
|
||||
cmLinkLineDeviceComputer& operator=(cmLinkLineDeviceComputer const&) =
|
||||
delete;
|
||||
|
||||
bool ComputeRequiresDeviceLinking(cmComputeLinkInformation& cli);
|
||||
|
||||
std::string ComputeLinkLibraries(cmComputeLinkInformation& cli,
|
||||
std::string const& stdLibString) override;
|
||||
|
||||
@@ -33,4 +36,7 @@ public:
|
||||
std::string const& config) override;
|
||||
};
|
||||
|
||||
bool requireDeviceLinking(cmGeneratorTarget& target, cmLocalGenerator& lg,
|
||||
const std::string& config);
|
||||
|
||||
#endif
|
||||
|
@@ -2,7 +2,6 @@
|
||||
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||
#include "cmMakefileExecutableTargetGenerator.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory> // IWYU pragma: keep
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
@@ -87,20 +86,9 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule(
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string cuda_lang("CUDA");
|
||||
cmGeneratorTarget::LinkClosure const* closure =
|
||||
this->GeneratorTarget->GetLinkClosure(this->ConfigName);
|
||||
|
||||
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) {
|
||||
bool requiresDeviceLinking = requireDeviceLinking(
|
||||
*this->GeneratorTarget, *this->LocalGenerator, this->ConfigName);
|
||||
if (!requiresDeviceLinking) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -2,7 +2,6 @@
|
||||
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||
#include "cmMakefileLibraryTargetGenerator.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory> // IWYU pragma: keep
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
@@ -124,20 +123,10 @@ void cmMakefileLibraryTargetGenerator::WriteObjectLibraryRules()
|
||||
|
||||
void cmMakefileLibraryTargetGenerator::WriteStaticLibraryRules()
|
||||
{
|
||||
const std::string cuda_lang("CUDA");
|
||||
cmGeneratorTarget::LinkClosure const* closure =
|
||||
this->GeneratorTarget->GetLinkClosure(this->ConfigName);
|
||||
|
||||
const bool hasCUDA =
|
||||
(std::find(closure->Languages.begin(), closure->Languages.end(),
|
||||
cuda_lang) != closure->Languages.end());
|
||||
|
||||
bool doDeviceLinking = false;
|
||||
if (const char* resolveDeviceSymbols =
|
||||
this->GeneratorTarget->GetProperty("CUDA_RESOLVE_DEVICE_SYMBOLS")) {
|
||||
doDeviceLinking = cmSystemTools::IsOn(resolveDeviceSymbols);
|
||||
}
|
||||
if (hasCUDA && doDeviceLinking) {
|
||||
bool requiresDeviceLinking = requireDeviceLinking(
|
||||
*this->GeneratorTarget, *this->LocalGenerator, this->ConfigName);
|
||||
if (requiresDeviceLinking) {
|
||||
std::string linkRuleVar = "CMAKE_CUDA_DEVICE_LINK_LIBRARY";
|
||||
this->WriteDeviceLibraryRules(linkRuleVar, false);
|
||||
}
|
||||
@@ -163,19 +152,9 @@ void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules(bool relink)
|
||||
}
|
||||
|
||||
if (!relink) {
|
||||
const std::string cuda_lang("CUDA");
|
||||
cmGeneratorTarget::LinkClosure const* closure =
|
||||
this->GeneratorTarget->GetLinkClosure(this->ConfigName);
|
||||
|
||||
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) {
|
||||
bool requiresDeviceLinking = requireDeviceLinking(
|
||||
*this->GeneratorTarget, *this->LocalGenerator, this->ConfigName);
|
||||
if (requiresDeviceLinking) {
|
||||
std::string linkRuleVar = "CMAKE_CUDA_DEVICE_LINK_LIBRARY";
|
||||
this->WriteDeviceLibraryRules(linkRuleVar, relink);
|
||||
}
|
||||
@@ -209,19 +188,9 @@ void cmMakefileLibraryTargetGenerator::WriteModuleLibraryRules(bool relink)
|
||||
{
|
||||
|
||||
if (!relink) {
|
||||
const std::string cuda_lang("CUDA");
|
||||
cmGeneratorTarget::LinkClosure const* closure =
|
||||
this->GeneratorTarget->GetLinkClosure(this->ConfigName);
|
||||
|
||||
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) {
|
||||
bool requiresDeviceLinking = requireDeviceLinking(
|
||||
*this->GeneratorTarget, *this->LocalGenerator, this->ConfigName);
|
||||
if (requiresDeviceLinking) {
|
||||
std::string linkRuleVar = "CMAKE_CUDA_DEVICE_LINK_LIBRARY";
|
||||
this->WriteDeviceLibraryRules(linkRuleVar, relink);
|
||||
}
|
||||
|
@@ -18,6 +18,7 @@
|
||||
#include "cmGeneratorTarget.h"
|
||||
#include "cmGlobalNinjaGenerator.h"
|
||||
#include "cmLinkLineComputer.h"
|
||||
#include "cmLinkLineDeviceComputer.h"
|
||||
#include "cmLocalGenerator.h"
|
||||
#include "cmLocalNinjaGenerator.h"
|
||||
#include "cmMakefile.h"
|
||||
@@ -571,32 +572,9 @@ void cmNinjaNormalTargetGenerator::WriteDeviceLinkStatement()
|
||||
|
||||
cmGeneratorTarget& genTarget = *this->GetGeneratorTarget();
|
||||
|
||||
// determine if we need to do any device linking for this target
|
||||
const std::string cuda_lang("CUDA");
|
||||
cmGeneratorTarget::LinkClosure const* closure =
|
||||
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)) {
|
||||
bool requiresDeviceLinking = requireDeviceLinking(
|
||||
*this->GeneratorTarget, *this->GetLocalGenerator(), this->ConfigName);
|
||||
if (!requiresDeviceLinking) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -10,6 +10,7 @@
|
||||
#include "cmGeneratorExpression.h"
|
||||
#include "cmGeneratorTarget.h"
|
||||
#include "cmGlobalVisualStudio10Generator.h"
|
||||
#include "cmLinkLineDeviceComputer.h"
|
||||
#include "cmLocalVisualStudio10Generator.h"
|
||||
#include "cmMakefile.h"
|
||||
#include "cmSourceFile.h"
|
||||
@@ -3007,21 +3008,8 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaLinkOptions(
|
||||
Options& cudaLinkOptions = *pOptions;
|
||||
|
||||
// Determine if we need to do a device link
|
||||
bool doDeviceLinking = false;
|
||||
if (const char* resolveDeviceSymbols =
|
||||
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;
|
||||
}
|
||||
}
|
||||
bool doDeviceLinking = requireDeviceLinking(
|
||||
*this->GeneratorTarget, *this->LocalGenerator, configName);
|
||||
|
||||
cudaLinkOptions.AddFlag("PerformDeviceLink",
|
||||
doDeviceLinking ? "true" : "false");
|
||||
|
Reference in New Issue
Block a user