Optimize OrderOnlyDeps computation using ResolvedTargetData caching This is a follow-up to https://gn-review.googlesource.com/c/gn/+/22400 to address unresolved review comments. - Add GetOrderOnlyDeps() to ResolvedTargetData to compute and cache order-only dependencies of targets in a bottom-up manner. - Generalize this by making group() targets export the order-only dependencies of their direct dependents. - Refactor NinjaBinaryTargetWriter::GetOrderOnlyDepsFromNonLinkableDeps to use this cached data and simplify duplicate elimination using UniqueVector<OutputFile>. Bug: 502431091 Change-Id: I6a2486a00bc9efe98629799601e8c149113bbdcb Reviewed-on: https://gn-review.googlesource.com/c/gn/+/22540 Commit-Queue: Takuto Ikuta <tikuta@google.com> Reviewed-by: David Turner <digit@google.com>
diff --git a/src/gn/ninja_binary_target_writer.cc b/src/gn/ninja_binary_target_writer.cc index aad2eb2..b075df3 100644 --- a/src/gn/ninja_binary_target_writer.cc +++ b/src/gn/ninja_binary_target_writer.cc
@@ -551,56 +551,9 @@ std::vector<OutputFile> NinjaBinaryTargetWriter::GetOrderOnlyDepsFromNonLinkableDeps( const UniqueVector<const Target*>& non_linkable_deps) const { - std::vector<const Target*> group_stack; - std::vector<OutputFile> outputs_to_write; - std::set<std::string> seen_outputs; - - auto add_output = [&](const OutputFile& output) { - if (seen_outputs.insert(output.value()).second) { - outputs_to_write.push_back(output); - } - }; - - auto process_dep = [&](const Target* dep) { - if (dep->output_type() == Target::GROUP) { - group_stack.push_back(dep); - } else if (dep->has_dependency_output()) { - OutputFile dep_output = dep->dependency_output(); - if (dep->output_type() == Target::SOURCE_SET) { - dep_output.value().append(".linkdeps"); - } - add_output(dep_output); - } - }; - - for (auto* dep : non_linkable_deps) { - process_dep(dep); + UniqueVector<OutputFile> outputs_to_write; + for (const Target* dep : non_linkable_deps) { + outputs_to_write.Append(resolved().GetOrderOnlyDeps(dep)); } - - // Recursively expand dependencies of groups to avoid unnecessary - // dependencies. If a group depends on a source set, we depend on its - // .linkdeps instead of the group itself. This prevents including non-object - // files (like .dwo files) in order-only dependencies. This is crucial for - // remote linking to avoid uploading unnecessary files, which increases data - // transfer and could hit file count limits. - std::set<const Target*> visited_groups; - while (!group_stack.empty()) { - const Target* current = group_stack.back(); - group_stack.pop_back(); - - if (!visited_groups.insert(current).second) - continue; - - auto add_deps = [&](const LabelTargetVector& deps) { - for (const auto& pair : deps) { - process_dep(pair.ptr); - } - }; - - add_deps(current->public_deps()); - add_deps(current->private_deps()); - add_deps(current->data_deps()); - } - - return outputs_to_write; + return outputs_to_write.release(); }
diff --git a/src/gn/resolved_target_data.cc b/src/gn/resolved_target_data.cc index 86ab233..7b4a495 100644 --- a/src/gn/resolved_target_data.cc +++ b/src/gn/resolved_target_data.cc
@@ -310,3 +310,28 @@ } info->has_swift_values = true; } + +void ResolvedTargetData::ComputeOrderOnlyDeps(TargetInfo* info) const { + UniqueVector<OutputFile> all_order_only_deps; + const Target* target = info->target; + + if (target->output_type() == Target::GROUP) { + auto add_deps = [&](base::span<const Target*> deps) { + for (const Target* dep : deps) { + const TargetInfo* dep_info = GetTargetOrderOnlyDeps(dep); + all_order_only_deps.Append(dep_info->order_only_deps); + } + }; + add_deps(info->deps.public_deps()); + add_deps(info->deps.private_deps()); + add_deps(info->deps.data_deps()); + } else if (target->has_dependency_output()) { + OutputFile dep_output = target->dependency_output(); + if (target->output_type() == Target::SOURCE_SET) { + dep_output.value().append(".linkdeps"); + } + all_order_only_deps.push_back(dep_output); + } + + info->order_only_deps = all_order_only_deps.release(); +}
diff --git a/src/gn/resolved_target_data.h b/src/gn/resolved_target_data.h index cc04fdb..a184e3d 100644 --- a/src/gn/resolved_target_data.h +++ b/src/gn/resolved_target_data.h
@@ -13,6 +13,7 @@ #include "base/containers/span.h" #include "gn/lib_file.h" +#include "gn/output_file.h" #include "gn/resolved_target_deps.h" #include "gn/source_dir.h" #include "gn/target.h" @@ -145,6 +146,12 @@ return info->swift_values->modules; } + // Retrieves an ordered list of all order-only dependency outputs for this + // target. + const std::vector<OutputFile>& GetOrderOnlyDeps(const Target* target) const { + return GetTargetOrderOnlyDeps(target)->order_only_deps; + } + private: // The information associated with a given Target pointer. struct TargetInfo { @@ -167,6 +174,7 @@ std::atomic<bool> has_module_deps_information = false; std::atomic<bool> has_rust_libs = false; std::atomic<bool> has_swift_values = false; + std::atomic<bool> has_order_only_deps = false; // Only valid if |has_lib_info| is true. std::vector<SourceDir> lib_dirs; @@ -205,6 +213,9 @@ public_modules(std::move(public_modules)) {} }; std::unique_ptr<SwiftValues> swift_values; + + // Only valid if |has_order_only_deps| is true. + std::vector<OutputFile> order_only_deps; }; // Retrieve TargetInfo value associated with |target|. Create @@ -296,6 +307,18 @@ return info; } + const TargetInfo* GetTargetOrderOnlyDeps(const Target* target) const { + TargetInfo* info = GetTargetInfo(target); + if (!info->has_order_only_deps.load(std::memory_order_acquire)) { + std::lock_guard<std::mutex> lock(info->mutex); + if (!info->has_order_only_deps.load(std::memory_order_relaxed)) { + ComputeOrderOnlyDeps(info); + info->has_order_only_deps.store(true, std::memory_order_release); + } + } + return info; + } + // Compute the portion of TargetInfo guarded by one of the |has_xxx| // booleans. This performs recursive and expensive computations and // should only be called once per TargetInfo instance. @@ -306,6 +329,7 @@ void ComputeModuleDepsInformation(TargetInfo* info) const; void ComputeRustLibs(TargetInfo* info) const; void ComputeSwiftValues(TargetInfo* info) const; + void ComputeOrderOnlyDeps(TargetInfo* info) const; // Helper function used by ComputeInheritedLibs(). void ComputeInheritedLibsFor(