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