Improve computation of data-structures used for include scanning to be more
resource effective. Specifically, only flatten the transitiveHeaderInfo
structure once and use more effective hash maps.

RELNOTES: None.
PiperOrigin-RevId: 248513186
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationContext.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationContext.java
index 4e41b74..ab44ccc 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationContext.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcCompilationContext.java
@@ -44,6 +44,7 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import javax.annotation.Nullable;
@@ -250,17 +251,22 @@
     return headerInfo.textualHeaders;
   }
 
+  public ImmutableList<HeaderInfo> getTransitiveHeaderInfos() {
+    return transitiveHeaderInfos.toList();
+  }
+
   public IncludeScanningHeaderData.Builder createIncludeScanningHeaderData(
-      boolean usePic, boolean createModularHeaders) {
+      boolean usePic, boolean createModularHeaders, List<HeaderInfo> transitiveHeaderInfoList) {
     // We'd prefer for these types to use ImmutableSet/ImmutableMap. However, constructing these is
     // substantially more costly in a way that shows up in profiles.
     Map<PathFragment, Artifact> pathToLegalOutputArtifact = new HashMap<>();
-    ImmutableList<HeaderInfo> infos = transitiveHeaderInfos.toList();
-    Set<Artifact> modularHeaders = CompactHashSet.createWithExpectedSize(infos.size());
-    for (HeaderInfo transitiveHeaderInfo : infos) {
+    Set<Artifact> modularHeaders =
+        CompactHashSet.createWithExpectedSize(transitiveHeaderInfoList.size());
+    // Not using range-based for loops here and below as the additional overhead of the
+    // ImmutableList iterators has shown up in profiles.
+    for (int c = 0; c < transitiveHeaderInfoList.size(); c++) {
+      HeaderInfo transitiveHeaderInfo = transitiveHeaderInfoList.get(c);
       boolean isModule = createModularHeaders && transitiveHeaderInfo.getModule(usePic) != null;
-      // Not using range-based for loops here as often there is exactly one element in this list
-      // and the amount of garbage created by SingletonImmutableList.iterator() is significant.
       for (int i = 0; i < transitiveHeaderInfo.modularHeaders.size(); i++) {
         Artifact a = transitiveHeaderInfo.modularHeaders.get(i);
         if (!a.isSourceArtifact()) {
@@ -290,8 +296,8 @@
     public final Collection<Artifact> modules;
 
     HeadersAndModules(int expectedHeaderCount) {
-      headers = new HashSet<>(expectedHeaderCount);
-      modules = new LinkedHashSet<>();
+      headers = CompactHashSet.createWithExpectedSize(expectedHeaderCount);
+      modules = CompactHashSet.create();
     }
   }
 
@@ -300,9 +306,10 @@
    * the modules that they are in.
    */
   public HeadersAndModules computeDeclaredHeadersAndUsedModules(
-      boolean usePic, Set<Artifact> includes) {
+      boolean usePic, Set<Artifact> includes, List<HeaderInfo> transitiveHeaderInfoList) {
     HeadersAndModules result = new HeadersAndModules(includes.size());
-    for (HeaderInfo transitiveHeaderInfo : transitiveHeaderInfos) {
+    for (int c = 0; c < transitiveHeaderInfoList.size(); c++) {
+      HeaderInfo transitiveHeaderInfo = transitiveHeaderInfoList.get(c);
       Artifact module = transitiveHeaderInfo.getModule(usePic);
       // Not using range-based for loops here as often there is exactly one element in this list
       // and the amount of garbage created by SingletonImmutableList.iterator() is significant.
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileAction.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileAction.java
index c3dad12..fb520b5 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileAction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CppCompileAction.java
@@ -441,12 +441,15 @@
    * sand-boxed environment) and can diagnose the missing headers.
    */
   private Iterable<Artifact> filterDiscoveredHeaders(
-      ActionExecutionContext actionExecutionContext, Iterable<Artifact> headers) {
+      ActionExecutionContext actionExecutionContext,
+      Iterable<Artifact> headers,
+      List<CcCompilationContext.HeaderInfo> headerInfo) {
     Set<Artifact> undeclaredHeaders = Sets.newHashSet(headers);
 
     // Remove all declared headers and find out which modules were used while at it.
     CcCompilationContext.HeadersAndModules headersAndModules =
-        ccCompilationContext.computeDeclaredHeadersAndUsedModules(usePic, undeclaredHeaders);
+        ccCompilationContext.computeDeclaredHeadersAndUsedModules(
+            usePic, undeclaredHeaders, headerInfo);
     usedModules = ImmutableList.copyOf(headersAndModules.modules);
     undeclaredHeaders.removeAll(headersAndModules.headers);
 
@@ -511,11 +514,13 @@
       }
       commandLineKey = computeCommandLineKey(options);
       List<PathFragment> systemIncludeDirs = getSystemIncludeDirs(options);
+      List<CcCompilationContext.HeaderInfo> headerInfo =
+          ccCompilationContext.getTransitiveHeaderInfos();
       additionalInputs =
           findUsedHeaders(
               actionExecutionContext,
               ccCompilationContext
-                  .createIncludeScanningHeaderData(usePic, useHeaderModules)
+                  .createIncludeScanningHeaderData(usePic, useHeaderModules, headerInfo)
                   .setSystemIncludeDirs(systemIncludeDirs)
                   .setCmdlineIncludes(getCmdlineIncludes(options))
                   .build());
@@ -529,7 +534,8 @@
 
       if (!shouldScanDotdFiles()) {
         // If we aren't looking at .d files later, remove undeclared inputs now.
-        additionalInputs = filterDiscoveredHeaders(actionExecutionContext, additionalInputs);
+        additionalInputs =
+            filterDiscoveredHeaders(actionExecutionContext, additionalInputs, headerInfo);
       }
     }
 
@@ -1451,7 +1457,8 @@
           findUsedHeaders(
               actionExecutionContext,
               ccCompilationContext
-                  .createIncludeScanningHeaderData(usePic, useHeaderModules)
+                  .createIncludeScanningHeaderData(
+                      usePic, useHeaderModules, ccCompilationContext.getTransitiveHeaderInfos())
                   .setSystemIncludeDirs(getSystemIncludeDirs())
                   .setCmdlineIncludes(getCmdlineIncludes(getCompilerOptions()))
                   .build());