blob: a4b846ec7a01c3ec9cf047fe702ea0378901954d [file] [log] [blame]
scheib@chromium.org603f46e2011-05-10 11:23:58 +09001// 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
3// found in the LICENSE file.
4
5#include "base/debug/trace_event.h"
6
7#include "base/bind.h"
8#include "base/command_line.h"
9#include "base/json/json_reader.h"
10#include "base/json/json_writer.h"
11#include "base/memory/scoped_ptr.h"
12#include "base/stringprintf.h"
13#include "base/synchronization/waitable_event.h"
14#include "base/threading/thread.h"
15#include "base/values.h"
16#include "testing/gmock/include/gmock/gmock.h"
17#include "testing/gtest/include/gtest/gtest.h"
18
19namespace base {
20namespace debug {
21
22namespace {
23
jbates@chromium.orgb3cab862011-05-14 08:30:35 +090024struct JsonKeyValue {
25 const char* key;
26 const char* value;
27};
28
scheib@chromium.org603f46e2011-05-10 11:23:58 +090029class TraceEventTestFixture : public testing::Test {
30 public:
31 void ManualTestSetUp();
32 void OnTraceDataCollected(TraceLog::RefCountedString* json_events_str);
jbates@chromium.orgb3cab862011-05-14 08:30:35 +090033 bool FindMatchingTraceEntry(const JsonKeyValue* key_values);
34 bool FindNamePhase(const char* name, const char* phase);
scheib@chromium.org603f46e2011-05-10 11:23:58 +090035
36 std::string trace_string_;
37 ListValue trace_parsed_;
38
39 private:
40 // We want our singleton torn down after each test.
41 ShadowingAtExitManager at_exit_manager_;
42};
43
44void TraceEventTestFixture::ManualTestSetUp() {
45 TraceLog::Resurrect();
46 TraceLog* tracelog = TraceLog::GetInstance();
47 ASSERT_TRUE(tracelog);
48 ASSERT_FALSE(tracelog->IsEnabled());
49 tracelog->SetOutputCallback(
50 base::Bind(&TraceEventTestFixture::OnTraceDataCollected,
51 base::Unretained(this)));
52}
53
54void TraceEventTestFixture::OnTraceDataCollected(
55 TraceLog::RefCountedString* json_events_str) {
56 trace_string_ += json_events_str->data;
57
58 scoped_ptr<Value> root;
59 root.reset(base::JSONReader::Read(json_events_str->data, false));
60
61 ListValue* root_list = NULL;
62 ASSERT_TRUE(root.get());
63 ASSERT_TRUE(root->GetAsList(&root_list));
64
65 // Move items into our aggregate collection
66 while (root_list->GetSize()) {
67 Value* item = NULL;
68 root_list->Remove(0, &item);
69 trace_parsed_.Append(item);
70 }
71}
72
jbates@chromium.orgb3cab862011-05-14 08:30:35 +090073static bool IsKeyValueInDict(const JsonKeyValue* key_value,
74 DictionaryValue* dict) {
75 Value* value = NULL;
76 std::string value_str;
77 if (dict->Get(key_value->key, &value) &&
78 value->GetAsString(&value_str) &&
79 value_str == key_value->value)
80 return true;
81
82 // Recurse to test arguments
83 DictionaryValue* args_dict = NULL;
84 dict->GetDictionary("args", &args_dict);
85 if (args_dict)
86 return IsKeyValueInDict(key_value, args_dict);
87
88 return false;
89}
90
91static bool IsAllKeyValueInDict(const JsonKeyValue* key_values,
92 DictionaryValue* dict) {
93 // Scan all key_values, they must all be present and equal.
94 while (key_values && key_values->key) {
95 if (!IsKeyValueInDict(key_values, dict))
96 return false;
97 ++key_values;
98 }
99 return true;
100}
101
102bool TraceEventTestFixture::FindMatchingTraceEntry(
103 const JsonKeyValue* key_values) {
104 // Scan all items
105 size_t trace_parsed_count = trace_parsed_.GetSize();
106 for (size_t i = 0; i < trace_parsed_count; i++) {
107 Value* value = NULL;
108 trace_parsed_.Get(i, &value);
109 if (!value || value->GetType() != Value::TYPE_DICTIONARY)
110 continue;
111 DictionaryValue* dict = static_cast<DictionaryValue*>(value);
112
113 if (IsAllKeyValueInDict(key_values, dict))
114 return true;
115 }
116 return false;
117}
118
119bool TraceEventTestFixture::FindNamePhase(const char* name, const char* phase) {
120 JsonKeyValue key_values[] = {
121 {"name", name},
122 {"ph", phase},
123 {0, 0}
124 };
125 return FindMatchingTraceEntry(key_values);
126}
127
scheib@chromium.org603f46e2011-05-10 11:23:58 +0900128bool IsStringInDict(const char* string_to_match, DictionaryValue* dict) {
129 for (DictionaryValue::key_iterator ikey = dict->begin_keys();
130 ikey != dict->end_keys(); ++ikey) {
131 Value* child = NULL;
132 if (!dict->GetWithoutPathExpansion(*ikey, &child))
133 continue;
134
135 if ((*ikey).find(string_to_match) != std::string::npos)
136 return true;
137
138 std::string value_str;
139 child->GetAsString(&value_str);
140 if (value_str.find(string_to_match) != std::string::npos)
141 return true;
142 }
143
144 // Recurse to test arguments
145 DictionaryValue* args_dict = NULL;
146 dict->GetDictionary("args", &args_dict);
147 if (args_dict)
148 return IsStringInDict(string_to_match, args_dict);
149
150 return false;
151}
152
153DictionaryValue* FindTraceEntry(const ListValue& trace_parsed,
154 const char *string_to_match,
155 DictionaryValue* match_after_this_item = NULL) {
156 // Scan all items
157 size_t trace_parsed_count = trace_parsed.GetSize();
158 for (size_t i = 0; i < trace_parsed_count; i++) {
159 Value* value = NULL;
160 trace_parsed.Get(i, &value);
161 if (match_after_this_item) {
162 if (value == match_after_this_item)
163 match_after_this_item = NULL;
164 continue;
165 }
166 if (!value || value->GetType() != Value::TYPE_DICTIONARY)
167 continue;
168 DictionaryValue* dict = static_cast<DictionaryValue*>(value);
169
170 if (IsStringInDict(string_to_match, dict))
171 return dict;
172 }
173 return NULL;
174}
175
176void DataCapturedCallTraces(WaitableEvent* task_complete_event) {
177 {
178 TRACE_EVENT_BEGIN_ETW("TRACE_EVENT_BEGIN_ETW call", 1122, "extrastring1");
179 TRACE_EVENT_END_ETW("TRACE_EVENT_END_ETW call", 3344, "extrastring2");
180 TRACE_EVENT_INSTANT_ETW("TRACE_EVENT_INSTANT_ETW call",
181 5566, "extrastring3");
182
183 TRACE_EVENT0("all", "TRACE_EVENT0 call");
184 TRACE_EVENT1("all", "TRACE_EVENT1 call", "name1", "value1");
185 TRACE_EVENT2("all", "TRACE_EVENT2 call",
186 "name1", "value1",
187 "name2", "value2");
188
189 TRACE_EVENT_INSTANT0("all", "TRACE_EVENT_INSTANT0 call");
190 TRACE_EVENT_INSTANT1("all", "TRACE_EVENT_INSTANT1 call", "name1", "value1");
191 TRACE_EVENT_INSTANT2("all", "TRACE_EVENT_INSTANT2 call",
192 "name1", "value1",
193 "name2", "value2");
194
195 TRACE_EVENT_BEGIN0("all", "TRACE_EVENT_BEGIN0 call");
196 TRACE_EVENT_BEGIN1("all", "TRACE_EVENT_BEGIN1 call", "name1", "value1");
197 TRACE_EVENT_BEGIN2("all", "TRACE_EVENT_BEGIN2 call",
198 "name1", "value1",
199 "name2", "value2");
200
201 TRACE_EVENT_END0("all", "TRACE_EVENT_END0 call");
202 TRACE_EVENT_END1("all", "TRACE_EVENT_END1 call", "name1", "value1");
203 TRACE_EVENT_END2("all", "TRACE_EVENT_END2 call",
204 "name1", "value1",
205 "name2", "value2");
206 } // Scope close causes TRACE_EVENT0 etc to send their END events.
207
208 if (task_complete_event)
209 task_complete_event->Signal();
210}
211
212void DataCapturedValidateTraces(const ListValue& trace_parsed,
213 const std::string& trace_string) {
214 DictionaryValue* item = NULL;
215
216#define EXPECT_FIND_(string) \
217 EXPECT_TRUE((item = FindTraceEntry(trace_parsed, string)));
218#define EXPECT_NOT_FIND_(string) \
219 EXPECT_FALSE((item = FindTraceEntry(trace_parsed, string)));
220#define EXPECT_SUB_FIND_(string) \
221 if (item) EXPECT_TRUE((IsStringInDict(string, item)));
222
223 EXPECT_FIND_("ETW Trace Event");
224 EXPECT_FIND_("all");
225 EXPECT_FIND_("TRACE_EVENT_BEGIN_ETW call");
226 {
227 int int_val = 0;
228 EXPECT_TRUE(item && item->GetInteger("args.id", &int_val));
229 EXPECT_EQ(1122, int_val);
230 }
231 EXPECT_SUB_FIND_("extrastring1");
232 EXPECT_FIND_("TRACE_EVENT_END_ETW call");
233 EXPECT_FIND_("TRACE_EVENT_INSTANT_ETW call");
234 EXPECT_FIND_("TRACE_EVENT0 call");
235 {
236 std::string ph_begin;
237 std::string ph_end;
238 EXPECT_TRUE((item = FindTraceEntry(trace_parsed, "TRACE_EVENT0 call")));
239 EXPECT_TRUE((item && item->GetString("ph", &ph_begin)));
240 EXPECT_TRUE((item = FindTraceEntry(trace_parsed, "TRACE_EVENT0 call",
241 item)));
242 EXPECT_TRUE((item && item->GetString("ph", &ph_end)));
243 EXPECT_EQ("B", ph_begin);
244 EXPECT_EQ("E", ph_end);
245 }
246 EXPECT_FIND_("TRACE_EVENT1 call");
247 EXPECT_FIND_("TRACE_EVENT2 call");
248 EXPECT_SUB_FIND_("name1");
249 EXPECT_SUB_FIND_("value1");
250 EXPECT_SUB_FIND_("name2");
251 EXPECT_SUB_FIND_("value2");
252 EXPECT_FIND_("TRACE_EVENT_INSTANT0 call");
253 EXPECT_FIND_("TRACE_EVENT_INSTANT1 call");
254 EXPECT_FIND_("TRACE_EVENT_INSTANT2 call");
255 EXPECT_SUB_FIND_("name1");
256 EXPECT_SUB_FIND_("value1");
257 EXPECT_SUB_FIND_("name2");
258 EXPECT_SUB_FIND_("value2");
259 EXPECT_FIND_("TRACE_EVENT_BEGIN0 call");
260 EXPECT_FIND_("TRACE_EVENT_BEGIN1 call");
261 EXPECT_FIND_("TRACE_EVENT_BEGIN2 call");
262 EXPECT_SUB_FIND_("name1");
263 EXPECT_SUB_FIND_("value1");
264 EXPECT_SUB_FIND_("name2");
265 EXPECT_SUB_FIND_("value2");
266 EXPECT_FIND_("TRACE_EVENT_END0 call");
267 EXPECT_FIND_("TRACE_EVENT_END1 call");
268 EXPECT_FIND_("TRACE_EVENT_END2 call");
269 EXPECT_SUB_FIND_("name1");
270 EXPECT_SUB_FIND_("value1");
271 EXPECT_SUB_FIND_("name2");
272 EXPECT_SUB_FIND_("value2");
273}
274
275} // namespace
276
277// Simple Test for emitting data and validating it was received.
278TEST_F(TraceEventTestFixture, DataCaptured) {
279 ManualTestSetUp();
280 TraceLog::GetInstance()->SetEnabled(true);
281
282 DataCapturedCallTraces(NULL);
283
284 TraceLog::GetInstance()->SetEnabled(false);
285
286 DataCapturedValidateTraces(trace_parsed_, trace_string_);
287}
288
jbates@chromium.orgb3cab862011-05-14 08:30:35 +0900289// Simple Test for time threshold events.
290TEST_F(TraceEventTestFixture, DataCapturedThreshold) {
291 ManualTestSetUp();
292 TraceLog::GetInstance()->SetEnabled(true);
293
294 // Test that events at the same level are properly filtered by threshold.
295 {
296 TRACE_EVENT_IF_LONGER_THAN0(100, "time", "threshold 100");
297 TRACE_EVENT_IF_LONGER_THAN0(1000, "time", "threshold 1000");
298 TRACE_EVENT_IF_LONGER_THAN0(10000, "time", "threshold 10000");
299 // 100+ seconds to avoid flakiness.
300 TRACE_EVENT_IF_LONGER_THAN0(100000000, "time", "threshold long1");
301 TRACE_EVENT_IF_LONGER_THAN0(200000000, "time", "threshold long2");
302 base::PlatformThread::Sleep(20); // 20000 us
303 }
304
305 // Test that a normal nested event remains after it's parent event is dropped.
306 {
307 TRACE_EVENT_IF_LONGER_THAN0(1000000, "time", "2threshold10000");
308 {
309 TRACE_EVENT0("time", "nonthreshold1");
310 }
311 }
312
313 // Test that parent thresholded events are dropped while some nested events
314 // remain.
315 {
316 TRACE_EVENT0("time", "nonthreshold3");
317 {
318 TRACE_EVENT_IF_LONGER_THAN0(200000000, "time", "3thresholdlong2");
319 {
320 TRACE_EVENT_IF_LONGER_THAN0(100000000, "time", "3thresholdlong1");
321 {
322 TRACE_EVENT_IF_LONGER_THAN0(10000, "time", "3threshold10000");
323 {
324 TRACE_EVENT_IF_LONGER_THAN0(1000, "time", "3threshold1000");
325 {
326 TRACE_EVENT_IF_LONGER_THAN0(100, "time", "3threshold100");
327 base::PlatformThread::Sleep(20);
328 }
329 }
330 }
331 }
332 }
333 }
334
335 // Test that child thresholded events are dropped while some parent events
336 // remain.
337 {
338 TRACE_EVENT0("time", "nonthreshold4");
339 {
340 TRACE_EVENT_IF_LONGER_THAN0(100, "time", "4threshold100");
341 {
342 TRACE_EVENT_IF_LONGER_THAN0(1000, "time", "4threshold1000");
343 {
344 TRACE_EVENT_IF_LONGER_THAN0(10000, "time", "4threshold10000");
345 {
346 TRACE_EVENT_IF_LONGER_THAN0(100000000, "time",
347 "4thresholdlong1");
348 {
349 TRACE_EVENT_IF_LONGER_THAN0(200000000, "time",
350 "4thresholdlong2");
351 base::PlatformThread::Sleep(20);
352 }
353 }
354 }
355 }
356 }
357 }
358
359 TraceLog::GetInstance()->SetEnabled(false);
360
361#define EXPECT_FIND_BE_(str) \
362 EXPECT_TRUE(FindNamePhase(str, "B")); \
363 EXPECT_TRUE(FindNamePhase(str, "E"))
364#define EXPECT_NOT_FIND_BE_(str) \
365 EXPECT_FALSE(FindNamePhase(str, "B")); \
366 EXPECT_FALSE(FindNamePhase(str, "E"))
367
368 EXPECT_FIND_BE_("threshold 100");
369 EXPECT_FIND_BE_("threshold 1000");
370 EXPECT_FIND_BE_("threshold 10000");
371 EXPECT_NOT_FIND_BE_("threshold long1");
372 EXPECT_NOT_FIND_BE_("threshold long2");
373
374 EXPECT_NOT_FIND_BE_("2threshold10000");
375 EXPECT_FIND_BE_("nonthreshold1");
376
377 EXPECT_FIND_BE_("nonthreshold3");
378 EXPECT_FIND_BE_("3threshold100");
379 EXPECT_FIND_BE_("3threshold1000");
380 EXPECT_FIND_BE_("3threshold10000");
381 EXPECT_NOT_FIND_BE_("3thresholdlong1");
382 EXPECT_NOT_FIND_BE_("3thresholdlong2");
383
384 EXPECT_FIND_BE_("nonthreshold4");
385 EXPECT_FIND_BE_("4threshold100");
386 EXPECT_FIND_BE_("4threshold1000");
387 EXPECT_FIND_BE_("4threshold10000");
388 EXPECT_NOT_FIND_BE_("4thresholdlong1");
389 EXPECT_NOT_FIND_BE_("4thresholdlong2");
390}
391
scheib@chromium.org603f46e2011-05-10 11:23:58 +0900392// Test that data sent from other threads is gathered
393TEST_F(TraceEventTestFixture, DataCapturedOnThread) {
394 ManualTestSetUp();
395 TraceLog::GetInstance()->SetEnabled(true);
396
397 Thread thread("1");
398 WaitableEvent task_complete_event(false, false);
399 thread.Start();
400
401 thread.message_loop()->PostTask(
402 FROM_HERE, NewRunnableFunction(&DataCapturedCallTraces,
403 &task_complete_event));
404 task_complete_event.Wait();
405
406 TraceLog::GetInstance()->SetEnabled(false);
407 thread.Stop();
408 DataCapturedValidateTraces(trace_parsed_, trace_string_);
409}
410
411namespace {
412
413void DataCapturedCallManyTraces(int thread_id, int num_events,
414 WaitableEvent* task_complete_event) {
415 for (int i = 0; i < num_events; i++) {
416 TRACE_EVENT_INSTANT2("all", "multi thread event",
417 "thread", thread_id,
418 "event", i);
419 }
420
421 if (task_complete_event)
422 task_complete_event->Signal();
423}
424
425void DataCapturedValidateManyTraces(const ListValue& trace_parsed,
426 const std::string& trace_string,
427 int num_threads, int num_events) {
428 std::map<int, std::map<int, bool> > results;
429
430 size_t trace_parsed_count = trace_parsed.GetSize();
431 for (size_t i = 0; i < trace_parsed_count; i++) {
432 Value* value = NULL;
433 trace_parsed.Get(i, &value);
434 if (!value || value->GetType() != Value::TYPE_DICTIONARY)
435 continue;
436 DictionaryValue* dict = static_cast<DictionaryValue*>(value);
437 std::string name;
438 dict->GetString("name", &name);
439 if (name != "multi thread event")
440 continue;
441
442 int thread = 0;
443 int event = 0;
444 EXPECT_TRUE(dict->GetInteger("args.thread", &thread));
445 EXPECT_TRUE(dict->GetInteger("args.event", &event));
446 results[thread][event] = true;
447 }
448
449 EXPECT_FALSE(results[-1][-1]);
450 for (int thread = 0; thread < num_threads; thread++) {
451 for (int event = 0; event < num_events; event++) {
452 EXPECT_TRUE(results[thread][event]);
453 }
454 }
455}
456
457} // namespace
458
459// Test that data sent from multiple threads is gathered
460TEST_F(TraceEventTestFixture, DataCapturedManyThreads) {
461 ManualTestSetUp();
462 TraceLog::GetInstance()->SetEnabled(true);
463
464 const int num_threads = 4;
465 const int num_events = 4000;
466 Thread* threads[num_threads];
467 WaitableEvent* task_complete_events[num_threads];
468 for (int i = 0; i < num_threads; i++) {
469 threads[i] = new Thread(StringPrintf("Thread %d", i).c_str());
470 task_complete_events[i] = new WaitableEvent(false, false);
471 threads[i]->Start();
472 threads[i]->message_loop()->PostTask(
473 FROM_HERE, NewRunnableFunction(&DataCapturedCallManyTraces,
474 i, num_events, task_complete_events[i]));
475 }
476
477 for (int i = 0; i < num_threads; i++) {
478 task_complete_events[i]->Wait();
479 }
480
481 TraceLog::GetInstance()->SetEnabled(false);
482
483 for (int i = 0; i < num_threads; i++) {
484 threads[i]->Stop();
485 delete threads[i];
486 delete task_complete_events[i];
487 }
488
489 DataCapturedValidateManyTraces(trace_parsed_, trace_string_,
490 num_threads, num_events);
491}
492
493void TraceCallsWithCachedCategoryPointersPointers(const char* name_str) {
494 TRACE_EVENT0("category name1", name_str);
495 TRACE_EVENT_INSTANT0("category name2", name_str);
496 TRACE_EVENT_BEGIN0("category name3", name_str);
497 TRACE_EVENT_END0("category name4", name_str);
498}
499
500// Test trace calls made after tracing singleton shut down.
501//
502// The singleton is destroyed by our base::AtExitManager, but there can be
503// code still executing as the C++ static objects are destroyed. This test
504// forces the singleton to destroy early, and intentinally makes trace calls
505// afterwards.
506TEST_F(TraceEventTestFixture, AtExit) {
507 // Repeat this test a few times. Besides just showing robustness, it also
508 // allows us to test that events at shutdown do not appear with valid events
509 // recorded after the system is started again.
510 for (int i = 0; i < 4; i++) {
511 // Scope to contain the then destroy the TraceLog singleton.
512 {
513 base::ShadowingAtExitManager exit_manager_will_destroy_singletons;
514
515 // Setup TraceLog singleton inside this test's exit manager scope
516 // so that it will be destroyed when this scope closes.
517 ManualTestSetUp();
518
519 TRACE_EVENT_INSTANT0("all", "not recorded; system not enabled");
520
521 TraceLog::GetInstance()->SetEnabled(true);
522
523 TRACE_EVENT_INSTANT0("all", "is recorded 1; system has been enabled");
524 // Trace calls that will cache pointers to categories; they're valid here
525 TraceCallsWithCachedCategoryPointersPointers(
526 "is recorded 2; system has been enabled");
527
528 TraceLog::GetInstance()->SetEnabled(false);
529 } // scope to destroy singleton
530 ASSERT_FALSE(TraceLog::GetInstance());
531
532 // Now that singleton is destroyed, check what trace events were recorded
533 DictionaryValue* item = NULL;
534 ListValue& trace_parsed = trace_parsed_;
535 EXPECT_FIND_("is recorded 1");
536 EXPECT_FIND_("is recorded 2");
537 EXPECT_NOT_FIND_("not recorded");
538
539 // Make additional trace event calls on the shutdown system. They should
540 // all pass cleanly, but the data not be recorded. We'll verify that next
541 // time around the loop (the only way to flush the trace buffers).
542 TRACE_EVENT_BEGIN_ETW("not recorded; system shutdown", 0, NULL);
543 TRACE_EVENT_END_ETW("not recorded; system shutdown", 0, NULL);
544 TRACE_EVENT_INSTANT_ETW("not recorded; system shutdown", 0, NULL);
545 TRACE_EVENT0("all", "not recorded; system shutdown");
546 TRACE_EVENT_INSTANT0("all", "not recorded; system shutdown");
547 TRACE_EVENT_BEGIN0("all", "not recorded; system shutdown");
548 TRACE_EVENT_END0("all", "not recorded; system shutdown");
549
550 TRACE_EVENT0("new category 0!", "not recorded; system shutdown");
551 TRACE_EVENT_INSTANT0("new category 1!", "not recorded; system shutdown");
552 TRACE_EVENT_BEGIN0("new category 2!", "not recorded; system shutdown");
553 TRACE_EVENT_END0("new category 3!", "not recorded; system shutdown");
554
555 // Cached categories should be safe to check, and still disable traces
556 TraceCallsWithCachedCategoryPointersPointers(
557 "not recorded; system shutdown");
558 }
559}
560
561} // namespace debug
562} // namespace base