|
15 | 15 | #include "llvm/Config/llvm-config.h" |
16 | 16 | #include "llvm/Support/Debug.h" |
17 | 17 | #include "llvm/Support/Parallel.h" |
| 18 | +#include "llvm/Support/Program.h" |
18 | 19 | #include "llvm/Support/ThreadPool.h" |
19 | 20 | #include "llvm/Support/raw_ostream.h" |
20 | 21 | #include "gtest/gtest.h" |
|
40 | 41 |
|
41 | 42 | using namespace llvm; |
42 | 43 |
|
| 44 | +// Provided by the unit test main to locate the current test binary. |
| 45 | +extern const char *TestMainArgv0; |
| 46 | + |
43 | 47 | namespace { |
44 | 48 |
|
| 49 | +// Unique anchor whose address helps locate the current test binary. |
| 50 | +static int JobserverTestAnchor = 0; |
| 51 | + |
45 | 52 | // RAII helper to set an environment variable for the duration of a test. |
46 | 53 | class ScopedEnvironment { |
47 | 54 | std::string Name; |
@@ -382,51 +389,93 @@ TEST_F(JobserverStrategyTest, ThreadPoolConcurrencyIsLimited) { |
382 | 389 | EXPECT_EQ(CompletedTasks, NumTasks); |
383 | 390 | } |
384 | 391 |
|
385 | | -TEST_F(JobserverStrategyTest, ParallelForIsLimited) { |
| 392 | +// Parent-side driver that spawns a fresh process to run the child test which |
| 393 | +// validates that parallelFor respects the jobserver limit when it is the first |
| 394 | +// user of the default executor in that process. |
| 395 | +TEST_F(JobserverStrategyTest, ParallelForIsLimited_Subprocess) { |
| 396 | + // Mark child execution. |
| 397 | + setenv("LLVM_JOBSERVER_TEST_CHILD", "1", 1); |
| 398 | + |
| 399 | + // Find the current test binary and build args to run only the child test. |
| 400 | + std::string Executable = |
| 401 | + sys::fs::getMainExecutable(TestMainArgv0, &JobserverTestAnchor); |
| 402 | + ASSERT_FALSE(Executable.empty()) << "Failed to get main executable path"; |
| 403 | + SmallVector<StringRef, 4> Args{Executable, |
| 404 | + "--gtest_filter=JobserverStrategyTest." |
| 405 | + "ParallelForIsLimited_SubprocessChild"}; |
| 406 | + |
| 407 | + std::string Error; |
| 408 | + bool ExecFailed = false; |
| 409 | + int RC = sys::ExecuteAndWait(Executable, Args, std::nullopt, {}, 0, 0, &Error, |
| 410 | + &ExecFailed); |
| 411 | + unsetenv("LLVM_JOBSERVER_TEST_CHILD"); |
| 412 | + ASSERT_FALSE(ExecFailed) << Error; |
| 413 | + ASSERT_EQ(RC, 0) << "Executable failed with exit code " << RC; |
| 414 | +} |
| 415 | + |
| 416 | +// Child-side test: create FIFO and make-proxy in this process, set the |
| 417 | +// jobserver strategy, and then run parallelFor. |
| 418 | +TEST_F(JobserverStrategyTest, ParallelForIsLimited_SubprocessChild) { |
| 419 | + if (!getenv("LLVM_JOBSERVER_TEST_CHILD")) |
| 420 | + GTEST_SKIP() << "Not running in child mode"; |
| 421 | + |
386 | 422 | // This test verifies that llvm::parallelFor respects the jobserver limit. |
387 | 423 | const int NumExplicitJobs = 3; |
388 | 424 | const int ConcurrencyLimit = NumExplicitJobs + 1; // +1 implicit |
389 | 425 | const int NumTasks = 20; |
390 | 426 |
|
391 | | - LLVM_DEBUG(dbgs() << "Calling startMakeProxy with " << NumExplicitJobs |
392 | | - << " jobs.\n"); |
393 | 427 | startMakeProxy(NumExplicitJobs); |
394 | | - LLVM_DEBUG(dbgs() << "MakeProxy is running.\n"); |
395 | 428 |
|
396 | | - // Set the global strategy. parallelFor will use this. |
| 429 | + // Set the global strategy before any default executor is created. |
397 | 430 | parallel::strategy = jobserver_concurrency(); |
398 | 431 |
|
399 | 432 | std::atomic<int> ActiveTasks{0}; |
400 | 433 | std::atomic<int> MaxActiveTasks{0}; |
401 | 434 |
|
402 | | - parallelFor(0, NumTasks, [&](int i) { |
| 435 | + parallelFor(0, NumTasks, [&]([[maybe_unused]] int i) { |
403 | 436 | int CurrentActive = ++ActiveTasks; |
404 | | - LLVM_DEBUG(dbgs() << "Task " << i << ": Active tasks: " << CurrentActive |
405 | | - << "\n"); |
406 | 437 | int OldMax = MaxActiveTasks.load(); |
407 | 438 | while (CurrentActive > OldMax) |
408 | 439 | MaxActiveTasks.compare_exchange_weak(OldMax, CurrentActive); |
409 | | - |
410 | 440 | std::this_thread::sleep_for(std::chrono::milliseconds(20)); |
411 | 441 | --ActiveTasks; |
412 | 442 | }); |
413 | 443 |
|
414 | | - LLVM_DEBUG(dbgs() << "ParallelFor finished. Max active tasks was " |
415 | | - << MaxActiveTasks << ".\n"); |
416 | 444 | EXPECT_LE(MaxActiveTasks, ConcurrencyLimit); |
417 | 445 | } |
418 | 446 |
|
419 | | -TEST_F(JobserverStrategyTest, ParallelSortIsLimited) { |
420 | | - // This test serves as an integration test to ensure parallelSort completes |
421 | | - // correctly when running under the jobserver strategy. It doesn't directly |
422 | | - // measure concurrency but verifies correctness. |
| 447 | +// Parent-side driver for parallelSort child test. |
| 448 | +TEST_F(JobserverStrategyTest, ParallelSortIsLimited_Subprocess) { |
| 449 | + setenv("LLVM_JOBSERVER_TEST_CHILD", "1", 1); |
| 450 | + |
| 451 | + std::string Executable = |
| 452 | + sys::fs::getMainExecutable(TestMainArgv0, &JobserverTestAnchor); |
| 453 | + ASSERT_FALSE(Executable.empty()) << "Failed to get main executable path"; |
| 454 | + SmallVector<StringRef, 4> Args{Executable, |
| 455 | + "--gtest_filter=JobserverStrategyTest." |
| 456 | + "ParallelSortIsLimited_SubprocessChild"}; |
| 457 | + |
| 458 | + std::string Error; |
| 459 | + bool ExecFailed = false; |
| 460 | + int RC = sys::ExecuteAndWait(Executable, Args, std::nullopt, {}, 0, 0, &Error, |
| 461 | + &ExecFailed); |
| 462 | + unsetenv("LLVM_JOBSERVER_TEST_CHILD"); |
| 463 | + ASSERT_FALSE(ExecFailed) << Error; |
| 464 | + ASSERT_EQ(RC, 0) << "Executable failed with exit code " << RC; |
| 465 | +} |
| 466 | + |
| 467 | +// Child-side test: ensure parallelSort runs and completes correctly under the |
| 468 | +// jobserver strategy when it owns default executor initialization. |
| 469 | +TEST_F(JobserverStrategyTest, ParallelSortIsLimited_SubprocessChild) { |
| 470 | + if (!getenv("LLVM_JOBSERVER_TEST_CHILD")) |
| 471 | + GTEST_SKIP() << "Not running in child mode"; |
| 472 | + |
423 | 473 | const int NumExplicitJobs = 3; |
424 | 474 | startMakeProxy(NumExplicitJobs); |
425 | 475 |
|
426 | 476 | parallel::strategy = jobserver_concurrency(); |
427 | 477 |
|
428 | 478 | std::vector<int> V(1024); |
429 | | - // Fill with random data |
430 | 479 | std::mt19937 randEngine; |
431 | 480 | std::uniform_int_distribution<int> dist; |
432 | 481 | for (int &i : V) |
|
0 commit comments