Line data Source code
1 : // Copyright 2016 the V8 project 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 : #include <limits>
5 :
6 : #include "include/libplatform/v8-tracing.h"
7 : #include "src/libplatform/default-platform.h"
8 : #include "src/tracing/trace-event.h"
9 : #include "test/cctest/cctest.h"
10 :
11 : namespace v8 {
12 : namespace platform {
13 : namespace tracing {
14 :
15 23724 : TEST(TestTraceConfig) {
16 6 : LocalContext env;
17 6 : TraceConfig* trace_config = new TraceConfig();
18 6 : trace_config->AddIncludedCategory("v8");
19 6 : trace_config->AddIncludedCategory(TRACE_DISABLED_BY_DEFAULT("v8.runtime"));
20 :
21 6 : CHECK_EQ(trace_config->IsSystraceEnabled(), false);
22 6 : CHECK_EQ(trace_config->IsArgumentFilterEnabled(), false);
23 6 : CHECK_EQ(trace_config->IsCategoryGroupEnabled("v8"), true);
24 12 : CHECK_EQ(trace_config->IsCategoryGroupEnabled("v8.cpu_profile"), false);
25 12 : CHECK_EQ(trace_config->IsCategoryGroupEnabled("v8.cpu_profile.hires"), false);
26 6 : CHECK_EQ(trace_config->IsCategoryGroupEnabled(
27 : TRACE_DISABLED_BY_DEFAULT("v8.runtime")),
28 : true);
29 6 : CHECK_EQ(trace_config->IsCategoryGroupEnabled("v8,v8.cpu_profile"), true);
30 6 : CHECK_EQ(
31 : trace_config->IsCategoryGroupEnabled("v8,disabled-by-default-v8.runtime"),
32 : true);
33 12 : CHECK_EQ(trace_config->IsCategoryGroupEnabled(
34 : "v8_cpu_profile,v8.cpu_profile.hires"),
35 : false);
36 :
37 12 : delete trace_config;
38 6 : }
39 :
40 23724 : TEST(TestTraceObject) {
41 : TraceObject trace_object;
42 6 : uint8_t category_enabled_flag = 41;
43 : trace_object.Initialize('X', &category_enabled_flag, "Test.Trace",
44 : "Test.Scope", 42, 123, 0, nullptr, nullptr, nullptr,
45 6 : nullptr, 0);
46 6 : CHECK_EQ('X', trace_object.phase());
47 6 : CHECK_EQ(category_enabled_flag, *trace_object.category_enabled_flag());
48 18 : CHECK_EQ(std::string("Test.Trace"), std::string(trace_object.name()));
49 18 : CHECK_EQ(std::string("Test.Scope"), std::string(trace_object.scope()));
50 6 : CHECK_EQ(0u, trace_object.duration());
51 6 : CHECK_EQ(0u, trace_object.cpu_duration());
52 6 : }
53 :
54 36 : class ConvertableToTraceFormatMock : public v8::ConvertableToTraceFormat {
55 : public:
56 18 : explicit ConvertableToTraceFormatMock(int value) : value_(value) {}
57 18 : void AppendAsTraceFormat(std::string* out) const override {
58 162 : *out += "[" + std::to_string(value_) + "," + std::to_string(value_) + "]";
59 18 : }
60 :
61 : private:
62 : int value_;
63 :
64 : DISALLOW_COPY_AND_ASSIGN(ConvertableToTraceFormatMock);
65 : };
66 :
67 54 : class MockTraceWriter : public TraceWriter {
68 : public:
69 402 : void AppendTraceEvent(TraceObject* trace_event) override {
70 804 : events_.push_back(trace_event->name());
71 402 : }
72 :
73 24 : void Flush() override {}
74 :
75 24 : std::vector<std::string> events() { return events_; }
76 :
77 : private:
78 : std::vector<std::string> events_;
79 : };
80 :
81 23724 : TEST(TestTraceBufferRingBuffer) {
82 : // We should be able to add kChunkSize * 2 + 1 trace events.
83 : const int HANDLES_COUNT = TraceBufferChunk::kChunkSize * 2 + 1;
84 6 : MockTraceWriter* writer = new MockTraceWriter();
85 : TraceBuffer* ring_buffer =
86 6 : TraceBuffer::CreateTraceBufferRingBuffer(2, writer);
87 780 : std::string names[HANDLES_COUNT];
88 774 : for (int i = 0; i < HANDLES_COUNT; ++i) {
89 2322 : names[i] = "Test.EventNo" + std::to_string(i);
90 : }
91 :
92 6 : std::vector<uint64_t> handles(HANDLES_COUNT);
93 6 : uint8_t category_enabled_flag = 41;
94 1560 : for (size_t i = 0; i < handles.size(); ++i) {
95 3870 : TraceObject* trace_object = ring_buffer->AddTraceEvent(&handles[i]);
96 774 : CHECK_NOT_NULL(trace_object);
97 : trace_object->Initialize('X', &category_enabled_flag, names[i].c_str(),
98 : "Test.Scope", 42, 123, 0, nullptr, nullptr,
99 1548 : nullptr, nullptr, 0);
100 1548 : trace_object = ring_buffer->GetEventByHandle(handles[i]);
101 774 : CHECK_NOT_NULL(trace_object);
102 774 : CHECK_EQ('X', trace_object->phase());
103 1548 : CHECK_EQ(names[i], std::string(trace_object->name()));
104 774 : CHECK_EQ(category_enabled_flag, *trace_object->category_enabled_flag());
105 : }
106 :
107 : // We should only be able to retrieve the last kChunkSize + 1.
108 384 : for (size_t i = 0; i < TraceBufferChunk::kChunkSize; ++i) {
109 768 : CHECK_NULL(ring_buffer->GetEventByHandle(handles[i]));
110 : }
111 :
112 786 : for (size_t i = TraceBufferChunk::kChunkSize; i < handles.size(); ++i) {
113 1950 : TraceObject* trace_object = ring_buffer->GetEventByHandle(handles[i]);
114 390 : CHECK_NOT_NULL(trace_object);
115 : // The object properties should be correct.
116 390 : CHECK_EQ('X', trace_object->phase());
117 780 : CHECK_EQ(names[i], std::string(trace_object->name()));
118 390 : CHECK_EQ(category_enabled_flag, *trace_object->category_enabled_flag());
119 : }
120 :
121 : // Check Flush(), that the writer wrote the last kChunkSize 1 event names.
122 6 : ring_buffer->Flush();
123 6 : auto events = writer->events();
124 12 : CHECK_EQ(TraceBufferChunk::kChunkSize + 1, events.size());
125 786 : for (size_t i = TraceBufferChunk::kChunkSize; i < handles.size(); ++i) {
126 1170 : CHECK_EQ(names[i], events[i - TraceBufferChunk::kChunkSize]);
127 : }
128 786 : delete ring_buffer;
129 6 : }
130 :
131 23724 : TEST(TestJSONTraceWriter) {
132 6 : std::ostringstream stream;
133 6 : v8::Platform* old_platform = i::V8::GetCurrentPlatform();
134 6 : v8::Platform* default_platform = v8::platform::CreateDefaultPlatform();
135 6 : i::V8::SetPlatformForTesting(default_platform);
136 : // Create a scope for the tracing controller to terminate the trace writer.
137 : {
138 6 : TracingController tracing_controller;
139 : static_cast<v8::platform::DefaultPlatform*>(default_platform)
140 6 : ->SetTracingController(&tracing_controller);
141 6 : TraceWriter* writer = TraceWriter::CreateJSONTraceWriter(stream);
142 :
143 : TraceBuffer* ring_buffer =
144 6 : TraceBuffer::CreateTraceBufferRingBuffer(1, writer);
145 6 : tracing_controller.Initialize(ring_buffer);
146 6 : TraceConfig* trace_config = new TraceConfig();
147 6 : trace_config->AddIncludedCategory("v8-cat");
148 6 : tracing_controller.StartTracing(trace_config);
149 :
150 6 : TraceObject trace_object;
151 : trace_object.InitializeForTesting(
152 : 'X', tracing_controller.GetCategoryGroupEnabled("v8-cat"), "Test0",
153 : v8::internal::tracing::kGlobalScope, 42, 123, 0, nullptr, nullptr,
154 6 : nullptr, nullptr, TRACE_EVENT_FLAG_HAS_ID, 11, 22, 100, 50, 33, 44);
155 6 : writer->AppendTraceEvent(&trace_object);
156 : trace_object.InitializeForTesting(
157 : 'Y', tracing_controller.GetCategoryGroupEnabled("v8-cat"), "Test1",
158 : v8::internal::tracing::kGlobalScope, 43, 456, 0, nullptr, nullptr,
159 6 : nullptr, nullptr, 0, 55, 66, 110, 55, 77, 88);
160 6 : writer->AppendTraceEvent(&trace_object);
161 12 : tracing_controller.StopTracing();
162 : }
163 :
164 : std::string trace_str = stream.str();
165 : std::string expected_trace_str =
166 : "{\"traceEvents\":[{\"pid\":11,\"tid\":22,\"ts\":100,\"tts\":50,"
167 : "\"ph\":\"X\",\"cat\":\"v8-cat\",\"name\":\"Test0\",\"dur\":33,"
168 : "\"tdur\":44,\"id\":\"0x2a\",\"args\":{}},{\"pid\":55,\"tid\":66,"
169 : "\"ts\":110,\"tts\":55,\"ph\":\"Y\",\"cat\":\"v8-cat\",\"name\":"
170 6 : "\"Test1\",\"dur\":77,\"tdur\":88,\"args\":{}}]}";
171 :
172 6 : CHECK_EQ(expected_trace_str, trace_str);
173 :
174 12 : i::V8::SetPlatformForTesting(old_platform);
175 6 : }
176 :
177 23724 : TEST(TestTracingController) {
178 6 : v8::Platform* old_platform = i::V8::GetCurrentPlatform();
179 6 : v8::Platform* default_platform = v8::platform::CreateDefaultPlatform();
180 6 : i::V8::SetPlatformForTesting(default_platform);
181 :
182 6 : TracingController tracing_controller;
183 : static_cast<v8::platform::DefaultPlatform*>(default_platform)
184 6 : ->SetTracingController(&tracing_controller);
185 :
186 6 : MockTraceWriter* writer = new MockTraceWriter();
187 : TraceBuffer* ring_buffer =
188 6 : TraceBuffer::CreateTraceBufferRingBuffer(1, writer);
189 6 : tracing_controller.Initialize(ring_buffer);
190 6 : TraceConfig* trace_config = new TraceConfig();
191 6 : trace_config->AddIncludedCategory("v8");
192 6 : tracing_controller.StartTracing(trace_config);
193 :
194 18 : TRACE_EVENT0("v8", "v8.Test");
195 : // cat category is not included in default config
196 18 : TRACE_EVENT0("cat", "v8.Test2");
197 18 : TRACE_EVENT0("v8", "v8.Test3");
198 6 : tracing_controller.StopTracing();
199 :
200 12 : CHECK_EQ(2u, writer->events().size());
201 12 : CHECK_EQ(std::string("v8.Test"), writer->events()[0]);
202 12 : CHECK_EQ(std::string("v8.Test3"), writer->events()[1]);
203 :
204 12 : i::V8::SetPlatformForTesting(old_platform);
205 6 : }
206 :
207 18 : void GetJSONStrings(std::vector<std::string>& ret, std::string str,
208 : std::string param, std::string start_delim,
209 : std::string end_delim) {
210 : size_t pos = str.find(param);
211 468 : while (pos != std::string::npos) {
212 432 : size_t start_pos = str.find(start_delim, pos + param.length());
213 432 : size_t end_pos = str.find(end_delim, start_pos + 1);
214 432 : CHECK_NE(start_pos, std::string::npos);
215 432 : CHECK_NE(end_pos, std::string::npos);
216 864 : ret.push_back(str.substr(start_pos + 1, end_pos - start_pos - 1));
217 432 : pos = str.find(param, pos + 1);
218 : }
219 18 : }
220 :
221 23724 : TEST(TestTracingControllerMultipleArgsAndCopy) {
222 6 : std::ostringstream stream;
223 6 : v8::Platform* old_platform = i::V8::GetCurrentPlatform();
224 6 : v8::Platform* default_platform = v8::platform::CreateDefaultPlatform();
225 6 : i::V8::SetPlatformForTesting(default_platform);
226 :
227 6 : uint64_t aa = 11;
228 6 : unsigned int bb = 22;
229 6 : uint16_t cc = 33;
230 6 : unsigned char dd = 44;
231 6 : int64_t ee = -55;
232 6 : int ff = -66;
233 6 : int16_t gg = -77;
234 6 : signed char hh = -88;
235 6 : bool ii1 = true;
236 6 : bool ii2 = false;
237 6 : double jj1 = 99.0;
238 6 : double jj2 = 1e100;
239 6 : double jj3 = std::numeric_limits<double>::quiet_NaN();
240 6 : double jj4 = std::numeric_limits<double>::infinity();
241 6 : double jj5 = -std::numeric_limits<double>::infinity();
242 6 : void* kk = &aa;
243 6 : const char* ll = "100";
244 6 : std::string mm = "INIT";
245 6 : std::string mmm = "\"INIT\"";
246 :
247 : // Create a scope for the tracing controller to terminate the trace writer.
248 : {
249 6 : TracingController tracing_controller;
250 : static_cast<v8::platform::DefaultPlatform*>(default_platform)
251 6 : ->SetTracingController(&tracing_controller);
252 6 : TraceWriter* writer = TraceWriter::CreateJSONTraceWriter(stream);
253 :
254 : TraceBuffer* ring_buffer =
255 6 : TraceBuffer::CreateTraceBufferRingBuffer(1, writer);
256 6 : tracing_controller.Initialize(ring_buffer);
257 6 : TraceConfig* trace_config = new TraceConfig();
258 6 : trace_config->AddIncludedCategory("v8");
259 6 : tracing_controller.StartTracing(trace_config);
260 :
261 18 : TRACE_EVENT1("v8", "v8.Test.aa", "aa", aa);
262 18 : TRACE_EVENT1("v8", "v8.Test.bb", "bb", bb);
263 18 : TRACE_EVENT1("v8", "v8.Test.cc", "cc", cc);
264 18 : TRACE_EVENT1("v8", "v8.Test.dd", "dd", dd);
265 18 : TRACE_EVENT1("v8", "v8.Test.ee", "ee", ee);
266 18 : TRACE_EVENT1("v8", "v8.Test.ff", "ff", ff);
267 18 : TRACE_EVENT1("v8", "v8.Test.gg", "gg", gg);
268 18 : TRACE_EVENT1("v8", "v8.Test.hh", "hh", hh);
269 18 : TRACE_EVENT1("v8", "v8.Test.ii", "ii1", ii1);
270 18 : TRACE_EVENT1("v8", "v8.Test.ii", "ii2", ii2);
271 18 : TRACE_EVENT1("v8", "v8.Test.jj1", "jj1", jj1);
272 18 : TRACE_EVENT1("v8", "v8.Test.jj2", "jj2", jj2);
273 18 : TRACE_EVENT1("v8", "v8.Test.jj3", "jj3", jj3);
274 18 : TRACE_EVENT1("v8", "v8.Test.jj4", "jj4", jj4);
275 18 : TRACE_EVENT1("v8", "v8.Test.jj5", "jj5", jj5);
276 18 : TRACE_EVENT1("v8", "v8.Test.kk", "kk", kk);
277 18 : TRACE_EVENT1("v8", "v8.Test.ll", "ll", ll);
278 24 : TRACE_EVENT1("v8", "v8.Test.mm", "mm", TRACE_STR_COPY(mmm.c_str()));
279 :
280 18 : TRACE_EVENT2("v8", "v8.Test2.1", "aa", aa, "ll", ll);
281 24 : TRACE_EVENT2("v8", "v8.Test2.2", "mm1", TRACE_STR_COPY(mm.c_str()), "mm2",
282 : TRACE_STR_COPY(mmm.c_str()));
283 :
284 : // Check copies are correct.
285 12 : TRACE_EVENT_COPY_INSTANT0("v8", mm.c_str(), TRACE_EVENT_SCOPE_THREAD);
286 30 : TRACE_EVENT_COPY_INSTANT2("v8", mm.c_str(), TRACE_EVENT_SCOPE_THREAD, "mm1",
287 : mm.c_str(), "mm2", mmm.c_str());
288 : mm = "CHANGED";
289 : mmm = "CHANGED";
290 :
291 24 : TRACE_EVENT_INSTANT1("v8", "v8.Test", TRACE_EVENT_SCOPE_THREAD, "a1",
292 : new ConvertableToTraceFormatMock(42));
293 : std::unique_ptr<ConvertableToTraceFormatMock> trace_event_arg(
294 6 : new ConvertableToTraceFormatMock(42));
295 24 : TRACE_EVENT_INSTANT2("v8", "v8.Test", TRACE_EVENT_SCOPE_THREAD, "a1",
296 : std::move(trace_event_arg), "a2",
297 : new ConvertableToTraceFormatMock(123));
298 :
299 12 : tracing_controller.StopTracing();
300 : }
301 :
302 : std::string trace_str = stream.str();
303 :
304 6 : std::vector<std::string> all_args, all_names, all_cats;
305 30 : GetJSONStrings(all_args, trace_str, "\"args\"", "{", "}");
306 30 : GetJSONStrings(all_names, trace_str, "\"name\"", "\"", "\"");
307 30 : GetJSONStrings(all_cats, trace_str, "\"cat\"", "\"", "\"");
308 :
309 12 : CHECK_EQ(all_args.size(), 24u);
310 6 : CHECK_EQ(all_args[0], "\"aa\":11");
311 12 : CHECK_EQ(all_args[1], "\"bb\":22");
312 12 : CHECK_EQ(all_args[2], "\"cc\":33");
313 12 : CHECK_EQ(all_args[3], "\"dd\":44");
314 12 : CHECK_EQ(all_args[4], "\"ee\":-55");
315 12 : CHECK_EQ(all_args[5], "\"ff\":-66");
316 12 : CHECK_EQ(all_args[6], "\"gg\":-77");
317 12 : CHECK_EQ(all_args[7], "\"hh\":-88");
318 12 : CHECK_EQ(all_args[8], "\"ii1\":true");
319 12 : CHECK_EQ(all_args[9], "\"ii2\":false");
320 12 : CHECK_EQ(all_args[10], "\"jj1\":99.0");
321 12 : CHECK_EQ(all_args[11], "\"jj2\":1e+100");
322 12 : CHECK_EQ(all_args[12], "\"jj3\":\"NaN\"");
323 12 : CHECK_EQ(all_args[13], "\"jj4\":\"Infinity\"");
324 12 : CHECK_EQ(all_args[14], "\"jj5\":\"-Infinity\"");
325 12 : std::ostringstream pointer_stream;
326 12 : pointer_stream << "\"kk\":\"" << &aa << "\"";
327 12 : CHECK_EQ(all_args[15], pointer_stream.str());
328 12 : CHECK_EQ(all_args[16], "\"ll\":\"100\"");
329 12 : CHECK_EQ(all_args[17], "\"mm\":\"\\\"INIT\\\"\"");
330 :
331 12 : CHECK_EQ(all_names[18], "v8.Test2.1");
332 12 : CHECK_EQ(all_args[18], "\"aa\":11,\"ll\":\"100\"");
333 12 : CHECK_EQ(all_args[19], "\"mm1\":\"INIT\",\"mm2\":\"\\\"INIT\\\"\"");
334 :
335 12 : CHECK_EQ(all_names[20], "INIT");
336 12 : CHECK_EQ(all_names[21], "INIT");
337 12 : CHECK_EQ(all_args[21], "\"mm1\":\"INIT\",\"mm2\":\"\\\"INIT\\\"\"");
338 12 : CHECK_EQ(all_args[22], "\"a1\":[42,42]");
339 12 : CHECK_EQ(all_args[23], "\"a1\":[42,42],\"a2\":[123,123]");
340 :
341 12 : i::V8::SetPlatformForTesting(old_platform);
342 6 : }
343 :
344 : namespace {
345 :
346 12 : class TraceStateObserverImpl : public TracingController::TraceStateObserver {
347 : public:
348 12 : void OnTraceEnabled() override { ++enabled_count; }
349 6 : void OnTraceDisabled() override { ++disabled_count; }
350 :
351 : int enabled_count = 0;
352 : int disabled_count = 0;
353 : };
354 :
355 : } // namespace
356 :
357 23724 : TEST(TracingObservers) {
358 6 : v8::Platform* old_platform = i::V8::GetCurrentPlatform();
359 6 : v8::Platform* default_platform = v8::platform::CreateDefaultPlatform();
360 6 : i::V8::SetPlatformForTesting(default_platform);
361 :
362 6 : v8::platform::tracing::TracingController tracing_controller;
363 : static_cast<v8::platform::DefaultPlatform*>(default_platform)
364 6 : ->SetTracingController(&tracing_controller);
365 6 : MockTraceWriter* writer = new MockTraceWriter();
366 : v8::platform::tracing::TraceBuffer* ring_buffer =
367 : v8::platform::tracing::TraceBuffer::CreateTraceBufferRingBuffer(1,
368 6 : writer);
369 6 : tracing_controller.Initialize(ring_buffer);
370 : v8::platform::tracing::TraceConfig* trace_config =
371 6 : new v8::platform::tracing::TraceConfig();
372 6 : trace_config->AddIncludedCategory("v8");
373 :
374 6 : TraceStateObserverImpl observer;
375 6 : tracing_controller.AddTraceStateObserver(&observer);
376 :
377 6 : CHECK_EQ(0, observer.enabled_count);
378 6 : CHECK_EQ(0, observer.disabled_count);
379 :
380 6 : tracing_controller.StartTracing(trace_config);
381 :
382 6 : CHECK_EQ(1, observer.enabled_count);
383 6 : CHECK_EQ(0, observer.disabled_count);
384 :
385 6 : TraceStateObserverImpl observer2;
386 6 : tracing_controller.AddTraceStateObserver(&observer2);
387 :
388 6 : CHECK_EQ(1, observer2.enabled_count);
389 6 : CHECK_EQ(0, observer2.disabled_count);
390 :
391 6 : tracing_controller.RemoveTraceStateObserver(&observer2);
392 :
393 6 : CHECK_EQ(1, observer2.enabled_count);
394 6 : CHECK_EQ(0, observer2.disabled_count);
395 :
396 6 : tracing_controller.StopTracing();
397 :
398 6 : CHECK_EQ(1, observer.enabled_count);
399 6 : CHECK_EQ(1, observer.disabled_count);
400 6 : CHECK_EQ(1, observer2.enabled_count);
401 6 : CHECK_EQ(0, observer2.disabled_count);
402 :
403 6 : tracing_controller.RemoveTraceStateObserver(&observer);
404 :
405 6 : CHECK_EQ(1, observer.enabled_count);
406 6 : CHECK_EQ(1, observer.disabled_count);
407 :
408 6 : trace_config = new v8::platform::tracing::TraceConfig();
409 6 : tracing_controller.StartTracing(trace_config);
410 6 : tracing_controller.StopTracing();
411 :
412 6 : CHECK_EQ(1, observer.enabled_count);
413 6 : CHECK_EQ(1, observer.disabled_count);
414 :
415 12 : i::V8::SetPlatformForTesting(old_platform);
416 6 : }
417 :
418 : } // namespace tracing
419 : } // namespace platform
420 71154 : } // namespace v8
|