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 125 : 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 250 : timestamp(timestamp) {}
35 : };
36 :
37 : typedef std::vector<MockTraceObject*> MockTraceObjectList;
38 :
39 : class MockTracingController : public v8::TracingController {
40 : public:
41 50 : MockTracingController() = default;
42 100 : ~MockTracingController() override {
43 300 : for (size_t i = 0; i < trace_object_list_.size(); ++i) {
44 250 : delete trace_object_list_[i];
45 : }
46 : trace_object_list_.clear();
47 50 : }
48 :
49 100 : 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 100 : return AddTraceEventWithTimestamp(
57 : phase, category_enabled_flag, name, scope, id, bind_id, num_args,
58 200 : arg_names, arg_types, arg_values, arg_convertables, flags, 0);
59 : }
60 :
61 125 : 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 375 : phase, std::string(name), id, bind_id, num_args, flags, timestamp);
70 125 : trace_object_list_.push_back(to);
71 125 : return 0;
72 : }
73 :
74 30 : void UpdateTraceEventDuration(const uint8_t* category_enabled_flag,
75 30 : const char* name, uint64_t handle) override {}
76 :
77 165 : const uint8_t* GetCategoryGroupEnabled(const char* name) override {
78 165 : if (strncmp(name, "v8-cat", 6)) {
79 : static uint8_t no = 0;
80 : return &no;
81 : } else {
82 : static uint8_t yes = 0x7;
83 135 : 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 100 : MockTracingPlatform() {
98 : // Now that it's completely constructed, make this the current platform.
99 50 : i::V8::SetPlatformForTesting(this);
100 50 : }
101 100 : ~MockTracingPlatform() override = default;
102 :
103 320 : v8::TracingController* GetTracingController() override {
104 320 : 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 26068 : 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 26068 : 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 5 : 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 26068 : TEST(TraceEventWithOneArg) {
145 5 : MockTracingPlatform platform;
146 :
147 10 : TRACE_EVENT_BEGIN1("v8-cat", "e1", "arg1", 42);
148 10 : 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 5 : 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 26068 : TEST(TraceEventWithTwoArgs) {
162 5 : MockTracingPlatform platform;
163 :
164 10 : TRACE_EVENT_BEGIN2("v8-cat", "e1", "arg1", 42, "arg2", "abc");
165 10 : TRACE_EVENT_END2("v8-cat", "e1", "arg1", 42, "arg2", "abc");
166 10 : TRACE_EVENT_BEGIN2("v8-cat", "e2", "arg1", "abc", "arg2", 43);
167 10 : TRACE_EVENT_END2("v8-cat", "e2", "arg1", "abc", "arg2", 43);
168 :
169 5 : 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 26068 : TEST(ScopedTraceEvent) {
179 5 : MockTracingPlatform platform;
180 :
181 15 : { TRACE_EVENT0("v8-cat", "e"); }
182 :
183 5 : 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 5 : CHECK_EQ(2, GET_TRACE_OBJECTS_LIST->size());
189 5 : CHECK_EQ(1, GET_TRACE_OBJECT(1)->num_args);
190 :
191 15 : { TRACE_EVENT2("v8-cat", "e1", "arg1", "abc", "arg2", 42); }
192 :
193 5 : CHECK_EQ(3, GET_TRACE_OBJECTS_LIST->size());
194 5 : CHECK_EQ(2, GET_TRACE_OBJECT(2)->num_args);
195 5 : }
196 :
197 :
198 26068 : 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 15 : TRACE_EVENT_WITH_FLOW0(
207 : "v8-cat", "f2", bind_id,
208 : 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 5 : 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 26068 : 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 5 : 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 26068 : TEST(TestEventWithTimestamp) {
238 5 : MockTracingPlatform platform;
239 :
240 10 : TRACE_EVENT_INSTANT_WITH_TIMESTAMP0("v8-cat", "0arg",
241 : TRACE_EVENT_SCOPE_GLOBAL, 1729);
242 10 : TRACE_EVENT_INSTANT_WITH_TIMESTAMP1("v8-cat", "1arg",
243 : TRACE_EVENT_SCOPE_GLOBAL, 4104, "val", 1);
244 10 : TRACE_EVENT_MARK_WITH_TIMESTAMP2("v8-cat", "mark", 13832, "a", 1, "b", 2);
245 :
246 10 : TRACE_EVENT_COPY_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0("v8-cat", "begin", 5,
247 : 20683);
248 10 : TRACE_EVENT_COPY_NESTABLE_ASYNC_END_WITH_TIMESTAMP0("v8-cat", "end", 5,
249 : 32832);
250 :
251 5 : CHECK_EQ(5, GET_TRACE_OBJECTS_LIST->size());
252 :
253 5 : CHECK_EQ(1729, GET_TRACE_OBJECT(0)->timestamp);
254 5 : CHECK_EQ(0, GET_TRACE_OBJECT(0)->num_args);
255 :
256 5 : CHECK_EQ(4104, GET_TRACE_OBJECT(1)->timestamp);
257 5 : CHECK_EQ(1, GET_TRACE_OBJECT(1)->num_args);
258 :
259 5 : CHECK_EQ(13832, GET_TRACE_OBJECT(2)->timestamp);
260 5 : CHECK_EQ(2, GET_TRACE_OBJECT(2)->num_args);
261 :
262 5 : CHECK_EQ(20683, GET_TRACE_OBJECT(3)->timestamp);
263 5 : CHECK_EQ(32832, GET_TRACE_OBJECT(4)->timestamp);
264 5 : }
265 :
266 26068 : TEST(BuiltinsIsTraceCategoryEnabled) {
267 5 : CcTest::InitializeVM();
268 5 : MockTracingPlatform platform;
269 :
270 5 : v8::Isolate* isolate = CcTest::isolate();
271 10 : v8::HandleScope handle_scope(isolate);
272 5 : LocalContext env;
273 :
274 5 : v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
275 5 : CHECK(!binding.IsEmpty());
276 :
277 : auto undefined = v8::Undefined(isolate);
278 : auto isTraceCategoryEnabled =
279 15 : binding->Get(env.local(), v8_str("isTraceCategoryEnabled"))
280 : .ToLocalChecked()
281 : .As<v8::Function>();
282 :
283 : {
284 : // Test with an enabled category
285 5 : v8::Local<v8::Value> argv[] = {v8_str("v8-cat")};
286 10 : auto result = isTraceCategoryEnabled->Call(env.local(), undefined, 1, argv)
287 : .ToLocalChecked()
288 : .As<v8::Boolean>();
289 :
290 5 : CHECK(result->BooleanValue(isolate));
291 : }
292 :
293 : {
294 : // Test with a disabled category
295 5 : v8::Local<v8::Value> argv[] = {v8_str("cat")};
296 10 : auto result = isTraceCategoryEnabled->Call(env.local(), undefined, 1, argv)
297 : .ToLocalChecked()
298 : .As<v8::Boolean>();
299 :
300 5 : CHECK(!result->BooleanValue(isolate));
301 : }
302 :
303 : {
304 : // Test with an enabled utf8 category
305 5 : v8::Local<v8::Value> argv[] = {v8_str("v8-cat\u20ac")};
306 10 : auto result = isTraceCategoryEnabled->Call(env.local(), undefined, 1, argv)
307 : .ToLocalChecked()
308 : .As<v8::Boolean>();
309 :
310 5 : CHECK(result->BooleanValue(isolate));
311 : }
312 5 : }
313 :
314 26068 : TEST(BuiltinsTrace) {
315 5 : CcTest::InitializeVM();
316 5 : MockTracingPlatform platform;
317 :
318 5 : v8::Isolate* isolate = CcTest::isolate();
319 10 : v8::HandleScope handle_scope(isolate);
320 5 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
321 5 : LocalContext env;
322 :
323 5 : v8::Local<v8::Object> binding = env->GetExtrasBindingObject();
324 5 : CHECK(!binding.IsEmpty());
325 :
326 : auto undefined = v8::Undefined(isolate);
327 15 : auto trace = binding->Get(env.local(), v8_str("trace"))
328 : .ToLocalChecked()
329 : .As<v8::Function>();
330 :
331 : // Test with disabled category
332 : {
333 5 : v8::Local<v8::String> category = v8_str("cat");
334 5 : v8::Local<v8::String> name = v8_str("name");
335 : v8::Local<v8::Value> argv[] = {
336 : v8::Integer::New(isolate, 'b'), // phase
337 : category, name, v8::Integer::New(isolate, 0), // id
338 : undefined // data
339 10 : };
340 10 : auto result = trace->Call(env.local(), undefined, 5, argv)
341 : .ToLocalChecked()
342 : .As<v8::Boolean>();
343 :
344 5 : CHECK(!result->BooleanValue(isolate));
345 5 : CHECK_EQ(0, GET_TRACE_OBJECTS_LIST->size());
346 : }
347 :
348 : // Test with enabled category
349 : {
350 5 : v8::Local<v8::String> category = v8_str("v8-cat");
351 5 : v8::Local<v8::String> name = v8_str("name");
352 5 : v8::Local<v8::Object> data = v8::Object::New(isolate);
353 20 : data->Set(context, v8_str("foo"), v8_str("bar")).FromJust();
354 : v8::Local<v8::Value> argv[] = {
355 : v8::Integer::New(isolate, 'b'), // phase
356 : category, name, v8::Integer::New(isolate, 123), // id
357 : data // data arg
358 10 : };
359 10 : auto result = trace->Call(env.local(), undefined, 5, argv)
360 : .ToLocalChecked()
361 : .As<v8::Boolean>();
362 :
363 5 : CHECK(result->BooleanValue(isolate));
364 5 : CHECK_EQ(1, GET_TRACE_OBJECTS_LIST->size());
365 :
366 10 : CHECK_EQ(123, GET_TRACE_OBJECT(0)->id);
367 5 : CHECK_EQ('b', GET_TRACE_OBJECT(0)->phase);
368 10 : CHECK_EQ("name", GET_TRACE_OBJECT(0)->name);
369 5 : CHECK_EQ(1, GET_TRACE_OBJECT(0)->num_args);
370 : }
371 :
372 : // Test with enabled utf8 category
373 : {
374 5 : v8::Local<v8::String> category = v8_str("v8-cat\u20ac");
375 5 : v8::Local<v8::String> name = v8_str("name\u20ac");
376 5 : v8::Local<v8::Object> data = v8::Object::New(isolate);
377 20 : data->Set(context, v8_str("foo"), v8_str("bar")).FromJust();
378 : v8::Local<v8::Value> argv[] = {
379 : v8::Integer::New(isolate, 'b'), // phase
380 : category, name, v8::Integer::New(isolate, 123), // id
381 : data // data arg
382 10 : };
383 10 : auto result = trace->Call(env.local(), undefined, 5, argv)
384 : .ToLocalChecked()
385 : .As<v8::Boolean>();
386 :
387 5 : CHECK(result->BooleanValue(isolate));
388 5 : CHECK_EQ(2, GET_TRACE_OBJECTS_LIST->size());
389 :
390 10 : CHECK_EQ(123, GET_TRACE_OBJECT(1)->id);
391 5 : CHECK_EQ('b', GET_TRACE_OBJECT(1)->phase);
392 10 : CHECK_EQ("name\u20ac", GET_TRACE_OBJECT(1)->name);
393 5 : CHECK_EQ(1, GET_TRACE_OBJECT(1)->num_args);
394 : }
395 78194 : }
|