Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(582)

Unified Diff: base/debug/activity_tracker_unittest.cc

Issue 2255503002: New cache for the activity tracker. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: more comment improvements Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« base/debug/activity_tracker.cc ('K') | « base/debug/activity_tracker.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..7a57caff6a676bcf26f2efdab025d195ff540304 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,212 @@ class TestActivityTracker : public ThreadActivityTracker {
std::unique_ptr<char[]> mem_segment_;
};
+
+// The interval between which the Stack threads will wait for the stack to
+// become full or empty. It's prime so that it won't correspond to any other
+// interval (except itself).
+const int kStackTestOperationInterval = 997;
+
+class StackPushThread : public SimpleThread {
+ public:
+ StackPushThread(LockFreeSimpleStack<int>* stack, int count)
+ : SimpleThread("StackPush", Options()), stack_(stack), count_(count) {}
+ ~StackPushThread() override {}
+
+ void Run() override {
+ int yield_after = RandInt(1, stack_->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 (!stack_->push(i))
+ ;
+ } else {
+ // This is valid because there is exactly one thread pushing.
+ while (stack_->full())
+ ;
+ DCHECK(stack_->push(i));
+ }
+
+ // Take a break once in a while.
+ if (--yield_after <= 0) {
+ PlatformThread::YieldCurrentThread();
+ yield_after = RandInt(1, stack_->size() * 2);
+ }
+
+ // Every so often, wait for the stack to empty.
+ if (i < count_ - kStackTestOperationInterval &&
+ i % kStackTestOperationInterval == kStackTestOperationInterval - 1) {
+ while (!stack_->empty())
+ ;
+ }
+ }
+ }
+
+ private:
+ LockFreeSimpleStack<int>* const stack_;
+ const int count_;
+
+ DISALLOW_COPY_AND_ASSIGN(StackPushThread);
+};
+
+class StackPopThread : public SimpleThread {
+ public:
+ StackPopThread(LockFreeSimpleStack<int>* stack, int count)
+ : SimpleThread("StackPop", Options()), stack_(stack), count_(count) {}
+ ~StackPopThread() override {}
+
+ void Run() override {
+ int yield_after = RandInt(1, stack_->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 = stack_->pop()) < 0)
+ ;
+ } else {
+ // This is valid only because there is exactly one thread popping.
+ while (stack_->empty())
+ ;
+ popped = stack_->pop();
+ }
+ DCHECK_LE(0, popped);
+ DCHECK_GT(i + static_cast<int>(stack_->size()), popped);
+
+ // Take a break once in a while.
+ if (--yield_after <= 0) {
+ PlatformThread::YieldCurrentThread();
+ yield_after = RandInt(1, stack_->size() * 2);
+ }
+
+ // Every so often, wait for the stack to fill.
+ if (i < count_ - kStackTestOperationInterval &&
+ i % kStackTestOperationInterval == kStackTestOperationInterval / 2) {
+ while (!stack_->full())
+ ;
+ }
+ }
+ }
+
+ private:
+ LockFreeSimpleStack<int>* const stack_;
+ const int count_;
+
+ DISALLOW_COPY_AND_ASSIGN(StackPopThread);
+};
+
+class StackParallelThread : public SimpleThread {
+ public:
+ StackParallelThread(LockFreeSimpleStack<int>* stack,
+ int thread_number,
+ bool push_not_pop,
+ std::atomic<char>* pending,
+ int count)
+ : SimpleThread(std::string("Stack") + (push_not_pop ? "Push" : "Pop") +
+ static_cast<char>('A' + thread_number),
+ Options()),
+ stack_(stack),
+ pending_(pending),
+ push_not_pop_(push_not_pop),
+ count_(count) {}
+ ~StackParallelThread() override {}
+
+ void Run() override {
+ int yield_after = RandInt(1, stack_->size() * 2);
+
+ for (int i = 0; i < count_; ++i) {
+ if (push_not_pop_) {
+ while (!stack_->push(i))
+ ;
+ pending_[i].fetch_add(1);
+ } else {
+ int popped;
+ while ((popped = stack_->pop()) < 0)
+ ;
+ pending_[popped].fetch_sub(1);
+ }
+
+ // Take a break once in a while.
+ if (--yield_after <= 0) {
+ PlatformThread::YieldCurrentThread();
+ yield_after = RandInt(1, stack_->size() * 2);
+ }
+ }
+ }
+
+ private:
+ LockFreeSimpleStack<int>* const stack_;
+ std::atomic<char>* const pending_;
+ const bool push_not_pop_;
+ const int count_;
+
+ DISALLOW_COPY_AND_ASSIGN(StackParallelThread);
+};
+
} // namespace
+TEST(LockFreeSimpleStack, PushPopTest) {
+ LockFreeSimpleStack<int> stack(50U, -1);
+ ASSERT_EQ(50U, stack.size());
+ ASSERT_EQ(0U, stack.used());
+
+ stack.push(1001);
+ EXPECT_EQ(1U, stack.used());
+
+ stack.push(2002);
+ EXPECT_EQ(2U, stack.used());
+
+ int value = stack.pop();
+ EXPECT_EQ(2002, value);
+ EXPECT_EQ(1U, stack.used());
+
+ value = stack.pop();
+ EXPECT_EQ(1001, value);
+ EXPECT_EQ(0U, stack.used());
+
+ value = stack.pop();
+ ASSERT_EQ(-1, value);
+ ASSERT_TRUE(stack.empty());
+
+ // Test push/pop many times and in parallel.
+ const int kStackOperations = 1000000;
+ StackPushThread pusher(&stack, kStackOperations);
+ StackPopThread popper(&stack, kStackOperations);
+ pusher.Start();
+ popper.Start();
+ pusher.Join();
+ popper.Join();
+
+ // Test many push/pop threads.
+ const int kParallelThreads = 10;
+ const int kParallelOperations = kStackOperations / kParallelThreads;
+ std::unique_ptr<std::atomic<char>[]> pending(
+ new std::atomic<char>[kParallelOperations]);
+ for (int i = 0; i < kParallelOperations; ++i)
+ pending[i].store(0, std::memory_order_relaxed);
+ std::unique_ptr<StackParallelThread> pushers[kParallelThreads];
+ std::unique_ptr<StackParallelThread> poppers[kParallelThreads];
+ for (int t = 0; t < kParallelThreads; ++t) {
+ pushers[t].reset(new StackParallelThread(&stack, t, true, pending.get(),
+ kParallelOperations));
+ poppers[t].reset(new StackParallelThread(&stack, t, false, pending.get(),
+ kParallelOperations));
+ }
+ for (int t = 0; t < kParallelThreads; ++t) {
+ pushers[t]->Start();
+ poppers[t]->Start();
+ }
+ for (int t = 0; t < kParallelThreads; ++t) {
+ pushers[t]->Join();
+ poppers[t]->Join();
+ }
+ for (int i = 0; i < kParallelOperations; ++i)
+ EXPECT_EQ(0, static_cast<int>(pending[i].load(std::memory_order_relaxed)));
+}
+
+
class ActivityTrackerTest : public testing::Test {
public:
const int kMemorySize = 1 << 10; // 1MiB
@@ -72,8 +277,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() {}
« base/debug/activity_tracker.cc ('K') | « base/debug/activity_tracker.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698