libjxl

FORK: libjxl patches used on blog
git clone https://git.neptards.moe/blog/libjxl.git
Log | Files | Refs | Submodules | README | LICENSE

thread_parallel_runner_test.cc (3772B)


      1 // Copyright (c) the JPEG XL Project Authors. All rights reserved.
      2 //
      3 // Use of this source code is governed by a BSD-style
      4 // license that can be found in the LICENSE file.
      5 
      6 #include <atomic>
      7 
      8 #include "lib/jxl/base/data_parallel.h"
      9 #include "lib/jxl/test_utils.h"
     10 #include "lib/jxl/testing.h"
     11 
     12 using jxl::test::ThreadPoolForTests;
     13 
     14 namespace jpegxl {
     15 namespace {
     16 
     17 int PopulationCount(uint64_t bits) {
     18   int num_set = 0;
     19   while (bits != 0) {
     20     num_set += bits & 1;
     21     bits >>= 1;
     22   }
     23   return num_set;
     24 }
     25 
     26 // Ensures task parameter is in bounds, every parameter is reached,
     27 // pool can be reused (multiple consecutive Run calls), pool can be destroyed
     28 // (joining with its threads), num_threads=0 works (runs on current thread).
     29 TEST(ThreadParallelRunnerTest, TestPool) {
     30   for (int num_threads = 0; num_threads <= 18; ++num_threads) {
     31     ThreadPoolForTests pool(num_threads);
     32     for (int num_tasks = 0; num_tasks < 32; ++num_tasks) {
     33       std::vector<int> mementos(num_tasks);
     34       for (int begin = 0; begin < 32; ++begin) {
     35         std::fill(mementos.begin(), mementos.end(), 0);
     36         EXPECT_TRUE(RunOnPool(
     37             &pool, begin, begin + num_tasks, jxl::ThreadPool::NoInit,
     38             [begin, num_tasks, &mementos](const int task, const int thread) {
     39               // Parameter is in the given range
     40               EXPECT_GE(task, begin);
     41               EXPECT_LT(task, begin + num_tasks);
     42 
     43               // Store mementos to be sure we visited each task.
     44               mementos.at(task - begin) = 1000 + task;
     45             },
     46             "TestPool"));
     47         for (int task = begin; task < begin + num_tasks; ++task) {
     48           EXPECT_EQ(1000 + task, mementos.at(task - begin));
     49         }
     50       }
     51     }
     52   }
     53 }
     54 
     55 // Verify "thread" parameter when processing few tasks.
     56 TEST(ThreadParallelRunnerTest, TestSmallAssignments) {
     57   const int kMaxThreads = 8;
     58   for (int num_threads = 1; num_threads <= kMaxThreads; ++num_threads) {
     59     ThreadPoolForTests pool(num_threads);
     60 
     61     // (Avoid mutex because it may perturb the worker thread scheduling)
     62     std::atomic<uint64_t> id_bits{0};
     63     std::atomic<int> num_calls{0};
     64 
     65     EXPECT_TRUE(RunOnPool(
     66         &pool, 0, num_threads, jxl::ThreadPool::NoInit,
     67         [&num_calls, num_threads, &id_bits](const int task, const int thread) {
     68           num_calls.fetch_add(1, std::memory_order_relaxed);
     69 
     70           EXPECT_LT(thread, num_threads);
     71           uint64_t bits = id_bits.load(std::memory_order_relaxed);
     72           while (
     73               !id_bits.compare_exchange_weak(bits, bits | (1ULL << thread))) {
     74           }
     75         },
     76         "TestSmallAssignments"));
     77 
     78     // Correct number of tasks.
     79     EXPECT_EQ(num_threads, num_calls.load());
     80 
     81     const int num_participants = PopulationCount(id_bits.load());
     82     // Can't expect equality because other workers may have woken up too late.
     83     EXPECT_LE(num_participants, num_threads);
     84   }
     85 }
     86 
     87 struct Counter {
     88   Counter() {
     89     // Suppress "unused-field" warning.
     90     (void)padding;
     91   }
     92   void Assimilate(const Counter& victim) { counter += victim.counter; }
     93   int counter = 0;
     94   int padding[31];
     95 };
     96 
     97 TEST(ThreadParallelRunnerTest, TestCounter) {
     98   const int kNumThreads = 12;
     99   ThreadPoolForTests pool(kNumThreads);
    100   alignas(128) Counter counters[kNumThreads];
    101 
    102   const int kNumTasks = kNumThreads * 19;
    103   EXPECT_TRUE(RunOnPool(
    104       &pool, 0, kNumTasks, jxl::ThreadPool::NoInit,
    105       [&counters](const int task, const int thread) {
    106         counters[thread].counter += task;
    107       },
    108       "TestCounter"));
    109 
    110   int expected = 0;
    111   for (int i = 0; i < kNumTasks; ++i) {
    112     expected += i;
    113   }
    114 
    115   for (int i = 1; i < kNumThreads; ++i) {
    116     counters[0].Assimilate(counters[i]);
    117   }
    118   EXPECT_EQ(expected, counters[0].counter);
    119 }
    120 
    121 }  // namespace
    122 }  // namespace jpegxl