Line data Source code
1 : // Copyright 2015 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 <stdlib.h>
5 : #include <string.h>
6 :
7 : #include "src/v8.h"
8 :
9 : #include "test/cctest/cctest.h"
10 :
11 : #include "src/tracing/trace-event.h"
12 :
13 : #define GET_TRACE_OBJECTS_LIST platform.GetMockTraceObjects()
14 :
15 : #define GET_TRACE_OBJECT(Index) GET_TRACE_OBJECTS_LIST->at(Index)
16 :
17 :
18 : struct MockTraceObject {
19 : char phase;
20 : std::string name;
21 : uint64_t id;
22 : uint64_t bind_id;
23 : int num_args;
24 : unsigned int flags;
25 : int64_t timestamp;
26 : MockTraceObject(char phase, std::string name, uint64_t id, uint64_t bind_id,
27 : int num_args, int flags, int64_t timestamp)
28 : : phase(phase),
29 : name(name),
30 : id(id),
31 : bind_id(bind_id),
32 : num_args(num_args),
33 : flags(flags),
34 140 : timestamp(timestamp) {}
35 : };
36 :
37 : typedef std::vector<MockTraceObject*> MockTraceObjectList;
38 :
39 : class MockTracingController : public v8::TracingController {
40 : public:
41 55 : MockTracingController() = default;
42 55 : ~MockTracingController() override {
43 390 : for (size_t i = 0; i < trace_object_list_.size(); ++i) {
44 475 : delete trace_object_list_[i];
45 : }
46 : trace_object_list_.clear();
47 55 : }
48 :
49 115 : uint64_t AddTraceEvent(
50 : char phase, const uint8_t* category_enabled_flag, const char* name,
51 : const char* scope, uint64_t id, uint64_t bind_id, int num_args,
52 : const char** arg_names, const uint8_t* arg_types,
53 : const uint64_t* arg_values,
54 : std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables,
55 : unsigned int flags) override {
56 : return AddTraceEventWithTimestamp(
57 : phase, category_enabled_flag, name, scope, id, bind_id, num_args,
58 115 : arg_names, arg_types, arg_values, arg_convertables, flags, 0);
59 : }
60 :
61 140 : uint64_t AddTraceEventWithTimestamp(
62 : char phase, const uint8_t* category_enabled_flag, const char* name,
63 : const char* scope, uint64_t id, uint64_t bind_id, int num_args,
64 : const char** arg_names, const uint8_t* arg_types,
65 : const uint64_t* arg_values,
66 : std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables,
67 : unsigned int flags, int64_t timestamp) override {
68 : MockTraceObject* to = new MockTraceObject(
69 420 : phase, std::string(name), id, bind_id, num_args, flags, timestamp);
70 140 : trace_object_list_.push_back(to);
71 140 : return 0;
72 : }
73 :
74 35 : void UpdateTraceEventDuration(const uint8_t* category_enabled_flag,
75 35 : const char* name, uint64_t handle) override {}
76 :
77 180 : const uint8_t* GetCategoryGroupEnabled(const char* name) override {
78 180 : if (strncmp(name, "v8-cat", 6)) {
79 : static uint8_t no = 0;
80 : return &no;
81 : } else {
82 : static uint8_t yes = 0x7;
83 150 : return &yes;
84 : }
85 : }
86 :
87 : MockTraceObjectList* GetMockTraceObjects() { return &trace_object_list_; }
88 :
89 : private:
90 : MockTraceObjectList trace_object_list_;
91 :
92 : DISALLOW_COPY_AND_ASSIGN(MockTracingController);
93 : };
94 :
95 : class MockTracingPlatform : public TestPlatform {
96 : public:
97 110 : MockTracingPlatform() {
98 : // Now that it's completely constructed, make this the current platform.
99 55 : i::V8::SetPlatformForTesting(this);
100 55 : }
101 110 : ~MockTracingPlatform() override = default;
102 :
103 355 : v8::TracingController* GetTracingController() override {
104 355 : return &tracing_controller_;
105 : }
106 :
107 : MockTraceObjectList* GetMockTraceObjects() {
108 : return tracing_controller_.GetMockTraceObjects();
109 : }
110 :
111 : private:
112 : MockTracingController tracing_controller_;
113 : };
114 :
115 :
116 25880 : TEST(TraceEventDisabledCategory) {
117 5 : MockTracingPlatform platform;
118 :
119 : // Disabled category, will not add events.
120 10 : TRACE_EVENT_BEGIN0("cat", "e1");
121 5 : TRACE_EVENT_END0("cat", "e1");
122 5 : CHECK(GET_TRACE_OBJECTS_LIST->empty());
123 5 : }
124 :
125 :
126 25880 : TEST(TraceEventNoArgs) {
127 5 : MockTracingPlatform platform;
128 :
129 : // Enabled category will add 2 events.
130 10 : TRACE_EVENT_BEGIN0("v8-cat", "e1");
131 10 : TRACE_EVENT_END0("v8-cat", "e1");
132 :
133 10 : CHECK_EQ(2, GET_TRACE_OBJECTS_LIST->size());
134 5 : CHECK_EQ('B', GET_TRACE_OBJECT(0)->phase);
135 10 : CHECK_EQ("e1", GET_TRACE_OBJECT(0)->name);
136 5 : CHECK_EQ(0, GET_TRACE_OBJECT(0)->num_args);
137 :
138 5 : CHECK_EQ('E', GET_TRACE_OBJECT(1)->phase);
139 10 : CHECK_EQ("e1", GET_TRACE_OBJECT(1)->name);
140 5 : CHECK_EQ(0, GET_TRACE_OBJECT(1)->num_args);
141 5 : }
142 :
143 :
144 25880 : TEST(TraceEventWithOneArg) {
145 5 : MockTracingPlatform platform;
146 :
147 15 : TRACE_EVENT_BEGIN1("v8-cat", "e1", "arg1", 42);
148 15 : TRACE_EVENT_END1("v8-cat", "e1", "arg1", 42);
149 10 : TRACE_EVENT_BEGIN1("v8-cat", "e2", "arg1", "abc");
150 10 : TRACE_EVENT_END1("v8-cat", "e2", "arg1", "abc");
151 :
152 10 : CHECK_EQ(4, GET_TRACE_OBJECTS_LIST->size());
153 :
154 5 : CHECK_EQ(1, GET_TRACE_OBJECT(0)->num_args);
155 5 : CHECK_EQ(1, GET_TRACE_OBJECT(1)->num_args);
156 5 : CHECK_EQ(1, GET_TRACE_OBJECT(2)->num_args);
157 5 : CHECK_EQ(1, GET_TRACE_OBJECT(3)->num_args);
158 5 : }
159 :
160 :
161 25880 : TEST(TraceEventWithTwoArgs) {
162 5 : MockTracingPlatform platform;
163 :
164 15 : TRACE_EVENT_BEGIN2("v8-cat", "e1", "arg1", 42, "arg2", "abc");
165 15 : TRACE_EVENT_END2("v8-cat", "e1", "arg1", 42, "arg2", "abc");
166 15 : TRACE_EVENT_BEGIN2("v8-cat", "e2", "arg1", "abc", "arg2", 43);
167 15 : TRACE_EVENT_END2("v8-cat", "e2", "arg1", "abc", "arg2", 43);
168 :
169 10 : CHECK_EQ(4, GET_TRACE_OBJECTS_LIST->size());
170 :
171 5 : CHECK_EQ(2, GET_TRACE_OBJECT(0)->num_args);
172 5 : CHECK_EQ(2, GET_TRACE_OBJECT(1)->num_args);
173 5 : CHECK_EQ(2, GET_TRACE_OBJECT(2)->num_args);
174 5 : CHECK_EQ(2, GET_TRACE_OBJECT(3)->num_args);
175 5 : }
176 :
177 :
178 25880 : TEST(ScopedTraceEvent) {
179 5 : MockTracingPlatform platform;
180 :
181 15 : { TRACE_EVENT0("v8-cat", "e"); }
182 :
183 10 : CHECK_EQ(1, GET_TRACE_OBJECTS_LIST->size());
184 5 : CHECK_EQ(0, GET_TRACE_OBJECT(0)->num_args);
185 :
186 15 : { TRACE_EVENT1("v8-cat", "e1", "arg1", "abc"); }
187 :
188 10 : CHECK_EQ(2, GET_TRACE_OBJECTS_LIST->size());
189 5 : CHECK_EQ(1, GET_TRACE_OBJECT(1)->num_args);
190 :
191 20 : { TRACE_EVENT2("v8-cat", "e1", "arg1", "abc", "arg2", 42); }
192 :
193 10 : CHECK_EQ(3, GET_TRACE_OBJECTS_LIST->size());
194 5 : CHECK_EQ(2, GET_TRACE_OBJECT(2)->num_args);
195 5 : }
196 :
197 :
198 25880 : TEST(TestEventWithFlow) {
199 5 : MockTracingPlatform platform;
200 :
201 : static uint64_t bind_id = 21;
202 : {
203 15 : TRACE_EVENT_WITH_FLOW0("v8-cat", "f1", bind_id, TRACE_EVENT_FLAG_FLOW_OUT);
204 : }
205 : {
206 10 : TRACE_EVENT_WITH_FLOW0(
207 : "v8-cat", "f2", bind_id,
208 5 : TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
209 : }
210 15 : { TRACE_EVENT_WITH_FLOW0("v8-cat", "f3", bind_id, TRACE_EVENT_FLAG_FLOW_IN); }
211 :
212 10 : CHECK_EQ(3, GET_TRACE_OBJECTS_LIST->size());
213 5 : CHECK_EQ(bind_id, GET_TRACE_OBJECT(0)->bind_id);
214 5 : CHECK_EQ(TRACE_EVENT_FLAG_FLOW_OUT, GET_TRACE_OBJECT(0)->flags);
215 5 : CHECK_EQ(bind_id, GET_TRACE_OBJECT(1)->bind_id);
216 5 : CHECK_EQ(TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
217 : GET_TRACE_OBJECT(1)->flags);
218 5 : CHECK_EQ(bind_id, GET_TRACE_OBJECT(2)->bind_id);
219 5 : CHECK_EQ(TRACE_EVENT_FLAG_FLOW_IN, GET_TRACE_OBJECT(2)->flags);
220 5 : }
221 :
222 :
223 25880 : TEST(TestEventWithId) {
224 5 : MockTracingPlatform platform;
225 :
226 : static uint64_t event_id = 21;
227 10 : TRACE_EVENT_ASYNC_BEGIN0("v8-cat", "a1", event_id);
228 10 : TRACE_EVENT_ASYNC_END0("v8-cat", "a1", event_id);
229 :
230 10 : CHECK_EQ(2, GET_TRACE_OBJECTS_LIST->size());
231 5 : CHECK_EQ(TRACE_EVENT_PHASE_ASYNC_BEGIN, GET_TRACE_OBJECT(0)->phase);
232 5 : CHECK_EQ(event_id, GET_TRACE_OBJECT(0)->id);
233 5 : CHECK_EQ(TRACE_EVENT_PHASE_ASYNC_END, GET_TRACE_OBJECT(1)->phase);
234 5 : CHECK_EQ(event_id, GET_TRACE_OBJECT(1)->id);
235 5 : }
236 :
237 25880 : TEST(TestEventInContext) {
238 5 : MockTracingPlatform platform;
239 :
240 : static uint64_t isolate_id = 0x20151021;
241 : {
242 45 : TRACE_EVENT_SCOPED_CONTEXT("v8-cat", "Isolate", isolate_id);
243 15 : TRACE_EVENT0("v8-cat", "e");
244 : }
245 :
246 10 : CHECK_EQ(3, GET_TRACE_OBJECTS_LIST->size());
247 5 : CHECK_EQ(TRACE_EVENT_PHASE_ENTER_CONTEXT, GET_TRACE_OBJECT(0)->phase);
248 10 : CHECK_EQ("Isolate", GET_TRACE_OBJECT(0)->name);
249 5 : CHECK_EQ(isolate_id, GET_TRACE_OBJECT(0)->id);
250 5 : CHECK_EQ(TRACE_EVENT_PHASE_COMPLETE, GET_TRACE_OBJECT(1)->phase);
251 10 : CHECK_EQ("e", GET_TRACE_OBJECT(1)->name);
252 5 : CHECK_EQ(TRACE_EVENT_PHASE_LEAVE_CONTEXT, GET_TRACE_OBJECT(2)->phase);
253 10 : CHECK_EQ("Isolate", GET_TRACE_OBJECT(2)->name);
254 5 : CHECK_EQ(isolate_id, GET_TRACE_OBJECT(2)->id);
255 5 : }
256 :
257 25880 : TEST(TestEventWithTimestamp) {
258 5 : MockTracingPlatform platform;
259 :
260 10 : TRACE_EVENT_INSTANT_WITH_TIMESTAMP0("v8-cat", "0arg",
261 : TRACE_EVENT_SCOPE_GLOBAL, 1729);
262 15 : TRACE_EVENT_INSTANT_WITH_TIMESTAMP1("v8-cat", "1arg",
263 : TRACE_EVENT_SCOPE_GLOBAL, 4104, "val", 1);
264 15 : TRACE_EVENT_MARK_WITH_TIMESTAMP2("v8-cat", "mark", 13832, "a", 1, "b", 2);
265 :
266 10 : TRACE_EVENT_COPY_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0("v8-cat", "begin", 5,
267 : 20683);
268 10 : TRACE_EVENT_COPY_NESTABLE_ASYNC_END_WITH_TIMESTAMP0("v8-cat", "end", 5,
269 : 32832);
270 :
271 10 : CHECK_EQ(5, GET_TRACE_OBJECTS_LIST->size());
272 :
273 5 : CHECK_EQ(1729, GET_TRACE_OBJECT(0)->timestamp);
274 5 : CHECK_EQ(0, GET_TRACE_OBJECT(0)->num_args);
275 :
276 5 : CHECK_EQ(4104, GET_TRACE_OBJECT(1)->timestamp);
277 5 : CHECK_EQ(1, GET_TRACE_OBJECT(1)->num_args);
278 :
279 5 : CHECK_EQ(13832, GET_TRACE_OBJECT(2)->timestamp);
280 5 : CHECK_EQ(2, GET_TRACE_OBJECT(2)->num_args);
281 :
282 5 : CHECK_EQ(20683, GET_TRACE_OBJECT(3)->timestamp);
283 5 : CHECK_EQ(32832, GET_TRACE_OBJECT(4)->timestamp);
284 5 : }
285 :
286 25880 : TEST(BuiltinsIsTraceCategoryEnabled) {
287 5 : CcTest::InitializeVM();
288 5 : MockTracingPlatform platform;
289 :
290 5 : v8::Isolate* isolate = CcTest::isolate();
291 10 : v8::HandleScope handle_scope(isolate);
292 10 : LocalContext env;
293 :
294 5 : v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
295 5 : CHECK(!binding.IsEmpty());
296 :
297 : auto undefined = v8::Undefined(isolate);
298 : auto isTraceCategoryEnabled =
299 15 : binding->Get(env.local(), v8_str("isTraceCategoryEnabled"))
300 5 : .ToLocalChecked()
301 : .As<v8::Function>();
302 :
303 : {
304 : // Test with an enabled category
305 5 : v8::Local<v8::Value> argv[] = {v8_str("v8-cat")};
306 10 : auto result = isTraceCategoryEnabled->Call(env.local(), undefined, 1, argv)
307 5 : .ToLocalChecked()
308 : .As<v8::Boolean>();
309 :
310 5 : CHECK(result->BooleanValue(isolate));
311 : }
312 :
313 : {
314 : // Test with a disabled category
315 5 : v8::Local<v8::Value> argv[] = {v8_str("cat")};
316 10 : auto result = isTraceCategoryEnabled->Call(env.local(), undefined, 1, argv)
317 5 : .ToLocalChecked()
318 : .As<v8::Boolean>();
319 :
320 5 : CHECK(!result->BooleanValue(isolate));
321 : }
322 :
323 : {
324 : // Test with an enabled utf8 category
325 5 : v8::Local<v8::Value> argv[] = {v8_str("v8-cat\u20ac")};
326 10 : auto result = isTraceCategoryEnabled->Call(env.local(), undefined, 1, argv)
327 5 : .ToLocalChecked()
328 : .As<v8::Boolean>();
329 :
330 5 : CHECK(result->BooleanValue(isolate));
331 5 : }
332 5 : }
333 :
334 25880 : TEST(BuiltinsTrace) {
335 5 : CcTest::InitializeVM();
336 5 : MockTracingPlatform platform;
337 :
338 5 : v8::Isolate* isolate = CcTest::isolate();
339 10 : v8::HandleScope handle_scope(isolate);
340 5 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
341 10 : LocalContext env;
342 :
343 5 : v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
344 5 : CHECK(!binding.IsEmpty());
345 :
346 : auto undefined = v8::Undefined(isolate);
347 15 : auto trace = binding->Get(env.local(), v8_str("trace"))
348 5 : .ToLocalChecked()
349 : .As<v8::Function>();
350 :
351 : // Test with disabled category
352 : {
353 5 : v8::Local<v8::String> category = v8_str("cat");
354 5 : v8::Local<v8::String> name = v8_str("name");
355 : v8::Local<v8::Value> argv[] = {
356 : v8::Integer::New(isolate, 'b'), // phase
357 : category, name, v8::Integer::New(isolate, 0), // id
358 : undefined // data
359 10 : };
360 10 : auto result = trace->Call(env.local(), undefined, 5, argv)
361 5 : .ToLocalChecked()
362 : .As<v8::Boolean>();
363 :
364 5 : CHECK(!result->BooleanValue(isolate));
365 10 : CHECK_EQ(0, GET_TRACE_OBJECTS_LIST->size());
366 : }
367 :
368 : // Test with enabled category
369 : {
370 5 : v8::Local<v8::String> category = v8_str("v8-cat");
371 5 : v8::Local<v8::String> name = v8_str("name");
372 5 : v8::Local<v8::Object> data = v8::Object::New(isolate);
373 20 : data->Set(context, v8_str("foo"), v8_str("bar")).FromJust();
374 : v8::Local<v8::Value> argv[] = {
375 : v8::Integer::New(isolate, 'b'), // phase
376 : category, name, v8::Integer::New(isolate, 123), // id
377 : data // data arg
378 10 : };
379 10 : auto result = trace->Call(env.local(), undefined, 5, argv)
380 5 : .ToLocalChecked()
381 : .As<v8::Boolean>();
382 :
383 5 : CHECK(result->BooleanValue(isolate));
384 10 : CHECK_EQ(1, GET_TRACE_OBJECTS_LIST->size());
385 :
386 10 : CHECK_EQ(123, GET_TRACE_OBJECT(0)->id);
387 5 : CHECK_EQ('b', GET_TRACE_OBJECT(0)->phase);
388 10 : CHECK_EQ("name", GET_TRACE_OBJECT(0)->name);
389 5 : CHECK_EQ(1, GET_TRACE_OBJECT(0)->num_args);
390 : }
391 :
392 : // Test with enabled utf8 category
393 : {
394 5 : v8::Local<v8::String> category = v8_str("v8-cat\u20ac");
395 5 : v8::Local<v8::String> name = v8_str("name\u20ac");
396 5 : v8::Local<v8::Object> data = v8::Object::New(isolate);
397 20 : data->Set(context, v8_str("foo"), v8_str("bar")).FromJust();
398 : v8::Local<v8::Value> argv[] = {
399 : v8::Integer::New(isolate, 'b'), // phase
400 : category, name, v8::Integer::New(isolate, 123), // id
401 : data // data arg
402 10 : };
403 10 : auto result = trace->Call(env.local(), undefined, 5, argv)
404 5 : .ToLocalChecked()
405 : .As<v8::Boolean>();
406 :
407 5 : CHECK(result->BooleanValue(isolate));
408 10 : CHECK_EQ(2, GET_TRACE_OBJECTS_LIST->size());
409 :
410 10 : CHECK_EQ(123, GET_TRACE_OBJECT(1)->id);
411 5 : CHECK_EQ('b', GET_TRACE_OBJECT(1)->phase);
412 10 : CHECK_EQ("name\u20ac", GET_TRACE_OBJECT(1)->name);
413 5 : CHECK_EQ(1, GET_TRACE_OBJECT(1)->num_args);
414 5 : }
415 77630 : }
|