diff options
Diffstat (limited to 'runtime/gc/task_processor_test.cc')
-rw-r--r-- | runtime/gc/task_processor_test.cc | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/runtime/gc/task_processor_test.cc b/runtime/gc/task_processor_test.cc new file mode 100644 index 0000000000..5dd6d8fb7b --- /dev/null +++ b/runtime/gc/task_processor_test.cc @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "common_runtime_test.h" +#include "task_processor.h" +#include "thread_pool.h" +#include "thread-inl.h" +#include "utils.h" + +namespace art { +namespace gc { + +class TaskProcessorTest : public CommonRuntimeTest { + public: +}; + +class RecursiveTask : public HeapTask { + public: + RecursiveTask(TaskProcessor* task_processor, Atomic<size_t>* counter, size_t max_recursion) + : HeapTask(NanoTime() + MsToNs(10)), task_processor_(task_processor), counter_(counter), + max_recursion_(max_recursion) { + } + virtual void Run(Thread* self) OVERRIDE { + if (max_recursion_ > 0) { + task_processor_->AddTask(self, + new RecursiveTask(task_processor_, counter_, max_recursion_ - 1)); + counter_->FetchAndAddSequentiallyConsistent(1U); + } + } + + private: + TaskProcessor* const task_processor_; + Atomic<size_t>* const counter_; + const size_t max_recursion_; +}; + +class WorkUntilDoneTask : public SelfDeletingTask { + public: + WorkUntilDoneTask(TaskProcessor* task_processor, Atomic<bool>* done_running) + : task_processor_(task_processor), done_running_(done_running) { + } + virtual void Run(Thread* self) OVERRIDE { + task_processor_->RunAllTasks(self); + done_running_->StoreSequentiallyConsistent(true); + } + + private: + TaskProcessor* const task_processor_; + Atomic<bool>* done_running_; +}; + +TEST_F(TaskProcessorTest, Interrupt) { + ThreadPool thread_pool("task processor test", 1U); + Thread* const self = Thread::Current(); + TaskProcessor task_processor; + static constexpr size_t kRecursion = 10; + Atomic<bool> done_running(false); + Atomic<size_t> counter(0); + task_processor.AddTask(self, new RecursiveTask(&task_processor, &counter, kRecursion)); + task_processor.Start(self); + // Add a task which will wait until interrupted to the thread pool. + thread_pool.AddTask(self, new WorkUntilDoneTask(&task_processor, &done_running)); + thread_pool.StartWorkers(self); + ASSERT_FALSE(done_running); + // Wait until all the tasks are done, but since we didn't interrupt, done_running should be 0. + while (counter.LoadSequentiallyConsistent() != kRecursion) { + usleep(10); + } + ASSERT_FALSE(done_running); + task_processor.Stop(self); + thread_pool.Wait(self, true, false); + // After the interrupt and wait, the WorkUntilInterruptedTasktask should have terminated and + // set done_running_ to true. + ASSERT_TRUE(done_running.LoadSequentiallyConsistent()); + + // Test that we finish remaining tasks before returning from RunTasksUntilInterrupted. + counter.StoreSequentiallyConsistent(0); + done_running.StoreSequentiallyConsistent(false); + // Self interrupt before any of the other tasks run, but since we added them we should keep on + // working until all the tasks are completed. + task_processor.Stop(self); + task_processor.AddTask(self, new RecursiveTask(&task_processor, &counter, kRecursion)); + thread_pool.AddTask(self, new WorkUntilDoneTask(&task_processor, &done_running)); + thread_pool.StartWorkers(self); + thread_pool.Wait(self, true, false); + ASSERT_TRUE(done_running.LoadSequentiallyConsistent()); + ASSERT_EQ(counter.LoadSequentiallyConsistent(), kRecursion); +} + +class TestOrderTask : public HeapTask { + public: + explicit TestOrderTask(uint64_t expected_time, size_t expected_counter, size_t* counter) + : HeapTask(expected_time), expected_counter_(expected_counter), counter_(counter) { + } + virtual void Run(Thread* thread) OVERRIDE { + UNUSED(thread); // Fix cppling bug. + ASSERT_EQ(*counter_, expected_counter_); + ++*counter_; + } + + private: + const size_t expected_counter_; + size_t* const counter_; +}; + +TEST_F(TaskProcessorTest, Ordering) { + static const size_t kNumTasks = 25; + const uint64_t current_time = NanoTime(); + Thread* const self = Thread::Current(); + TaskProcessor task_processor; + task_processor.Stop(self); + size_t counter = 0; + std::vector<std::pair<uint64_t, size_t>> orderings; + for (size_t i = 0; i < kNumTasks; ++i) { + orderings.push_back(std::make_pair(current_time + MsToNs(10U * i), i)); + } + for (size_t i = 0; i < kNumTasks; ++i) { + std::swap(orderings[i], orderings[(i * 87654231 + 12345) % orderings.size()]); + } + for (const auto& pair : orderings) { + auto* task = new TestOrderTask(pair.first, pair.second, &counter); + task_processor.AddTask(self, task); + } + ThreadPool thread_pool("task processor test", 1U); + Atomic<bool> done_running(false); + // Add a task which will wait until interrupted to the thread pool. + thread_pool.AddTask(self, new WorkUntilDoneTask(&task_processor, &done_running)); + ASSERT_FALSE(done_running.LoadSequentiallyConsistent()); + thread_pool.StartWorkers(self); + thread_pool.Wait(self, true, false); + ASSERT_TRUE(done_running.LoadSequentiallyConsistent()); + ASSERT_EQ(counter, kNumTasks); +} + +} // namespace gc +} // namespace art |