1*14675a02SAndroid Build Coastguard Worker /*
2*14675a02SAndroid Build Coastguard Worker * Copyright 2018 Google LLC
3*14675a02SAndroid Build Coastguard Worker *
4*14675a02SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*14675a02SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*14675a02SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*14675a02SAndroid Build Coastguard Worker *
8*14675a02SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*14675a02SAndroid Build Coastguard Worker *
10*14675a02SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*14675a02SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*14675a02SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*14675a02SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*14675a02SAndroid Build Coastguard Worker * limitations under the License.
15*14675a02SAndroid Build Coastguard Worker */
16*14675a02SAndroid Build Coastguard Worker
17*14675a02SAndroid Build Coastguard Worker #include "fcp/base/scheduler.h"
18*14675a02SAndroid Build Coastguard Worker
19*14675a02SAndroid Build Coastguard Worker #include <atomic>
20*14675a02SAndroid Build Coastguard Worker #include <cstdlib> // for std::rand
21*14675a02SAndroid Build Coastguard Worker
22*14675a02SAndroid Build Coastguard Worker #include "gmock/gmock.h"
23*14675a02SAndroid Build Coastguard Worker #include "gtest/gtest.h"
24*14675a02SAndroid Build Coastguard Worker #include "absl/synchronization/blocking_counter.h"
25*14675a02SAndroid Build Coastguard Worker #include "fcp/base/monitoring.h"
26*14675a02SAndroid Build Coastguard Worker #include "fcp/testing/testing.h"
27*14675a02SAndroid Build Coastguard Worker
28*14675a02SAndroid Build Coastguard Worker namespace fcp {
29*14675a02SAndroid Build Coastguard Worker namespace base {
30*14675a02SAndroid Build Coastguard Worker namespace {
31*14675a02SAndroid Build Coastguard Worker
32*14675a02SAndroid Build Coastguard Worker // NOTE: many of tests below use reference captures in lambdas for locals.
33*14675a02SAndroid Build Coastguard Worker // This is sound because the test methods do not return before the thread
34*14675a02SAndroid Build Coastguard Worker // pool has become idle (pool->WaitUntilIdle()).
35*14675a02SAndroid Build Coastguard Worker
36*14675a02SAndroid Build Coastguard Worker // Tests whether scheduled tasks are successfully executed.
TEST(ThreadPool,TasksAreExecuted)37*14675a02SAndroid Build Coastguard Worker TEST(ThreadPool, TasksAreExecuted) {
38*14675a02SAndroid Build Coastguard Worker auto pool = CreateThreadPoolScheduler(2);
39*14675a02SAndroid Build Coastguard Worker
40*14675a02SAndroid Build Coastguard Worker bool b1 = false;
41*14675a02SAndroid Build Coastguard Worker bool b2 = false;
42*14675a02SAndroid Build Coastguard Worker pool->Schedule([&b1]() { b1 = true; });
43*14675a02SAndroid Build Coastguard Worker pool->Schedule([&b2]() { b2 = true; });
44*14675a02SAndroid Build Coastguard Worker
45*14675a02SAndroid Build Coastguard Worker pool->WaitUntilIdle();
46*14675a02SAndroid Build Coastguard Worker
47*14675a02SAndroid Build Coastguard Worker EXPECT_TRUE(b1);
48*14675a02SAndroid Build Coastguard Worker EXPECT_TRUE(b2);
49*14675a02SAndroid Build Coastguard Worker }
50*14675a02SAndroid Build Coastguard Worker
51*14675a02SAndroid Build Coastguard Worker // Tests whether the pool uses actually multiple threads to execute tasks.
52*14675a02SAndroid Build Coastguard Worker // The test goal is achieved by blocking in one task until another task
53*14675a02SAndroid Build Coastguard Worker // unblocks, which can only work if multiple threads are used.
TEST(ThreadPool,ThreadsAreUtilized)54*14675a02SAndroid Build Coastguard Worker TEST(ThreadPool, ThreadsAreUtilized) {
55*14675a02SAndroid Build Coastguard Worker auto pool = CreateThreadPoolScheduler(2);
56*14675a02SAndroid Build Coastguard Worker
57*14675a02SAndroid Build Coastguard Worker absl::BlockingCounter counter(1);
58*14675a02SAndroid Build Coastguard Worker bool b1 = false;
59*14675a02SAndroid Build Coastguard Worker bool b2 = false;
60*14675a02SAndroid Build Coastguard Worker
61*14675a02SAndroid Build Coastguard Worker pool->Schedule([&b1, &counter] {
62*14675a02SAndroid Build Coastguard Worker counter.Wait();
63*14675a02SAndroid Build Coastguard Worker b1 = true;
64*14675a02SAndroid Build Coastguard Worker });
65*14675a02SAndroid Build Coastguard Worker pool->Schedule([&b2, &counter] {
66*14675a02SAndroid Build Coastguard Worker counter.DecrementCount();
67*14675a02SAndroid Build Coastguard Worker b2 = true;
68*14675a02SAndroid Build Coastguard Worker });
69*14675a02SAndroid Build Coastguard Worker
70*14675a02SAndroid Build Coastguard Worker pool->WaitUntilIdle();
71*14675a02SAndroid Build Coastguard Worker
72*14675a02SAndroid Build Coastguard Worker EXPECT_TRUE(b1);
73*14675a02SAndroid Build Coastguard Worker EXPECT_TRUE(b2);
74*14675a02SAndroid Build Coastguard Worker }
75*14675a02SAndroid Build Coastguard Worker
TEST(ThreadPool,StressTest)76*14675a02SAndroid Build Coastguard Worker TEST(ThreadPool, StressTest) {
77*14675a02SAndroid Build Coastguard Worker // A simple stress test where we spawn many threads and let them after
78*14675a02SAndroid Build Coastguard Worker // a random wait time increment a counter.
79*14675a02SAndroid Build Coastguard Worker static constexpr int kThreads = 32;
80*14675a02SAndroid Build Coastguard Worker static constexpr int kIterations = 16;
81*14675a02SAndroid Build Coastguard Worker auto pool = CreateThreadPoolScheduler(kThreads);
82*14675a02SAndroid Build Coastguard Worker std::atomic<int64_t> atomic_counter{0};
83*14675a02SAndroid Build Coastguard Worker
84*14675a02SAndroid Build Coastguard Worker for (auto i = 0; i < kThreads; ++i) {
85*14675a02SAndroid Build Coastguard Worker auto task = [&atomic_counter] {
86*14675a02SAndroid Build Coastguard Worker for (auto j = 0; j < kIterations; ++j) {
87*14675a02SAndroid Build Coastguard Worker absl::SleepFor(absl::Microseconds(std::rand() % 500));
88*14675a02SAndroid Build Coastguard Worker atomic_counter.fetch_add(1);
89*14675a02SAndroid Build Coastguard Worker }
90*14675a02SAndroid Build Coastguard Worker };
91*14675a02SAndroid Build Coastguard Worker pool->Schedule(task);
92*14675a02SAndroid Build Coastguard Worker }
93*14675a02SAndroid Build Coastguard Worker
94*14675a02SAndroid Build Coastguard Worker pool->WaitUntilIdle();
95*14675a02SAndroid Build Coastguard Worker ASSERT_EQ(atomic_counter, kThreads * kIterations);
96*14675a02SAndroid Build Coastguard Worker }
97*14675a02SAndroid Build Coastguard Worker
TEST(Worker,TasksAreExecutedSequentially)98*14675a02SAndroid Build Coastguard Worker TEST(Worker, TasksAreExecutedSequentially) {
99*14675a02SAndroid Build Coastguard Worker auto pool = CreateThreadPoolScheduler(3);
100*14675a02SAndroid Build Coastguard Worker auto worker = pool->CreateWorker();
101*14675a02SAndroid Build Coastguard Worker absl::Mutex mutex{};
102*14675a02SAndroid Build Coastguard Worker std::vector<int> recorded{};
103*14675a02SAndroid Build Coastguard Worker for (int i = 0; i < 128; i++) {
104*14675a02SAndroid Build Coastguard Worker worker->Schedule([&mutex, &recorded, i] {
105*14675a02SAndroid Build Coastguard Worker // Expect that no one is holding the mutex (tests for non-overlap).
106*14675a02SAndroid Build Coastguard Worker if (mutex.TryLock()) {
107*14675a02SAndroid Build Coastguard Worker // Add i to the recorded values (tests for execution in order).
108*14675a02SAndroid Build Coastguard Worker recorded.push_back(i);
109*14675a02SAndroid Build Coastguard Worker // Idle wait to be sure we don't execute faster than we schedule
110*14675a02SAndroid Build Coastguard Worker absl::SleepFor(absl::Milliseconds(50));
111*14675a02SAndroid Build Coastguard Worker mutex.Unlock();
112*14675a02SAndroid Build Coastguard Worker } else {
113*14675a02SAndroid Build Coastguard Worker FAIL() << "mutex was unexpectedly hold";
114*14675a02SAndroid Build Coastguard Worker }
115*14675a02SAndroid Build Coastguard Worker });
116*14675a02SAndroid Build Coastguard Worker }
117*14675a02SAndroid Build Coastguard Worker pool->WaitUntilIdle();
118*14675a02SAndroid Build Coastguard Worker
119*14675a02SAndroid Build Coastguard Worker // Verify recorded values.
120*14675a02SAndroid Build Coastguard Worker for (int i = 0; i < 128; i++) {
121*14675a02SAndroid Build Coastguard Worker ASSERT_EQ(recorded[i], i);
122*14675a02SAndroid Build Coastguard Worker }
123*14675a02SAndroid Build Coastguard Worker }
124*14675a02SAndroid Build Coastguard Worker
125*14675a02SAndroid Build Coastguard Worker } // namespace
126*14675a02SAndroid Build Coastguard Worker
127*14675a02SAndroid Build Coastguard Worker } // namespace base
128*14675a02SAndroid Build Coastguard Worker } // namespace fcp
129