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

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

Powered by Google App Engine
This is Rietveld 408576698