| 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..30cc1115fa69f867640fccfa436b874df4a1fd67 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 % 2 == 0) {
|
| + // 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())
|
| + ;
|
| + }
|
| + }
|
| + }
|
| +
|
| + 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() {}
|
|
|