xref: /aosp_15_r20/external/libgav1/src/utils/threadpool_test.cc (revision 095378508e87ed692bf8dfeb34008b65b3735891)
1*09537850SAkhilesh Sanikop // Copyright 2021 The libgav1 Authors
2*09537850SAkhilesh Sanikop //
3*09537850SAkhilesh Sanikop // Licensed under the Apache License, Version 2.0 (the "License");
4*09537850SAkhilesh Sanikop // you may not use this file except in compliance with the License.
5*09537850SAkhilesh Sanikop // You may obtain a copy of the License at
6*09537850SAkhilesh Sanikop //
7*09537850SAkhilesh Sanikop //      http://www.apache.org/licenses/LICENSE-2.0
8*09537850SAkhilesh Sanikop //
9*09537850SAkhilesh Sanikop // Unless required by applicable law or agreed to in writing, software
10*09537850SAkhilesh Sanikop // distributed under the License is distributed on an "AS IS" BASIS,
11*09537850SAkhilesh Sanikop // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*09537850SAkhilesh Sanikop // See the License for the specific language governing permissions and
13*09537850SAkhilesh Sanikop // limitations under the License.
14*09537850SAkhilesh Sanikop 
15*09537850SAkhilesh Sanikop #include "src/utils/threadpool.h"
16*09537850SAkhilesh Sanikop 
17*09537850SAkhilesh Sanikop #include <cassert>
18*09537850SAkhilesh Sanikop #include <cstdint>
19*09537850SAkhilesh Sanikop #include <memory>
20*09537850SAkhilesh Sanikop 
21*09537850SAkhilesh Sanikop #include "absl/synchronization/mutex.h"
22*09537850SAkhilesh Sanikop #include "absl/time/clock.h"
23*09537850SAkhilesh Sanikop #include "absl/time/time.h"
24*09537850SAkhilesh Sanikop #include "gtest/gtest.h"
25*09537850SAkhilesh Sanikop #include "src/utils/compiler_attributes.h"
26*09537850SAkhilesh Sanikop #include "src/utils/executor.h"
27*09537850SAkhilesh Sanikop 
28*09537850SAkhilesh Sanikop namespace libgav1 {
29*09537850SAkhilesh Sanikop namespace {
30*09537850SAkhilesh Sanikop 
31*09537850SAkhilesh Sanikop class SimpleGuardedInteger {
32*09537850SAkhilesh Sanikop  public:
SimpleGuardedInteger(int initial_value)33*09537850SAkhilesh Sanikop   explicit SimpleGuardedInteger(int initial_value) : value_(initial_value) {}
34*09537850SAkhilesh Sanikop   SimpleGuardedInteger(const SimpleGuardedInteger&) = delete;
35*09537850SAkhilesh Sanikop   SimpleGuardedInteger& operator=(const SimpleGuardedInteger&) = delete;
36*09537850SAkhilesh Sanikop 
Decrement()37*09537850SAkhilesh Sanikop   void Decrement() {
38*09537850SAkhilesh Sanikop     absl::MutexLock l(&mutex_);
39*09537850SAkhilesh Sanikop     assert(value_ >= 1);
40*09537850SAkhilesh Sanikop     --value_;
41*09537850SAkhilesh Sanikop     changed_.SignalAll();
42*09537850SAkhilesh Sanikop   }
43*09537850SAkhilesh Sanikop 
Increment()44*09537850SAkhilesh Sanikop   void Increment() {
45*09537850SAkhilesh Sanikop     absl::MutexLock l(&mutex_);
46*09537850SAkhilesh Sanikop     ++value_;
47*09537850SAkhilesh Sanikop     changed_.SignalAll();
48*09537850SAkhilesh Sanikop   }
49*09537850SAkhilesh Sanikop 
Value()50*09537850SAkhilesh Sanikop   int Value() {
51*09537850SAkhilesh Sanikop     absl::MutexLock l(&mutex_);
52*09537850SAkhilesh Sanikop     return value_;
53*09537850SAkhilesh Sanikop   }
54*09537850SAkhilesh Sanikop 
WaitForZero()55*09537850SAkhilesh Sanikop   void WaitForZero() {
56*09537850SAkhilesh Sanikop     absl::MutexLock l(&mutex_);
57*09537850SAkhilesh Sanikop     while (value_ != 0) {
58*09537850SAkhilesh Sanikop       changed_.Wait(&mutex_);
59*09537850SAkhilesh Sanikop     }
60*09537850SAkhilesh Sanikop   }
61*09537850SAkhilesh Sanikop 
62*09537850SAkhilesh Sanikop  private:
63*09537850SAkhilesh Sanikop   absl::Mutex mutex_;
64*09537850SAkhilesh Sanikop   absl::CondVar changed_;
65*09537850SAkhilesh Sanikop   int value_ LIBGAV1_GUARDED_BY(mutex_);
66*09537850SAkhilesh Sanikop };
67*09537850SAkhilesh Sanikop 
68*09537850SAkhilesh Sanikop // Loops for |milliseconds| of wall-clock time.
LoopForMs(int64_t milliseconds)69*09537850SAkhilesh Sanikop void LoopForMs(int64_t milliseconds) {
70*09537850SAkhilesh Sanikop   const absl::Time deadline = absl::Now() + absl::Milliseconds(milliseconds);
71*09537850SAkhilesh Sanikop   while (absl::Now() < deadline) {
72*09537850SAkhilesh Sanikop   }
73*09537850SAkhilesh Sanikop }
74*09537850SAkhilesh Sanikop 
75*09537850SAkhilesh Sanikop // A function that increments the given integer.
IncrementIntegerJob(SimpleGuardedInteger * value)76*09537850SAkhilesh Sanikop void IncrementIntegerJob(SimpleGuardedInteger* value) {
77*09537850SAkhilesh Sanikop   LoopForMs(100);
78*09537850SAkhilesh Sanikop   value->Increment();
79*09537850SAkhilesh Sanikop }
80*09537850SAkhilesh Sanikop 
TEST(ThreadPoolTest,ThreadedIntegerIncrement)81*09537850SAkhilesh Sanikop TEST(ThreadPoolTest, ThreadedIntegerIncrement) {
82*09537850SAkhilesh Sanikop   std::unique_ptr<ThreadPool> thread_pool = ThreadPool::Create(100);
83*09537850SAkhilesh Sanikop   ASSERT_NE(thread_pool, nullptr);
84*09537850SAkhilesh Sanikop   EXPECT_EQ(thread_pool->num_threads(), 100);
85*09537850SAkhilesh Sanikop   SimpleGuardedInteger count(0);
86*09537850SAkhilesh Sanikop   for (int i = 0; i < 1000; ++i) {
87*09537850SAkhilesh Sanikop     thread_pool->Schedule([&count]() { IncrementIntegerJob(&count); });
88*09537850SAkhilesh Sanikop   }
89*09537850SAkhilesh Sanikop   thread_pool.reset(nullptr);
90*09537850SAkhilesh Sanikop   EXPECT_EQ(count.Value(), 1000);
91*09537850SAkhilesh Sanikop }
92*09537850SAkhilesh Sanikop 
93*09537850SAkhilesh Sanikop // Test a ThreadPool via the Executor interface.
TEST(ThreadPoolTest,ExecutorInterface)94*09537850SAkhilesh Sanikop TEST(ThreadPoolTest, ExecutorInterface) {
95*09537850SAkhilesh Sanikop   std::unique_ptr<ThreadPool> thread_pool = ThreadPool::Create(100);
96*09537850SAkhilesh Sanikop   ASSERT_NE(thread_pool, nullptr);
97*09537850SAkhilesh Sanikop   std::unique_ptr<Executor> executor(thread_pool.release());
98*09537850SAkhilesh Sanikop   SimpleGuardedInteger count(0);
99*09537850SAkhilesh Sanikop   for (int i = 0; i < 1000; ++i) {
100*09537850SAkhilesh Sanikop     executor->Schedule([&count]() { IncrementIntegerJob(&count); });
101*09537850SAkhilesh Sanikop   }
102*09537850SAkhilesh Sanikop   executor.reset(nullptr);
103*09537850SAkhilesh Sanikop   EXPECT_EQ(count.Value(), 1000);
104*09537850SAkhilesh Sanikop }
105*09537850SAkhilesh Sanikop 
TEST(ThreadPoolTest,DestroyWithoutUse)106*09537850SAkhilesh Sanikop TEST(ThreadPoolTest, DestroyWithoutUse) {
107*09537850SAkhilesh Sanikop   std::unique_ptr<ThreadPool> thread_pool = ThreadPool::Create(100);
108*09537850SAkhilesh Sanikop   EXPECT_NE(thread_pool, nullptr);
109*09537850SAkhilesh Sanikop   thread_pool.reset(nullptr);
110*09537850SAkhilesh Sanikop }
111*09537850SAkhilesh Sanikop 
112*09537850SAkhilesh Sanikop // If num_threads is 0, ThreadPool::Create() should return a null pointer.
TEST(ThreadPoolTest,NumThreadsZero)113*09537850SAkhilesh Sanikop TEST(ThreadPoolTest, NumThreadsZero) {
114*09537850SAkhilesh Sanikop   std::unique_ptr<ThreadPool> thread_pool = ThreadPool::Create(0);
115*09537850SAkhilesh Sanikop   EXPECT_EQ(thread_pool, nullptr);
116*09537850SAkhilesh Sanikop }
117*09537850SAkhilesh Sanikop 
118*09537850SAkhilesh Sanikop // If num_threads is 1, the closures are run in FIFO order.
TEST(ThreadPoolTest,OneThreadRunsClosuresFIFO)119*09537850SAkhilesh Sanikop TEST(ThreadPoolTest, OneThreadRunsClosuresFIFO) {
120*09537850SAkhilesh Sanikop   int count = 0;  // Declare first so that it outlives the thread pool.
121*09537850SAkhilesh Sanikop   std::unique_ptr<ThreadPool> pool = ThreadPool::Create(1);
122*09537850SAkhilesh Sanikop   ASSERT_NE(pool, nullptr);
123*09537850SAkhilesh Sanikop   EXPECT_EQ(pool->num_threads(), 1);
124*09537850SAkhilesh Sanikop   for (int i = 0; i < 1000; ++i) {
125*09537850SAkhilesh Sanikop     pool->Schedule([&count, i]() {
126*09537850SAkhilesh Sanikop       EXPECT_EQ(count, i);
127*09537850SAkhilesh Sanikop       count++;
128*09537850SAkhilesh Sanikop     });
129*09537850SAkhilesh Sanikop   }
130*09537850SAkhilesh Sanikop }
131*09537850SAkhilesh Sanikop 
132*09537850SAkhilesh Sanikop }  // namespace
133*09537850SAkhilesh Sanikop }  // namespace libgav1
134