OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // Test of classes in the tracked_objects.h classes. | 5 // Test of classes in the tracked_objects.h classes. |
6 | 6 |
7 #include "base/tracked_objects.h" | 7 #include "base/tracked_objects.h" |
8 | 8 |
9 #include "base/message_loop.h" | 9 #include "base/json/json_writer.h" |
10 #include "base/memory/scoped_ptr.h" | |
10 #include "base/time.h" | 11 #include "base/time.h" |
11 #include "testing/gtest/include/gtest/gtest.h" | 12 #include "testing/gtest/include/gtest/gtest.h" |
12 | 13 |
13 namespace tracked_objects { | 14 namespace tracked_objects { |
14 | 15 |
15 class TrackedObjectsTest : public testing::Test { | 16 class TrackedObjectsTest : public testing::Test { |
16 public: | 17 public: |
17 MessageLoop message_loop_; | 18 ~TrackedObjectsTest() { |
eroman
2011/10/24 22:23:04
nit: indentation
jar (doing other things)
2011/10/27 06:23:35
Done.
| |
19 ThreadData::ShutdownSingleThreadedCleanup(); | |
20 } | |
21 | |
18 }; | 22 }; |
19 | 23 |
20 TEST_F(TrackedObjectsTest, MinimalStartupShutdown) { | 24 TEST_F(TrackedObjectsTest, MinimalStartupShutdown) { |
21 // Minimal test doesn't even create any tasks. | 25 // Minimal test doesn't even create any tasks. |
22 if (!ThreadData::StartTracking(true)) | 26 if (!ThreadData::StartTracking(true)) |
23 return; | 27 return; |
24 | 28 |
25 EXPECT_FALSE(ThreadData::first()); // No activity even on this thread. | 29 EXPECT_FALSE(ThreadData::first()); // No activity even on this thread. |
26 ThreadData* data = ThreadData::Get(); | 30 ThreadData* data = ThreadData::Get(); |
27 EXPECT_TRUE(ThreadData::first()); // Now class was constructed. | 31 EXPECT_TRUE(ThreadData::first()); // Now class was constructed. |
(...skipping 15 matching lines...) Expand all Loading... | |
43 EXPECT_TRUE(ThreadData::first()); // Now class was constructed. | 47 EXPECT_TRUE(ThreadData::first()); // Now class was constructed. |
44 EXPECT_TRUE(data); | 48 EXPECT_TRUE(data); |
45 EXPECT_TRUE(!data->next()); | 49 EXPECT_TRUE(!data->next()); |
46 EXPECT_EQ(data, ThreadData::Get()); | 50 EXPECT_EQ(data, ThreadData::Get()); |
47 birth_map.clear(); | 51 birth_map.clear(); |
48 data->SnapshotBirthMap(&birth_map); | 52 data->SnapshotBirthMap(&birth_map); |
49 EXPECT_EQ(0u, birth_map.size()); | 53 EXPECT_EQ(0u, birth_map.size()); |
50 death_map.clear(); | 54 death_map.clear(); |
51 data->SnapshotDeathMap(&death_map); | 55 data->SnapshotDeathMap(&death_map); |
52 EXPECT_EQ(0u, death_map.size()); | 56 EXPECT_EQ(0u, death_map.size()); |
53 ThreadData::ShutdownSingleThreadedCleanup(); | |
54 } | 57 } |
55 | 58 |
56 TEST_F(TrackedObjectsTest, TinyStartupShutdown) { | 59 TEST_F(TrackedObjectsTest, TinyStartupShutdown) { |
57 if (!ThreadData::StartTracking(true)) | 60 if (!ThreadData::StartTracking(true)) |
58 return; | 61 return; |
59 | 62 |
60 // Instigate tracking on a single tracked object, or our thread. | 63 // Instigate tracking on a single tracked object, on our thread. |
61 const Location& location = FROM_HERE; | 64 const Location& location = FROM_HERE; |
62 ThreadData::TallyABirthIfActive(location); | 65 ThreadData::TallyABirthIfActive(location); |
63 | 66 |
64 const ThreadData* data = ThreadData::first(); | 67 const ThreadData* data = ThreadData::first(); |
65 ASSERT_TRUE(data); | 68 ASSERT_TRUE(data); |
66 EXPECT_TRUE(!data->next()); | 69 EXPECT_TRUE(!data->next()); |
67 EXPECT_EQ(data, ThreadData::Get()); | 70 EXPECT_EQ(data, ThreadData::Get()); |
68 ThreadData::BirthMap birth_map; | 71 ThreadData::BirthMap birth_map; |
69 data->SnapshotBirthMap(&birth_map); | 72 data->SnapshotBirthMap(&birth_map); |
70 EXPECT_EQ(1u, birth_map.size()); // 1 birth location. | 73 EXPECT_EQ(1u, birth_map.size()); // 1 birth location. |
71 EXPECT_EQ(1, birth_map.begin()->second->birth_count()); // 1 birth. | 74 EXPECT_EQ(1, birth_map.begin()->second->birth_count()); // 1 birth. |
72 ThreadData::DeathMap death_map; | 75 ThreadData::DeathMap death_map; |
73 data->SnapshotDeathMap(&death_map); | 76 data->SnapshotDeathMap(&death_map); |
74 EXPECT_EQ(0u, death_map.size()); // No deaths. | 77 EXPECT_EQ(0u, death_map.size()); // No deaths. |
75 | 78 |
76 | 79 |
77 // Now instigate a birth, and a death. | 80 // Now instigate a birth, and a death. |
78 const Births* second_birth = ThreadData::TallyABirthIfActive(location); | 81 const Births* second_birth = ThreadData::TallyABirthIfActive(location); |
79 ThreadData::TallyADeathIfActive( | 82 ThreadData::TallyADeathIfActive( |
80 second_birth, | 83 second_birth, |
81 base::TimeTicks(), /* Bogus post_time. */ | 84 base::TimeTicks(), /* Bogus post_time. */ |
82 base::TimeTicks(), /* Bogus delayed_start_time. */ | 85 base::TimeTicks(), /* Bogus delayed_start_time. */ |
83 base::TimeTicks() /* Bogus start_run_time. */); | 86 base::TimeTicks(), /* Bogus start_run_time. */ |
87 base::TimeTicks() /* Bogus end_run_time */ ); | |
84 | 88 |
85 birth_map.clear(); | 89 birth_map.clear(); |
86 data->SnapshotBirthMap(&birth_map); | 90 data->SnapshotBirthMap(&birth_map); |
87 EXPECT_EQ(1u, birth_map.size()); // 1 birth location. | 91 EXPECT_EQ(1u, birth_map.size()); // 1 birth location. |
88 EXPECT_EQ(2, birth_map.begin()->second->birth_count()); // 2 births. | 92 EXPECT_EQ(2, birth_map.begin()->second->birth_count()); // 2 births. |
89 death_map.clear(); | 93 death_map.clear(); |
90 data->SnapshotDeathMap(&death_map); | 94 data->SnapshotDeathMap(&death_map); |
91 EXPECT_EQ(1u, death_map.size()); // 1 location. | 95 EXPECT_EQ(1u, death_map.size()); // 1 location. |
92 EXPECT_EQ(1, death_map.begin()->second.count()); // 1 death. | 96 EXPECT_EQ(1, death_map.begin()->second.count()); // 1 death. |
93 | 97 |
94 // The births were at the same location as the one known death. | 98 // The births were at the same location as the one known death. |
95 EXPECT_EQ(birth_map.begin()->second, death_map.begin()->first); | 99 EXPECT_EQ(birth_map.begin()->second, death_map.begin()->first); |
96 | 100 } |
97 ThreadData::ShutdownSingleThreadedCleanup(); | 101 |
102 TEST_F(TrackedObjectsTest, DeathDataTest) { | |
103 if (!ThreadData::StartTracking(true)) | |
104 return; | |
105 | |
106 scoped_ptr<DeathData> data(new DeathData()); | |
107 ASSERT_NE(data, reinterpret_cast<DeathData*>(NULL)); | |
108 EXPECT_EQ(data->run_duration(), base::TimeDelta()); | |
109 EXPECT_EQ(data->queue_duration(), base::TimeDelta()); | |
110 EXPECT_EQ(data->AverageMsRunDuration(), 0); | |
111 EXPECT_EQ(data->AverageMsQueueDuration(), 0); | |
112 EXPECT_EQ(data->count(), 0); | |
113 | |
114 int run_ms = 42; | |
115 int queue_ms = 8; | |
116 | |
117 base::TimeDelta run_duration = base::TimeDelta().FromMilliseconds(run_ms); | |
118 base::TimeDelta queue_duration = base::TimeDelta().FromMilliseconds(queue_ms); | |
119 data->RecordDeath(queue_duration, run_duration); | |
120 EXPECT_EQ(data->run_duration(), run_duration); | |
121 EXPECT_EQ(data->queue_duration(), queue_duration); | |
122 EXPECT_EQ(data->AverageMsRunDuration(), run_ms); | |
123 EXPECT_EQ(data->AverageMsQueueDuration(), queue_ms); | |
124 EXPECT_EQ(data->count(), 1); | |
125 | |
126 data->RecordDeath(queue_duration, run_duration); | |
127 EXPECT_EQ(data->run_duration(), run_duration + run_duration); | |
128 EXPECT_EQ(data->queue_duration(), queue_duration + queue_duration); | |
129 EXPECT_EQ(data->AverageMsRunDuration(), run_ms); | |
130 EXPECT_EQ(data->AverageMsQueueDuration(), queue_ms); | |
131 EXPECT_EQ(data->count(), 2); | |
132 | |
133 scoped_ptr<base::DictionaryValue> dictionary(data->ToValue()); | |
134 int integer; | |
135 EXPECT_TRUE(dictionary->GetInteger("run_ms", &integer)); | |
136 EXPECT_EQ(integer, 2 * run_ms); | |
137 EXPECT_TRUE(dictionary->GetInteger("queue_ms", &integer)); | |
138 EXPECT_EQ(integer, 2* queue_ms); | |
139 EXPECT_TRUE(dictionary->GetInteger("count", &integer)); | |
140 EXPECT_EQ(integer, 2); | |
141 | |
142 std::string output; | |
143 data->WriteHTML(&output); | |
144 std::string results = "Lives:2, Run:84ms(42ms/life) Queue:16ms(8ms/life) "; | |
145 EXPECT_EQ(output, results); | |
146 | |
147 scoped_ptr<base::Value> value(data->ToValue()); | |
148 std::string json; | |
149 base::JSONWriter::Write(value.get(), false, &json); | |
150 std::string birth_only_result = "{\"count\":2,\"queue_ms\":16,\"run_ms\":84}"; | |
151 EXPECT_EQ(json, birth_only_result); | |
152 } | |
153 | |
154 TEST_F(TrackedObjectsTest, BirthOnlyToValueWorkerThread) { | |
155 if (!ThreadData::StartTracking(true)) | |
156 return; | |
157 // We don't initialize system with a thread name, so we're viewed as a worker | |
158 // thread. | |
159 int fake_line_number = 173; | |
160 const char* kFile = "FixedFileName"; | |
161 const char* kFunction = "BirthOnlyToValueWorkerThread"; | |
162 Location location(kFunction, kFile, fake_line_number, NULL); | |
163 Births* birth = ThreadData::TallyABirthIfActive(location); | |
164 EXPECT_NE(birth, reinterpret_cast<Births*>(NULL)); | |
165 | |
166 int process_type = 3; | |
167 scoped_ptr<base::Value> value(ThreadData::ToValue(process_type)); | |
168 std::string json; | |
169 base::JSONWriter::Write(value.get(), false, &json); | |
170 std::string birth_only_result = "{" | |
171 "\"list\":[" | |
172 "{" | |
173 "\"birth_thread\":\"WorkerThread-1\"," | |
eroman
2011/10/24 22:23:04
Are thread names guaranteed to be unique? I wander
jar (doing other things)
2011/10/27 06:23:35
It is possible (within a single process) to have t
| |
174 "\"death_data\":{" | |
175 "\"count\":1," | |
176 "\"queue_ms\":0," | |
177 "\"run_ms\":0" | |
178 "}," | |
179 "\"death_thread\":\"Still_Alive\"," | |
180 "\"location\":{" | |
181 "\"file_name\":\"FixedFileName\"," | |
182 "\"function_name\":\"BirthOnlyToValueWorkerThread\"," | |
183 "\"line_number\":173" | |
184 "}" | |
185 "}" | |
186 "]," | |
187 "\"process\":3" | |
188 "}"; | |
189 EXPECT_EQ(json, birth_only_result); | |
190 } | |
191 | |
192 TEST_F(TrackedObjectsTest, BirthOnlyToValueMainThread) { | |
193 if (!ThreadData::StartTracking(true)) | |
194 return; | |
195 | |
196 // Use a well named thread. | |
197 ThreadData::InitializeThreadContext("SomeMainThreadName"); | |
198 int fake_line_number = 173; | |
199 const char* kFile = "FixedFileName"; | |
200 const char* kFunction = "BirthOnlyToValueMainThread"; | |
201 Location location(kFunction, kFile, fake_line_number, NULL); | |
202 // Do not delete birth. We don't own it. | |
203 Births* birth = ThreadData::TallyABirthIfActive(location); | |
204 EXPECT_NE(birth, reinterpret_cast<Births*>(NULL)); | |
205 | |
206 int process_type = 34; | |
207 scoped_ptr<base::Value> value(ThreadData::ToValue(process_type)); | |
208 std::string json; | |
209 base::JSONWriter::Write(value.get(), false, &json); | |
210 std::string birth_only_result = "{" | |
211 "\"list\":[" | |
212 "{" | |
213 "\"birth_thread\":\"SomeMainThreadName\"," | |
214 "\"death_data\":{" | |
215 "\"count\":1," | |
216 "\"queue_ms\":0," | |
217 "\"run_ms\":0" | |
218 "}," | |
219 "\"death_thread\":\"Still_Alive\"," | |
220 "\"location\":{" | |
221 "\"file_name\":\"FixedFileName\"," | |
222 "\"function_name\":\"BirthOnlyToValueMainThread\"," | |
223 "\"line_number\":173" | |
224 "}" | |
225 "}" | |
226 "]," | |
227 "\"process\":34" | |
228 "}"; | |
229 EXPECT_EQ(json, birth_only_result); | |
230 } | |
231 | |
232 TEST_F(TrackedObjectsTest, LifeCycleToValueMainThread) { | |
233 if (!ThreadData::StartTracking(true)) | |
234 return; | |
235 | |
236 // Use a well named thread. | |
237 ThreadData::InitializeThreadContext("SomeMainThreadName"); | |
238 int fake_line_number = 236; | |
239 const char* kFile = "FixedFileName"; | |
240 const char* kFunction = "LifeCycleToValueMainThread"; | |
241 Location location(kFunction, kFile, fake_line_number, NULL); | |
242 // Do not delete birth. We don't own it. | |
243 Births* birth = ThreadData::TallyABirthIfActive(location); | |
244 EXPECT_NE(birth, reinterpret_cast<Births*>(NULL)); | |
245 | |
246 // TimeTicks initializers ar ein microseconds. Durations are calculated in | |
247 // milliseconds, so we need to use 1000x. | |
248 const base::TimeTicks time_posted = base::TimeTicks() + | |
249 base::TimeDelta::FromMilliseconds(1); | |
250 const base::TimeTicks delayed_start_time = base::TimeTicks(); | |
251 const base::TimeTicks start_of_run = base::TimeTicks() + | |
252 base::TimeDelta::FromMilliseconds(5); | |
253 const base::TimeTicks end_of_run = base::TimeTicks() + | |
254 base::TimeDelta::FromMilliseconds(7); | |
255 ThreadData::TallyADeathIfActive(birth, time_posted, delayed_start_time, | |
256 start_of_run, end_of_run); | |
257 | |
258 int process_type = 7; | |
259 scoped_ptr<base::Value> value(ThreadData::ToValue(process_type)); | |
260 std::string json; | |
261 base::JSONWriter::Write(value.get(), false, &json); | |
262 std::string one_line_result = "{" | |
263 "\"list\":[" | |
264 "{" | |
265 "\"birth_thread\":\"SomeMainThreadName\"," | |
266 "\"death_data\":{" | |
267 "\"count\":1," | |
268 "\"queue_ms\":4," | |
269 "\"run_ms\":2" | |
270 "}," | |
271 "\"death_thread\":\"SomeMainThreadName\"," | |
272 "\"location\":{" | |
273 "\"file_name\":\"FixedFileName\"," | |
274 "\"function_name\":\"LifeCycleToValueMainThread\"," | |
275 "\"line_number\":236" | |
276 "}" | |
277 "}" | |
278 "]," | |
279 "\"process\":7" | |
280 "}"; | |
281 EXPECT_EQ(json, one_line_result); | |
282 } | |
283 | |
284 TEST_F(TrackedObjectsTest, TwoLives) { | |
285 if (!ThreadData::StartTracking(true)) | |
286 return; | |
287 | |
288 // Use a well named thread. | |
289 ThreadData::InitializeThreadContext("SomeFileThreadName"); | |
290 int fake_line_number = 222; | |
291 const char* kFile = "AnotherFileName"; | |
292 const char* kFunction = "TwoLives"; | |
293 Location location(kFunction, kFile, fake_line_number, NULL); | |
294 // Do not delete birth. We don't own it. | |
295 Births* birth = ThreadData::TallyABirthIfActive(location); | |
296 EXPECT_NE(birth, reinterpret_cast<Births*>(NULL)); | |
297 | |
298 // TimeTicks initializers ar ein microseconds. Durations are calculated in | |
299 // milliseconds, so we need to use 1000x. | |
300 const base::TimeTicks time_posted = base::TimeTicks() + | |
301 base::TimeDelta::FromMilliseconds(1); | |
302 const base::TimeTicks delayed_start_time = base::TimeTicks(); | |
303 const base::TimeTicks start_of_run = base::TimeTicks() + | |
304 base::TimeDelta::FromMilliseconds(5); | |
305 const base::TimeTicks end_of_run = base::TimeTicks() + | |
306 base::TimeDelta::FromMilliseconds(7); | |
307 ThreadData::TallyADeathIfActive(birth, time_posted, delayed_start_time, | |
308 start_of_run, end_of_run); | |
309 | |
310 birth = ThreadData::TallyABirthIfActive(location); | |
311 ThreadData::TallyADeathIfActive(birth, time_posted, delayed_start_time, | |
312 start_of_run, end_of_run); | |
313 | |
314 int process_type = 7; | |
315 scoped_ptr<base::Value> value(ThreadData::ToValue(process_type)); | |
316 std::string json; | |
317 base::JSONWriter::Write(value.get(), false, &json); | |
318 std::string one_line_result = "{" | |
319 "\"list\":[" | |
320 "{" | |
321 "\"birth_thread\":\"SomeFileThreadName\"," | |
322 "\"death_data\":{" | |
323 "\"count\":2," | |
324 "\"queue_ms\":8," | |
325 "\"run_ms\":4" | |
326 "}," | |
327 "\"death_thread\":\"SomeFileThreadName\"," | |
328 "\"location\":{" | |
329 "\"file_name\":\"AnotherFileName\"," | |
330 "\"function_name\":\"TwoLives\"," | |
331 "\"line_number\":222" | |
332 "}" | |
333 "}" | |
334 "]," | |
335 "\"process\":7" | |
336 "}"; | |
337 EXPECT_EQ(json, one_line_result); | |
338 } | |
339 | |
340 TEST_F(TrackedObjectsTest, DifferentLives) { | |
341 if (!ThreadData::StartTracking(true)) | |
342 return; | |
343 | |
344 // Use a well named thread. | |
345 ThreadData::InitializeThreadContext("SomeFileThreadName"); | |
346 int fake_line_number = 567; | |
347 const char* kFile = "AnotherFileName"; | |
348 const char* kFunction = "DifferentLives"; | |
349 Location location(kFunction, kFile, fake_line_number, NULL); | |
350 // Do not delete birth. We don't own it. | |
351 Births* birth = ThreadData::TallyABirthIfActive(location); | |
352 EXPECT_NE(birth, reinterpret_cast<Births*>(NULL)); | |
353 | |
354 // TimeTicks initializers ar ein microseconds. Durations are calculated in | |
355 // milliseconds, so we need to use 1000x. | |
356 const base::TimeTicks time_posted = base::TimeTicks() + | |
357 base::TimeDelta::FromMilliseconds(1); | |
358 const base::TimeTicks delayed_start_time = base::TimeTicks(); | |
359 const base::TimeTicks start_of_run = base::TimeTicks() + | |
360 base::TimeDelta::FromMilliseconds(5); | |
361 const base::TimeTicks end_of_run = base::TimeTicks() + | |
362 base::TimeDelta::FromMilliseconds(7); | |
363 ThreadData::TallyADeathIfActive(birth, time_posted, delayed_start_time, | |
364 start_of_run, end_of_run); | |
365 | |
366 int second_fake_line_number = 999; | |
367 Location second_location(kFunction, kFile, second_fake_line_number, NULL); | |
368 birth = ThreadData::TallyABirthIfActive(second_location); | |
369 | |
370 int process_type = 2; | |
371 scoped_ptr<base::Value> value(ThreadData::ToValue(process_type)); | |
372 std::string json; | |
373 base::JSONWriter::Write(value.get(), false, &json); | |
374 std::string one_line_result = "{" | |
375 "\"list\":[" | |
376 "{" | |
377 "\"birth_thread\":\"SomeFileThreadName\"," | |
378 "\"death_data\":{" | |
379 "\"count\":1," | |
380 "\"queue_ms\":4," | |
381 "\"run_ms\":2" | |
382 "}," | |
383 "\"death_thread\":\"SomeFileThreadName\"," | |
384 "\"location\":{" | |
385 "\"file_name\":\"AnotherFileName\"," | |
386 "\"function_name\":\"DifferentLives\"," | |
387 "\"line_number\":567" | |
388 "}" | |
389 "}," | |
390 "{" | |
391 "\"birth_thread\":\"SomeFileThreadName\"," | |
392 "\"death_data\":{" | |
393 "\"count\":1," | |
394 "\"queue_ms\":0," | |
395 "\"run_ms\":0" | |
396 "}," | |
397 "\"death_thread\":\"Still_Alive\"," | |
398 "\"location\":{" | |
399 "\"file_name\":\"AnotherFileName\"," | |
400 "\"function_name\":\"DifferentLives\"," | |
401 "\"line_number\":999" | |
402 "}" | |
403 "}" | |
404 "]," | |
405 "\"process\":2" | |
406 "}"; | |
407 EXPECT_EQ(json, one_line_result); | |
98 } | 408 } |
99 | 409 |
100 } // namespace tracked_objects | 410 } // namespace tracked_objects |
OLD | NEW |