OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/debug/activity_tracker.h" | 5 #include "base/debug/activity_tracker.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/files/file.h" | 10 #include "base/files/file.h" |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
84 return GlobalActivityTracker::Get()->user_data_allocator_.cache_used(); | 84 return GlobalActivityTracker::Get()->user_data_allocator_.cache_used(); |
85 } | 85 } |
86 | 86 |
87 static void DoNothing() {} | 87 static void DoNothing() {} |
88 }; | 88 }; |
89 | 89 |
90 TEST_F(ActivityTrackerTest, UserDataTest) { | 90 TEST_F(ActivityTrackerTest, UserDataTest) { |
91 char buffer[256]; | 91 char buffer[256]; |
92 memset(buffer, 0, sizeof(buffer)); | 92 memset(buffer, 0, sizeof(buffer)); |
93 ActivityUserData data(buffer, sizeof(buffer)); | 93 ActivityUserData data(buffer, sizeof(buffer)); |
94 ASSERT_EQ(sizeof(buffer) - 8, data.available_); | 94 ASSERT_EQ(sizeof(buffer) - 24, data.available_); |
95 | 95 |
96 data.SetInt("foo", 1); | 96 data.SetInt("foo", 1); |
97 ASSERT_EQ(sizeof(buffer) - 8 - 24, data.available_); | 97 ASSERT_EQ(sizeof(buffer) - 24 - 24, data.available_); |
98 | 98 |
99 data.SetUint("b", 1U); // Small names fit beside header in a word. | 99 data.SetUint("b", 1U); // Small names fit beside header in a word. |
100 ASSERT_EQ(sizeof(buffer) - 8 - 24 - 16, data.available_); | 100 ASSERT_EQ(sizeof(buffer) - 24 - 24 - 16, data.available_); |
101 | 101 |
102 data.Set("c", buffer, 10); | 102 data.Set("c", buffer, 10); |
103 ASSERT_EQ(sizeof(buffer) - 8 - 24 - 16 - 24, data.available_); | 103 ASSERT_EQ(sizeof(buffer) - 24 - 24 - 16 - 24, data.available_); |
104 | 104 |
105 data.SetString("dear john", "it's been fun"); | 105 data.SetString("dear john", "it's been fun"); |
106 ASSERT_EQ(sizeof(buffer) - 8 - 24 - 16 - 24 - 32, data.available_); | 106 ASSERT_EQ(sizeof(buffer) - 24 - 24 - 16 - 24 - 32, data.available_); |
107 | 107 |
108 data.Set("c", buffer, 20); | 108 data.Set("c", buffer, 20); |
109 ASSERT_EQ(sizeof(buffer) - 8 - 24 - 16 - 24 - 32, data.available_); | 109 ASSERT_EQ(sizeof(buffer) - 24 - 24 - 16 - 24 - 32, data.available_); |
110 | 110 |
111 data.SetString("dear john", "but we're done together"); | 111 data.SetString("dear john", "but we're done together"); |
112 ASSERT_EQ(sizeof(buffer) - 8 - 24 - 16 - 24 - 32, data.available_); | 112 ASSERT_EQ(sizeof(buffer) - 24 - 24 - 16 - 24 - 32, data.available_); |
113 | 113 |
114 data.SetString("dear john", "bye"); | 114 data.SetString("dear john", "bye"); |
115 ASSERT_EQ(sizeof(buffer) - 8 - 24 - 16 - 24 - 32, data.available_); | 115 ASSERT_EQ(sizeof(buffer) - 24 - 24 - 16 - 24 - 32, data.available_); |
116 | 116 |
117 data.SetChar("d", 'x'); | 117 data.SetChar("d", 'x'); |
118 ASSERT_EQ(sizeof(buffer) - 8 - 24 - 16 - 24 - 32 - 8, data.available_); | 118 ASSERT_EQ(sizeof(buffer) - 24 - 24 - 16 - 24 - 32 - 8, data.available_); |
119 | 119 |
120 data.SetBool("ee", true); | 120 data.SetBool("ee", true); |
121 ASSERT_EQ(sizeof(buffer) - 8 - 24 - 16 - 24 - 32 - 8 - 16, data.available_); | 121 ASSERT_EQ(sizeof(buffer) - 24 - 24 - 16 - 24 - 32 - 8 - 16, data.available_); |
122 } | 122 } |
123 | 123 |
124 TEST_F(ActivityTrackerTest, PushPopTest) { | 124 TEST_F(ActivityTrackerTest, PushPopTest) { |
125 std::unique_ptr<ThreadActivityTracker> tracker = CreateActivityTracker(); | 125 std::unique_ptr<ThreadActivityTracker> tracker = CreateActivityTracker(); |
126 ThreadActivityTracker::Snapshot snapshot; | 126 ThreadActivityTracker::Snapshot snapshot; |
127 | 127 |
128 ASSERT_TRUE(tracker->CreateSnapshot(&snapshot)); | 128 ASSERT_TRUE(tracker->CreateSnapshot(&snapshot)); |
129 ASSERT_EQ(0U, snapshot.activity_stack_depth); | 129 ASSERT_EQ(0U, snapshot.activity_stack_depth); |
130 ASSERT_EQ(0U, snapshot.activity_stack.size()); | 130 ASSERT_EQ(0U, snapshot.activity_stack.size()); |
131 | 131 |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
239 GlobalActivityTracker::CreateWithFile(temp_file, temp_size, 0, "bar", 3); | 239 GlobalActivityTracker::CreateWithFile(temp_file, temp_size, 0, "bar", 3); |
240 global = GlobalActivityTracker::Get(); | 240 global = GlobalActivityTracker::Get(); |
241 EXPECT_EQ(std::string("bar"), global->allocator()->Name()); | 241 EXPECT_EQ(std::string("bar"), global->allocator()->Name()); |
242 global->ReleaseTrackerForCurrentThreadForTesting(); | 242 global->ReleaseTrackerForCurrentThreadForTesting(); |
243 delete global; | 243 delete global; |
244 } | 244 } |
245 | 245 |
246 | 246 |
247 // GlobalActivityTracker tests below. | 247 // GlobalActivityTracker tests below. |
248 | 248 |
| 249 TEST_F(ActivityTrackerTest, BasicTest) { |
| 250 GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3); |
| 251 GlobalActivityTracker* global = GlobalActivityTracker::Get(); |
| 252 |
| 253 // Ensure the data repositories have backing store, indicated by non-zero ID. |
| 254 EXPECT_NE(0U, global->process_data().id()); |
| 255 EXPECT_NE(0U, global->global_data().id()); |
| 256 EXPECT_NE(global->process_data().id(), global->global_data().id()); |
| 257 } |
| 258 |
249 class SimpleActivityThread : public SimpleThread { | 259 class SimpleActivityThread : public SimpleThread { |
250 public: | 260 public: |
251 SimpleActivityThread(const std::string& name, | 261 SimpleActivityThread(const std::string& name, |
252 const void* origin, | 262 const void* origin, |
253 Activity::Type activity, | 263 Activity::Type activity, |
254 const ActivityData& data) | 264 const ActivityData& data) |
255 : SimpleThread(name, Options()), | 265 : SimpleThread(name, Options()), |
256 origin_(origin), | 266 origin_(origin), |
257 activity_(activity), | 267 activity_(activity), |
258 data_(data), | 268 data_(data), |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
325 t2.WaitReady(); | 335 t2.WaitReady(); |
326 EXPECT_EQ(starting_active + 1, GetGlobalActiveTrackerCount()); | 336 EXPECT_EQ(starting_active + 1, GetGlobalActiveTrackerCount()); |
327 EXPECT_EQ(starting_inactive, GetGlobalInactiveTrackerCount()); | 337 EXPECT_EQ(starting_inactive, GetGlobalInactiveTrackerCount()); |
328 | 338 |
329 t2.Exit(); | 339 t2.Exit(); |
330 t2.Join(); | 340 t2.Join(); |
331 EXPECT_EQ(starting_active, GetGlobalActiveTrackerCount()); | 341 EXPECT_EQ(starting_active, GetGlobalActiveTrackerCount()); |
332 EXPECT_EQ(starting_inactive + 1, GetGlobalInactiveTrackerCount()); | 342 EXPECT_EQ(starting_inactive + 1, GetGlobalInactiveTrackerCount()); |
333 } | 343 } |
334 | 344 |
| 345 TEST_F(ActivityTrackerTest, ProcessDeathTest) { |
| 346 // This doesn't actually create and destroy a process. Instead, it uses for- |
| 347 // testing interfaces to simulate data created by other processes. |
| 348 const ProcessId other_process_id = GetCurrentProcId() + 1; |
| 349 |
| 350 GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3); |
| 351 GlobalActivityTracker* global = GlobalActivityTracker::Get(); |
| 352 ThreadActivityTracker* thread = global->GetOrCreateTrackerForCurrentThread(); |
| 353 |
| 354 // Pretend than another process has started. |
| 355 global->RecordProcessLaunch(other_process_id); |
| 356 |
| 357 // Do some activities. |
| 358 PendingTask task(FROM_HERE, base::Bind(&DoNothing)); |
| 359 ScopedTaskRunActivity activity(task); |
| 360 ActivityUserData& user_data = activity.user_data(); |
| 361 ASSERT_NE(0U, user_data.id()); |
| 362 |
| 363 // Get the memory-allocator references to that data. |
| 364 PersistentMemoryAllocator::Reference proc_data_ref = |
| 365 global->allocator()->GetAsReference( |
| 366 global->process_data().GetBaseAddress(), |
| 367 GlobalActivityTracker::kTypeIdProcessDataRecord); |
| 368 ASSERT_TRUE(proc_data_ref); |
| 369 PersistentMemoryAllocator::Reference tracker_ref = |
| 370 global->allocator()->GetAsReference( |
| 371 thread->GetBaseAddress(), |
| 372 GlobalActivityTracker::kTypeIdActivityTracker); |
| 373 ASSERT_TRUE(tracker_ref); |
| 374 PersistentMemoryAllocator::Reference user_data_ref = |
| 375 global->allocator()->GetAsReference( |
| 376 user_data.GetBaseAddress(), |
| 377 GlobalActivityTracker::kTypeIdUserDataRecord); |
| 378 ASSERT_TRUE(user_data_ref); |
| 379 |
| 380 // Make a copy of the thread-tracker state so it can be restored later. |
| 381 const size_t tracker_size = global->allocator()->GetAllocSize(tracker_ref); |
| 382 std::unique_ptr<char[]> tracker_copy(new char[tracker_size]); |
| 383 memcpy(tracker_copy.get(), thread->GetBaseAddress(), tracker_size); |
| 384 |
| 385 // Change the objects to appear to be owned by another process. |
| 386 ProcessId owning_id; |
| 387 int64_t stamp; |
| 388 ASSERT_TRUE(ActivityUserData::OwningProcessId( |
| 389 global->process_data().GetBaseAddress(), &owning_id, &stamp)); |
| 390 EXPECT_NE(other_process_id, owning_id); |
| 391 ASSERT_TRUE(ThreadActivityTracker::OwningProcessId(thread->GetBaseAddress(), |
| 392 &owning_id, &stamp)); |
| 393 EXPECT_NE(other_process_id, owning_id); |
| 394 ASSERT_TRUE(ActivityUserData::OwningProcessId(user_data.GetBaseAddress(), |
| 395 &owning_id, &stamp)); |
| 396 EXPECT_NE(other_process_id, owning_id); |
| 397 global->process_data().SetOwningProcessIdForTesting(other_process_id, stamp); |
| 398 thread->SetOwningProcessIdForTesting(other_process_id, stamp); |
| 399 user_data.SetOwningProcessIdForTesting(other_process_id, stamp); |
| 400 ASSERT_TRUE(ActivityUserData::OwningProcessId( |
| 401 global->process_data().GetBaseAddress(), &owning_id, &stamp)); |
| 402 EXPECT_EQ(other_process_id, owning_id); |
| 403 ASSERT_TRUE(ThreadActivityTracker::OwningProcessId(thread->GetBaseAddress(), |
| 404 &owning_id, &stamp)); |
| 405 EXPECT_EQ(other_process_id, owning_id); |
| 406 ASSERT_TRUE(ActivityUserData::OwningProcessId(user_data.GetBaseAddress(), |
| 407 &owning_id, &stamp)); |
| 408 EXPECT_EQ(other_process_id, owning_id); |
| 409 |
| 410 // Check that process exit will free the allocations. |
| 411 ASSERT_EQ(GlobalActivityTracker::kTypeIdProcessDataRecord, |
| 412 global->allocator()->GetType(proc_data_ref)); |
| 413 ASSERT_EQ(GlobalActivityTracker::kTypeIdActivityTracker, |
| 414 global->allocator()->GetType(tracker_ref)); |
| 415 ASSERT_EQ(GlobalActivityTracker::kTypeIdUserDataRecord, |
| 416 global->allocator()->GetType(user_data_ref)); |
| 417 global->RecordProcessExit(other_process_id, 0); |
| 418 EXPECT_EQ(GlobalActivityTracker::kTypeIdProcessDataRecordFree, |
| 419 global->allocator()->GetType(proc_data_ref)); |
| 420 EXPECT_EQ(GlobalActivityTracker::kTypeIdActivityTrackerFree, |
| 421 global->allocator()->GetType(tracker_ref)); |
| 422 EXPECT_EQ(GlobalActivityTracker::kTypeIdUserDataRecordFree, |
| 423 global->allocator()->GetType(user_data_ref)); |
| 424 |
| 425 // Restore memory contents and types so things don't crash when doing real |
| 426 // process clean-up. |
| 427 memcpy(const_cast<void*>(thread->GetBaseAddress()), tracker_copy.get(), |
| 428 tracker_size); |
| 429 global->allocator()->ChangeType( |
| 430 proc_data_ref, GlobalActivityTracker::kTypeIdProcessDataRecord, |
| 431 GlobalActivityTracker::kTypeIdUserDataRecordFree, false); |
| 432 global->allocator()->ChangeType( |
| 433 tracker_ref, GlobalActivityTracker::kTypeIdActivityTracker, |
| 434 GlobalActivityTracker::kTypeIdActivityTrackerFree, false); |
| 435 global->allocator()->ChangeType( |
| 436 user_data_ref, GlobalActivityTracker::kTypeIdUserDataRecord, |
| 437 GlobalActivityTracker::kTypeIdUserDataRecordFree, false); |
| 438 } |
| 439 |
335 } // namespace debug | 440 } // namespace debug |
336 } // namespace base | 441 } // namespace base |
OLD | NEW |