Просмотр исходного кода

Distribute autoupdate across threads. (#3443)

Also switch how we ensure that stdin is closed for tests, so that `bazel
run` doesn't hang if invoked manually.

---------

Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
Richard Smith 2 лет назад
Родитель
Сommit
9c46d15f78
2 измененных файлов с 28 добавлено и 8 удалено
  1. 27 7
      testing/file_test/file_test_base.cpp
  2. 1 1
      toolchain/autoupdate_testdata.py

+ 27 - 7
testing/file_test/file_test_base.cpp

@@ -20,6 +20,8 @@
 #include "llvm/Support/InitLLVM.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/ThreadPool.h"
 #include "testing/file_test/autoupdate.h"
 
 ABSL_FLAG(std::vector<std::string>, file_tests, {},
@@ -30,6 +32,9 @@ ABSL_FLAG(std::string, test_targets_file, "",
 ABSL_FLAG(bool, autoupdate, false,
           "Instead of verifying files match test output, autoupdate files "
           "based on test output.");
+ABSL_FLAG(unsigned int, threads, 0,
+          "Number of threads to use when autoupdating tests, or 0 to "
+          "automatically determine a thread count.");
 
 namespace Carbon::Testing {
 
@@ -720,18 +725,33 @@ static auto Main(int argc, char** argv) -> int {
     return EXIT_FAILURE;
   }
 
+  // Tests might try to read from stdin. Ensure those reads fail by closing
+  // stdin and reopening it as /dev/null. Note that STDIN_FILENO doesn't exist
+  // on Windows, but POSIX requires it to be 0.
+  llvm::sys::Process::SafelyCloseFileDescriptor(0);
+  llvm::sys::Process::FixupStandardFileDescriptors();
+
   llvm::SmallVector<std::string> tests = GetTests();
   auto test_factory = GetFileTestFactory();
   if (absl::GetFlag(FLAGS_autoupdate)) {
+    llvm::ThreadPool pool({.ThreadsRequested = absl::GetFlag(FLAGS_threads)});
+    std::mutex errs_mutex;
+
     for (const auto& test_name : tests) {
-      std::unique_ptr<FileTestBase> test(test_factory.factory_fn(test_name));
-      auto result = test->Autoupdate();
-      if (result.ok()) {
-        llvm::errs() << (*result ? "!" : ".");
-      } else {
-        llvm::errs() << result.error().message() << "\n";
-      }
+      pool.async([&test_factory, &errs_mutex, test_name] {
+        std::unique_ptr<FileTestBase> test(test_factory.factory_fn(test_name));
+        auto result = test->Autoupdate();
+
+        // Guard access to llvm::errs, which is not thread-safe.
+        std::unique_lock<std::mutex> lock(errs_mutex);
+        if (result.ok()) {
+          llvm::errs() << (*result ? "!" : ".");
+        } else {
+          llvm::errs() << "\n" << result.error().message() << "\n";
+        }
+      });
     }
+    pool.wait();
     llvm::errs() << "\nDone!\n";
     return EXIT_SUCCESS;
   } else {

+ 1 - 1
toolchain/autoupdate_testdata.py

@@ -43,7 +43,7 @@ def main() -> None:
         argv.append("--file_tests=" + ",".join(file_tests))
     # Provide an empty stdin so that the driver tests that read from stdin
     # don't block waiting for input. This matches the behavior of `bazel test`.
-    subprocess.run(argv, check=True, stdin=subprocess.DEVNULL)
+    subprocess.run(argv, check=True)
 
 
 if __name__ == "__main__":