Skip to content

Commit c938e87

Browse files
committed
[clang][deps] Generate command lines lazily (llvm#65691)
This patch makes the generation of command lines for modular dependencies lazy/on-demand. That operation is somewhat expensive and prior to this patch used to be performed multiple times for the identical `ModuleDeps` (i.e. when they were imported from multiple different TUs).
1 parent 386d1b2 commit c938e87

File tree

4 files changed

+42
-17
lines changed

4 files changed

+42
-17
lines changed

clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h

+10-3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <optional>
2525
#include <string>
2626
#include <unordered_map>
27+
#include <variant>
2728

2829
namespace clang {
2930
namespace tooling {
@@ -148,9 +149,15 @@ struct ModuleDeps {
148149
/// The \c ActionCache key for this module, if any.
149150
std::optional<std::string> ModuleCacheKey;
150151

151-
/// Compiler invocation that can be used to build this module. Does not
152-
/// include argv[0].
153-
std::vector<std::string> BuildArguments;
152+
/// Get (or compute) the compiler invocation that can be used to build this
153+
/// module. Does not include argv[0].
154+
const std::vector<std::string> &getBuildArguments();
155+
156+
private:
157+
friend class ModuleDepCollectorPP;
158+
159+
std::variant<std::monostate, CowCompilerInvocation, std::vector<std::string>>
160+
BuildInfo;
154161
};
155162

156163
class ModuleDepCollector;

clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp

+9-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@ using namespace clang;
2626
using namespace tooling;
2727
using namespace dependencies;
2828

29+
const std::vector<std::string> &ModuleDeps::getBuildArguments() {
30+
assert(!std::holds_alternative<std::monostate>(BuildInfo) &&
31+
"Using uninitialized ModuleDeps");
32+
if (const auto *CI = std::get_if<CowCompilerInvocation>(&BuildInfo))
33+
BuildInfo = CI->getCC1CommandLine();
34+
return std::get<std::vector<std::string>>(BuildInfo);
35+
}
36+
2937
static void optimizeHeaderSearchOpts(HeaderSearchOptions &Opts,
3038
ASTReader &Reader,
3139
const serialization::ModuleFile &MF) {
@@ -638,7 +646,7 @@ ModuleDepCollectorPP::handleTopLevelModule(const Module *M) {
638646
}
639647
#endif
640648

641-
MD.BuildArguments = CI.getCC1CommandLine();
649+
MD.BuildInfo = std::move(CI);
642650

643651
return MD.ID;
644652
}

clang/tools/clang-scan-deps/ClangScanDeps.cpp

+18-9
Original file line numberDiff line numberDiff line change
@@ -613,14 +613,23 @@ class FullDeps {
613613
}
614614

615615
void mergeDeps(ModuleDepsGraph Graph, size_t InputIndex) {
616-
std::unique_lock<std::mutex> ul(Lock);
617-
for (const ModuleDeps &MD : Graph) {
618-
auto I = Modules.find({MD.ID, 0});
619-
if (I != Modules.end()) {
620-
I->first.InputIndex = std::min(I->first.InputIndex, InputIndex);
621-
continue;
616+
std::vector<ModuleDeps *> NewMDs;
617+
{
618+
std::unique_lock<std::mutex> ul(Lock);
619+
for (const ModuleDeps &MD : Graph) {
620+
auto I = Modules.find({MD.ID, 0});
621+
if (I != Modules.end()) {
622+
I->first.InputIndex = std::min(I->first.InputIndex, InputIndex);
623+
continue;
624+
}
625+
auto Res = Modules.insert(I, {{MD.ID, InputIndex}, std::move(MD)});
626+
NewMDs.push_back(&Res->second);
622627
}
623-
Modules.insert(I, {{MD.ID, InputIndex}, std::move(MD)});
628+
// First call to \c getBuildArguments is somewhat expensive. Let's call it
629+
// on the current thread (instead of the main one), and outside the
630+
// critical section.
631+
for (ModuleDeps *MD : NewMDs)
632+
(void)MD->getBuildArguments();
624633
}
625634
}
626635

@@ -644,7 +653,7 @@ class FullDeps {
644653
/*ShouldOwnClient=*/false);
645654

646655
for (auto &&M : Modules)
647-
if (roundTripCommand(M.second.BuildArguments, *Diags))
656+
if (roundTripCommand(M.second.getBuildArguments(), *Diags))
648657
return true;
649658

650659
for (auto &&I : Inputs)
@@ -673,7 +682,7 @@ class FullDeps {
673682
{"file-deps", toJSONSorted(MD.FileDeps)},
674683
{"clang-module-deps", toJSONSorted(MD.ClangModuleDeps)},
675684
{"clang-modulemap-file", MD.ClangModuleMapFile},
676-
{"command-line", MD.BuildArguments},
685+
{"command-line", MD.getBuildArguments()},
677686
};
678687
if (MD.ModuleCacheKey)
679688
O.try_emplace("cache-key", MD.ModuleCacheKey);

clang/tools/libclang/CDependencies.cpp

+5-4
Original file line numberDiff line numberDiff line change
@@ -266,16 +266,16 @@ static CXErrorCode getFullDependencies(DependencyScanningWorker *Worker,
266266
MDS->Modules = new CXModuleDependency[MDS->Count];
267267
for (int I = 0; I < MDS->Count; ++I) {
268268
CXModuleDependency &M = MDS->Modules[I];
269-
const ModuleDeps &MD = TU.ModuleGraph[I];
269+
ModuleDeps &MD = TU.ModuleGraph[I];
270270
M.Name = cxstring::createDup(MD.ID.ModuleName);
271271
M.ContextHash = cxstring::createDup(MD.ID.ContextHash);
272272
M.ModuleMapPath = cxstring::createDup(MD.ClangModuleMapFile);
273273
M.FileDeps = cxstring::createSet(MD.FileDeps);
274274
std::vector<std::string> Modules;
275-
for (const ModuleID &MID : MD.ClangModuleDeps)
275+
for (ModuleID &MID : MD.ClangModuleDeps)
276276
Modules.push_back(MID.ModuleName + ":" + MID.ContextHash);
277277
M.ModuleDeps = cxstring::createSet(Modules);
278-
M.BuildArguments = cxstring::createSet(MD.BuildArguments);
278+
M.BuildArguments = cxstring::createSet(MD.getBuildArguments());
279279
}
280280
MDC(Context, MDS);
281281
}
@@ -594,7 +594,8 @@ clang_experimental_DepGraphModule_getModuleDeps(CXDepGraphModule CXDepMod) {
594594
CXCStringArray
595595
clang_experimental_DepGraphModule_getBuildArguments(CXDepGraphModule CXDepMod) {
596596
ModuleDeps &ModDeps = *unwrap(CXDepMod)->ModDeps;
597-
return unwrap(CXDepMod)->StrMgr.createCStringsRef(ModDeps.BuildArguments);
597+
return unwrap(CXDepMod)->StrMgr.createCStringsRef(
598+
ModDeps.getBuildArguments());
598599
}
599600

600601
const char *

0 commit comments

Comments
 (0)