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

Side by Side Diff: base/debug/trace_event_unittest.cc

Issue 6862002: Merge gpu_trace_event back into base/debug/trace_event (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Flaky test fixed, found race in my test Created 9 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 | Annotate | Revision Log
OLDNEW
(Empty)
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
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/stringprintf.h"
12 #include "base/synchronization/waitable_event.h"
13 #include "base/threading/thread.h"
14 #include "base/values.h"
15 #include "testing/gmock/include/gmock/gmock.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17
18 namespace base {
19 namespace debug {
20
21 namespace {
22
23 class TraceEventTestFixture : public testing::Test {
24 public:
25 void ManualTestSetUp();
26 void OnTraceDataCollected(TraceLog::RefCountedString* json_events_str);
27
28 std::string trace_string_;
29 ListValue trace_parsed_;
30
31 private:
32 // We want our singleton torn down after each test.
33 ShadowingAtExitManager at_exit_manager_;
34 };
35
36 void TraceEventTestFixture::ManualTestSetUp() {
37 TraceLog::Resurrect();
38 TraceLog* tracelog = TraceLog::GetInstance();
39 ASSERT_TRUE(tracelog);
40 ASSERT_FALSE(tracelog->IsEnabled());
41 tracelog->SetOutputCallback(
42 base::Bind(&TraceEventTestFixture::OnTraceDataCollected,
43 base::Unretained(this)));
44 }
45
46 void TraceEventTestFixture::OnTraceDataCollected(
47 TraceLog::RefCountedString* json_events_str) {
48 trace_string_ += json_events_str->data;
49
50 scoped_ptr<Value> root;
51 root.reset(base::JSONReader::Read(json_events_str->data, false));
52
53 ListValue* root_list = NULL;
54 ASSERT_TRUE(root.get());
55 ASSERT_TRUE(root->GetAsList(&root_list));
56
57 // Move items into our aggregate collection
58 while (root_list->GetSize()) {
59 Value* item = NULL;
60 root_list->Remove(0, &item);
61 trace_parsed_.Append(item);
62 }
63 }
64
65 bool IsStringInDict(const char* string_to_match, DictionaryValue* dict) {
66 for (DictionaryValue::key_iterator ikey = dict->begin_keys();
67 ikey != dict->end_keys(); ++ikey) {
68 Value* child = NULL;
69 if (!dict->GetWithoutPathExpansion(*ikey, &child))
70 continue;
71
72 if ((*ikey).find(string_to_match) != std::string::npos)
73 return true;
74
75 std::string value_str;
76 child->GetAsString(&value_str);
77 if (value_str.find(string_to_match) != std::string::npos)
78 return true;
79 }
80
81 // Recurse to test arguments
82 DictionaryValue* args_dict = NULL;
83 dict->GetDictionary("args", &args_dict);
84 if (args_dict)
85 return IsStringInDict(string_to_match, args_dict);
86
87 return false;
88 }
89
90 DictionaryValue* FindTraceEntry(const ListValue& trace_parsed,
91 const char *string_to_match,
92 DictionaryValue* match_after_this_item = NULL) {
93 // Scan all items
94 size_t trace_parsed_count = trace_parsed.GetSize();
95 for (size_t i = 0; i < trace_parsed_count; i++) {
96 Value* value = NULL;
97 trace_parsed.Get(i, &value);
98 if (match_after_this_item) {
99 if (value == match_after_this_item)
100 match_after_this_item = NULL;
101 continue;
102 }
103 if (!value || value->GetType() != Value::TYPE_DICTIONARY)
104 continue;
105 DictionaryValue* dict = static_cast<DictionaryValue*>(value);
106
107 if (IsStringInDict(string_to_match, dict))
108 return dict;
109 }
110 return NULL;
111 }
112
113 void DataCapturedCallTraces(WaitableEvent* task_complete_event) {
114 {
115 TRACE_EVENT_BEGIN_ETW("TRACE_EVENT_BEGIN_ETW call", 1122, "extrastring1");
116 TRACE_EVENT_END_ETW("TRACE_EVENT_END_ETW call", 3344, "extrastring2");
117 TRACE_EVENT_INSTANT_ETW("TRACE_EVENT_INSTANT_ETW call",
118 5566, "extrastring3");
119
120 TRACE_EVENT0("all", "TRACE_EVENT0 call");
121 TRACE_EVENT1("all", "TRACE_EVENT1 call", "name1", "value1");
122 TRACE_EVENT2("all", "TRACE_EVENT2 call",
123 "name1", "value1",
124 "name2", "value2");
125
126 TRACE_EVENT_INSTANT0("all", "TRACE_EVENT_INSTANT0 call");
127 TRACE_EVENT_INSTANT1("all", "TRACE_EVENT_INSTANT1 call", "name1", "value1");
128 TRACE_EVENT_INSTANT2("all", "TRACE_EVENT_INSTANT2 call",
129 "name1", "value1",
130 "name2", "value2");
131
132 TRACE_EVENT_BEGIN0("all", "TRACE_EVENT_BEGIN0 call");
133 TRACE_EVENT_BEGIN1("all", "TRACE_EVENT_BEGIN1 call", "name1", "value1");
134 TRACE_EVENT_BEGIN2("all", "TRACE_EVENT_BEGIN2 call",
135 "name1", "value1",
136 "name2", "value2");
137
138 TRACE_EVENT_END0("all", "TRACE_EVENT_END0 call");
139 TRACE_EVENT_END1("all", "TRACE_EVENT_END1 call", "name1", "value1");
140 TRACE_EVENT_END2("all", "TRACE_EVENT_END2 call",
141 "name1", "value1",
142 "name2", "value2");
143 } // Scope close causes TRACE_EVENT0 etc to send their END events.
144
145 if (task_complete_event)
146 task_complete_event->Signal();
147 }
148
149 void DataCapturedValidateTraces(const ListValue& trace_parsed,
150 const std::string& trace_string) {
151 DictionaryValue* item = NULL;
152
153 #define EXPECT_FIND_(string) \
154 EXPECT_TRUE((item = FindTraceEntry(trace_parsed, string)));
155 #define EXPECT_NOT_FIND_(string) \
156 EXPECT_FALSE((item = FindTraceEntry(trace_parsed, string)));
157 #define EXPECT_SUB_FIND_(string) \
158 if (item) EXPECT_TRUE((IsStringInDict(string, item)));
159
160 EXPECT_FIND_("ETW Trace Event");
161 EXPECT_FIND_("all");
162 EXPECT_FIND_("TRACE_EVENT_BEGIN_ETW call");
163 {
164 int int_val = 0;
165 EXPECT_TRUE(item && item->GetInteger("args.id", &int_val));
166 EXPECT_EQ(1122, int_val);
167 }
168 EXPECT_SUB_FIND_("extrastring1");
169 EXPECT_FIND_("TRACE_EVENT_END_ETW call");
170 EXPECT_FIND_("TRACE_EVENT_INSTANT_ETW call");
171 EXPECT_FIND_("TRACE_EVENT0 call");
172 {
173 std::string ph_begin;
174 std::string ph_end;
175 EXPECT_TRUE((item = FindTraceEntry(trace_parsed, "TRACE_EVENT0 call")));
176 EXPECT_TRUE((item && item->GetString("ph", &ph_begin)));
177 EXPECT_TRUE((item = FindTraceEntry(trace_parsed, "TRACE_EVENT0 call",
178 item)));
179 EXPECT_TRUE((item && item->GetString("ph", &ph_end)));
180 EXPECT_EQ("B", ph_begin);
181 EXPECT_EQ("E", ph_end);
182 }
183 EXPECT_FIND_("TRACE_EVENT1 call");
184 EXPECT_FIND_("TRACE_EVENT2 call");
185 EXPECT_SUB_FIND_("name1");
186 EXPECT_SUB_FIND_("value1");
187 EXPECT_SUB_FIND_("name2");
188 EXPECT_SUB_FIND_("value2");
189 EXPECT_FIND_("TRACE_EVENT_INSTANT0 call");
190 EXPECT_FIND_("TRACE_EVENT_INSTANT1 call");
191 EXPECT_FIND_("TRACE_EVENT_INSTANT2 call");
192 EXPECT_SUB_FIND_("name1");
193 EXPECT_SUB_FIND_("value1");
194 EXPECT_SUB_FIND_("name2");
195 EXPECT_SUB_FIND_("value2");
196 EXPECT_FIND_("TRACE_EVENT_BEGIN0 call");
197 EXPECT_FIND_("TRACE_EVENT_BEGIN1 call");
198 EXPECT_FIND_("TRACE_EVENT_BEGIN2 call");
199 EXPECT_SUB_FIND_("name1");
200 EXPECT_SUB_FIND_("value1");
201 EXPECT_SUB_FIND_("name2");
202 EXPECT_SUB_FIND_("value2");
203 EXPECT_FIND_("TRACE_EVENT_END0 call");
204 EXPECT_FIND_("TRACE_EVENT_END1 call");
205 EXPECT_FIND_("TRACE_EVENT_END2 call");
206 EXPECT_SUB_FIND_("name1");
207 EXPECT_SUB_FIND_("value1");
208 EXPECT_SUB_FIND_("name2");
209 EXPECT_SUB_FIND_("value2");
210 }
211
212 } // namespace
213
214 // Simple Test for emitting data and validating it was received.
215 TEST_F(TraceEventTestFixture, DataCaptured) {
216 ManualTestSetUp();
217 TraceLog::GetInstance()->SetEnabled(true);
218
219 DataCapturedCallTraces(NULL);
220
221 TraceLog::GetInstance()->SetEnabled(false);
222
223 DataCapturedValidateTraces(trace_parsed_, trace_string_);
224 }
225
226 // Test that data sent from other threads is gathered
227 TEST_F(TraceEventTestFixture, DataCapturedOnThread) {
228 ManualTestSetUp();
229 TraceLog::GetInstance()->SetEnabled(true);
230
231 Thread thread("1");
232 WaitableEvent task_complete_event(false, false);
233 thread.Start();
234
235 thread.message_loop()->PostTask(
236 FROM_HERE, NewRunnableFunction(&DataCapturedCallTraces,
237 &task_complete_event));
238 task_complete_event.Wait();
239
240 TraceLog::GetInstance()->SetEnabled(false);
241 thread.Stop();
242 DataCapturedValidateTraces(trace_parsed_, trace_string_);
243 }
244
245 namespace {
246
247 void DataCapturedCallManyTraces(int thread_id, int num_events,
248 WaitableEvent* task_complete_event) {
249 for (int i = 0; i < num_events; i++) {
250 TRACE_EVENT_INSTANT2("all", "multi thread event",
251 "thread", thread_id,
252 "event", i);
253 }
254
255 if (task_complete_event)
256 task_complete_event->Signal();
257 }
258
259 void DataCapturedValidateManyTraces(const ListValue& trace_parsed,
260 const std::string& trace_string,
261 int num_threads, int num_events) {
262 std::map<int, std::map<int, bool> > results;
263
264 size_t trace_parsed_count = trace_parsed.GetSize();
265 for (size_t i = 0; i < trace_parsed_count; i++) {
266 Value* value = NULL;
267 trace_parsed.Get(i, &value);
268 if (!value || value->GetType() != Value::TYPE_DICTIONARY)
269 continue;
270 DictionaryValue* dict = static_cast<DictionaryValue*>(value);
271 std::string name;
272 dict->GetString("name", &name);
273 if (name != "multi thread event")
274 continue;
275
276 int thread = 0;
277 int event = 0;
278 EXPECT_TRUE(dict->GetInteger("args.thread", &thread));
279 EXPECT_TRUE(dict->GetInteger("args.event", &event));
280 results[thread][event] = true;
281 }
282
283 EXPECT_FALSE(results[-1][-1]);
284 for (int thread = 0; thread < num_threads; thread++) {
285 for (int event = 0; event < num_events; event++) {
286 EXPECT_TRUE(results[thread][event]);
287 }
288 }
289 }
290
291 } // namespace
292
293 // Test that data sent from multiple threads is gathered
294 TEST_F(TraceEventTestFixture, DataCapturedManyThreads) {
295 ManualTestSetUp();
296 TraceLog::GetInstance()->SetEnabled(true);
297
298 const int num_threads = 4;
299 const int num_events = 4000;
300 Thread* threads[num_threads];
301 WaitableEvent* task_complete_events[num_threads];
302 for (int i = 0; i < num_threads; i++) {
303 threads[i] = new Thread(StringPrintf("Thread %d", i).c_str());
304 task_complete_events[i] = new WaitableEvent(false, false);
305 threads[i]->Start();
306 threads[i]->message_loop()->PostTask(
307 FROM_HERE, NewRunnableFunction(&DataCapturedCallManyTraces,
308 i, num_events, task_complete_events[i]));
309 }
310
311 for (int i = 0; i < num_threads; i++) {
312 task_complete_events[i]->Wait();
313 }
314
315 TraceLog::GetInstance()->SetEnabled(false);
316
317 for (int i = 0; i < num_threads; i++) {
318 threads[i]->Stop();
319 delete threads[i];
320 delete task_complete_events[i];
321 }
322
323 DataCapturedValidateManyTraces(trace_parsed_, trace_string_,
324 num_threads, num_events);
325 }
326
327 void TraceCallsWithCachedCategoryPointersPointers(const char* name_str) {
328 TRACE_EVENT0("category name1", name_str);
329 TRACE_EVENT_INSTANT0("category name2", name_str);
330 TRACE_EVENT_BEGIN0("category name3", name_str);
331 TRACE_EVENT_END0("category name4", name_str);
332 }
333
334 // Test trace calls made after tracing singleton shut down.
335 //
336 // The singleton is destroyed by our base::AtExitManager, but there can be
337 // code still executing as the C++ static objects are destroyed. This test
338 // forces the singleton to destroy early, and intentinally makes trace calls
339 // afterwards.
340 TEST_F(TraceEventTestFixture, AtExit) {
341 // Repeat this test a few times. Besides just showing robustness, it also
342 // allows us to test that events at shutdown do not appear with valid events
343 // recorded after the system is started again.
344 for (int i = 0; i < 4; i++) {
345 // Scope to contain the then destroy the TraceLog singleton
Sigurður Ásgeirsson 2011/05/04 18:58:08 supernit: comments start with a capital letter and
scheib 2011/05/05 00:06:37 Done.
346 {
347 base::ShadowingAtExitManager exit_manager_will_destroy_singletons;
348
349 // Setup TraceLog singleton inside this test's exit manager scope
350 // so that it will be destroyed when this scope closes.
351 ManualTestSetUp();
352
353 TRACE_EVENT_INSTANT0("all", "not recorded; system not enabled");
354
355 TraceLog::GetInstance()->SetEnabled(true);
356
357 TRACE_EVENT_INSTANT0("all", "is recorded 1; system has been enabled");
358 // Trace calls that will cache pointers to categories; they're valid here
359 TraceCallsWithCachedCategoryPointersPointers(
360 "is recorded 2; system has been enabled");
Sigurður Ásgeirsson 2011/05/04 18:58:08 nit: indent
scheib 2011/05/05 00:06:37 Done.
361
362 TraceLog::GetInstance()->SetEnabled(false);
363 } // scope to destroy singleton
364 ASSERT_FALSE(TraceLog::GetInstance());
365
366 // Now that singleton is destroyed, check what trace events were recorded
367 DictionaryValue* item = NULL;
368 ListValue& trace_parsed = trace_parsed_;
369 EXPECT_FIND_("is recorded 1");
370 EXPECT_FIND_("is recorded 2");
371 EXPECT_NOT_FIND_("not recorded");
372
373 // Make additional trace event calls on the shutdown system. They should
374 // all pass cleanly, but the data not be recorded. We'll verify that next
375 // time around the loop (the only way to flush the trace buffers).
376 TRACE_EVENT_BEGIN_ETW("not recorded; system shutdown", 0, NULL);
377 TRACE_EVENT_END_ETW("not recorded; system shutdown", 0, NULL);
378 TRACE_EVENT_INSTANT_ETW("not recorded; system shutdown", 0, NULL);
379 TRACE_EVENT0("all", "not recorded; system shutdown");
380 TRACE_EVENT_INSTANT0("all", "not recorded; system shutdown");
381 TRACE_EVENT_BEGIN0("all", "not recorded; system shutdown");
382 TRACE_EVENT_END0("all", "not recorded; system shutdown");
383
384 TRACE_EVENT0("new category 0!", "not recorded; system shutdown");
385 TRACE_EVENT_INSTANT0("new category 1!", "not recorded; system shutdown");
386 TRACE_EVENT_BEGIN0("new category 2!", "not recorded; system shutdown");
387 TRACE_EVENT_END0("new category 3!", "not recorded; system shutdown");
388
389 // Cached categories should be safe to check, and still disable traces
390 TraceCallsWithCachedCategoryPointersPointers(
391 "not recorded; system shutdown");
Sigurður Ásgeirsson 2011/05/04 18:58:08 nit: indent.
scheib 2011/05/05 00:06:37 Done.
392 }
393 }
394
395 } // namespace debug
396 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698