OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "base/debug/activity_tracker.h" |
| 6 |
| 7 #include <memory> |
| 8 |
| 9 #include "base/bind.h" |
| 10 #include "base/files/file.h" |
| 11 #include "base/files/file_util.h" |
| 12 #include "base/files/memory_mapped_file.h" |
| 13 #include "base/files/scoped_temp_dir.h" |
| 14 #include "base/memory/ptr_util.h" |
| 15 #include "base/pending_task.h" |
| 16 #include "base/synchronization/condition_variable.h" |
| 17 #include "base/synchronization/lock.h" |
| 18 #include "base/synchronization/spin_wait.h" |
| 19 #include "base/threading/simple_thread.h" |
| 20 #include "base/time/time.h" |
| 21 #include "testing/gtest/include/gtest/gtest.h" |
| 22 |
| 23 namespace base { |
| 24 namespace debug { |
| 25 |
| 26 namespace { |
| 27 |
| 28 class TestActivityTracker : public ThreadActivityTracker { |
| 29 public: |
| 30 TestActivityTracker(std::unique_ptr<char[]> memory, size_t mem_size) |
| 31 : ThreadActivityTracker(memset(memory.get(), 0, mem_size), mem_size), |
| 32 mem_segment_(std::move(memory)) {} |
| 33 |
| 34 ~TestActivityTracker() override {} |
| 35 |
| 36 private: |
| 37 std::unique_ptr<char[]> mem_segment_; |
| 38 }; |
| 39 |
| 40 } // namespace |
| 41 |
| 42 |
| 43 class ActivityTrackerTest : public testing::Test { |
| 44 public: |
| 45 const int kMemorySize = 1 << 10; // 1KiB |
| 46 const int kStackSize = 256; |
| 47 |
| 48 ActivityTrackerTest() {} |
| 49 |
| 50 ~ActivityTrackerTest() override { |
| 51 GlobalActivityTracker* global_tracker = GlobalActivityTracker::Get(); |
| 52 if (global_tracker) { |
| 53 global_tracker->ReleaseTrackerForCurrentThreadForTesting(); |
| 54 delete global_tracker; |
| 55 } |
| 56 } |
| 57 |
| 58 std::unique_ptr<ThreadActivityTracker> CreateActivityTracker() { |
| 59 std::unique_ptr<char[]> memory(new char[kStackSize]); |
| 60 return WrapUnique(new TestActivityTracker(std::move(memory), kStackSize)); |
| 61 } |
| 62 |
| 63 size_t GetGlobalActiveTrackerCount() { |
| 64 GlobalActivityTracker* global_tracker = GlobalActivityTracker::Get(); |
| 65 if (!global_tracker) |
| 66 return 0; |
| 67 return global_tracker->thread_trackers_.size(); |
| 68 } |
| 69 |
| 70 size_t GetGlobalInactiveTrackerCount() { |
| 71 GlobalActivityTracker* global_tracker = GlobalActivityTracker::Get(); |
| 72 if (!global_tracker) |
| 73 return 0; |
| 74 return global_tracker->available_memories_.size(); |
| 75 } |
| 76 |
| 77 static void DoNothing() {} |
| 78 }; |
| 79 |
| 80 TEST_F(ActivityTrackerTest, PushPopTest) { |
| 81 std::unique_ptr<ThreadActivityTracker> tracker = CreateActivityTracker(); |
| 82 std::unique_ptr<ThreadActivityAnalyzer> analyzer = tracker->CreateAnalyzer(); |
| 83 std::vector<ThreadActivityTracker::StackEntry> stack; |
| 84 |
| 85 ASSERT_EQ(0U, analyzer->SnapshotStack(&stack)); |
| 86 ASSERT_EQ(0U, stack.size()); |
| 87 |
| 88 char source1; |
| 89 tracker->PushActivity(&source1, ThreadActivityTracker::ACT_TASK, 2, 3); |
| 90 ASSERT_EQ(1U, analyzer->SnapshotStack(&stack)); |
| 91 ASSERT_EQ(1U, stack.size()); |
| 92 EXPECT_NE(0, stack[0].time_ticks); |
| 93 EXPECT_EQ(ThreadActivityTracker::ACT_TASK, stack[0].activity_type); |
| 94 EXPECT_EQ(reinterpret_cast<intptr_t>(&source1), stack[0].source_address); |
| 95 EXPECT_EQ(2, stack[0].method_address); |
| 96 EXPECT_EQ(3U, stack[0].sequence_id); |
| 97 |
| 98 char source2; |
| 99 tracker->PushActivity(&source2, ThreadActivityTracker::ACT_LOCK, 3, 4); |
| 100 ASSERT_EQ(2U, analyzer->SnapshotStack(&stack)); |
| 101 ASSERT_EQ(2U, stack.size()); |
| 102 EXPECT_LE(stack[0].time_ticks, stack[1].time_ticks); |
| 103 EXPECT_EQ(ThreadActivityTracker::ACT_LOCK, stack[1].activity_type); |
| 104 EXPECT_EQ(reinterpret_cast<intptr_t>(&source2), stack[1].source_address); |
| 105 EXPECT_EQ(3, stack[1].method_address); |
| 106 EXPECT_EQ(4U, stack[1].sequence_id); |
| 107 |
| 108 tracker->PopActivity(&source2); |
| 109 ASSERT_EQ(1U, analyzer->SnapshotStack(&stack)); |
| 110 ASSERT_EQ(1U, stack.size()); |
| 111 EXPECT_EQ(ThreadActivityTracker::ACT_TASK, stack[0].activity_type); |
| 112 EXPECT_EQ(reinterpret_cast<intptr_t>(&source1), stack[0].source_address); |
| 113 EXPECT_EQ(2, stack[0].method_address); |
| 114 EXPECT_EQ(3U, stack[0].sequence_id); |
| 115 |
| 116 tracker->PopActivity(&source1); |
| 117 ASSERT_EQ(0U, analyzer->SnapshotStack(&stack)); |
| 118 ASSERT_EQ(0U, stack.size()); |
| 119 } |
| 120 |
| 121 TEST_F(ActivityTrackerTest, ScopedTaskTest) { |
| 122 GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3); |
| 123 |
| 124 ThreadActivityTracker* tracker = |
| 125 GlobalActivityTracker::Get()->GetOrCreateTrackerForCurrentThread(); |
| 126 std::unique_ptr<ThreadActivityAnalyzer> analyzer = tracker->CreateAnalyzer(); |
| 127 std::vector<ThreadActivityTracker::StackEntry> stack; |
| 128 |
| 129 ASSERT_EQ(0U, analyzer->SnapshotStack(&stack)); |
| 130 ASSERT_EQ(0U, stack.size()); |
| 131 |
| 132 { |
| 133 PendingTask task1(FROM_HERE, base::Bind(&DoNothing)); |
| 134 ScopedTaskActivity activity1(task1); |
| 135 |
| 136 ASSERT_EQ(1U, analyzer->SnapshotStack(&stack)); |
| 137 ASSERT_EQ(1U, stack.size()); |
| 138 EXPECT_EQ(ThreadActivityTracker::ACT_TASK, stack[0].activity_type); |
| 139 |
| 140 { |
| 141 PendingTask task2(FROM_HERE, base::Bind(&DoNothing)); |
| 142 ScopedTaskActivity activity2(task2); |
| 143 |
| 144 ASSERT_EQ(2U, analyzer->SnapshotStack(&stack)); |
| 145 ASSERT_EQ(2U, stack.size()); |
| 146 EXPECT_EQ(ThreadActivityTracker::ACT_TASK, stack[1].activity_type); |
| 147 } |
| 148 |
| 149 ASSERT_EQ(1U, analyzer->SnapshotStack(&stack)); |
| 150 ASSERT_EQ(1U, stack.size()); |
| 151 EXPECT_EQ(ThreadActivityTracker::ACT_TASK, stack[0].activity_type); |
| 152 } |
| 153 |
| 154 ASSERT_EQ(0U, analyzer->SnapshotStack(&stack)); |
| 155 ASSERT_EQ(0U, stack.size()); |
| 156 } |
| 157 |
| 158 class SimpleActivityThread : public SimpleThread { |
| 159 public: |
| 160 SimpleActivityThread(const std::string& name, |
| 161 const void* source, |
| 162 ThreadActivityTracker::ActivityType activity, |
| 163 intptr_t method, |
| 164 uint64_t sequence) |
| 165 : SimpleThread(name, Options()), |
| 166 source_(source), |
| 167 activity_(activity), |
| 168 method_(method), |
| 169 sequence_(sequence), |
| 170 exit_condition_(&lock_) {} |
| 171 |
| 172 ~SimpleActivityThread() {} |
| 173 |
| 174 void Run() override { |
| 175 GlobalActivityTracker::Get() |
| 176 ->GetOrCreateTrackerForCurrentThread() |
| 177 ->PushActivity(source_, activity_, method_, sequence_); |
| 178 |
| 179 { |
| 180 AutoLock auto_lock(lock_); |
| 181 ready_ = true; |
| 182 while (!exit_) |
| 183 exit_condition_.Wait(); |
| 184 } |
| 185 |
| 186 GlobalActivityTracker::Get() |
| 187 ->GetOrCreateTrackerForCurrentThread() |
| 188 ->PopActivity(source_); |
| 189 } |
| 190 |
| 191 void Exit() { |
| 192 AutoLock auto_lock(lock_); |
| 193 exit_ = true; |
| 194 exit_condition_.Signal(); |
| 195 } |
| 196 |
| 197 void WaitReady() { |
| 198 SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(ready_); |
| 199 } |
| 200 |
| 201 private: |
| 202 const void* source_; |
| 203 ThreadActivityTracker::ActivityType activity_; |
| 204 intptr_t method_; |
| 205 uint64_t sequence_; |
| 206 |
| 207 bool ready_ = false; |
| 208 bool exit_ = false; |
| 209 Lock lock_; |
| 210 ConditionVariable exit_condition_; |
| 211 |
| 212 DISALLOW_COPY_AND_ASSIGN(SimpleActivityThread); |
| 213 }; |
| 214 |
| 215 TEST_F(ActivityTrackerTest, ThreadDeathTest) { |
| 216 GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3); |
| 217 GlobalActivityTracker::Get()->GetOrCreateTrackerForCurrentThread(); |
| 218 const size_t starting_active = GetGlobalActiveTrackerCount(); |
| 219 const size_t starting_inactive = GetGlobalInactiveTrackerCount(); |
| 220 |
| 221 SimpleActivityThread t1("t1", nullptr, ThreadActivityTracker::ACT_TASK, 1, 2); |
| 222 t1.Start(); |
| 223 t1.WaitReady(); |
| 224 EXPECT_EQ(starting_active + 1, GetGlobalActiveTrackerCount()); |
| 225 EXPECT_EQ(starting_inactive, GetGlobalInactiveTrackerCount()); |
| 226 |
| 227 t1.Exit(); |
| 228 t1.Join(); |
| 229 EXPECT_EQ(starting_active, GetGlobalActiveTrackerCount()); |
| 230 EXPECT_EQ(starting_inactive + 1, GetGlobalInactiveTrackerCount()); |
| 231 } |
| 232 |
| 233 } // namespace debug |
| 234 } // namespace base |
OLD | NEW |