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

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: addressed review comments Created 4 years, 7 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 ActivityTrackerTest() {}
49
50 ~ActivityTrackerTest() override {
51 GlobalActivityTracker* global_tracker = GlobalActivityTracker::Get();
52 if (global_tracker) {
53 global_tracker->ReleaseTrackerForCurrentThreadForTesting();
54 delete global_tracker;
55 }
56 }
57
58 std::unique_ptr<ThreadActivityTracker> CreateActivityTracker() {
59 std::unique_ptr<char[]> memory(new char[kStackSize]);
60 return WrapUnique(new TestActivityTracker(std::move(memory), kStackSize));
61 }
62
63 size_t GetGlobalActiveTrackerCount() {
64 GlobalActivityTracker* global_tracker = GlobalActivityTracker::Get();
65 if (!global_tracker)
66 return 0;
67 return global_tracker->thread_trackers_.size();
68 }
69
70 size_t GetGlobalInactiveTrackerCount() {
71 GlobalActivityTracker* global_tracker = GlobalActivityTracker::Get();
72 if (!global_tracker)
73 return 0;
74 return global_tracker->available_memories_.size();
75 }
76
77 static void DoNothing() {}
78 };
79
80 TEST_F(ActivityTrackerTest, PushPopTest) {
81 std::unique_ptr<ThreadActivityTracker> tracker = CreateActivityTracker();
82 std::unique_ptr<ThreadActivityAnalyzer> analyzer = tracker->CreateAnalyzer();
83 std::vector<ThreadActivityTracker::StackEntry> stack;
84
85 ASSERT_EQ(0U, analyzer->SnapshotStack(&stack));
86 ASSERT_EQ(0U, stack.size());
87
88 char source1;
89 tracker->PushActivity(&source1, ThreadActivityTracker::ACT_TASK, 2, 3);
90 ASSERT_EQ(1U, analyzer->SnapshotStack(&stack));
91 ASSERT_EQ(1U, stack.size());
92 EXPECT_NE(0, stack[0].time_ticks);
93 EXPECT_EQ(ThreadActivityTracker::ACT_TASK, stack[0].activity_type);
94 EXPECT_EQ(reinterpret_cast<intptr_t>(&source1), stack[0].source_address);
95 EXPECT_EQ(2, stack[0].method_address);
96 EXPECT_EQ(3U, stack[0].sequence_id);
97
98 char source2;
99 tracker->PushActivity(&source2, ThreadActivityTracker::ACT_LOCK, 3, 4);
100 ASSERT_EQ(2U, analyzer->SnapshotStack(&stack));
101 ASSERT_EQ(2U, stack.size());
102 EXPECT_LE(stack[0].time_ticks, stack[1].time_ticks);
103 EXPECT_EQ(ThreadActivityTracker::ACT_LOCK, stack[1].activity_type);
104 EXPECT_EQ(reinterpret_cast<intptr_t>(&source2), stack[1].source_address);
105 EXPECT_EQ(3, stack[1].method_address);
106 EXPECT_EQ(4U, stack[1].sequence_id);
107
108 tracker->PopActivity(&source2);
109 ASSERT_EQ(1U, analyzer->SnapshotStack(&stack));
110 ASSERT_EQ(1U, stack.size());
111 EXPECT_EQ(ThreadActivityTracker::ACT_TASK, stack[0].activity_type);
112 EXPECT_EQ(reinterpret_cast<intptr_t>(&source1), stack[0].source_address);
113 EXPECT_EQ(2, stack[0].method_address);
114 EXPECT_EQ(3U, stack[0].sequence_id);
115
116 tracker->PopActivity(&source1);
117 ASSERT_EQ(0U, analyzer->SnapshotStack(&stack));
118 ASSERT_EQ(0U, stack.size());
119 }
120
121 TEST_F(ActivityTrackerTest, ScopedTaskTest) {
122 GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3);
123
124 ThreadActivityTracker* tracker =
125 GlobalActivityTracker::Get()->GetOrCreateTrackerForCurrentThread();
126 std::unique_ptr<ThreadActivityAnalyzer> analyzer = tracker->CreateAnalyzer();
127 std::vector<ThreadActivityTracker::StackEntry> stack;
128
129 ASSERT_EQ(0U, analyzer->SnapshotStack(&stack));
130 ASSERT_EQ(0U, stack.size());
131
132 {
133 PendingTask task1(FROM_HERE, base::Bind(&DoNothing));
134 ScopedTaskActivity activity1(task1);
135
136 ASSERT_EQ(1U, analyzer->SnapshotStack(&stack));
137 ASSERT_EQ(1U, stack.size());
138 EXPECT_EQ(ThreadActivityTracker::ACT_TASK, stack[0].activity_type);
139
140 {
141 PendingTask task2(FROM_HERE, base::Bind(&DoNothing));
142 ScopedTaskActivity activity2(task2);
143
144 ASSERT_EQ(2U, analyzer->SnapshotStack(&stack));
145 ASSERT_EQ(2U, stack.size());
146 EXPECT_EQ(ThreadActivityTracker::ACT_TASK, stack[1].activity_type);
147 }
148
149 ASSERT_EQ(1U, analyzer->SnapshotStack(&stack));
150 ASSERT_EQ(1U, stack.size());
151 EXPECT_EQ(ThreadActivityTracker::ACT_TASK, stack[0].activity_type);
152 }
153
154 ASSERT_EQ(0U, analyzer->SnapshotStack(&stack));
155 ASSERT_EQ(0U, stack.size());
156 }
157
158 class SimpleActivityThread : public SimpleThread {
159 public:
160 SimpleActivityThread(const std::string& name,
161 const void* source,
162 ThreadActivityTracker::ActivityType activity,
163 intptr_t method,
164 uint64_t sequence)
165 : SimpleThread(name, Options()),
166 source_(source),
167 activity_(activity),
168 method_(method),
169 sequence_(sequence),
170 exit_condition_(&lock_) {}
171
172 ~SimpleActivityThread() {}
173
174 void Run() override {
175 GlobalActivityTracker::Get()
176 ->GetOrCreateTrackerForCurrentThread()
177 ->PushActivity(source_, activity_, method_, sequence_);
178
179 {
180 AutoLock auto_lock(lock_);
181 ready_ = true;
182 while (!exit_)
183 exit_condition_.Wait();
184 }
185
186 GlobalActivityTracker::Get()
187 ->GetOrCreateTrackerForCurrentThread()
188 ->PopActivity(source_);
189 }
190
191 void Exit() {
192 AutoLock auto_lock(lock_);
193 exit_ = true;
194 exit_condition_.Signal();
195 }
196
197 void WaitReady() {
198 SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(ready_);
199 }
200
201 private:
202 const void* source_;
203 ThreadActivityTracker::ActivityType activity_;
204 intptr_t method_;
205 uint64_t sequence_;
206
207 bool ready_ = false;
208 bool exit_ = false;
209 Lock lock_;
210 ConditionVariable exit_condition_;
211
212 DISALLOW_COPY_AND_ASSIGN(SimpleActivityThread);
213 };
214
215 TEST_F(ActivityTrackerTest, ThreadDeathTest) {
216 GlobalActivityTracker::CreateWithLocalMemory(kMemorySize, 0, "", 3);
217 GlobalActivityTracker::Get()->GetOrCreateTrackerForCurrentThread();
218 const size_t starting_active = GetGlobalActiveTrackerCount();
219 const size_t starting_inactive = GetGlobalInactiveTrackerCount();
220
221 SimpleActivityThread t1("t1", nullptr, ThreadActivityTracker::ACT_TASK, 1, 2);
222 t1.Start();
223 t1.WaitReady();
224 EXPECT_EQ(starting_active + 1, GetGlobalActiveTrackerCount());
225 EXPECT_EQ(starting_inactive, GetGlobalInactiveTrackerCount());
226
227 t1.Exit();
228 t1.Join();
229 EXPECT_EQ(starting_active, GetGlobalActiveTrackerCount());
230 EXPECT_EQ(starting_inactive + 1, GetGlobalInactiveTrackerCount());
231 }
232
233 } // namespace debug
234 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698