blob: a5c889f5608f4f7758174ac835a3af64e9beb60b [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"
jbates@chromium.org1f18e462011-09-07 02:56:24 +090011#include "base/memory/ref_counted_memory.h"
scheib@chromium.org603f46e2011-05-10 11:23:58 +090012#include "base/memory/scoped_ptr.h"
nduca@chromium.org6d048772011-08-10 00:16:25 +090013#include "base/process_util.h"
scheib@chromium.org603f46e2011-05-10 11:23:58 +090014#include "base/stringprintf.h"
15#include "base/synchronization/waitable_event.h"
16#include "base/threading/thread.h"
17#include "base/values.h"
18#include "testing/gmock/include/gmock/gmock.h"
19#include "testing/gtest/include/gtest/gtest.h"
20
21namespace base {
22namespace debug {
23
24namespace {
25
jbates@chromium.org11d4c362011-09-13 07:03:41 +090026enum CompareOp {
27 IS_EQUAL,
28 IS_NOT_EQUAL,
29};
30
jbates@chromium.orgb3cab862011-05-14 08:30:35 +090031struct JsonKeyValue {
32 const char* key;
33 const char* value;
jbates@chromium.org11d4c362011-09-13 07:03:41 +090034 CompareOp op;
jbates@chromium.orgb3cab862011-05-14 08:30:35 +090035};
36
scheib@chromium.org603f46e2011-05-10 11:23:58 +090037class TraceEventTestFixture : public testing::Test {
38 public:
joth@chromium.org113de992011-07-21 21:28:59 +090039 // This fixture does not use SetUp() because the fixture must be manually set
40 // up multiple times when testing AtExit. Use ManualTestSetUp for this.
scheib@chromium.org603f46e2011-05-10 11:23:58 +090041 void ManualTestSetUp();
ajwong@chromium.orgec1750a2011-06-27 01:22:50 +090042 void OnTraceDataCollected(
43 scoped_refptr<TraceLog::RefCountedString> json_events_str);
jbates@chromium.orgb3cab862011-05-14 08:30:35 +090044 bool FindMatchingTraceEntry(const JsonKeyValue* key_values);
45 bool FindNamePhase(const char* name, const char* phase);
jbates@chromium.org11d4c362011-09-13 07:03:41 +090046 bool FindMatchingValue(const char* key,
47 const char* value);
48 bool FindNonMatchingValue(const char* key,
49 const char* value);
50 void Clear() {
51 trace_string_.clear();
52 trace_parsed_.Clear();
53 }
scheib@chromium.org603f46e2011-05-10 11:23:58 +090054
55 std::string trace_string_;
56 ListValue trace_parsed_;
57
58 private:
59 // We want our singleton torn down after each test.
60 ShadowingAtExitManager at_exit_manager_;
61};
62
63void TraceEventTestFixture::ManualTestSetUp() {
64 TraceLog::Resurrect();
65 TraceLog* tracelog = TraceLog::GetInstance();
66 ASSERT_TRUE(tracelog);
67 ASSERT_FALSE(tracelog->IsEnabled());
68 tracelog->SetOutputCallback(
69 base::Bind(&TraceEventTestFixture::OnTraceDataCollected,
70 base::Unretained(this)));
71}
72
73void TraceEventTestFixture::OnTraceDataCollected(
ajwong@chromium.orgec1750a2011-06-27 01:22:50 +090074 scoped_refptr<TraceLog::RefCountedString> json_events_str) {
scheib@chromium.org603f46e2011-05-10 11:23:58 +090075 trace_string_ += json_events_str->data;
76
77 scoped_ptr<Value> root;
78 root.reset(base::JSONReader::Read(json_events_str->data, false));
79
80 ListValue* root_list = NULL;
81 ASSERT_TRUE(root.get());
82 ASSERT_TRUE(root->GetAsList(&root_list));
83
84 // Move items into our aggregate collection
85 while (root_list->GetSize()) {
86 Value* item = NULL;
87 root_list->Remove(0, &item);
88 trace_parsed_.Append(item);
89 }
90}
91
jbates@chromium.org11d4c362011-09-13 07:03:41 +090092static bool CompareJsonValues(const std::string& lhs,
93 const std::string& rhs,
94 CompareOp op) {
95 switch (op) {
96 case IS_EQUAL:
97 return lhs == rhs;
98 case IS_NOT_EQUAL:
99 return lhs != rhs;
100 default:
101 CHECK(0);
102 }
103 return false;
104}
105
jbates@chromium.orgb3cab862011-05-14 08:30:35 +0900106static bool IsKeyValueInDict(const JsonKeyValue* key_value,
107 DictionaryValue* dict) {
108 Value* value = NULL;
109 std::string value_str;
110 if (dict->Get(key_value->key, &value) &&
111 value->GetAsString(&value_str) &&
jbates@chromium.org11d4c362011-09-13 07:03:41 +0900112 CompareJsonValues(value_str, key_value->value, key_value->op))
jbates@chromium.orgb3cab862011-05-14 08:30:35 +0900113 return true;
114
115 // Recurse to test arguments
116 DictionaryValue* args_dict = NULL;
117 dict->GetDictionary("args", &args_dict);
118 if (args_dict)
119 return IsKeyValueInDict(key_value, args_dict);
120
121 return false;
122}
123
124static bool IsAllKeyValueInDict(const JsonKeyValue* key_values,
125 DictionaryValue* dict) {
126 // Scan all key_values, they must all be present and equal.
127 while (key_values && key_values->key) {
128 if (!IsKeyValueInDict(key_values, dict))
129 return false;
130 ++key_values;
131 }
132 return true;
133}
134
135bool TraceEventTestFixture::FindMatchingTraceEntry(
136 const JsonKeyValue* key_values) {
137 // Scan all items
138 size_t trace_parsed_count = trace_parsed_.GetSize();
139 for (size_t i = 0; i < trace_parsed_count; i++) {
140 Value* value = NULL;
141 trace_parsed_.Get(i, &value);
142 if (!value || value->GetType() != Value::TYPE_DICTIONARY)
143 continue;
144 DictionaryValue* dict = static_cast<DictionaryValue*>(value);
145
146 if (IsAllKeyValueInDict(key_values, dict))
147 return true;
148 }
149 return false;
150}
151
152bool TraceEventTestFixture::FindNamePhase(const char* name, const char* phase) {
153 JsonKeyValue key_values[] = {
jbates@chromium.org11d4c362011-09-13 07:03:41 +0900154 {"name", name, IS_EQUAL},
155 {"ph", phase, IS_EQUAL},
156 {0, 0, IS_EQUAL}
157 };
158 return FindMatchingTraceEntry(key_values);
159}
160
161bool TraceEventTestFixture::FindMatchingValue(const char* key,
162 const char* value) {
163 JsonKeyValue key_values[] = {
164 {key, value, IS_EQUAL},
165 {0, 0, IS_EQUAL}
166 };
167 return FindMatchingTraceEntry(key_values);
168}
169
170bool TraceEventTestFixture::FindNonMatchingValue(const char* key,
171 const char* value) {
172 JsonKeyValue key_values[] = {
173 {key, value, IS_NOT_EQUAL},
174 {0, 0, IS_EQUAL}
jbates@chromium.orgb3cab862011-05-14 08:30:35 +0900175 };
176 return FindMatchingTraceEntry(key_values);
177}
178
scheib@chromium.org603f46e2011-05-10 11:23:58 +0900179bool IsStringInDict(const char* string_to_match, DictionaryValue* dict) {
180 for (DictionaryValue::key_iterator ikey = dict->begin_keys();
181 ikey != dict->end_keys(); ++ikey) {
182 Value* child = NULL;
183 if (!dict->GetWithoutPathExpansion(*ikey, &child))
184 continue;
185
186 if ((*ikey).find(string_to_match) != std::string::npos)
187 return true;
188
189 std::string value_str;
190 child->GetAsString(&value_str);
191 if (value_str.find(string_to_match) != std::string::npos)
192 return true;
193 }
194
195 // Recurse to test arguments
196 DictionaryValue* args_dict = NULL;
197 dict->GetDictionary("args", &args_dict);
198 if (args_dict)
199 return IsStringInDict(string_to_match, args_dict);
200
201 return false;
202}
203
204DictionaryValue* FindTraceEntry(const ListValue& trace_parsed,
nduca@chromium.org6d048772011-08-10 00:16:25 +0900205 const char* string_to_match,
scheib@chromium.org603f46e2011-05-10 11:23:58 +0900206 DictionaryValue* match_after_this_item = NULL) {
207 // Scan all items
208 size_t trace_parsed_count = trace_parsed.GetSize();
209 for (size_t i = 0; i < trace_parsed_count; i++) {
210 Value* value = NULL;
211 trace_parsed.Get(i, &value);
212 if (match_after_this_item) {
213 if (value == match_after_this_item)
214 match_after_this_item = NULL;
215 continue;
216 }
217 if (!value || value->GetType() != Value::TYPE_DICTIONARY)
218 continue;
219 DictionaryValue* dict = static_cast<DictionaryValue*>(value);
220
221 if (IsStringInDict(string_to_match, dict))
222 return dict;
223 }
224 return NULL;
225}
226
nduca@chromium.org6d048772011-08-10 00:16:25 +0900227std::vector<DictionaryValue*> FindTraceEntries(
228 const ListValue& trace_parsed,
229 const char* string_to_match) {
230 std::vector<DictionaryValue*> hits;
231 size_t trace_parsed_count = trace_parsed.GetSize();
232 for (size_t i = 0; i < trace_parsed_count; i++) {
233 Value* value = NULL;
234 trace_parsed.Get(i, &value);
235 if (!value || value->GetType() != Value::TYPE_DICTIONARY)
236 continue;
237 DictionaryValue* dict = static_cast<DictionaryValue*>(value);
238
239 if (IsStringInDict(string_to_match, dict))
240 hits.push_back(dict);
241 }
242 return hits;
243}
244
245void TraceWithAllMacroVariants(WaitableEvent* task_complete_event) {
scheib@chromium.org603f46e2011-05-10 11:23:58 +0900246 {
247 TRACE_EVENT_BEGIN_ETW("TRACE_EVENT_BEGIN_ETW call", 1122, "extrastring1");
248 TRACE_EVENT_END_ETW("TRACE_EVENT_END_ETW call", 3344, "extrastring2");
249 TRACE_EVENT_INSTANT_ETW("TRACE_EVENT_INSTANT_ETW call",
250 5566, "extrastring3");
251
252 TRACE_EVENT0("all", "TRACE_EVENT0 call");
253 TRACE_EVENT1("all", "TRACE_EVENT1 call", "name1", "value1");
254 TRACE_EVENT2("all", "TRACE_EVENT2 call",
jbates@chromium.org788d5a12011-09-07 09:43:11 +0900255 "name1", "\"value1\"",
256 "name2", "value\\2");
scheib@chromium.org603f46e2011-05-10 11:23:58 +0900257
258 TRACE_EVENT_INSTANT0("all", "TRACE_EVENT_INSTANT0 call");
259 TRACE_EVENT_INSTANT1("all", "TRACE_EVENT_INSTANT1 call", "name1", "value1");
260 TRACE_EVENT_INSTANT2("all", "TRACE_EVENT_INSTANT2 call",
261 "name1", "value1",
262 "name2", "value2");
263
264 TRACE_EVENT_BEGIN0("all", "TRACE_EVENT_BEGIN0 call");
265 TRACE_EVENT_BEGIN1("all", "TRACE_EVENT_BEGIN1 call", "name1", "value1");
266 TRACE_EVENT_BEGIN2("all", "TRACE_EVENT_BEGIN2 call",
267 "name1", "value1",
268 "name2", "value2");
269
270 TRACE_EVENT_END0("all", "TRACE_EVENT_END0 call");
271 TRACE_EVENT_END1("all", "TRACE_EVENT_END1 call", "name1", "value1");
272 TRACE_EVENT_END2("all", "TRACE_EVENT_END2 call",
273 "name1", "value1",
274 "name2", "value2");
275 } // Scope close causes TRACE_EVENT0 etc to send their END events.
276
277 if (task_complete_event)
278 task_complete_event->Signal();
279}
280
nduca@chromium.org6d048772011-08-10 00:16:25 +0900281void ValidateAllTraceMacrosCreatedData(const ListValue& trace_parsed,
scheib@chromium.org603f46e2011-05-10 11:23:58 +0900282 const std::string& trace_string) {
283 DictionaryValue* item = NULL;
284
285#define EXPECT_FIND_(string) \
286 EXPECT_TRUE((item = FindTraceEntry(trace_parsed, string)));
287#define EXPECT_NOT_FIND_(string) \
288 EXPECT_FALSE((item = FindTraceEntry(trace_parsed, string)));
289#define EXPECT_SUB_FIND_(string) \
290 if (item) EXPECT_TRUE((IsStringInDict(string, item)));
291
292 EXPECT_FIND_("ETW Trace Event");
293 EXPECT_FIND_("all");
294 EXPECT_FIND_("TRACE_EVENT_BEGIN_ETW call");
295 {
296 int int_val = 0;
297 EXPECT_TRUE(item && item->GetInteger("args.id", &int_val));
298 EXPECT_EQ(1122, int_val);
299 }
300 EXPECT_SUB_FIND_("extrastring1");
301 EXPECT_FIND_("TRACE_EVENT_END_ETW call");
302 EXPECT_FIND_("TRACE_EVENT_INSTANT_ETW call");
303 EXPECT_FIND_("TRACE_EVENT0 call");
304 {
305 std::string ph_begin;
306 std::string ph_end;
307 EXPECT_TRUE((item = FindTraceEntry(trace_parsed, "TRACE_EVENT0 call")));
308 EXPECT_TRUE((item && item->GetString("ph", &ph_begin)));
309 EXPECT_TRUE((item = FindTraceEntry(trace_parsed, "TRACE_EVENT0 call",
310 item)));
311 EXPECT_TRUE((item && item->GetString("ph", &ph_end)));
312 EXPECT_EQ("B", ph_begin);
313 EXPECT_EQ("E", ph_end);
314 }
315 EXPECT_FIND_("TRACE_EVENT1 call");
316 EXPECT_FIND_("TRACE_EVENT2 call");
317 EXPECT_SUB_FIND_("name1");
jbates@chromium.org788d5a12011-09-07 09:43:11 +0900318 EXPECT_SUB_FIND_("\"value1\"");
scheib@chromium.org603f46e2011-05-10 11:23:58 +0900319 EXPECT_SUB_FIND_("name2");
jbates@chromium.org788d5a12011-09-07 09:43:11 +0900320 EXPECT_SUB_FIND_("value\\2");
scheib@chromium.org603f46e2011-05-10 11:23:58 +0900321 EXPECT_FIND_("TRACE_EVENT_INSTANT0 call");
322 EXPECT_FIND_("TRACE_EVENT_INSTANT1 call");
323 EXPECT_FIND_("TRACE_EVENT_INSTANT2 call");
324 EXPECT_SUB_FIND_("name1");
325 EXPECT_SUB_FIND_("value1");
326 EXPECT_SUB_FIND_("name2");
327 EXPECT_SUB_FIND_("value2");
328 EXPECT_FIND_("TRACE_EVENT_BEGIN0 call");
329 EXPECT_FIND_("TRACE_EVENT_BEGIN1 call");
330 EXPECT_FIND_("TRACE_EVENT_BEGIN2 call");
331 EXPECT_SUB_FIND_("name1");
332 EXPECT_SUB_FIND_("value1");
333 EXPECT_SUB_FIND_("name2");
334 EXPECT_SUB_FIND_("value2");
335 EXPECT_FIND_("TRACE_EVENT_END0 call");
336 EXPECT_FIND_("TRACE_EVENT_END1 call");
337 EXPECT_FIND_("TRACE_EVENT_END2 call");
338 EXPECT_SUB_FIND_("name1");
339 EXPECT_SUB_FIND_("value1");
340 EXPECT_SUB_FIND_("name2");
341 EXPECT_SUB_FIND_("value2");
342}
343
nduca@chromium.org6d048772011-08-10 00:16:25 +0900344void TraceManyInstantEvents(int thread_id, int num_events,
345 WaitableEvent* task_complete_event) {
346 for (int i = 0; i < num_events; i++) {
347 TRACE_EVENT_INSTANT2("all", "multi thread event",
348 "thread", thread_id,
349 "event", i);
350 }
351
352 if (task_complete_event)
353 task_complete_event->Signal();
354}
355
356void ValidateInstantEventPresentOnEveryThread(const ListValue& trace_parsed,
357 const std::string& trace_string,
358 int num_threads, int num_events) {
359 std::map<int, std::map<int, bool> > results;
360
361 size_t trace_parsed_count = trace_parsed.GetSize();
362 for (size_t i = 0; i < trace_parsed_count; i++) {
363 Value* value = NULL;
364 trace_parsed.Get(i, &value);
365 if (!value || value->GetType() != Value::TYPE_DICTIONARY)
366 continue;
367 DictionaryValue* dict = static_cast<DictionaryValue*>(value);
368 std::string name;
369 dict->GetString("name", &name);
370 if (name != "multi thread event")
371 continue;
372
373 int thread = 0;
374 int event = 0;
375 EXPECT_TRUE(dict->GetInteger("args.thread", &thread));
376 EXPECT_TRUE(dict->GetInteger("args.event", &event));
377 results[thread][event] = true;
378 }
379
380 EXPECT_FALSE(results[-1][-1]);
381 for (int thread = 0; thread < num_threads; thread++) {
382 for (int event = 0; event < num_events; event++) {
383 EXPECT_TRUE(results[thread][event]);
384 }
385 }
386}
387
388void TraceCallsWithCachedCategoryPointersPointers(const char* name_str) {
389 TRACE_EVENT0("category name1", name_str);
390 TRACE_EVENT_INSTANT0("category name2", name_str);
391 TRACE_EVENT_BEGIN0("category name3", name_str);
392 TRACE_EVENT_END0("category name4", name_str);
393}
394
scheib@chromium.org603f46e2011-05-10 11:23:58 +0900395} // namespace
396
397// Simple Test for emitting data and validating it was received.
398TEST_F(TraceEventTestFixture, DataCaptured) {
399 ManualTestSetUp();
400 TraceLog::GetInstance()->SetEnabled(true);
401
nduca@chromium.org6d048772011-08-10 00:16:25 +0900402 TraceWithAllMacroVariants(NULL);
scheib@chromium.org603f46e2011-05-10 11:23:58 +0900403
404 TraceLog::GetInstance()->SetEnabled(false);
405
nduca@chromium.org6d048772011-08-10 00:16:25 +0900406 ValidateAllTraceMacrosCreatedData(trace_parsed_, trace_string_);
scheib@chromium.org603f46e2011-05-10 11:23:58 +0900407}
408
jbates@chromium.org11d4c362011-09-13 07:03:41 +0900409// Test that categories work.
410TEST_F(TraceEventTestFixture, Categories) {
411 ManualTestSetUp();
412
413 // Test that categories that are used can be retrieved whether trace was
414 // enabled or disabled when the trace event was encountered.
415 TRACE_EVENT_INSTANT0("c1", "name");
416 TRACE_EVENT_INSTANT0("c2", "name");
417 TraceLog::GetInstance()->SetEnabled(true);
418 TRACE_EVENT_INSTANT0("c3", "name");
419 TRACE_EVENT_INSTANT0("c4", "name");
420 TraceLog::GetInstance()->SetEnabled(false);
421 std::vector<std::string> cats;
422 TraceLog::GetInstance()->GetKnownCategories(&cats);
423 EXPECT_TRUE(std::find(cats.begin(), cats.end(), "c1") != cats.end());
424 EXPECT_TRUE(std::find(cats.begin(), cats.end(), "c2") != cats.end());
425 EXPECT_TRUE(std::find(cats.begin(), cats.end(), "c3") != cats.end());
426 EXPECT_TRUE(std::find(cats.begin(), cats.end(), "c4") != cats.end());
427
428 const std::vector<std::string> empty_categories;
429 std::vector<std::string> included_categories;
430 std::vector<std::string> excluded_categories;
431
432 // Test that category filtering works.
433
434 // Include nonexistent category -> no events
435 Clear();
436 included_categories.clear();
437 included_categories.push_back("not_found823564786");
438 TraceLog::GetInstance()->SetEnabled(included_categories, empty_categories);
439 TRACE_EVENT_INSTANT0("cat1", "name");
440 TRACE_EVENT_INSTANT0("cat2", "name");
441 TraceLog::GetInstance()->SetDisabled();
442 EXPECT_TRUE(trace_parsed_.empty());
443
444 // Include existent category -> only events of that category
445 Clear();
446 included_categories.clear();
447 included_categories.push_back("inc");
448 TraceLog::GetInstance()->SetEnabled(included_categories, empty_categories);
449 TRACE_EVENT_INSTANT0("inc", "name");
450 TRACE_EVENT_INSTANT0("inc2", "name");
451 TraceLog::GetInstance()->SetDisabled();
452 EXPECT_TRUE(FindMatchingValue("cat", "inc"));
453 EXPECT_FALSE(FindNonMatchingValue("cat", "inc"));
454
455 // Include existent wildcard -> all categories matching wildcard
456 Clear();
457 included_categories.clear();
458 included_categories.push_back("inc_wildcard_*");
459 included_categories.push_back("inc_wildchar_?_end");
460 TraceLog::GetInstance()->SetEnabled(included_categories, empty_categories);
461 TRACE_EVENT_INSTANT0("inc_wildcard_abc", "included");
462 TRACE_EVENT_INSTANT0("inc_wildcard_", "included");
463 TRACE_EVENT_INSTANT0("inc_wildchar_x_end", "included");
464 TRACE_EVENT_INSTANT0("inc_wildchar_bla_end", "not_inc");
465 TRACE_EVENT_INSTANT0("cat1", "not_inc");
466 TRACE_EVENT_INSTANT0("cat2", "not_inc");
467 TraceLog::GetInstance()->SetDisabled();
468 EXPECT_TRUE(FindMatchingValue("cat", "inc_wildcard_abc"));
469 EXPECT_TRUE(FindMatchingValue("cat", "inc_wildcard_"));
470 EXPECT_TRUE(FindMatchingValue("cat", "inc_wildchar_x_end"));
471 EXPECT_FALSE(FindMatchingValue("name", "not_inc"));
472
473 included_categories.clear();
474
475 // Exclude nonexistent category -> all events
476 Clear();
477 excluded_categories.clear();
478 excluded_categories.push_back("not_found823564786");
479 TraceLog::GetInstance()->SetEnabled(empty_categories, excluded_categories);
480 TRACE_EVENT_INSTANT0("cat1", "name");
481 TRACE_EVENT_INSTANT0("cat2", "name");
482 TraceLog::GetInstance()->SetDisabled();
483 EXPECT_TRUE(FindMatchingValue("cat", "cat1"));
484 EXPECT_TRUE(FindMatchingValue("cat", "cat2"));
485
486 // Exclude existent category -> only events of other categories
487 Clear();
488 excluded_categories.clear();
489 excluded_categories.push_back("inc");
490 TraceLog::GetInstance()->SetEnabled(empty_categories, excluded_categories);
491 TRACE_EVENT_INSTANT0("inc", "name");
492 TRACE_EVENT_INSTANT0("inc2", "name");
493 TraceLog::GetInstance()->SetDisabled();
494 EXPECT_TRUE(FindMatchingValue("cat", "inc2"));
495 EXPECT_FALSE(FindMatchingValue("cat", "inc"));
496
497 // Exclude existent wildcard -> all categories not matching wildcard
498 Clear();
499 excluded_categories.clear();
500 excluded_categories.push_back("inc_wildcard_*");
501 excluded_categories.push_back("inc_wildchar_?_end");
502 TraceLog::GetInstance()->SetEnabled(empty_categories, excluded_categories);
503 TRACE_EVENT_INSTANT0("inc_wildcard_abc", "not_inc");
504 TRACE_EVENT_INSTANT0("inc_wildcard_", "not_inc");
505 TRACE_EVENT_INSTANT0("inc_wildchar_x_end", "not_inc");
506 TRACE_EVENT_INSTANT0("inc_wildchar_bla_end", "included");
507 TRACE_EVENT_INSTANT0("cat1", "included");
508 TRACE_EVENT_INSTANT0("cat2", "included");
509 TraceLog::GetInstance()->SetDisabled();
510 EXPECT_TRUE(FindMatchingValue("cat", "inc_wildchar_bla_end"));
511 EXPECT_TRUE(FindMatchingValue("cat", "cat1"));
512 EXPECT_TRUE(FindMatchingValue("cat", "cat2"));
513 EXPECT_FALSE(FindMatchingValue("name", "not_inc"));
514}
515
jbates@chromium.orgb3cab862011-05-14 08:30:35 +0900516// Simple Test for time threshold events.
517TEST_F(TraceEventTestFixture, DataCapturedThreshold) {
518 ManualTestSetUp();
519 TraceLog::GetInstance()->SetEnabled(true);
520
521 // Test that events at the same level are properly filtered by threshold.
522 {
523 TRACE_EVENT_IF_LONGER_THAN0(100, "time", "threshold 100");
524 TRACE_EVENT_IF_LONGER_THAN0(1000, "time", "threshold 1000");
525 TRACE_EVENT_IF_LONGER_THAN0(10000, "time", "threshold 10000");
526 // 100+ seconds to avoid flakiness.
527 TRACE_EVENT_IF_LONGER_THAN0(100000000, "time", "threshold long1");
528 TRACE_EVENT_IF_LONGER_THAN0(200000000, "time", "threshold long2");
529 base::PlatformThread::Sleep(20); // 20000 us
530 }
531
532 // Test that a normal nested event remains after it's parent event is dropped.
533 {
534 TRACE_EVENT_IF_LONGER_THAN0(1000000, "time", "2threshold10000");
535 {
536 TRACE_EVENT0("time", "nonthreshold1");
537 }
538 }
539
540 // Test that parent thresholded events are dropped while some nested events
541 // remain.
542 {
543 TRACE_EVENT0("time", "nonthreshold3");
544 {
545 TRACE_EVENT_IF_LONGER_THAN0(200000000, "time", "3thresholdlong2");
546 {
547 TRACE_EVENT_IF_LONGER_THAN0(100000000, "time", "3thresholdlong1");
548 {
549 TRACE_EVENT_IF_LONGER_THAN0(10000, "time", "3threshold10000");
550 {
551 TRACE_EVENT_IF_LONGER_THAN0(1000, "time", "3threshold1000");
552 {
553 TRACE_EVENT_IF_LONGER_THAN0(100, "time", "3threshold100");
554 base::PlatformThread::Sleep(20);
555 }
556 }
557 }
558 }
559 }
560 }
561
562 // Test that child thresholded events are dropped while some parent events
563 // remain.
564 {
565 TRACE_EVENT0("time", "nonthreshold4");
566 {
567 TRACE_EVENT_IF_LONGER_THAN0(100, "time", "4threshold100");
568 {
569 TRACE_EVENT_IF_LONGER_THAN0(1000, "time", "4threshold1000");
570 {
571 TRACE_EVENT_IF_LONGER_THAN0(10000, "time", "4threshold10000");
572 {
573 TRACE_EVENT_IF_LONGER_THAN0(100000000, "time",
574 "4thresholdlong1");
575 {
576 TRACE_EVENT_IF_LONGER_THAN0(200000000, "time",
577 "4thresholdlong2");
578 base::PlatformThread::Sleep(20);
579 }
580 }
581 }
582 }
583 }
584 }
585
586 TraceLog::GetInstance()->SetEnabled(false);
587
588#define EXPECT_FIND_BE_(str) \
589 EXPECT_TRUE(FindNamePhase(str, "B")); \
590 EXPECT_TRUE(FindNamePhase(str, "E"))
591#define EXPECT_NOT_FIND_BE_(str) \
592 EXPECT_FALSE(FindNamePhase(str, "B")); \
593 EXPECT_FALSE(FindNamePhase(str, "E"))
594
595 EXPECT_FIND_BE_("threshold 100");
596 EXPECT_FIND_BE_("threshold 1000");
597 EXPECT_FIND_BE_("threshold 10000");
598 EXPECT_NOT_FIND_BE_("threshold long1");
599 EXPECT_NOT_FIND_BE_("threshold long2");
600
601 EXPECT_NOT_FIND_BE_("2threshold10000");
602 EXPECT_FIND_BE_("nonthreshold1");
603
604 EXPECT_FIND_BE_("nonthreshold3");
605 EXPECT_FIND_BE_("3threshold100");
606 EXPECT_FIND_BE_("3threshold1000");
607 EXPECT_FIND_BE_("3threshold10000");
608 EXPECT_NOT_FIND_BE_("3thresholdlong1");
609 EXPECT_NOT_FIND_BE_("3thresholdlong2");
610
611 EXPECT_FIND_BE_("nonthreshold4");
612 EXPECT_FIND_BE_("4threshold100");
613 EXPECT_FIND_BE_("4threshold1000");
614 EXPECT_FIND_BE_("4threshold10000");
615 EXPECT_NOT_FIND_BE_("4thresholdlong1");
616 EXPECT_NOT_FIND_BE_("4thresholdlong2");
617}
618
jbates@chromium.org1f18e462011-09-07 02:56:24 +0900619// Test that static strings are not copied.
620TEST_F(TraceEventTestFixture, StaticStringVsString) {
621 ManualTestSetUp();
622 TraceLog* tracer = TraceLog::GetInstance();
623 // Make sure old events are flushed:
624 tracer->SetEnabled(false);
625 EXPECT_EQ(0u, tracer->GetEventsSize());
626
627 {
628 tracer->SetEnabled(true);
629 // Test that string arguments are copied.
630 TRACE_EVENT2("cat", "name1",
631 "arg1", std::string("argval"), "arg2", std::string("argval"));
632 // Test that static TRACE_STR_COPY string arguments are copied.
633 TRACE_EVENT2("cat", "name2",
634 "arg1", TRACE_STR_COPY("argval"),
635 "arg2", TRACE_STR_COPY("argval"));
636 size_t num_events = tracer->GetEventsSize();
637 EXPECT_GT(num_events, 1u);
638 const TraceEvent& event1 = tracer->GetEventAt(num_events - 2);
639 const TraceEvent& event2 = tracer->GetEventAt(num_events - 1);
640 EXPECT_STREQ("name1", event1.name());
641 EXPECT_STREQ("name2", event2.name());
642 EXPECT_TRUE(event1.parameter_copy_storage() != NULL);
643 EXPECT_TRUE(event2.parameter_copy_storage() != NULL);
644 EXPECT_GT(event1.parameter_copy_storage()->size(), 0u);
645 EXPECT_GT(event2.parameter_copy_storage()->size(), 0u);
646 tracer->SetEnabled(false);
647 }
648
649 {
650 tracer->SetEnabled(true);
651 // Test that static literal string arguments are not copied.
652 TRACE_EVENT2("cat", "name1",
653 "arg1", "argval", "arg2", "argval");
654 // Test that static TRACE_STR_COPY NULL string arguments are not copied.
655 const char* str1 = NULL;
656 const char* str2 = NULL;
657 TRACE_EVENT2("cat", "name2",
658 "arg1", TRACE_STR_COPY(str1),
659 "arg2", TRACE_STR_COPY(str2));
660 size_t num_events = tracer->GetEventsSize();
661 EXPECT_GT(num_events, 1u);
662 const TraceEvent& event1 = tracer->GetEventAt(num_events - 2);
663 const TraceEvent& event2 = tracer->GetEventAt(num_events - 1);
664 EXPECT_STREQ("name1", event1.name());
665 EXPECT_STREQ("name2", event2.name());
666 EXPECT_TRUE(event1.parameter_copy_storage() == NULL);
667 EXPECT_TRUE(event2.parameter_copy_storage() == NULL);
668 tracer->SetEnabled(false);
669 }
670}
671
scheib@chromium.org603f46e2011-05-10 11:23:58 +0900672// Test that data sent from other threads is gathered
673TEST_F(TraceEventTestFixture, DataCapturedOnThread) {
674 ManualTestSetUp();
675 TraceLog::GetInstance()->SetEnabled(true);
676
677 Thread thread("1");
678 WaitableEvent task_complete_event(false, false);
679 thread.Start();
680
681 thread.message_loop()->PostTask(
nduca@chromium.org6d048772011-08-10 00:16:25 +0900682 FROM_HERE, NewRunnableFunction(&TraceWithAllMacroVariants,
scheib@chromium.org603f46e2011-05-10 11:23:58 +0900683 &task_complete_event));
684 task_complete_event.Wait();
685
686 TraceLog::GetInstance()->SetEnabled(false);
687 thread.Stop();
nduca@chromium.org6d048772011-08-10 00:16:25 +0900688 ValidateAllTraceMacrosCreatedData(trace_parsed_, trace_string_);
scheib@chromium.org603f46e2011-05-10 11:23:58 +0900689}
690
scheib@chromium.org603f46e2011-05-10 11:23:58 +0900691// Test that data sent from multiple threads is gathered
692TEST_F(TraceEventTestFixture, DataCapturedManyThreads) {
693 ManualTestSetUp();
694 TraceLog::GetInstance()->SetEnabled(true);
695
696 const int num_threads = 4;
697 const int num_events = 4000;
698 Thread* threads[num_threads];
699 WaitableEvent* task_complete_events[num_threads];
700 for (int i = 0; i < num_threads; i++) {
701 threads[i] = new Thread(StringPrintf("Thread %d", i).c_str());
702 task_complete_events[i] = new WaitableEvent(false, false);
703 threads[i]->Start();
704 threads[i]->message_loop()->PostTask(
nduca@chromium.org6d048772011-08-10 00:16:25 +0900705 FROM_HERE, NewRunnableFunction(&TraceManyInstantEvents,
scheib@chromium.org603f46e2011-05-10 11:23:58 +0900706 i, num_events, task_complete_events[i]));
707 }
708
709 for (int i = 0; i < num_threads; i++) {
710 task_complete_events[i]->Wait();
711 }
712
713 TraceLog::GetInstance()->SetEnabled(false);
714
715 for (int i = 0; i < num_threads; i++) {
716 threads[i]->Stop();
717 delete threads[i];
718 delete task_complete_events[i];
719 }
720
nduca@chromium.org6d048772011-08-10 00:16:25 +0900721 ValidateInstantEventPresentOnEveryThread(trace_parsed_, trace_string_,
722 num_threads, num_events);
scheib@chromium.org603f46e2011-05-10 11:23:58 +0900723}
724
nduca@chromium.org6d048772011-08-10 00:16:25 +0900725// Test that thread and process names show up in the trace
726TEST_F(TraceEventTestFixture, ThreadNames) {
727 ManualTestSetUp();
728
729 // Create threads before we enable tracing to make sure
730 // that tracelog still captures them.
731 const int num_threads = 4;
732 const int num_events = 10;
733 Thread* threads[num_threads];
734 PlatformThreadId thread_ids[num_threads];
735 for (int i = 0; i < num_threads; i++)
736 threads[i] = new Thread(StringPrintf("Thread %d", i).c_str());
737
738 // Enable tracing.
739 TraceLog::GetInstance()->SetEnabled(true);
740
741 // Now run some trace code on these threads.
742 WaitableEvent* task_complete_events[num_threads];
743 for (int i = 0; i < num_threads; i++) {
744 task_complete_events[i] = new WaitableEvent(false, false);
745 threads[i]->Start();
746 thread_ids[i] = threads[i]->thread_id();
747 threads[i]->message_loop()->PostTask(
748 FROM_HERE, NewRunnableFunction(&TraceManyInstantEvents,
749 i, num_events, task_complete_events[i]));
750 }
751 for (int i = 0; i < num_threads; i++) {
752 task_complete_events[i]->Wait();
753 }
754
755 // Shut things down.
756 TraceLog::GetInstance()->SetEnabled(false);
757 for (int i = 0; i < num_threads; i++) {
758 threads[i]->Stop();
759 delete threads[i];
760 delete task_complete_events[i];
761 }
762
763 std::string tmp;
764 int tmp_int;
765 DictionaryValue* item;
766
767 // Make sure we get thread name metadata.
768 // Note, the test suite may have created a ton of threads.
769 // So, we'll have thread names for threads we didn't create.
770 std::vector<DictionaryValue*> items =
771 FindTraceEntries(trace_parsed_, "thread_name");
772 for (int i = 0; i < static_cast<int>(items.size()); i++) {
773 item = items[i];
774 EXPECT_TRUE(item);
775 EXPECT_TRUE(item->GetInteger("tid", &tmp_int));
776
777 // See if this thread name is one of the threads we just created
778 for (int j = 0; j < num_threads; j++) {
779 if(static_cast<int>(thread_ids[j]) != tmp_int)
780 continue;
781
782 std::string expected_name = StringPrintf("Thread %d", j).c_str();
783 EXPECT_TRUE(item->GetString("ph", &tmp) && tmp == "M");
784 EXPECT_TRUE(item->GetInteger("pid", &tmp_int) &&
785 tmp_int == static_cast<int>(base::GetCurrentProcId()));
786 EXPECT_TRUE(item->GetString("args.name", &tmp) &&
787 tmp == expected_name);
788 }
789 }
scheib@chromium.org603f46e2011-05-10 11:23:58 +0900790}
791
nduca@chromium.org6d048772011-08-10 00:16:25 +0900792
scheib@chromium.org603f46e2011-05-10 11:23:58 +0900793// Test trace calls made after tracing singleton shut down.
794//
795// The singleton is destroyed by our base::AtExitManager, but there can be
796// code still executing as the C++ static objects are destroyed. This test
797// forces the singleton to destroy early, and intentinally makes trace calls
798// afterwards.
799TEST_F(TraceEventTestFixture, AtExit) {
800 // Repeat this test a few times. Besides just showing robustness, it also
801 // allows us to test that events at shutdown do not appear with valid events
802 // recorded after the system is started again.
803 for (int i = 0; i < 4; i++) {
804 // Scope to contain the then destroy the TraceLog singleton.
805 {
806 base::ShadowingAtExitManager exit_manager_will_destroy_singletons;
807
808 // Setup TraceLog singleton inside this test's exit manager scope
809 // so that it will be destroyed when this scope closes.
810 ManualTestSetUp();
811
812 TRACE_EVENT_INSTANT0("all", "not recorded; system not enabled");
813
814 TraceLog::GetInstance()->SetEnabled(true);
815
816 TRACE_EVENT_INSTANT0("all", "is recorded 1; system has been enabled");
817 // Trace calls that will cache pointers to categories; they're valid here
818 TraceCallsWithCachedCategoryPointersPointers(
819 "is recorded 2; system has been enabled");
820
821 TraceLog::GetInstance()->SetEnabled(false);
822 } // scope to destroy singleton
823 ASSERT_FALSE(TraceLog::GetInstance());
824
825 // Now that singleton is destroyed, check what trace events were recorded
826 DictionaryValue* item = NULL;
827 ListValue& trace_parsed = trace_parsed_;
828 EXPECT_FIND_("is recorded 1");
829 EXPECT_FIND_("is recorded 2");
830 EXPECT_NOT_FIND_("not recorded");
831
832 // Make additional trace event calls on the shutdown system. They should
833 // all pass cleanly, but the data not be recorded. We'll verify that next
834 // time around the loop (the only way to flush the trace buffers).
835 TRACE_EVENT_BEGIN_ETW("not recorded; system shutdown", 0, NULL);
836 TRACE_EVENT_END_ETW("not recorded; system shutdown", 0, NULL);
837 TRACE_EVENT_INSTANT_ETW("not recorded; system shutdown", 0, NULL);
838 TRACE_EVENT0("all", "not recorded; system shutdown");
839 TRACE_EVENT_INSTANT0("all", "not recorded; system shutdown");
840 TRACE_EVENT_BEGIN0("all", "not recorded; system shutdown");
841 TRACE_EVENT_END0("all", "not recorded; system shutdown");
842
843 TRACE_EVENT0("new category 0!", "not recorded; system shutdown");
844 TRACE_EVENT_INSTANT0("new category 1!", "not recorded; system shutdown");
845 TRACE_EVENT_BEGIN0("new category 2!", "not recorded; system shutdown");
846 TRACE_EVENT_END0("new category 3!", "not recorded; system shutdown");
847
848 // Cached categories should be safe to check, and still disable traces
849 TraceCallsWithCachedCategoryPointersPointers(
850 "not recorded; system shutdown");
851 }
852}
853
joth@chromium.org113de992011-07-21 21:28:59 +0900854TEST_F(TraceEventTestFixture, NormallyNoDeepCopy) {
855 // Test that the TRACE_EVENT macros do not deep-copy their string. If they
856 // do so it may indicate a performance regression, but more-over it would
857 // make the DEEP_COPY overloads redundant.
858 ManualTestSetUp();
859
860 std::string name_string("event name");
861
862 TraceLog::GetInstance()->SetEnabled(true);
863 TRACE_EVENT_INSTANT0("category", name_string.c_str());
864
865 // Modify the string in place (a wholesale reassignment may leave the old
866 // string intact on the heap).
867 name_string[0] = '@';
868
869 TraceLog::GetInstance()->SetEnabled(false);
870
871 EXPECT_FALSE(FindTraceEntry(trace_parsed_, "event name"));
872 EXPECT_TRUE(FindTraceEntry(trace_parsed_, name_string.c_str()));
873}
874
875TEST_F(TraceEventTestFixture, DeepCopy) {
876 ManualTestSetUp();
877
878 static const char kOriginalName1[] = "name1";
879 static const char kOriginalName2[] = "name2";
880 static const char kOriginalName3[] = "name3";
881 std::string name1(kOriginalName1);
882 std::string name2(kOriginalName2);
883 std::string name3(kOriginalName3);
884 std::string arg1("arg1");
885 std::string arg2("arg2");
886 std::string val1("val1");
887 std::string val2("val2");
888
889 TraceLog::GetInstance()->SetEnabled(true);
890 TRACE_EVENT_COPY_INSTANT0("category", name1.c_str());
891 TRACE_EVENT_COPY_BEGIN1("category", name2.c_str(),
892 arg1.c_str(), 5);
893 TRACE_EVENT_COPY_END2("category", name3.c_str(),
jbates@chromium.org1f18e462011-09-07 02:56:24 +0900894 arg1.c_str(), val1,
895 arg2.c_str(), val2);
joth@chromium.org113de992011-07-21 21:28:59 +0900896
897 // As per NormallyNoDeepCopy, modify the strings in place.
898 name1[0] = name2[0] = name3[0] = arg1[0] = arg2[0] = val1[0] = val2[0] = '@';
899
900 TraceLog::GetInstance()->SetEnabled(false);
901
902 EXPECT_FALSE(FindTraceEntry(trace_parsed_, name1.c_str()));
903 EXPECT_FALSE(FindTraceEntry(trace_parsed_, name2.c_str()));
904 EXPECT_FALSE(FindTraceEntry(trace_parsed_, name3.c_str()));
905
906 DictionaryValue* entry1 = FindTraceEntry(trace_parsed_, kOriginalName1);
907 DictionaryValue* entry2 = FindTraceEntry(trace_parsed_, kOriginalName2);
908 DictionaryValue* entry3 = FindTraceEntry(trace_parsed_, kOriginalName3);
909 ASSERT_TRUE(entry1);
910 ASSERT_TRUE(entry2);
911 ASSERT_TRUE(entry3);
912
913 int i;
914 EXPECT_FALSE(entry2->GetInteger("args.@rg1", &i));
915 EXPECT_TRUE(entry2->GetInteger("args.arg1", &i));
916 EXPECT_EQ(5, i);
917
918 std::string s;
919 EXPECT_TRUE(entry3->GetString("args.arg1", &s));
920 EXPECT_EQ("val1", s);
921 EXPECT_TRUE(entry3->GetString("args.arg2", &s));
922 EXPECT_EQ("val2", s);
923}
924
scheib@chromium.org603f46e2011-05-10 11:23:58 +0900925} // namespace debug
926} // namespace base