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

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

Powered by Google App Engine
This is Rietveld 408576698