summaryrefslogtreecommitdiff
path: root/base/debug/activity_analyzer_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'base/debug/activity_analyzer_unittest.cc')
-rw-r--r--base/debug/activity_analyzer_unittest.cc546
1 files changed, 546 insertions, 0 deletions
diff --git a/base/debug/activity_analyzer_unittest.cc b/base/debug/activity_analyzer_unittest.cc
new file mode 100644
index 0000000000..e08b43aff3
--- /dev/null
+++ b/base/debug/activity_analyzer_unittest.cc
@@ -0,0 +1,546 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/activity_analyzer.h"
+
+#include <atomic>
+#include <memory>
+
+#include "base/auto_reset.h"
+#include "base/bind.h"
+#include "base/debug/activity_tracker.h"
+#include "base/files/file.h"
+#include "base/files/file_util.h"
+#include "base/files/memory_mapped_file.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/memory/ptr_util.h"
+#include "base/pending_task.h"
+#include "base/process/process.h"
+#include "base/stl_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"
+
+namespace base {
+namespace debug {
+
+namespace {
+
+class TestActivityTracker : public ThreadActivityTracker {
+ public:
+ TestActivityTracker(std::unique_ptr<char[]> memory, size_t mem_size)
+ : ThreadActivityTracker(memset(memory.get(), 0, mem_size), mem_size),
+ mem_segment_(std::move(memory)) {}
+
+ ~TestActivityTracker() override = default;
+
+ private:
+ std::unique_ptr<char[]> mem_segment_;
+};
+
+} // namespace
+
+
+class ActivityAnalyzerTest : public testing::Test {
+ public:
+ const int kMemorySize = 1 << 20; // 1MiB
+ const int kStackSize = 1 << 10; // 1KiB
+
+ ActivityAnalyzerTest() = default;
+
+ ~ActivityAnalyzerTest() override {
+ GlobalActivityTracker* global_tracker = GlobalActivityTracker::Get();
+ if (global_tracker) {
+ global_tracker->ReleaseTrackerForCurrentThreadForTesting();
+ delete global_tracker;
+ }
+ }
+
+ std::unique_ptr<ThreadActivityTracker> CreateActivityTracker() {
+ std::unique_ptr<char[]> memory(new char[kStackSize]);
+ return std::make_unique<TestActivityTracker>(std::move(memory), kStackSize);
+ }
+
+ template <typename Function>
+ void AsOtherProcess(int64_t pid, Function function) {
+ std::unique_ptr<GlobalActivityTracker> old_global =
+ GlobalActivityTracker::ReleaseForTesting();
+ ASSERT_TRUE(old_global);
+
+ PersistentMemoryAllocator* old_allocator = old_global->allocator();
+ std::unique_ptr<PersistentMemoryAllocator> new_allocator(
+ std::make_unique<PersistentMemoryAllocator>(
+ const_cast<void*>(old_allocator->data()), old_allocator->size(), 0,
+ 0, "", false));
+ GlobalActivityTracker::CreateWithAllocator(std::move(new_allocator), 3,
+ pid);
+
+ function();
+
+ GlobalActivityTracker::ReleaseForTesting();
+ GlobalActivityTracker::SetForTesting(std::move(old_global));
+ }
+
+ static void DoNothing() {}
+};
+
+TEST_F(ActivityAnalyzerTest, ThreadAnalyzerConstruction) {
+ std::unique_ptr<ThreadActivityTracker> tracker = CreateActivityTracker();
+ {
+ ThreadActivityAnalyzer analyzer(*tracker);
+ EXPECT_TRUE(analyzer.IsValid());
+ EXPECT_EQ(PlatformThread::GetName(), analyzer.GetThreadName());
+ }
+
+ // TODO(bcwhite): More tests once Analyzer does more.
+}
+
+
+// GlobalActivityAnalyzer tests below.
+
+namespace {
+
+class SimpleActivityThread : public SimpleThread {
+ public:
+ SimpleActivityThread(const std::string& name,
+ const void* source,
+ Activity::Type activity,
+ const ActivityData& data)
+ : SimpleThread(name, Options()),
+ source_(source),
+ activity_(activity),
+ data_(data),
+ ready_(false),
+ exit_(false),
+ exit_condition_(&lock_) {}
+
+ ~SimpleActivityThread() override = default;
+
+ void Run() override {
+ ThreadActivityTracker::ActivityId id =
+ GlobalActivityTracker::Get()
+ ->GetOrCreateTrackerForCurrentThread()
+ ->PushActivity(source_, activity_, data_);
+
+ {
+ AutoLock auto_lock(lock_);
+ ready_.store(true, std::memory_order_release);
+ while (!exit_.load(std::memory_order_relaxed))
+ exit_condition_.Wait();
+ }
+
+ GlobalActivityTracker::Get()->GetTrackerForCurrentThread()->PopActivity(id);
+ }
+
+ void Exit() {
+ AutoLock auto_lock(lock_);
+ exit_.store(true, std::memory_order_relaxed);
+ exit_condition_.Signal();
+ }
+
+ void WaitReady() {
+ SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(ready_.load(std::memory_order_acquire));
+ }
+
+ private:
+ const void* source_;
+ Activity::Type activity_;
+ ActivityData data_;
+
+ std::atomic<bool> ready_;
+ std::atomic<bool> exit_;
+ Lock lock_;
+ ConditionVariable exit_condition_;
+
+ DISALLOW_COPY_AND_ASSIGN(SimpleActivityThread);
+};
+
+} // namespace
+
+TEST_F(ActivityAnalyzerTest, GlobalAnalyzerConstruction) {
+ GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0);
+ GlobalActivityTracker::Get()->process_data().SetString("foo", "bar");
+
+ PersistentMemoryAllocator* allocator =
+ GlobalActivityTracker::Get()->allocator();
+ GlobalActivityAnalyzer analyzer(std::make_unique<PersistentMemoryAllocator>(
+ const_cast<void*>(allocator->data()), allocator->size(), 0, 0, "", true));
+
+ // The only thread at this point is the test thread of this process.
+ const int64_t pid = analyzer.GetFirstProcess();
+ ASSERT_NE(0, pid);
+ ThreadActivityAnalyzer* ta1 = analyzer.GetFirstAnalyzer(pid);
+ ASSERT_TRUE(ta1);
+ EXPECT_FALSE(analyzer.GetNextAnalyzer());
+ ThreadActivityAnalyzer::ThreadKey tk1 = ta1->GetThreadKey();
+ EXPECT_EQ(ta1, analyzer.GetAnalyzerForThread(tk1));
+ EXPECT_EQ(0, analyzer.GetNextProcess());
+
+ // Create a second thread that will do something.
+ SimpleActivityThread t2("t2", nullptr, Activity::ACT_TASK,
+ ActivityData::ForTask(11));
+ t2.Start();
+ t2.WaitReady();
+
+ // Now there should be two. Calling GetFirstProcess invalidates any
+ // previously returned analyzer pointers.
+ ASSERT_EQ(pid, analyzer.GetFirstProcess());
+ EXPECT_TRUE(analyzer.GetFirstAnalyzer(pid));
+ EXPECT_TRUE(analyzer.GetNextAnalyzer());
+ EXPECT_FALSE(analyzer.GetNextAnalyzer());
+ EXPECT_EQ(0, analyzer.GetNextProcess());
+
+ // Let thread exit.
+ t2.Exit();
+ t2.Join();
+
+ // Now there should be only one again.
+ ASSERT_EQ(pid, analyzer.GetFirstProcess());
+ ThreadActivityAnalyzer* ta2 = analyzer.GetFirstAnalyzer(pid);
+ ASSERT_TRUE(ta2);
+ EXPECT_FALSE(analyzer.GetNextAnalyzer());
+ ThreadActivityAnalyzer::ThreadKey tk2 = ta2->GetThreadKey();
+ EXPECT_EQ(ta2, analyzer.GetAnalyzerForThread(tk2));
+ EXPECT_EQ(tk1, tk2);
+ EXPECT_EQ(0, analyzer.GetNextProcess());
+
+ // Verify that there is process data.
+ const ActivityUserData::Snapshot& data_snapshot =
+ analyzer.GetProcessDataSnapshot(pid);
+ ASSERT_LE(1U, data_snapshot.size());
+ EXPECT_EQ("bar", data_snapshot.at("foo").GetString());
+}
+
+TEST_F(ActivityAnalyzerTest, GlobalAnalyzerFromSharedMemory) {
+ SharedMemoryHandle handle1;
+ SharedMemoryHandle handle2;
+
+ {
+ std::unique_ptr<SharedMemory> shmem(new SharedMemory());
+ ASSERT_TRUE(shmem->CreateAndMapAnonymous(kMemorySize));
+ handle1 = shmem->handle().Duplicate();
+ ASSERT_TRUE(handle1.IsValid());
+ handle2 = shmem->handle().Duplicate();
+ ASSERT_TRUE(handle2.IsValid());
+ }
+
+ GlobalActivityTracker::CreateWithSharedMemoryHandle(handle1, kMemorySize, 0,
+ "", 3);
+ GlobalActivityTracker::Get()->process_data().SetString("foo", "bar");
+
+ std::unique_ptr<GlobalActivityAnalyzer> analyzer =
+ GlobalActivityAnalyzer::CreateWithSharedMemoryHandle(handle2,
+ kMemorySize);
+
+ const int64_t pid = analyzer->GetFirstProcess();
+ ASSERT_NE(0, pid);
+ const ActivityUserData::Snapshot& data_snapshot =
+ analyzer->GetProcessDataSnapshot(pid);
+ ASSERT_LE(1U, data_snapshot.size());
+ EXPECT_EQ("bar", data_snapshot.at("foo").GetString());
+}
+
+TEST_F(ActivityAnalyzerTest, UserDataSnapshotTest) {
+ GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0);
+ ThreadActivityAnalyzer::Snapshot tracker_snapshot;
+
+ const char string1a[] = "string1a";
+ const char string1b[] = "string1b";
+ const char string2a[] = "string2a";
+ const char string2b[] = "string2b";
+
+ PersistentMemoryAllocator* allocator =
+ GlobalActivityTracker::Get()->allocator();
+ GlobalActivityAnalyzer global_analyzer(
+ std::make_unique<PersistentMemoryAllocator>(
+ const_cast<void*>(allocator->data()), allocator->size(), 0, 0, "",
+ true));
+
+ ThreadActivityTracker* tracker =
+ GlobalActivityTracker::Get()->GetOrCreateTrackerForCurrentThread();
+
+ {
+ ScopedActivity activity1(1, 11, 111);
+ ActivityUserData& user_data1 = activity1.user_data();
+ user_data1.Set("raw1", "foo1", 4);
+ user_data1.SetString("string1", "bar1");
+ user_data1.SetChar("char1", '1');
+ user_data1.SetInt("int1", -1111);
+ user_data1.SetUint("uint1", 1111);
+ user_data1.SetBool("bool1", true);
+ user_data1.SetReference("ref1", string1a, sizeof(string1a));
+ user_data1.SetStringReference("sref1", string1b);
+
+ {
+ ScopedActivity activity2(2, 22, 222);
+ ActivityUserData& user_data2 = activity2.user_data();
+ user_data2.Set("raw2", "foo2", 4);
+ user_data2.SetString("string2", "bar2");
+ user_data2.SetChar("char2", '2');
+ user_data2.SetInt("int2", -2222);
+ user_data2.SetUint("uint2", 2222);
+ user_data2.SetBool("bool2", false);
+ user_data2.SetReference("ref2", string2a, sizeof(string2a));
+ user_data2.SetStringReference("sref2", string2b);
+
+ ASSERT_TRUE(tracker->CreateSnapshot(&tracker_snapshot));
+ ASSERT_EQ(2U, tracker_snapshot.activity_stack.size());
+
+ ThreadActivityAnalyzer analyzer(*tracker);
+ analyzer.AddGlobalInformation(&global_analyzer);
+ const ThreadActivityAnalyzer::Snapshot& analyzer_snapshot =
+ analyzer.activity_snapshot();
+ ASSERT_EQ(2U, analyzer_snapshot.user_data_stack.size());
+ const ActivityUserData::Snapshot& user_data =
+ analyzer_snapshot.user_data_stack.at(1);
+ EXPECT_EQ(8U, user_data.size());
+ ASSERT_TRUE(ContainsKey(user_data, "raw2"));
+ EXPECT_EQ("foo2", user_data.at("raw2").Get().as_string());
+ ASSERT_TRUE(ContainsKey(user_data, "string2"));
+ EXPECT_EQ("bar2", user_data.at("string2").GetString().as_string());
+ ASSERT_TRUE(ContainsKey(user_data, "char2"));
+ EXPECT_EQ('2', user_data.at("char2").GetChar());
+ ASSERT_TRUE(ContainsKey(user_data, "int2"));
+ EXPECT_EQ(-2222, user_data.at("int2").GetInt());
+ ASSERT_TRUE(ContainsKey(user_data, "uint2"));
+ EXPECT_EQ(2222U, user_data.at("uint2").GetUint());
+ ASSERT_TRUE(ContainsKey(user_data, "bool2"));
+ EXPECT_FALSE(user_data.at("bool2").GetBool());
+ ASSERT_TRUE(ContainsKey(user_data, "ref2"));
+ EXPECT_EQ(string2a, user_data.at("ref2").GetReference().data());
+ EXPECT_EQ(sizeof(string2a), user_data.at("ref2").GetReference().size());
+ ASSERT_TRUE(ContainsKey(user_data, "sref2"));
+ EXPECT_EQ(string2b, user_data.at("sref2").GetStringReference().data());
+ EXPECT_EQ(strlen(string2b),
+ user_data.at("sref2").GetStringReference().size());
+ }
+
+ ASSERT_TRUE(tracker->CreateSnapshot(&tracker_snapshot));
+ ASSERT_EQ(1U, tracker_snapshot.activity_stack.size());
+
+ ThreadActivityAnalyzer analyzer(*tracker);
+ analyzer.AddGlobalInformation(&global_analyzer);
+ const ThreadActivityAnalyzer::Snapshot& analyzer_snapshot =
+ analyzer.activity_snapshot();
+ ASSERT_EQ(1U, analyzer_snapshot.user_data_stack.size());
+ const ActivityUserData::Snapshot& user_data =
+ analyzer_snapshot.user_data_stack.at(0);
+ EXPECT_EQ(8U, user_data.size());
+ EXPECT_EQ("foo1", user_data.at("raw1").Get().as_string());
+ EXPECT_EQ("bar1", user_data.at("string1").GetString().as_string());
+ EXPECT_EQ('1', user_data.at("char1").GetChar());
+ EXPECT_EQ(-1111, user_data.at("int1").GetInt());
+ EXPECT_EQ(1111U, user_data.at("uint1").GetUint());
+ EXPECT_TRUE(user_data.at("bool1").GetBool());
+ EXPECT_EQ(string1a, user_data.at("ref1").GetReference().data());
+ EXPECT_EQ(sizeof(string1a), user_data.at("ref1").GetReference().size());
+ EXPECT_EQ(string1b, user_data.at("sref1").GetStringReference().data());
+ EXPECT_EQ(strlen(string1b),
+ user_data.at("sref1").GetStringReference().size());
+ }
+
+ ASSERT_TRUE(tracker->CreateSnapshot(&tracker_snapshot));
+ ASSERT_EQ(0U, tracker_snapshot.activity_stack.size());
+}
+
+TEST_F(ActivityAnalyzerTest, GlobalUserDataTest) {
+ const int64_t pid = GetCurrentProcId();
+ GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0);
+
+ const char string1[] = "foo";
+ const char string2[] = "bar";
+
+ PersistentMemoryAllocator* allocator =
+ GlobalActivityTracker::Get()->allocator();
+ GlobalActivityAnalyzer global_analyzer(
+ std::make_unique<PersistentMemoryAllocator>(
+ const_cast<void*>(allocator->data()), allocator->size(), 0, 0, "",
+ true));
+
+ ActivityUserData& process_data = GlobalActivityTracker::Get()->process_data();
+ ASSERT_NE(0U, process_data.id());
+ process_data.Set("raw", "foo", 3);
+ process_data.SetString("string", "bar");
+ process_data.SetChar("char", '9');
+ process_data.SetInt("int", -9999);
+ process_data.SetUint("uint", 9999);
+ process_data.SetBool("bool", true);
+ process_data.SetReference("ref", string1, sizeof(string1));
+ process_data.SetStringReference("sref", string2);
+
+ int64_t first_pid = global_analyzer.GetFirstProcess();
+ DCHECK_EQ(pid, first_pid);
+ const ActivityUserData::Snapshot& snapshot =
+ global_analyzer.GetProcessDataSnapshot(pid);
+ ASSERT_TRUE(ContainsKey(snapshot, "raw"));
+ EXPECT_EQ("foo", snapshot.at("raw").Get().as_string());
+ ASSERT_TRUE(ContainsKey(snapshot, "string"));
+ EXPECT_EQ("bar", snapshot.at("string").GetString().as_string());
+ ASSERT_TRUE(ContainsKey(snapshot, "char"));
+ EXPECT_EQ('9', snapshot.at("char").GetChar());
+ ASSERT_TRUE(ContainsKey(snapshot, "int"));
+ EXPECT_EQ(-9999, snapshot.at("int").GetInt());
+ ASSERT_TRUE(ContainsKey(snapshot, "uint"));
+ EXPECT_EQ(9999U, snapshot.at("uint").GetUint());
+ ASSERT_TRUE(ContainsKey(snapshot, "bool"));
+ EXPECT_TRUE(snapshot.at("bool").GetBool());
+ ASSERT_TRUE(ContainsKey(snapshot, "ref"));
+ EXPECT_EQ(string1, snapshot.at("ref").GetReference().data());
+ EXPECT_EQ(sizeof(string1), snapshot.at("ref").GetReference().size());
+ ASSERT_TRUE(ContainsKey(snapshot, "sref"));
+ EXPECT_EQ(string2, snapshot.at("sref").GetStringReference().data());
+ EXPECT_EQ(strlen(string2), snapshot.at("sref").GetStringReference().size());
+}
+
+TEST_F(ActivityAnalyzerTest, GlobalModulesTest) {
+ GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0);
+ GlobalActivityTracker* global = GlobalActivityTracker::Get();
+
+ PersistentMemoryAllocator* allocator = global->allocator();
+ GlobalActivityAnalyzer global_analyzer(
+ std::make_unique<PersistentMemoryAllocator>(
+ const_cast<void*>(allocator->data()), allocator->size(), 0, 0, "",
+ true));
+
+ GlobalActivityTracker::ModuleInfo info1;
+ info1.is_loaded = true;
+ info1.address = 0x12345678;
+ info1.load_time = 1111;
+ info1.size = 0xABCDEF;
+ info1.timestamp = 111;
+ info1.age = 11;
+ info1.identifier[0] = 1;
+ info1.file = "anything";
+ info1.debug_file = "elsewhere";
+
+ global->RecordModuleInfo(info1);
+ std::vector<GlobalActivityTracker::ModuleInfo> modules1;
+ modules1 = global_analyzer.GetModules(global_analyzer.GetFirstProcess());
+ ASSERT_EQ(1U, modules1.size());
+ GlobalActivityTracker::ModuleInfo& stored1a = modules1[0];
+ EXPECT_EQ(info1.is_loaded, stored1a.is_loaded);
+ EXPECT_EQ(info1.address, stored1a.address);
+ EXPECT_NE(info1.load_time, stored1a.load_time);
+ EXPECT_EQ(info1.size, stored1a.size);
+ EXPECT_EQ(info1.timestamp, stored1a.timestamp);
+ EXPECT_EQ(info1.age, stored1a.age);
+ EXPECT_EQ(info1.identifier[0], stored1a.identifier[0]);
+ EXPECT_EQ(info1.file, stored1a.file);
+ EXPECT_EQ(info1.debug_file, stored1a.debug_file);
+
+ info1.is_loaded = false;
+ global->RecordModuleInfo(info1);
+ modules1 = global_analyzer.GetModules(global_analyzer.GetFirstProcess());
+ ASSERT_EQ(1U, modules1.size());
+ GlobalActivityTracker::ModuleInfo& stored1b = modules1[0];
+ EXPECT_EQ(info1.is_loaded, stored1b.is_loaded);
+ EXPECT_EQ(info1.address, stored1b.address);
+ EXPECT_NE(info1.load_time, stored1b.load_time);
+ EXPECT_EQ(info1.size, stored1b.size);
+ EXPECT_EQ(info1.timestamp, stored1b.timestamp);
+ EXPECT_EQ(info1.age, stored1b.age);
+ EXPECT_EQ(info1.identifier[0], stored1b.identifier[0]);
+ EXPECT_EQ(info1.file, stored1b.file);
+ EXPECT_EQ(info1.debug_file, stored1b.debug_file);
+
+ GlobalActivityTracker::ModuleInfo info2;
+ info2.is_loaded = true;
+ info2.address = 0x87654321;
+ info2.load_time = 2222;
+ info2.size = 0xFEDCBA;
+ info2.timestamp = 222;
+ info2.age = 22;
+ info2.identifier[0] = 2;
+ info2.file = "nothing";
+ info2.debug_file = "farewell";
+
+ global->RecordModuleInfo(info2);
+ std::vector<GlobalActivityTracker::ModuleInfo> modules2;
+ modules2 = global_analyzer.GetModules(global_analyzer.GetFirstProcess());
+ ASSERT_EQ(2U, modules2.size());
+ GlobalActivityTracker::ModuleInfo& stored2 = modules2[1];
+ EXPECT_EQ(info2.is_loaded, stored2.is_loaded);
+ EXPECT_EQ(info2.address, stored2.address);
+ EXPECT_NE(info2.load_time, stored2.load_time);
+ EXPECT_EQ(info2.size, stored2.size);
+ EXPECT_EQ(info2.timestamp, stored2.timestamp);
+ EXPECT_EQ(info2.age, stored2.age);
+ EXPECT_EQ(info2.identifier[0], stored2.identifier[0]);
+ EXPECT_EQ(info2.file, stored2.file);
+ EXPECT_EQ(info2.debug_file, stored2.debug_file);
+}
+
+TEST_F(ActivityAnalyzerTest, GlobalLogMessages) {
+ GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 0);
+
+ PersistentMemoryAllocator* allocator =
+ GlobalActivityTracker::Get()->allocator();
+ GlobalActivityAnalyzer analyzer(std::make_unique<PersistentMemoryAllocator>(
+ const_cast<void*>(allocator->data()), allocator->size(), 0, 0, "", true));
+
+ GlobalActivityTracker::Get()->RecordLogMessage("hello world");
+ GlobalActivityTracker::Get()->RecordLogMessage("foo bar");
+
+ std::vector<std::string> messages = analyzer.GetLogMessages();
+ ASSERT_EQ(2U, messages.size());
+ EXPECT_EQ("hello world", messages[0]);
+ EXPECT_EQ("foo bar", messages[1]);
+}
+
+TEST_F(ActivityAnalyzerTest, GlobalMultiProcess) {
+ GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3, 1001);
+ GlobalActivityTracker* global = GlobalActivityTracker::Get();
+ PersistentMemoryAllocator* allocator = global->allocator();
+ EXPECT_EQ(1001, global->process_id());
+
+ int64_t process_id;
+ int64_t create_stamp;
+ ActivityUserData::GetOwningProcessId(
+ GlobalActivityTracker::Get()->process_data().GetBaseAddress(),
+ &process_id, &create_stamp);
+ ASSERT_EQ(1001, process_id);
+
+ GlobalActivityTracker::Get()->process_data().SetInt("pid",
+ global->process_id());
+
+ GlobalActivityAnalyzer analyzer(std::make_unique<PersistentMemoryAllocator>(
+ const_cast<void*>(allocator->data()), allocator->size(), 0, 0, "", true));
+
+ AsOtherProcess(2002, [&global]() {
+ ASSERT_NE(global, GlobalActivityTracker::Get());
+ EXPECT_EQ(2002, GlobalActivityTracker::Get()->process_id());
+
+ int64_t process_id;
+ int64_t create_stamp;
+ ActivityUserData::GetOwningProcessId(
+ GlobalActivityTracker::Get()->process_data().GetBaseAddress(),
+ &process_id, &create_stamp);
+ ASSERT_EQ(2002, process_id);
+
+ GlobalActivityTracker::Get()->process_data().SetInt(
+ "pid", GlobalActivityTracker::Get()->process_id());
+ });
+ ASSERT_EQ(global, GlobalActivityTracker::Get());
+ EXPECT_EQ(1001, GlobalActivityTracker::Get()->process_id());
+
+ const int64_t pid1 = analyzer.GetFirstProcess();
+ ASSERT_EQ(1001, pid1);
+ const int64_t pid2 = analyzer.GetNextProcess();
+ ASSERT_EQ(2002, pid2);
+ EXPECT_EQ(0, analyzer.GetNextProcess());
+
+ const ActivityUserData::Snapshot& pdata1 =
+ analyzer.GetProcessDataSnapshot(pid1);
+ const ActivityUserData::Snapshot& pdata2 =
+ analyzer.GetProcessDataSnapshot(pid2);
+ EXPECT_EQ(1001, pdata1.at("pid").GetInt());
+ EXPECT_EQ(2002, pdata2.at("pid").GetInt());
+}
+
+} // namespace debug
+} // namespace base