Chromium Code Reviews| Index: base/debug/activity_tracker_unittest.cc |
| diff --git a/base/debug/activity_tracker_unittest.cc b/base/debug/activity_tracker_unittest.cc |
| index c36d8fac352cb169759d9a9e07db5c9648860010..4b357ad0f1d932fe12a25512c785d8bbb444d8f3 100644 |
| --- a/base/debug/activity_tracker_unittest.cc |
| +++ b/base/debug/activity_tracker_unittest.cc |
| @@ -13,9 +13,11 @@ |
| #include "base/files/scoped_temp_dir.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/pending_task.h" |
| +#include "base/rand_util.h" |
| #include "base/synchronization/condition_variable.h" |
| #include "base/synchronization/lock.h" |
| #include "base/synchronization/spin_wait.h" |
| +#include "base/threading/platform_thread.h" |
| #include "base/threading/simple_thread.h" |
| #include "base/time/time.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| @@ -37,9 +39,137 @@ class TestActivityTracker : public ThreadActivityTracker { |
| std::unique_ptr<char[]> mem_segment_; |
| }; |
| + |
| +// The interval between which the Queue threads will wait for the queue to |
| +// become full or empty. It's prime so that it won't correspond to any other |
| +// interval (except itself). |
| +const int kQueueTestOperationInterval = 997; |
| + |
| +class QueuePushThread : public SimpleThread { |
| + public: |
| + QueuePushThread(LockFreeSimpleQueue<int>* queue, int count) |
| + : SimpleThread("QueuePush", Options()), queue_(queue), count_(count) {} |
| + ~QueuePushThread() override {} |
| + |
| + void Run() override { |
| + int yield_after = RandInt(1, queue_->size() * 2); |
| + for (int i = 0; i < count_; ++i) { |
| + // Two ways of pushing: check for full first or check for failed push. |
| + if (i % 1 == 0) { |
|
manzagop (departed)
2016/08/23 16:02:03
This is always true?
bcwhite
2016/08/23 16:12:41
Fixed. I had changed in while testing the test an
|
| + // Will fail if full; keep trying. |
| + while (!queue_->push(i)) |
| + ; |
| + } else { |
| + // This is valid because there is exactly one thread pushing. |
| + while (queue_->full()) |
| + ; |
| + DCHECK(queue_->push(i)); |
| + } |
| + |
| + // Take a break once in a while. |
| + if (--yield_after <= 0) { |
| + PlatformThread::YieldCurrentThread(); |
| + yield_after = RandInt(1, queue_->size() * 2); |
| + } |
| + |
| + // Every so often, wait for the queue to empty. |
| + if (i < count_ - kQueueTestOperationInterval && |
| + i % kQueueTestOperationInterval == kQueueTestOperationInterval - 1) { |
| + while (!queue_->empty()) |
|
manzagop (departed)
2016/08/23 16:02:03
Is it guaranteed that the popper is still alive? S
bcwhite
2016/08/23 16:12:41
There's no protection against thread-death in the
manzagop (departed)
2016/08/23 19:46:08
Ah, what I meant is could it have exited already,
bcwhite
2016/08/23 20:16:46
Acknowledged.
|
| + ; |
| + } |
| + } |
| + } |
| + |
| + private: |
| + LockFreeSimpleQueue<int>* const queue_; |
| + const int count_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(QueuePushThread); |
| +}; |
| + |
| +class QueuePopThread : public SimpleThread { |
| + public: |
| + QueuePopThread(LockFreeSimpleQueue<int>* queue, int count) |
| + : SimpleThread("QueuePop", Options()), queue_(queue), count_(count) {} |
| + ~QueuePopThread() override {} |
| + |
| + void Run() override { |
| + int yield_after = RandInt(1, queue_->size() * 2); |
| + for (int i = 0; i < count_; ++i) { |
| + int popped; |
| + // Two ways of popping: check for empty first or check for invalid return. |
| + if (i % 2 == 0) { |
| + // Will return "invalid" if empty; keep trying. |
| + while ((popped = queue_->pop()) < 0) |
| + ; |
| + } else { |
| + // This is valid only because there is exactly one thread popping. |
| + while (queue_->empty()) |
| + ; |
| + popped = queue_->pop(); |
| + } |
| + DCHECK_EQ(i, popped); |
| + |
| + // Take a break once in a while. |
| + if (--yield_after <= 0) { |
| + PlatformThread::YieldCurrentThread(); |
| + yield_after = RandInt(1, queue_->size() * 2); |
| + } |
| + |
| + // Every so often, wait for the queue to fill. |
| + if (i < count_ - kQueueTestOperationInterval && |
| + i % kQueueTestOperationInterval == kQueueTestOperationInterval / 2) { |
| + while (!queue_->full()) |
| + ; |
| + } |
| + } |
| + } |
| + |
| + private: |
| + LockFreeSimpleQueue<int>* const queue_; |
| + const int count_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(QueuePopThread); |
| +}; |
| + |
| } // namespace |
| +TEST(LockFreeSimpleQueue, PushPopTest) { |
| + LockFreeSimpleQueue<int> queue(50U, -1); |
| + ASSERT_EQ(50U, queue.size()); |
| + ASSERT_EQ(0U, queue.used()); |
| + |
| + queue.push(1001); |
| + EXPECT_EQ(1U, queue.used()); |
| + |
| + queue.push(2002); |
| + EXPECT_EQ(2U, queue.used()); |
| + |
| + int value = queue.pop(); |
| + EXPECT_EQ(1001, value); |
| + EXPECT_EQ(1U, queue.used()); |
| + |
| + value = queue.pop(); |
| + EXPECT_EQ(2002, value); |
| + EXPECT_EQ(0U, queue.used()); |
| + |
| + value = queue.pop(); |
| + ASSERT_EQ(-1, value); |
| + ASSERT_TRUE(queue.empty()); |
| + |
| + // Test push/pop many times and in parallel. |
| + const int kQueueOperations = 1000000; |
| + QueuePushThread pusher(&queue, kQueueOperations); |
| + QueuePopThread popper(&queue, kQueueOperations); |
| + pusher.Start(); |
| + popper.Start(); |
| + pusher.Join(); |
| + popper.Join(); |
| +} |
| + |
| + |
| class ActivityTrackerTest : public testing::Test { |
| public: |
| const int kMemorySize = 1 << 10; // 1MiB |
| @@ -72,8 +202,7 @@ class ActivityTrackerTest : public testing::Test { |
| GlobalActivityTracker* global_tracker = GlobalActivityTracker::Get(); |
| if (!global_tracker) |
| return 0; |
| - return global_tracker->available_memories_count_.load( |
| - std::memory_order_relaxed); |
| + return global_tracker->available_memories_.used(); |
| } |
| static void DoNothing() {} |