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/list.h"
10 #include "src/list-inl.h"
11 #include "test/cctest/cctest.h"
12 
13 using v8::IdleTask;
14 using v8::Task;
15 using v8::Isolate;
16 
17 #include "src/tracing/trace-event.h"
18 
19 #define GET_TRACE_OBJECTS_LIST platform.GetMockTraceObjects()
20 
21 #define GET_TRACE_OBJECT(Index) GET_TRACE_OBJECTS_LIST->at(Index)
22 
23 
24 struct MockTraceObject {
25   char phase;
26   std::string name;
27   uint64_t id;
28   uint64_t bind_id;
29   int num_args;
30   unsigned int flags;
MockTraceObjectMockTraceObject31   MockTraceObject(char phase, std::string name, uint64_t id, uint64_t bind_id,
32                   int num_args, int flags)
33       : phase(phase),
34         name(name),
35         id(id),
36         bind_id(bind_id),
37         num_args(num_args),
38         flags(flags) {}
39 };
40 
41 typedef v8::internal::List<MockTraceObject*> MockTraceObjectList;
42 
43 class MockTracingPlatform : public v8::Platform {
44  public:
MockTracingPlatform(v8::Platform * platform)45   explicit MockTracingPlatform(v8::Platform* platform) {}
~MockTracingPlatform()46   virtual ~MockTracingPlatform() {
47     for (int i = 0; i < trace_object_list_.length(); ++i) {
48       delete trace_object_list_[i];
49     }
50     trace_object_list_.Clear();
51   }
CallOnBackgroundThread(Task * task,ExpectedRuntime expected_runtime)52   void CallOnBackgroundThread(Task* task,
53                               ExpectedRuntime expected_runtime) override {}
54 
CallOnForegroundThread(Isolate * isolate,Task * task)55   void CallOnForegroundThread(Isolate* isolate, Task* task) override {}
56 
CallDelayedOnForegroundThread(Isolate * isolate,Task * task,double delay_in_seconds)57   void CallDelayedOnForegroundThread(Isolate* isolate, Task* task,
58                                      double delay_in_seconds) override {}
59 
MonotonicallyIncreasingTime()60   double MonotonicallyIncreasingTime() override { return 0.0; }
61 
CallIdleOnForegroundThread(Isolate * isolate,IdleTask * task)62   void CallIdleOnForegroundThread(Isolate* isolate, IdleTask* task) override {}
63 
IdleTasksEnabled(Isolate * isolate)64   bool IdleTasksEnabled(Isolate* isolate) override { return false; }
65 
PendingIdleTask()66   bool PendingIdleTask() { return false; }
67 
PerformIdleTask(double idle_time_in_seconds)68   void PerformIdleTask(double idle_time_in_seconds) {}
69 
PendingDelayedTask()70   bool PendingDelayedTask() { return false; }
71 
PerformDelayedTask()72   void PerformDelayedTask() {}
73 
AddTraceEvent(char phase,const uint8_t * category_enabled_flag,const char * name,uint64_t id,uint64_t bind_id,int num_args,const char ** arg_names,const uint8_t * arg_types,const uint64_t * arg_values,unsigned int flags)74   uint64_t AddTraceEvent(char phase, const uint8_t* category_enabled_flag,
75                          const char* name, uint64_t id, uint64_t bind_id,
76                          int num_args, const char** arg_names,
77                          const uint8_t* arg_types, const uint64_t* arg_values,
78                          unsigned int flags) override {
79     MockTraceObject* to = new MockTraceObject(phase, std::string(name), id,
80                                               bind_id, num_args, flags);
81     trace_object_list_.Add(to);
82     return 0;
83   }
84 
UpdateTraceEventDuration(const uint8_t * category_enabled_flag,const char * name,uint64_t handle)85   void UpdateTraceEventDuration(const uint8_t* category_enabled_flag,
86                                 const char* name, uint64_t handle) override {}
87 
GetCategoryGroupEnabled(const char * name)88   const uint8_t* GetCategoryGroupEnabled(const char* name) override {
89     if (strcmp(name, "v8-cat")) {
90       static uint8_t no = 0;
91       return &no;
92     } else {
93       static uint8_t yes = 0x7;
94       return &yes;
95     }
96   }
97 
GetCategoryGroupName(const uint8_t * category_enabled_flag)98   const char* GetCategoryGroupName(
99       const uint8_t* category_enabled_flag) override {
100     static const char dummy[] = "dummy";
101     return dummy;
102   }
103 
GetMockTraceObjects()104   MockTraceObjectList* GetMockTraceObjects() { return &trace_object_list_; }
105 
106  private:
107   MockTraceObjectList trace_object_list_;
108 };
109 
110 
TEST(TraceEventDisabledCategory)111 TEST(TraceEventDisabledCategory) {
112   v8::Platform* old_platform = i::V8::GetCurrentPlatform();
113   MockTracingPlatform platform(old_platform);
114   i::V8::SetPlatformForTesting(&platform);
115 
116   // Disabled category, will not add events.
117   TRACE_EVENT_BEGIN0("cat", "e1");
118   TRACE_EVENT_END0("cat", "e1");
119   CHECK_EQ(0, GET_TRACE_OBJECTS_LIST->length());
120 
121   i::V8::SetPlatformForTesting(old_platform);
122 }
123 
124 
TEST(TraceEventNoArgs)125 TEST(TraceEventNoArgs) {
126   v8::Platform* old_platform = i::V8::GetCurrentPlatform();
127   MockTracingPlatform platform(old_platform);
128   i::V8::SetPlatformForTesting(&platform);
129 
130   // Enabled category will add 2 events.
131   TRACE_EVENT_BEGIN0("v8-cat", "e1");
132   TRACE_EVENT_END0("v8-cat", "e1");
133 
134   CHECK_EQ(2, GET_TRACE_OBJECTS_LIST->length());
135   CHECK_EQ('B', GET_TRACE_OBJECT(0)->phase);
136   CHECK_EQ("e1", GET_TRACE_OBJECT(0)->name);
137   CHECK_EQ(0, GET_TRACE_OBJECT(0)->num_args);
138 
139   CHECK_EQ('E', GET_TRACE_OBJECT(1)->phase);
140   CHECK_EQ("e1", GET_TRACE_OBJECT(1)->name);
141   CHECK_EQ(0, GET_TRACE_OBJECT(1)->num_args);
142 
143   i::V8::SetPlatformForTesting(old_platform);
144 }
145 
146 
TEST(TraceEventWithOneArg)147 TEST(TraceEventWithOneArg) {
148   v8::Platform* old_platform = i::V8::GetCurrentPlatform();
149   MockTracingPlatform platform(old_platform);
150   i::V8::SetPlatformForTesting(&platform);
151 
152   TRACE_EVENT_BEGIN1("v8-cat", "e1", "arg1", 42);
153   TRACE_EVENT_END1("v8-cat", "e1", "arg1", 42);
154   TRACE_EVENT_BEGIN1("v8-cat", "e2", "arg1", "abc");
155   TRACE_EVENT_END1("v8-cat", "e2", "arg1", "abc");
156 
157   CHECK_EQ(4, GET_TRACE_OBJECTS_LIST->length());
158 
159   CHECK_EQ(1, GET_TRACE_OBJECT(0)->num_args);
160   CHECK_EQ(1, GET_TRACE_OBJECT(1)->num_args);
161   CHECK_EQ(1, GET_TRACE_OBJECT(2)->num_args);
162   CHECK_EQ(1, GET_TRACE_OBJECT(3)->num_args);
163 
164   i::V8::SetPlatformForTesting(old_platform);
165 }
166 
167 
TEST(TraceEventWithTwoArgs)168 TEST(TraceEventWithTwoArgs) {
169   v8::Platform* old_platform = i::V8::GetCurrentPlatform();
170   MockTracingPlatform platform(old_platform);
171   i::V8::SetPlatformForTesting(&platform);
172 
173   TRACE_EVENT_BEGIN2("v8-cat", "e1", "arg1", 42, "arg2", "abc");
174   TRACE_EVENT_END2("v8-cat", "e1", "arg1", 42, "arg2", "abc");
175   TRACE_EVENT_BEGIN2("v8-cat", "e2", "arg1", "abc", "arg2", 43);
176   TRACE_EVENT_END2("v8-cat", "e2", "arg1", "abc", "arg2", 43);
177 
178   CHECK_EQ(4, GET_TRACE_OBJECTS_LIST->length());
179 
180   CHECK_EQ(2, GET_TRACE_OBJECT(0)->num_args);
181   CHECK_EQ(2, GET_TRACE_OBJECT(1)->num_args);
182   CHECK_EQ(2, GET_TRACE_OBJECT(2)->num_args);
183   CHECK_EQ(2, GET_TRACE_OBJECT(3)->num_args);
184 
185   i::V8::SetPlatformForTesting(old_platform);
186 }
187 
188 
TEST(ScopedTraceEvent)189 TEST(ScopedTraceEvent) {
190   v8::Platform* old_platform = i::V8::GetCurrentPlatform();
191   MockTracingPlatform platform(old_platform);
192   i::V8::SetPlatformForTesting(&platform);
193 
194   { TRACE_EVENT0("v8-cat", "e"); }
195 
196   CHECK_EQ(1, GET_TRACE_OBJECTS_LIST->length());
197   CHECK_EQ(0, GET_TRACE_OBJECT(0)->num_args);
198 
199   { TRACE_EVENT1("v8-cat", "e1", "arg1", "abc"); }
200 
201   CHECK_EQ(2, GET_TRACE_OBJECTS_LIST->length());
202   CHECK_EQ(1, GET_TRACE_OBJECT(1)->num_args);
203 
204   { TRACE_EVENT2("v8-cat", "e1", "arg1", "abc", "arg2", 42); }
205 
206   CHECK_EQ(3, GET_TRACE_OBJECTS_LIST->length());
207   CHECK_EQ(2, GET_TRACE_OBJECT(2)->num_args);
208 
209   i::V8::SetPlatformForTesting(old_platform);
210 }
211 
212 
TEST(TestEventWithFlow)213 TEST(TestEventWithFlow) {
214   v8::Platform* old_platform = i::V8::GetCurrentPlatform();
215   MockTracingPlatform platform(old_platform);
216   i::V8::SetPlatformForTesting(&platform);
217 
218   static uint64_t bind_id = 21;
219   {
220     TRACE_EVENT_WITH_FLOW0("v8-cat", "f1", bind_id, TRACE_EVENT_FLAG_FLOW_OUT);
221   }
222   {
223     TRACE_EVENT_WITH_FLOW0(
224         "v8-cat", "f2", bind_id,
225         TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
226   }
227   { TRACE_EVENT_WITH_FLOW0("v8-cat", "f3", bind_id, TRACE_EVENT_FLAG_FLOW_IN); }
228 
229   CHECK_EQ(3, GET_TRACE_OBJECTS_LIST->length());
230   CHECK_EQ(bind_id, GET_TRACE_OBJECT(0)->bind_id);
231   CHECK_EQ(TRACE_EVENT_FLAG_FLOW_OUT, GET_TRACE_OBJECT(0)->flags);
232   CHECK_EQ(bind_id, GET_TRACE_OBJECT(1)->bind_id);
233   CHECK_EQ(TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
234            GET_TRACE_OBJECT(1)->flags);
235   CHECK_EQ(bind_id, GET_TRACE_OBJECT(2)->bind_id);
236   CHECK_EQ(TRACE_EVENT_FLAG_FLOW_IN, GET_TRACE_OBJECT(2)->flags);
237 
238   i::V8::SetPlatformForTesting(old_platform);
239 }
240 
241 
TEST(TestEventWithId)242 TEST(TestEventWithId) {
243   v8::Platform* old_platform = i::V8::GetCurrentPlatform();
244   MockTracingPlatform platform(old_platform);
245   i::V8::SetPlatformForTesting(&platform);
246 
247   static uint64_t event_id = 21;
248   TRACE_EVENT_ASYNC_BEGIN0("v8-cat", "a1", event_id);
249   TRACE_EVENT_ASYNC_END0("v8-cat", "a1", event_id);
250 
251   CHECK_EQ(2, GET_TRACE_OBJECTS_LIST->length());
252   CHECK_EQ(TRACE_EVENT_PHASE_ASYNC_BEGIN, GET_TRACE_OBJECT(0)->phase);
253   CHECK_EQ(event_id, GET_TRACE_OBJECT(0)->id);
254   CHECK_EQ(TRACE_EVENT_PHASE_ASYNC_END, GET_TRACE_OBJECT(1)->phase);
255   CHECK_EQ(event_id, GET_TRACE_OBJECT(1)->id);
256 
257   i::V8::SetPlatformForTesting(old_platform);
258 }
259