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

Side by Side Diff: base/debug/activity_tracker_unittest.cc

Issue 1980743002: Track thread activities in order to diagnose hangs. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@readwrite-mmf
Patch Set: track locks and waitable events Created 4 years, 6 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 unified diff | Download patch
OLDNEW
(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 using StackEntry = ThreadActivityTracker::StackEntry;
49 using StackEntryData = ThreadActivityTracker::StackEntryData;
50
51 ActivityTrackerTest() {}
52
53 ~ActivityTrackerTest() override {
54 GlobalActivityTracker* global_tracker = GlobalActivityTracker::Get();
55 if (global_tracker) {
56 global_tracker->ReleaseTrackerForCurrentThreadForTesting();
57 delete global_tracker;
58 }
59 }
60
61 std::unique_ptr<ThreadActivityTracker> CreateActivityTracker() {
62 std::unique_ptr<char[]> memory(new char[kStackSize]);
63 return WrapUnique(new TestActivityTracker(std::move(memory), kStackSize));
64 }
65
66 size_t GetGlobalActiveTrackerCount() {
67 GlobalActivityTracker* global_tracker = GlobalActivityTracker::Get();
68 if (!global_tracker)
69 return 0;
70 return global_tracker->thread_tracker_count_.load(
71 std::memory_order_relaxed);
72 }
73
74 size_t GetGlobalInactiveTrackerCount() {
75 GlobalActivityTracker* global_tracker = GlobalActivityTracker::Get();
76 if (!global_tracker)
77 return 0;
78 return global_tracker->available_memories_count_.load(
79 std::memory_order_relaxed);
80 }
81
82 static void DoNothing() {}
83 };
84
85 TEST_F(ActivityTrackerTest, PushPopTest) {
86 std::unique_ptr<ThreadActivityTracker> tracker = CreateActivityTracker();
87 std::vector<ThreadActivityTracker::StackEntry> stack;
88 ThreadActivityAnalyzer analyzer(tracker.get());
89
90 ASSERT_EQ(0U, analyzer.SnapshotStack(&stack));
91 ASSERT_EQ(0U, stack.size());
92
93 char source1;
94 tracker->PushActivity(&source1, ThreadActivityTracker::ACT_TASK,
95 StackEntryData::ForTask(11));
96 ASSERT_EQ(1U, analyzer.SnapshotStack(&stack));
97 ASSERT_EQ(1U, stack.size());
98 EXPECT_NE(0, stack[0].time_ticks);
99 EXPECT_EQ(ThreadActivityTracker::ACT_TASK, stack[0].activity_type);
100 EXPECT_EQ(reinterpret_cast<uintptr_t>(&source1), stack[0].source_address);
101 EXPECT_EQ(11U, stack[0].data.task.sequence_id);
102
103 char source2;
104 char lock2;
105 tracker->PushActivity(&source2, ThreadActivityTracker::ACT_LOCK,
106 StackEntryData::ForLock(&lock2));
107 ASSERT_EQ(2U, analyzer.SnapshotStack(&stack));
108 ASSERT_EQ(2U, stack.size());
109 EXPECT_LE(stack[0].time_ticks, stack[1].time_ticks);
110 EXPECT_EQ(ThreadActivityTracker::ACT_LOCK, stack[1].activity_type);
111 EXPECT_EQ(reinterpret_cast<uintptr_t>(&source2), stack[1].source_address);
112 EXPECT_EQ(reinterpret_cast<uintptr_t>(&lock2),
113 stack[1].data.lock.lock_address);
114
115 tracker->PopActivity(&source2);
116 ASSERT_EQ(1U, analyzer.SnapshotStack(&stack));
117 ASSERT_EQ(1U, stack.size());
118 EXPECT_EQ(ThreadActivityTracker::ACT_TASK, stack[0].activity_type);
119 EXPECT_EQ(reinterpret_cast<uintptr_t>(&source1), stack[0].source_address);
120 EXPECT_EQ(11U, stack[0].data.task.sequence_id);
121
122 tracker->PopActivity(&source1);
123 ASSERT_EQ(0U, analyzer.SnapshotStack(&stack));
124 ASSERT_EQ(0U, stack.size());
125 }
126
127 TEST_F(ActivityTrackerTest, ScopedTaskTest) {
128 GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3);
129
130 ThreadActivityTracker* tracker =
131 GlobalActivityTracker::Get()->GetOrCreateTrackerForCurrentThread();
132 std::vector<ThreadActivityTracker::StackEntry> stack;
133 ThreadActivityAnalyzer analyzer(tracker);
134
135 ASSERT_EQ(0U, analyzer.SnapshotStack(&stack));
136 ASSERT_EQ(0U, stack.size());
137
138 {
139 PendingTask task1(FROM_HERE, base::Bind(&DoNothing));
140 ScopedTaskActivity activity1(task1);
141
142 ASSERT_EQ(1U, analyzer.SnapshotStack(&stack));
143 ASSERT_EQ(1U, stack.size());
144 EXPECT_EQ(ThreadActivityTracker::ACT_TASK, stack[0].activity_type);
145
146 {
147 PendingTask task2(FROM_HERE, base::Bind(&DoNothing));
148 ScopedTaskActivity activity2(task2);
149
150 ASSERT_EQ(2U, analyzer.SnapshotStack(&stack));
151 ASSERT_EQ(2U, stack.size());
152 EXPECT_EQ(ThreadActivityTracker::ACT_TASK, stack[1].activity_type);
153 }
154
155 ASSERT_EQ(1U, analyzer.SnapshotStack(&stack));
156 ASSERT_EQ(1U, stack.size());
157 EXPECT_EQ(ThreadActivityTracker::ACT_TASK, stack[0].activity_type);
158 }
159
160 ASSERT_EQ(0U, analyzer.SnapshotStack(&stack));
161 ASSERT_EQ(0U, stack.size());
162 }
163
164 class SimpleActivityThread : public SimpleThread {
165 public:
166 SimpleActivityThread(const std::string& name,
167 const void* source,
168 ThreadActivityTracker::ActivityType activity,
169 const ThreadActivityTracker::StackEntryData& data)
170 : SimpleThread(name, Options()),
171 source_(source),
172 activity_(activity),
173 data_(data),
174 exit_condition_(&lock_) {}
175
176 ~SimpleActivityThread() override {}
177
178 void Run() override {
179 GlobalActivityTracker::Get()
180 ->GetOrCreateTrackerForCurrentThread()
181 ->PushActivity(source_, activity_, data_);
182
183 {
184 AutoLock auto_lock(lock_);
185 ready_ = true;
186 while (!exit_)
187 exit_condition_.Wait();
188 }
189
190 GlobalActivityTracker::Get()
191 ->GetOrCreateTrackerForCurrentThread()
192 ->PopActivity(source_);
193 }
194
195 void Exit() {
196 AutoLock auto_lock(lock_);
197 exit_ = true;
198 exit_condition_.Signal();
199 }
200
201 void WaitReady() {
202 SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(ready_);
203 }
204
205 private:
206 const void* source_;
207 ThreadActivityTracker::ActivityType activity_;
208 ThreadActivityTracker::StackEntryData data_;
209
210 bool ready_ = false;
211 bool exit_ = false;
212 Lock lock_;
213 ConditionVariable exit_condition_;
214
215 DISALLOW_COPY_AND_ASSIGN(SimpleActivityThread);
216 };
217
218 TEST_F(ActivityTrackerTest, ThreadDeathTest) {
219 GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3);
220 GlobalActivityTracker::Get()->GetOrCreateTrackerForCurrentThread();
221 const size_t starting_active = GetGlobalActiveTrackerCount();
222 const size_t starting_inactive = GetGlobalInactiveTrackerCount();
223
224 SimpleActivityThread t1("t1", nullptr, ThreadActivityTracker::ACT_TASK,
225 StackEntryData::ForTask(11));
226 t1.Start();
227 t1.WaitReady();
228 EXPECT_EQ(starting_active + 1, GetGlobalActiveTrackerCount());
229 EXPECT_EQ(starting_inactive, GetGlobalInactiveTrackerCount());
230
231 t1.Exit();
232 t1.Join();
233 EXPECT_EQ(starting_active, GetGlobalActiveTrackerCount());
234 EXPECT_EQ(starting_inactive + 1, GetGlobalInactiveTrackerCount());
235
236 // Start another thread and ensure it re-uses the existing memory.
237
238 SimpleActivityThread t2("t2", nullptr, ThreadActivityTracker::ACT_TASK,
239 StackEntryData::ForTask(22));
240 t2.Start();
241 t2.WaitReady();
242 EXPECT_EQ(starting_active + 1, GetGlobalActiveTrackerCount());
243 EXPECT_EQ(starting_inactive, GetGlobalInactiveTrackerCount());
244
245 t2.Exit();
246 t2.Join();
247 EXPECT_EQ(starting_active, GetGlobalActiveTrackerCount());
248 EXPECT_EQ(starting_inactive + 1, GetGlobalInactiveTrackerCount());
249 }
250
251 } // namespace debug
252 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698