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

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: fixed thread-id discovery 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; // 1MiB
46 const int kStackSize = 1 << 10; // 1KiB
47
48 using Activity = ThreadActivityTracker::Activity;
49 using ActivityData = ThreadActivityTracker::ActivityData;
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 ThreadActivityTracker::ActivitySnapshot snapshot;
88
89 ASSERT_TRUE(tracker->Snapshot(&snapshot));
90 ASSERT_EQ(0U, snapshot.activity_stack_depth);
91 ASSERT_EQ(0U, snapshot.activity_stack.size());
92
93 char source1;
94 tracker->PushActivity(&source1, ThreadActivityTracker::ACT_TASK,
95 ActivityData::ForTask(11));
96 ASSERT_TRUE(tracker->Snapshot(&snapshot));
97 ASSERT_EQ(1U, snapshot.activity_stack_depth);
98 ASSERT_EQ(1U, snapshot.activity_stack.size());
99 EXPECT_NE(0, snapshot.activity_stack[0].time_internal);
100 EXPECT_EQ(ThreadActivityTracker::ACT_TASK,
101 snapshot.activity_stack[0].activity_type);
102 #if !defined(SYZYASAN)
103 EXPECT_EQ(reinterpret_cast<uintptr_t>(&source1),
104 snapshot.activity_stack[0].call_stack[0]);
105 #endif
106 EXPECT_EQ(11U, snapshot.activity_stack[0].data.task.sequence_id);
107
108 char source2;
109 char lock2;
110 tracker->PushActivity(&source2, ThreadActivityTracker::ACT_LOCK,
111 ActivityData::ForLock(&lock2));
112 ASSERT_TRUE(tracker->Snapshot(&snapshot));
113 ASSERT_EQ(2U, snapshot.activity_stack_depth);
114 ASSERT_EQ(2U, snapshot.activity_stack.size());
115 EXPECT_LE(snapshot.activity_stack[0].time_internal,
116 snapshot.activity_stack[1].time_internal);
117 EXPECT_EQ(ThreadActivityTracker::ACT_LOCK,
118 snapshot.activity_stack[1].activity_type);
119 #if !defined(SYZYASAN)
120 EXPECT_EQ(reinterpret_cast<uintptr_t>(&source2),
121 snapshot.activity_stack[1].call_stack[0]);
122 #endif
123 EXPECT_EQ(reinterpret_cast<uintptr_t>(&lock2),
124 snapshot.activity_stack[1].data.lock.lock_address);
125
126 tracker->PopActivity();
127 ASSERT_TRUE(tracker->Snapshot(&snapshot));
128 ASSERT_EQ(1U, snapshot.activity_stack_depth);
129 ASSERT_EQ(1U, snapshot.activity_stack.size());
130 EXPECT_EQ(ThreadActivityTracker::ACT_TASK,
131 snapshot.activity_stack[0].activity_type);
132 #if !defined(SYZYASAN)
133 EXPECT_EQ(reinterpret_cast<uintptr_t>(&source1),
134 snapshot.activity_stack[0].call_stack[0]);
135 #endif
136 EXPECT_EQ(11U, snapshot.activity_stack[0].data.task.sequence_id);
137
138 tracker->PopActivity();
139 ASSERT_TRUE(tracker->Snapshot(&snapshot));
140 ASSERT_EQ(0U, snapshot.activity_stack_depth);
141 ASSERT_EQ(0U, snapshot.activity_stack.size());
142 }
143
144 TEST_F(ActivityTrackerTest, ScopedTaskTest) {
145 GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3);
146
147 ThreadActivityTracker* tracker =
148 GlobalActivityTracker::Get()->GetOrCreateTrackerForCurrentThread();
149 ThreadActivityTracker::ActivitySnapshot snapshot;
150
151 ASSERT_TRUE(tracker->Snapshot(&snapshot));
152 ASSERT_EQ(0U, snapshot.activity_stack_depth);
153 ASSERT_EQ(0U, snapshot.activity_stack.size());
154
155 {
156 PendingTask task1(FROM_HERE, base::Bind(&DoNothing));
157 ScopedTaskRunActivity activity1(task1);
158
159 ASSERT_TRUE(tracker->Snapshot(&snapshot));
160 ASSERT_EQ(1U, snapshot.activity_stack_depth);
161 ASSERT_EQ(1U, snapshot.activity_stack.size());
162 EXPECT_EQ(ThreadActivityTracker::ACT_TASK,
163 snapshot.activity_stack[0].activity_type);
164
165 {
166 PendingTask task2(FROM_HERE, base::Bind(&DoNothing));
167 ScopedTaskRunActivity activity2(task2);
168
169 ASSERT_TRUE(tracker->Snapshot(&snapshot));
170 ASSERT_EQ(2U, snapshot.activity_stack_depth);
171 ASSERT_EQ(2U, snapshot.activity_stack.size());
172 EXPECT_EQ(ThreadActivityTracker::ACT_TASK,
173 snapshot.activity_stack[1].activity_type);
174 }
175
176 ASSERT_TRUE(tracker->Snapshot(&snapshot));
177 ASSERT_EQ(1U, snapshot.activity_stack_depth);
178 ASSERT_EQ(1U, snapshot.activity_stack.size());
179 EXPECT_EQ(ThreadActivityTracker::ACT_TASK,
180 snapshot.activity_stack[0].activity_type);
181 }
182
183 ASSERT_TRUE(tracker->Snapshot(&snapshot));
184 ASSERT_EQ(0U, snapshot.activity_stack_depth);
185 ASSERT_EQ(0U, snapshot.activity_stack.size());
186 }
187
188 TEST_F(ActivityTrackerTest, CreateWithFileTest) {
189 const char temp_name[] = "CreateWithFileTest";
190 ScopedTempDir temp_dir;
191 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
192 FilePath temp_file = temp_dir.path().AppendASCII(temp_name);
193 const size_t temp_size = 64 << 10; // 64 KiB
194
195 // Create a global tracker on a new file.
196 ASSERT_FALSE(PathExists(temp_file));
197 GlobalActivityTracker::CreateWithFile(temp_file, temp_size, 0, "foo", 3);
198 GlobalActivityTracker* global = GlobalActivityTracker::Get();
199 EXPECT_EQ(std::string("foo"), global->allocator()->Name());
200 global->ReleaseTrackerForCurrentThreadForTesting();
201 delete global;
202
203 // Create a global tracker over an existing file, replacing it. If the
204 // replacement doesn't work, the name will remain as it was first created.
205 ASSERT_TRUE(PathExists(temp_file));
206 GlobalActivityTracker::CreateWithFile(temp_file, temp_size, 0, "bar", 3);
207 global = GlobalActivityTracker::Get();
208 EXPECT_EQ(std::string("bar"), global->allocator()->Name());
209 global->ReleaseTrackerForCurrentThreadForTesting();
210 delete global;
211 }
212
213
214 // GlobalActivityTracker tests below.
215
216 class SimpleActivityThread : public SimpleThread {
217 public:
218 SimpleActivityThread(const std::string& name,
219 const void* source,
220 ThreadActivityTracker::ActivityType activity,
221 const ThreadActivityTracker::ActivityData& data)
222 : SimpleThread(name, Options()),
223 source_(source),
224 activity_(activity),
225 data_(data),
226 exit_condition_(&lock_) {}
227
228 ~SimpleActivityThread() override {}
229
230 void Run() override {
231 GlobalActivityTracker::Get()
232 ->GetOrCreateTrackerForCurrentThread()
233 ->PushActivity(source_, activity_, data_);
234
235 {
236 AutoLock auto_lock(lock_);
237 ready_ = true;
238 while (!exit_)
239 exit_condition_.Wait();
240 }
241
242 GlobalActivityTracker::Get()
243 ->GetOrCreateTrackerForCurrentThread()
244 ->PopActivity();
245 }
246
247 void Exit() {
248 AutoLock auto_lock(lock_);
249 exit_ = true;
250 exit_condition_.Signal();
251 }
252
253 void WaitReady() {
254 SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(ready_);
255 }
256
257 private:
258 const void* source_;
259 ThreadActivityTracker::ActivityType activity_;
260 ThreadActivityTracker::ActivityData data_;
261
262 bool ready_ = false;
263 bool exit_ = false;
264 Lock lock_;
265 ConditionVariable exit_condition_;
266
267 DISALLOW_COPY_AND_ASSIGN(SimpleActivityThread);
268 };
269
270 TEST_F(ActivityTrackerTest, ThreadDeathTest) {
271 GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3);
272 GlobalActivityTracker::Get()->GetOrCreateTrackerForCurrentThread();
273 const size_t starting_active = GetGlobalActiveTrackerCount();
274 const size_t starting_inactive = GetGlobalInactiveTrackerCount();
275
276 SimpleActivityThread t1("t1", nullptr, ThreadActivityTracker::ACT_TASK,
277 ThreadActivityTracker::ActivityData::ForTask(11));
278 t1.Start();
279 t1.WaitReady();
280 EXPECT_EQ(starting_active + 1, GetGlobalActiveTrackerCount());
281 EXPECT_EQ(starting_inactive, GetGlobalInactiveTrackerCount());
282
283 t1.Exit();
284 t1.Join();
285 EXPECT_EQ(starting_active, GetGlobalActiveTrackerCount());
286 EXPECT_EQ(starting_inactive + 1, GetGlobalInactiveTrackerCount());
287
288 // Start another thread and ensure it re-uses the existing memory.
289
290 SimpleActivityThread t2("t2", nullptr, ThreadActivityTracker::ACT_TASK,
291 ThreadActivityTracker::ActivityData::ForTask(22));
292 t2.Start();
293 t2.WaitReady();
294 EXPECT_EQ(starting_active + 1, GetGlobalActiveTrackerCount());
295 EXPECT_EQ(starting_inactive, GetGlobalInactiveTrackerCount());
296
297 t2.Exit();
298 t2.Join();
299 EXPECT_EQ(starting_active, GetGlobalActiveTrackerCount());
300 EXPECT_EQ(starting_inactive + 1, GetGlobalInactiveTrackerCount());
301 }
302
303 } // namespace debug
304 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698