bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 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" |
Peter Kasting | 24efe5e | 2018-02-24 09:03:01 +0900 | [diff] [blame^] | 10 | #include "base/bind_helpers.h" |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 11 | #include "base/files/file.h" |
| 12 | #include "base/files/file_util.h" |
| 13 | #include "base/files/memory_mapped_file.h" |
| 14 | #include "base/files/scoped_temp_dir.h" |
| 15 | #include "base/memory/ptr_util.h" |
| 16 | #include "base/pending_task.h" |
bcwhite | 83c487b | 2016-09-03 01:38:27 +0900 | [diff] [blame] | 17 | #include "base/rand_util.h" |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 18 | #include "base/synchronization/condition_variable.h" |
| 19 | #include "base/synchronization/lock.h" |
| 20 | #include "base/synchronization/spin_wait.h" |
bcwhite | 83c487b | 2016-09-03 01:38:27 +0900 | [diff] [blame] | 21 | #include "base/threading/platform_thread.h" |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 22 | #include "base/threading/simple_thread.h" |
| 23 | #include "base/time/time.h" |
| 24 | #include "testing/gtest/include/gtest/gtest.h" |
| 25 | |
| 26 | namespace base { |
| 27 | namespace debug { |
| 28 | |
| 29 | namespace { |
| 30 | |
| 31 | class TestActivityTracker : public ThreadActivityTracker { |
| 32 | public: |
| 33 | TestActivityTracker(std::unique_ptr<char[]> memory, size_t mem_size) |
| 34 | : ThreadActivityTracker(memset(memory.get(), 0, mem_size), mem_size), |
| 35 | mem_segment_(std::move(memory)) {} |
| 36 | |
Chris Watkins | d155d9f | 2017-11-29 16:16:38 +0900 | [diff] [blame] | 37 | ~TestActivityTracker() override = default; |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 38 | |
| 39 | private: |
| 40 | std::unique_ptr<char[]> mem_segment_; |
| 41 | }; |
| 42 | |
| 43 | } // namespace |
| 44 | |
| 45 | |
| 46 | class ActivityTrackerTest : public testing::Test { |
| 47 | public: |
bcwhite | 7490275 | 2016-11-16 02:41:56 +0900 | [diff] [blame] | 48 | const int kMemorySize = 1 << 20; // 1MiB |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 49 | const int kStackSize = 1 << 10; // 1KiB |
| 50 | |
bcwhite | 7490275 | 2016-11-16 02:41:56 +0900 | [diff] [blame] | 51 | using ActivityId = ThreadActivityTracker::ActivityId; |
| 52 | |
Chris Watkins | d155d9f | 2017-11-29 16:16:38 +0900 | [diff] [blame] | 53 | ActivityTrackerTest() = default; |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 54 | |
| 55 | ~ActivityTrackerTest() override { |
| 56 | GlobalActivityTracker* global_tracker = GlobalActivityTracker::Get(); |
| 57 | if (global_tracker) { |
| 58 | global_tracker->ReleaseTrackerForCurrentThreadForTesting(); |
| 59 | delete global_tracker; |
| 60 | } |
| 61 | } |
| 62 | |
| 63 | std::unique_ptr<ThreadActivityTracker> CreateActivityTracker() { |
| 64 | std::unique_ptr<char[]> memory(new char[kStackSize]); |
Jeremy Roman | cd0c467 | 2017-08-17 08:27:24 +0900 | [diff] [blame] | 65 | return std::make_unique<TestActivityTracker>(std::move(memory), kStackSize); |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 66 | } |
| 67 | |
| 68 | size_t GetGlobalActiveTrackerCount() { |
| 69 | GlobalActivityTracker* global_tracker = GlobalActivityTracker::Get(); |
| 70 | if (!global_tracker) |
| 71 | return 0; |
| 72 | return global_tracker->thread_tracker_count_.load( |
| 73 | std::memory_order_relaxed); |
| 74 | } |
| 75 | |
| 76 | size_t GetGlobalInactiveTrackerCount() { |
| 77 | GlobalActivityTracker* global_tracker = GlobalActivityTracker::Get(); |
| 78 | if (!global_tracker) |
| 79 | return 0; |
thestig | 475b253 | 2017-05-25 06:57:51 +0900 | [diff] [blame] | 80 | AutoLock autolock(global_tracker->thread_tracker_allocator_lock_); |
bcwhite | e26c224 | 2016-10-14 08:49:14 +0900 | [diff] [blame] | 81 | return global_tracker->thread_tracker_allocator_.cache_used(); |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 82 | } |
| 83 | |
bcwhite | 7490275 | 2016-11-16 02:41:56 +0900 | [diff] [blame] | 84 | size_t GetGlobalUserDataMemoryCacheUsed() { |
| 85 | return GlobalActivityTracker::Get()->user_data_allocator_.cache_used(); |
| 86 | } |
| 87 | |
bcwhite | 45cf1ef | 2017-03-17 03:41:12 +0900 | [diff] [blame] | 88 | void HandleProcessExit(int64_t id, |
| 89 | int64_t stamp, |
| 90 | int code, |
| 91 | GlobalActivityTracker::ProcessPhase phase, |
| 92 | std::string&& command, |
| 93 | ActivityUserData::Snapshot&& data) { |
bcwhite | 6bd84ae | 2017-05-23 22:09:20 +0900 | [diff] [blame] | 94 | exit_id_ = id; |
| 95 | exit_stamp_ = stamp; |
| 96 | exit_code_ = code; |
| 97 | exit_phase_ = phase; |
| 98 | exit_command_ = std::move(command); |
| 99 | exit_data_ = std::move(data); |
bcwhite | 45cf1ef | 2017-03-17 03:41:12 +0900 | [diff] [blame] | 100 | } |
| 101 | |
bcwhite | 6bd84ae | 2017-05-23 22:09:20 +0900 | [diff] [blame] | 102 | int64_t exit_id_ = 0; |
| 103 | int64_t exit_stamp_; |
| 104 | int exit_code_; |
| 105 | GlobalActivityTracker::ProcessPhase exit_phase_; |
| 106 | std::string exit_command_; |
| 107 | ActivityUserData::Snapshot exit_data_; |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 108 | }; |
| 109 | |
bcwhite | 7490275 | 2016-11-16 02:41:56 +0900 | [diff] [blame] | 110 | TEST_F(ActivityTrackerTest, UserDataTest) { |
| 111 | char buffer[256]; |
| 112 | memset(buffer, 0, sizeof(buffer)); |
| 113 | ActivityUserData data(buffer, sizeof(buffer)); |
bcwhite | 45cf1ef | 2017-03-17 03:41:12 +0900 | [diff] [blame] | 114 | size_t space = sizeof(buffer) - sizeof(ActivityUserData::MemoryHeader); |
bcwhite | a12d3ef | 2017-03-08 08:30:41 +0900 | [diff] [blame] | 115 | ASSERT_EQ(space, data.available_); |
bcwhite | 7490275 | 2016-11-16 02:41:56 +0900 | [diff] [blame] | 116 | |
| 117 | data.SetInt("foo", 1); |
bcwhite | 45cf1ef | 2017-03-17 03:41:12 +0900 | [diff] [blame] | 118 | space -= 24; |
| 119 | ASSERT_EQ(space, data.available_); |
bcwhite | 7490275 | 2016-11-16 02:41:56 +0900 | [diff] [blame] | 120 | |
| 121 | data.SetUint("b", 1U); // Small names fit beside header in a word. |
bcwhite | 45cf1ef | 2017-03-17 03:41:12 +0900 | [diff] [blame] | 122 | space -= 16; |
| 123 | ASSERT_EQ(space, data.available_); |
bcwhite | 7490275 | 2016-11-16 02:41:56 +0900 | [diff] [blame] | 124 | |
| 125 | data.Set("c", buffer, 10); |
bcwhite | 45cf1ef | 2017-03-17 03:41:12 +0900 | [diff] [blame] | 126 | space -= 24; |
| 127 | ASSERT_EQ(space, data.available_); |
bcwhite | 7490275 | 2016-11-16 02:41:56 +0900 | [diff] [blame] | 128 | |
| 129 | data.SetString("dear john", "it's been fun"); |
bcwhite | 45cf1ef | 2017-03-17 03:41:12 +0900 | [diff] [blame] | 130 | space -= 32; |
| 131 | ASSERT_EQ(space, data.available_); |
bcwhite | 7490275 | 2016-11-16 02:41:56 +0900 | [diff] [blame] | 132 | |
| 133 | data.Set("c", buffer, 20); |
bcwhite | 45cf1ef | 2017-03-17 03:41:12 +0900 | [diff] [blame] | 134 | ASSERT_EQ(space, data.available_); |
bcwhite | 7490275 | 2016-11-16 02:41:56 +0900 | [diff] [blame] | 135 | |
| 136 | data.SetString("dear john", "but we're done together"); |
bcwhite | 45cf1ef | 2017-03-17 03:41:12 +0900 | [diff] [blame] | 137 | ASSERT_EQ(space, data.available_); |
bcwhite | 7490275 | 2016-11-16 02:41:56 +0900 | [diff] [blame] | 138 | |
| 139 | data.SetString("dear john", "bye"); |
bcwhite | 45cf1ef | 2017-03-17 03:41:12 +0900 | [diff] [blame] | 140 | ASSERT_EQ(space, data.available_); |
bcwhite | 7490275 | 2016-11-16 02:41:56 +0900 | [diff] [blame] | 141 | |
| 142 | data.SetChar("d", 'x'); |
bcwhite | 45cf1ef | 2017-03-17 03:41:12 +0900 | [diff] [blame] | 143 | space -= 8; |
| 144 | ASSERT_EQ(space, data.available_); |
bcwhite | 2baebb1 | 2016-12-09 12:37:56 +0900 | [diff] [blame] | 145 | |
| 146 | data.SetBool("ee", true); |
bcwhite | 45cf1ef | 2017-03-17 03:41:12 +0900 | [diff] [blame] | 147 | space -= 16; |
| 148 | ASSERT_EQ(space, data.available_); |
bcwhite | a12d3ef | 2017-03-08 08:30:41 +0900 | [diff] [blame] | 149 | |
| 150 | data.SetString("f", ""); |
bcwhite | 45cf1ef | 2017-03-17 03:41:12 +0900 | [diff] [blame] | 151 | space -= 8; |
| 152 | ASSERT_EQ(space, data.available_); |
bcwhite | 7490275 | 2016-11-16 02:41:56 +0900 | [diff] [blame] | 153 | } |
| 154 | |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 155 | TEST_F(ActivityTrackerTest, PushPopTest) { |
| 156 | std::unique_ptr<ThreadActivityTracker> tracker = CreateActivityTracker(); |
bcwhite | 2baebb1 | 2016-12-09 12:37:56 +0900 | [diff] [blame] | 157 | ThreadActivityTracker::Snapshot snapshot; |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 158 | |
bcwhite | 2baebb1 | 2016-12-09 12:37:56 +0900 | [diff] [blame] | 159 | ASSERT_TRUE(tracker->CreateSnapshot(&snapshot)); |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 160 | ASSERT_EQ(0U, snapshot.activity_stack_depth); |
| 161 | ASSERT_EQ(0U, snapshot.activity_stack.size()); |
| 162 | |
| 163 | char origin1; |
bcwhite | 7490275 | 2016-11-16 02:41:56 +0900 | [diff] [blame] | 164 | ActivityId id1 = tracker->PushActivity(&origin1, Activity::ACT_TASK, |
| 165 | ActivityData::ForTask(11)); |
bcwhite | 2baebb1 | 2016-12-09 12:37:56 +0900 | [diff] [blame] | 166 | ASSERT_TRUE(tracker->CreateSnapshot(&snapshot)); |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 167 | ASSERT_EQ(1U, snapshot.activity_stack_depth); |
| 168 | ASSERT_EQ(1U, snapshot.activity_stack.size()); |
| 169 | EXPECT_NE(0, snapshot.activity_stack[0].time_internal); |
bcwhite | dc0d87c | 2016-08-12 09:04:13 +0900 | [diff] [blame] | 170 | EXPECT_EQ(Activity::ACT_TASK, snapshot.activity_stack[0].activity_type); |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 171 | EXPECT_EQ(reinterpret_cast<uintptr_t>(&origin1), |
| 172 | snapshot.activity_stack[0].origin_address); |
| 173 | EXPECT_EQ(11U, snapshot.activity_stack[0].data.task.sequence_id); |
| 174 | |
| 175 | char origin2; |
| 176 | char lock2; |
bcwhite | 7490275 | 2016-11-16 02:41:56 +0900 | [diff] [blame] | 177 | ActivityId id2 = tracker->PushActivity(&origin2, Activity::ACT_LOCK, |
| 178 | ActivityData::ForLock(&lock2)); |
bcwhite | 2baebb1 | 2016-12-09 12:37:56 +0900 | [diff] [blame] | 179 | ASSERT_TRUE(tracker->CreateSnapshot(&snapshot)); |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 180 | ASSERT_EQ(2U, snapshot.activity_stack_depth); |
| 181 | ASSERT_EQ(2U, snapshot.activity_stack.size()); |
| 182 | EXPECT_LE(snapshot.activity_stack[0].time_internal, |
| 183 | snapshot.activity_stack[1].time_internal); |
bcwhite | dc0d87c | 2016-08-12 09:04:13 +0900 | [diff] [blame] | 184 | EXPECT_EQ(Activity::ACT_LOCK, snapshot.activity_stack[1].activity_type); |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 185 | EXPECT_EQ(reinterpret_cast<uintptr_t>(&origin2), |
| 186 | snapshot.activity_stack[1].origin_address); |
| 187 | EXPECT_EQ(reinterpret_cast<uintptr_t>(&lock2), |
| 188 | snapshot.activity_stack[1].data.lock.lock_address); |
| 189 | |
bcwhite | 7490275 | 2016-11-16 02:41:56 +0900 | [diff] [blame] | 190 | tracker->PopActivity(id2); |
bcwhite | 2baebb1 | 2016-12-09 12:37:56 +0900 | [diff] [blame] | 191 | ASSERT_TRUE(tracker->CreateSnapshot(&snapshot)); |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 192 | ASSERT_EQ(1U, snapshot.activity_stack_depth); |
| 193 | ASSERT_EQ(1U, snapshot.activity_stack.size()); |
bcwhite | dc0d87c | 2016-08-12 09:04:13 +0900 | [diff] [blame] | 194 | EXPECT_EQ(Activity::ACT_TASK, snapshot.activity_stack[0].activity_type); |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 195 | EXPECT_EQ(reinterpret_cast<uintptr_t>(&origin1), |
| 196 | snapshot.activity_stack[0].origin_address); |
| 197 | EXPECT_EQ(11U, snapshot.activity_stack[0].data.task.sequence_id); |
| 198 | |
bcwhite | 7490275 | 2016-11-16 02:41:56 +0900 | [diff] [blame] | 199 | tracker->PopActivity(id1); |
bcwhite | 2baebb1 | 2016-12-09 12:37:56 +0900 | [diff] [blame] | 200 | ASSERT_TRUE(tracker->CreateSnapshot(&snapshot)); |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 201 | ASSERT_EQ(0U, snapshot.activity_stack_depth); |
| 202 | ASSERT_EQ(0U, snapshot.activity_stack.size()); |
| 203 | } |
| 204 | |
| 205 | TEST_F(ActivityTrackerTest, ScopedTaskTest) { |
bcwhite | 0aa1f8c | 2017-04-01 01:21:53 +0900 | [diff] [blame] | 206 | GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0); |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 207 | |
| 208 | ThreadActivityTracker* tracker = |
| 209 | GlobalActivityTracker::Get()->GetOrCreateTrackerForCurrentThread(); |
bcwhite | 2baebb1 | 2016-12-09 12:37:56 +0900 | [diff] [blame] | 210 | ThreadActivityTracker::Snapshot snapshot; |
bcwhite | 7490275 | 2016-11-16 02:41:56 +0900 | [diff] [blame] | 211 | ASSERT_EQ(0U, GetGlobalUserDataMemoryCacheUsed()); |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 212 | |
bcwhite | 2baebb1 | 2016-12-09 12:37:56 +0900 | [diff] [blame] | 213 | ASSERT_TRUE(tracker->CreateSnapshot(&snapshot)); |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 214 | ASSERT_EQ(0U, snapshot.activity_stack_depth); |
| 215 | ASSERT_EQ(0U, snapshot.activity_stack.size()); |
| 216 | |
| 217 | { |
Peter Kasting | 24efe5e | 2018-02-24 09:03:01 +0900 | [diff] [blame^] | 218 | PendingTask task1(FROM_HERE, DoNothing()); |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 219 | ScopedTaskRunActivity activity1(task1); |
bcwhite | 7490275 | 2016-11-16 02:41:56 +0900 | [diff] [blame] | 220 | ActivityUserData& user_data1 = activity1.user_data(); |
| 221 | (void)user_data1; // Tell compiler it's been used. |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 222 | |
bcwhite | 2baebb1 | 2016-12-09 12:37:56 +0900 | [diff] [blame] | 223 | ASSERT_TRUE(tracker->CreateSnapshot(&snapshot)); |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 224 | ASSERT_EQ(1U, snapshot.activity_stack_depth); |
| 225 | ASSERT_EQ(1U, snapshot.activity_stack.size()); |
bcwhite | dc0d87c | 2016-08-12 09:04:13 +0900 | [diff] [blame] | 226 | EXPECT_EQ(Activity::ACT_TASK, snapshot.activity_stack[0].activity_type); |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 227 | |
| 228 | { |
Peter Kasting | 24efe5e | 2018-02-24 09:03:01 +0900 | [diff] [blame^] | 229 | PendingTask task2(FROM_HERE, DoNothing()); |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 230 | ScopedTaskRunActivity activity2(task2); |
bcwhite | 7490275 | 2016-11-16 02:41:56 +0900 | [diff] [blame] | 231 | ActivityUserData& user_data2 = activity2.user_data(); |
| 232 | (void)user_data2; // Tell compiler it's been used. |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 233 | |
bcwhite | 2baebb1 | 2016-12-09 12:37:56 +0900 | [diff] [blame] | 234 | ASSERT_TRUE(tracker->CreateSnapshot(&snapshot)); |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 235 | ASSERT_EQ(2U, snapshot.activity_stack_depth); |
| 236 | ASSERT_EQ(2U, snapshot.activity_stack.size()); |
bcwhite | dc0d87c | 2016-08-12 09:04:13 +0900 | [diff] [blame] | 237 | EXPECT_EQ(Activity::ACT_TASK, snapshot.activity_stack[1].activity_type); |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 238 | } |
| 239 | |
bcwhite | 2baebb1 | 2016-12-09 12:37:56 +0900 | [diff] [blame] | 240 | ASSERT_TRUE(tracker->CreateSnapshot(&snapshot)); |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 241 | ASSERT_EQ(1U, snapshot.activity_stack_depth); |
| 242 | ASSERT_EQ(1U, snapshot.activity_stack.size()); |
bcwhite | dc0d87c | 2016-08-12 09:04:13 +0900 | [diff] [blame] | 243 | EXPECT_EQ(Activity::ACT_TASK, snapshot.activity_stack[0].activity_type); |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 244 | } |
| 245 | |
bcwhite | 2baebb1 | 2016-12-09 12:37:56 +0900 | [diff] [blame] | 246 | ASSERT_TRUE(tracker->CreateSnapshot(&snapshot)); |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 247 | ASSERT_EQ(0U, snapshot.activity_stack_depth); |
| 248 | ASSERT_EQ(0U, snapshot.activity_stack.size()); |
bcwhite | 7490275 | 2016-11-16 02:41:56 +0900 | [diff] [blame] | 249 | ASSERT_EQ(2U, GetGlobalUserDataMemoryCacheUsed()); |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 250 | } |
| 251 | |
Brian White | 43d72ee | 2017-10-26 06:44:03 +0900 | [diff] [blame] | 252 | namespace { |
| 253 | |
| 254 | class SimpleLockThread : public SimpleThread { |
| 255 | public: |
| 256 | SimpleLockThread(const std::string& name, Lock* lock) |
| 257 | : SimpleThread(name, Options()), |
| 258 | lock_(lock), |
| 259 | data_changed_(false), |
| 260 | is_running_(false) {} |
| 261 | |
Chris Watkins | d155d9f | 2017-11-29 16:16:38 +0900 | [diff] [blame] | 262 | ~SimpleLockThread() override = default; |
Brian White | 43d72ee | 2017-10-26 06:44:03 +0900 | [diff] [blame] | 263 | |
| 264 | void Run() override { |
| 265 | ThreadActivityTracker* tracker = |
| 266 | GlobalActivityTracker::Get()->GetOrCreateTrackerForCurrentThread(); |
Brian White | 74b52d2 | 2017-11-24 01:53:24 +0900 | [diff] [blame] | 267 | uint32_t pre_version = tracker->GetDataVersionForTesting(); |
Brian White | 43d72ee | 2017-10-26 06:44:03 +0900 | [diff] [blame] | 268 | |
| 269 | is_running_.store(true, std::memory_order_relaxed); |
| 270 | lock_->Acquire(); |
Brian White | 74b52d2 | 2017-11-24 01:53:24 +0900 | [diff] [blame] | 271 | data_changed_ = tracker->GetDataVersionForTesting() != pre_version; |
Brian White | 43d72ee | 2017-10-26 06:44:03 +0900 | [diff] [blame] | 272 | lock_->Release(); |
| 273 | is_running_.store(false, std::memory_order_relaxed); |
| 274 | } |
| 275 | |
| 276 | bool IsRunning() { return is_running_.load(std::memory_order_relaxed); } |
| 277 | |
| 278 | bool WasDataChanged() { return data_changed_; }; |
| 279 | |
| 280 | private: |
| 281 | Lock* lock_; |
| 282 | bool data_changed_; |
| 283 | std::atomic<bool> is_running_; |
| 284 | |
| 285 | DISALLOW_COPY_AND_ASSIGN(SimpleLockThread); |
| 286 | }; |
| 287 | |
| 288 | } // namespace |
| 289 | |
| 290 | TEST_F(ActivityTrackerTest, LockTest) { |
| 291 | GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0); |
| 292 | |
| 293 | ThreadActivityTracker* tracker = |
| 294 | GlobalActivityTracker::Get()->GetOrCreateTrackerForCurrentThread(); |
| 295 | ThreadActivityTracker::Snapshot snapshot; |
| 296 | ASSERT_EQ(0U, GetGlobalUserDataMemoryCacheUsed()); |
| 297 | |
| 298 | Lock lock; |
Brian White | 74b52d2 | 2017-11-24 01:53:24 +0900 | [diff] [blame] | 299 | uint32_t pre_version = tracker->GetDataVersionForTesting(); |
Brian White | 43d72ee | 2017-10-26 06:44:03 +0900 | [diff] [blame] | 300 | |
| 301 | // Check no activity when only "trying" a lock. |
| 302 | EXPECT_TRUE(lock.Try()); |
Brian White | 74b52d2 | 2017-11-24 01:53:24 +0900 | [diff] [blame] | 303 | EXPECT_EQ(pre_version, tracker->GetDataVersionForTesting()); |
Brian White | 43d72ee | 2017-10-26 06:44:03 +0900 | [diff] [blame] | 304 | lock.Release(); |
Brian White | 74b52d2 | 2017-11-24 01:53:24 +0900 | [diff] [blame] | 305 | EXPECT_EQ(pre_version, tracker->GetDataVersionForTesting()); |
Brian White | 43d72ee | 2017-10-26 06:44:03 +0900 | [diff] [blame] | 306 | |
| 307 | // Check no activity when acquiring a free lock. |
| 308 | SimpleLockThread t1("locker1", &lock); |
| 309 | t1.Start(); |
| 310 | t1.Join(); |
| 311 | EXPECT_FALSE(t1.WasDataChanged()); |
| 312 | |
| 313 | // Check that activity is recorded when acquring a busy lock. |
| 314 | SimpleLockThread t2("locker2", &lock); |
| 315 | lock.Acquire(); |
| 316 | t2.Start(); |
| 317 | while (!t2.IsRunning()) |
| 318 | PlatformThread::Sleep(TimeDelta::FromMilliseconds(10)); |
| 319 | // t2 can't join until the lock is released but have to give time for t2 to |
| 320 | // actually block on the lock before releasing it or the results will not |
| 321 | // be correct. |
| 322 | PlatformThread::Sleep(TimeDelta::FromMilliseconds(200)); |
| 323 | lock.Release(); |
| 324 | // Now the results will be valid. |
| 325 | t2.Join(); |
| 326 | EXPECT_TRUE(t2.WasDataChanged()); |
| 327 | } |
| 328 | |
bcwhite | 79603d9 | 2017-03-24 22:24:39 +0900 | [diff] [blame] | 329 | TEST_F(ActivityTrackerTest, ExceptionTest) { |
bcwhite | 0aa1f8c | 2017-04-01 01:21:53 +0900 | [diff] [blame] | 330 | GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0); |
bcwhite | 79603d9 | 2017-03-24 22:24:39 +0900 | [diff] [blame] | 331 | GlobalActivityTracker* global = GlobalActivityTracker::Get(); |
| 332 | |
| 333 | ThreadActivityTracker* tracker = |
| 334 | GlobalActivityTracker::Get()->GetOrCreateTrackerForCurrentThread(); |
| 335 | ThreadActivityTracker::Snapshot snapshot; |
| 336 | ASSERT_EQ(0U, GetGlobalUserDataMemoryCacheUsed()); |
| 337 | |
| 338 | ASSERT_TRUE(tracker->CreateSnapshot(&snapshot)); |
| 339 | ASSERT_EQ(0U, snapshot.last_exception.activity_type); |
| 340 | |
| 341 | char origin; |
| 342 | global->RecordException(&origin, 42); |
| 343 | |
| 344 | ASSERT_TRUE(tracker->CreateSnapshot(&snapshot)); |
| 345 | EXPECT_EQ(Activity::ACT_EXCEPTION, snapshot.last_exception.activity_type); |
| 346 | EXPECT_EQ(reinterpret_cast<uintptr_t>(&origin), |
| 347 | snapshot.last_exception.origin_address); |
| 348 | EXPECT_EQ(42U, snapshot.last_exception.data.exception.code); |
| 349 | } |
| 350 | |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 351 | TEST_F(ActivityTrackerTest, CreateWithFileTest) { |
| 352 | const char temp_name[] = "CreateWithFileTest"; |
| 353 | ScopedTempDir temp_dir; |
| 354 | ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
vabr | 31978e9 | 2016-09-08 18:26:27 +0900 | [diff] [blame] | 355 | FilePath temp_file = temp_dir.GetPath().AppendASCII(temp_name); |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 356 | const size_t temp_size = 64 << 10; // 64 KiB |
| 357 | |
| 358 | // Create a global tracker on a new file. |
| 359 | ASSERT_FALSE(PathExists(temp_file)); |
| 360 | GlobalActivityTracker::CreateWithFile(temp_file, temp_size, 0, "foo", 3); |
| 361 | GlobalActivityTracker* global = GlobalActivityTracker::Get(); |
| 362 | EXPECT_EQ(std::string("foo"), global->allocator()->Name()); |
| 363 | global->ReleaseTrackerForCurrentThreadForTesting(); |
| 364 | delete global; |
| 365 | |
| 366 | // Create a global tracker over an existing file, replacing it. If the |
| 367 | // replacement doesn't work, the name will remain as it was first created. |
| 368 | ASSERT_TRUE(PathExists(temp_file)); |
| 369 | GlobalActivityTracker::CreateWithFile(temp_file, temp_size, 0, "bar", 3); |
| 370 | global = GlobalActivityTracker::Get(); |
| 371 | EXPECT_EQ(std::string("bar"), global->allocator()->Name()); |
| 372 | global->ReleaseTrackerForCurrentThreadForTesting(); |
| 373 | delete global; |
| 374 | } |
| 375 | |
| 376 | |
| 377 | // GlobalActivityTracker tests below. |
| 378 | |
bcwhite | 45cf1ef | 2017-03-17 03:41:12 +0900 | [diff] [blame] | 379 | TEST_F(ActivityTrackerTest, BasicTest) { |
bcwhite | 0aa1f8c | 2017-04-01 01:21:53 +0900 | [diff] [blame] | 380 | GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0); |
bcwhite | 45cf1ef | 2017-03-17 03:41:12 +0900 | [diff] [blame] | 381 | GlobalActivityTracker* global = GlobalActivityTracker::Get(); |
| 382 | |
| 383 | // Ensure the data repositories have backing store, indicated by non-zero ID. |
| 384 | EXPECT_NE(0U, global->process_data().id()); |
bcwhite | 45cf1ef | 2017-03-17 03:41:12 +0900 | [diff] [blame] | 385 | } |
| 386 | |
thestig | 475b253 | 2017-05-25 06:57:51 +0900 | [diff] [blame] | 387 | namespace { |
| 388 | |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 389 | class SimpleActivityThread : public SimpleThread { |
| 390 | public: |
| 391 | SimpleActivityThread(const std::string& name, |
| 392 | const void* origin, |
bcwhite | dc0d87c | 2016-08-12 09:04:13 +0900 | [diff] [blame] | 393 | Activity::Type activity, |
| 394 | const ActivityData& data) |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 395 | : SimpleThread(name, Options()), |
| 396 | origin_(origin), |
| 397 | activity_(activity), |
| 398 | data_(data), |
thestig | 475b253 | 2017-05-25 06:57:51 +0900 | [diff] [blame] | 399 | ready_(false), |
| 400 | exit_(false), |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 401 | exit_condition_(&lock_) {} |
| 402 | |
Chris Watkins | d155d9f | 2017-11-29 16:16:38 +0900 | [diff] [blame] | 403 | ~SimpleActivityThread() override = default; |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 404 | |
| 405 | void Run() override { |
bcwhite | 7490275 | 2016-11-16 02:41:56 +0900 | [diff] [blame] | 406 | ThreadActivityTracker::ActivityId id = |
| 407 | GlobalActivityTracker::Get() |
| 408 | ->GetOrCreateTrackerForCurrentThread() |
| 409 | ->PushActivity(origin_, activity_, data_); |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 410 | |
| 411 | { |
| 412 | AutoLock auto_lock(lock_); |
thestig | 475b253 | 2017-05-25 06:57:51 +0900 | [diff] [blame] | 413 | ready_.store(true, std::memory_order_release); |
| 414 | while (!exit_.load(std::memory_order_relaxed)) |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 415 | exit_condition_.Wait(); |
| 416 | } |
| 417 | |
bcwhite | 7490275 | 2016-11-16 02:41:56 +0900 | [diff] [blame] | 418 | GlobalActivityTracker::Get()->GetTrackerForCurrentThread()->PopActivity(id); |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 419 | } |
| 420 | |
| 421 | void Exit() { |
| 422 | AutoLock auto_lock(lock_); |
thestig | 475b253 | 2017-05-25 06:57:51 +0900 | [diff] [blame] | 423 | exit_.store(true, std::memory_order_relaxed); |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 424 | exit_condition_.Signal(); |
| 425 | } |
| 426 | |
| 427 | void WaitReady() { |
thestig | 475b253 | 2017-05-25 06:57:51 +0900 | [diff] [blame] | 428 | SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(ready_.load(std::memory_order_acquire)); |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 429 | } |
| 430 | |
| 431 | private: |
| 432 | const void* origin_; |
bcwhite | dc0d87c | 2016-08-12 09:04:13 +0900 | [diff] [blame] | 433 | Activity::Type activity_; |
| 434 | ActivityData data_; |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 435 | |
thestig | 475b253 | 2017-05-25 06:57:51 +0900 | [diff] [blame] | 436 | std::atomic<bool> ready_; |
| 437 | std::atomic<bool> exit_; |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 438 | Lock lock_; |
| 439 | ConditionVariable exit_condition_; |
| 440 | |
| 441 | DISALLOW_COPY_AND_ASSIGN(SimpleActivityThread); |
| 442 | }; |
| 443 | |
thestig | 475b253 | 2017-05-25 06:57:51 +0900 | [diff] [blame] | 444 | } // namespace |
| 445 | |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 446 | TEST_F(ActivityTrackerTest, ThreadDeathTest) { |
bcwhite | 0aa1f8c | 2017-04-01 01:21:53 +0900 | [diff] [blame] | 447 | GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0); |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 448 | GlobalActivityTracker::Get()->GetOrCreateTrackerForCurrentThread(); |
| 449 | const size_t starting_active = GetGlobalActiveTrackerCount(); |
| 450 | const size_t starting_inactive = GetGlobalInactiveTrackerCount(); |
| 451 | |
bcwhite | dc0d87c | 2016-08-12 09:04:13 +0900 | [diff] [blame] | 452 | SimpleActivityThread t1("t1", nullptr, Activity::ACT_TASK, |
| 453 | ActivityData::ForTask(11)); |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 454 | t1.Start(); |
| 455 | t1.WaitReady(); |
| 456 | EXPECT_EQ(starting_active + 1, GetGlobalActiveTrackerCount()); |
| 457 | EXPECT_EQ(starting_inactive, GetGlobalInactiveTrackerCount()); |
| 458 | |
| 459 | t1.Exit(); |
| 460 | t1.Join(); |
| 461 | EXPECT_EQ(starting_active, GetGlobalActiveTrackerCount()); |
| 462 | EXPECT_EQ(starting_inactive + 1, GetGlobalInactiveTrackerCount()); |
| 463 | |
| 464 | // Start another thread and ensure it re-uses the existing memory. |
| 465 | |
bcwhite | dc0d87c | 2016-08-12 09:04:13 +0900 | [diff] [blame] | 466 | SimpleActivityThread t2("t2", nullptr, Activity::ACT_TASK, |
| 467 | ActivityData::ForTask(22)); |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 468 | t2.Start(); |
| 469 | t2.WaitReady(); |
| 470 | EXPECT_EQ(starting_active + 1, GetGlobalActiveTrackerCount()); |
| 471 | EXPECT_EQ(starting_inactive, GetGlobalInactiveTrackerCount()); |
| 472 | |
| 473 | t2.Exit(); |
| 474 | t2.Join(); |
| 475 | EXPECT_EQ(starting_active, GetGlobalActiveTrackerCount()); |
| 476 | EXPECT_EQ(starting_inactive + 1, GetGlobalInactiveTrackerCount()); |
| 477 | } |
| 478 | |
bcwhite | 6bd84ae | 2017-05-23 22:09:20 +0900 | [diff] [blame] | 479 | TEST_F(ActivityTrackerTest, ProcessDeathTest) { |
bcwhite | 45cf1ef | 2017-03-17 03:41:12 +0900 | [diff] [blame] | 480 | // This doesn't actually create and destroy a process. Instead, it uses for- |
| 481 | // testing interfaces to simulate data created by other processes. |
scottmg | ab60303 | 2017-05-24 12:45:58 +0900 | [diff] [blame] | 482 | const int64_t other_process_id = GetCurrentProcId() + 1; |
bcwhite | 45cf1ef | 2017-03-17 03:41:12 +0900 | [diff] [blame] | 483 | |
bcwhite | 0aa1f8c | 2017-04-01 01:21:53 +0900 | [diff] [blame] | 484 | GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0); |
bcwhite | 45cf1ef | 2017-03-17 03:41:12 +0900 | [diff] [blame] | 485 | GlobalActivityTracker* global = GlobalActivityTracker::Get(); |
| 486 | ThreadActivityTracker* thread = global->GetOrCreateTrackerForCurrentThread(); |
| 487 | |
| 488 | // Get callbacks for process exit. |
| 489 | global->SetProcessExitCallback( |
| 490 | Bind(&ActivityTrackerTest::HandleProcessExit, Unretained(this))); |
| 491 | |
| 492 | // Pretend than another process has started. |
| 493 | global->RecordProcessLaunch(other_process_id, FILE_PATH_LITERAL("foo --bar")); |
| 494 | |
| 495 | // Do some activities. |
Peter Kasting | 24efe5e | 2018-02-24 09:03:01 +0900 | [diff] [blame^] | 496 | PendingTask task(FROM_HERE, DoNothing()); |
bcwhite | 45cf1ef | 2017-03-17 03:41:12 +0900 | [diff] [blame] | 497 | ScopedTaskRunActivity activity(task); |
| 498 | ActivityUserData& user_data = activity.user_data(); |
| 499 | ASSERT_NE(0U, user_data.id()); |
| 500 | |
| 501 | // Get the memory-allocator references to that data. |
| 502 | PersistentMemoryAllocator::Reference proc_data_ref = |
| 503 | global->allocator()->GetAsReference( |
| 504 | global->process_data().GetBaseAddress(), |
| 505 | GlobalActivityTracker::kTypeIdProcessDataRecord); |
| 506 | ASSERT_TRUE(proc_data_ref); |
| 507 | PersistentMemoryAllocator::Reference tracker_ref = |
| 508 | global->allocator()->GetAsReference( |
| 509 | thread->GetBaseAddress(), |
| 510 | GlobalActivityTracker::kTypeIdActivityTracker); |
| 511 | ASSERT_TRUE(tracker_ref); |
| 512 | PersistentMemoryAllocator::Reference user_data_ref = |
| 513 | global->allocator()->GetAsReference( |
| 514 | user_data.GetBaseAddress(), |
| 515 | GlobalActivityTracker::kTypeIdUserDataRecord); |
| 516 | ASSERT_TRUE(user_data_ref); |
| 517 | |
| 518 | // Make a copy of the thread-tracker state so it can be restored later. |
| 519 | const size_t tracker_size = global->allocator()->GetAllocSize(tracker_ref); |
| 520 | std::unique_ptr<char[]> tracker_copy(new char[tracker_size]); |
| 521 | memcpy(tracker_copy.get(), thread->GetBaseAddress(), tracker_size); |
| 522 | |
bcwhite | 6bd84ae | 2017-05-23 22:09:20 +0900 | [diff] [blame] | 523 | // Change the objects to appear to be owned by another process. Use a "past" |
| 524 | // time so that exit-time is always later than create-time. |
| 525 | const int64_t past_stamp = Time::Now().ToInternalValue() - 1; |
bcwhite | 0aa1f8c | 2017-04-01 01:21:53 +0900 | [diff] [blame] | 526 | int64_t owning_id; |
bcwhite | 45cf1ef | 2017-03-17 03:41:12 +0900 | [diff] [blame] | 527 | int64_t stamp; |
| 528 | ASSERT_TRUE(ActivityUserData::GetOwningProcessId( |
| 529 | global->process_data().GetBaseAddress(), &owning_id, &stamp)); |
| 530 | EXPECT_NE(other_process_id, owning_id); |
| 531 | ASSERT_TRUE(ThreadActivityTracker::GetOwningProcessId( |
| 532 | thread->GetBaseAddress(), &owning_id, &stamp)); |
| 533 | EXPECT_NE(other_process_id, owning_id); |
| 534 | ASSERT_TRUE(ActivityUserData::GetOwningProcessId(user_data.GetBaseAddress(), |
| 535 | &owning_id, &stamp)); |
| 536 | EXPECT_NE(other_process_id, owning_id); |
bcwhite | 6bd84ae | 2017-05-23 22:09:20 +0900 | [diff] [blame] | 537 | global->process_data().SetOwningProcessIdForTesting(other_process_id, |
| 538 | past_stamp); |
| 539 | thread->SetOwningProcessIdForTesting(other_process_id, past_stamp); |
| 540 | user_data.SetOwningProcessIdForTesting(other_process_id, past_stamp); |
bcwhite | 45cf1ef | 2017-03-17 03:41:12 +0900 | [diff] [blame] | 541 | ASSERT_TRUE(ActivityUserData::GetOwningProcessId( |
| 542 | global->process_data().GetBaseAddress(), &owning_id, &stamp)); |
| 543 | EXPECT_EQ(other_process_id, owning_id); |
| 544 | ASSERT_TRUE(ThreadActivityTracker::GetOwningProcessId( |
| 545 | thread->GetBaseAddress(), &owning_id, &stamp)); |
| 546 | EXPECT_EQ(other_process_id, owning_id); |
| 547 | ASSERT_TRUE(ActivityUserData::GetOwningProcessId(user_data.GetBaseAddress(), |
| 548 | &owning_id, &stamp)); |
| 549 | EXPECT_EQ(other_process_id, owning_id); |
| 550 | |
| 551 | // Check that process exit will perform callback and free the allocations. |
bcwhite | 6bd84ae | 2017-05-23 22:09:20 +0900 | [diff] [blame] | 552 | ASSERT_EQ(0, exit_id_); |
bcwhite | 45cf1ef | 2017-03-17 03:41:12 +0900 | [diff] [blame] | 553 | ASSERT_EQ(GlobalActivityTracker::kTypeIdProcessDataRecord, |
| 554 | global->allocator()->GetType(proc_data_ref)); |
| 555 | ASSERT_EQ(GlobalActivityTracker::kTypeIdActivityTracker, |
| 556 | global->allocator()->GetType(tracker_ref)); |
| 557 | ASSERT_EQ(GlobalActivityTracker::kTypeIdUserDataRecord, |
| 558 | global->allocator()->GetType(user_data_ref)); |
| 559 | global->RecordProcessExit(other_process_id, 0); |
bcwhite | 6bd84ae | 2017-05-23 22:09:20 +0900 | [diff] [blame] | 560 | EXPECT_EQ(other_process_id, exit_id_); |
| 561 | EXPECT_EQ("foo --bar", exit_command_); |
bcwhite | 45cf1ef | 2017-03-17 03:41:12 +0900 | [diff] [blame] | 562 | EXPECT_EQ(GlobalActivityTracker::kTypeIdProcessDataRecordFree, |
| 563 | global->allocator()->GetType(proc_data_ref)); |
| 564 | EXPECT_EQ(GlobalActivityTracker::kTypeIdActivityTrackerFree, |
| 565 | global->allocator()->GetType(tracker_ref)); |
| 566 | EXPECT_EQ(GlobalActivityTracker::kTypeIdUserDataRecordFree, |
| 567 | global->allocator()->GetType(user_data_ref)); |
| 568 | |
| 569 | // Restore memory contents and types so things don't crash when doing real |
| 570 | // process clean-up. |
| 571 | memcpy(const_cast<void*>(thread->GetBaseAddress()), tracker_copy.get(), |
| 572 | tracker_size); |
| 573 | global->allocator()->ChangeType( |
| 574 | proc_data_ref, GlobalActivityTracker::kTypeIdProcessDataRecord, |
| 575 | GlobalActivityTracker::kTypeIdUserDataRecordFree, false); |
| 576 | global->allocator()->ChangeType( |
| 577 | tracker_ref, GlobalActivityTracker::kTypeIdActivityTracker, |
| 578 | GlobalActivityTracker::kTypeIdActivityTrackerFree, false); |
| 579 | global->allocator()->ChangeType( |
| 580 | user_data_ref, GlobalActivityTracker::kTypeIdUserDataRecord, |
| 581 | GlobalActivityTracker::kTypeIdUserDataRecordFree, false); |
| 582 | } |
| 583 | |
bcwhite | a156944 | 2016-08-10 12:10:03 +0900 | [diff] [blame] | 584 | } // namespace debug |
| 585 | } // namespace base |