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 
5 #include "include/libplatform/v8-tracing.h"
6 
7 #include "base/trace_event/common/trace_event_common.h"
8 #include "include/v8-platform.h"
9 #include "src/base/platform/platform.h"
10 #include "src/base/platform/time.h"
11 
12 namespace v8 {
13 namespace platform {
14 namespace tracing {
15 
16 // We perform checks for nullptr strings since it is possible that a string arg
17 // value is nullptr.
GetAllocLength(const char * str)18 V8_INLINE static size_t GetAllocLength(const char* str) {
19   return str ? strlen(str) + 1 : 0;
20 }
21 
22 // Copies |*member| into |*buffer|, sets |*member| to point to this new
23 // location, and then advances |*buffer| by the amount written.
CopyTraceObjectParameter(char ** buffer,const char ** member)24 V8_INLINE static void CopyTraceObjectParameter(char** buffer,
25                                                const char** member) {
26   if (*member) {
27     size_t length = strlen(*member) + 1;
28     strncpy(*buffer, *member, length);
29     *member = *buffer;
30     *buffer += length;
31   }
32 }
33 
Initialize(char phase,const uint8_t * category_enabled_flag,const char * name,const char * scope,uint64_t id,uint64_t bind_id,int num_args,const char ** arg_names,const uint8_t * arg_types,const uint64_t * arg_values,std::unique_ptr<v8::ConvertableToTraceFormat> * arg_convertables,unsigned int flags,int64_t timestamp,int64_t cpu_timestamp)34 void TraceObject::Initialize(
35     char phase, const uint8_t* category_enabled_flag, const char* name,
36     const char* scope, uint64_t id, uint64_t bind_id, int num_args,
37     const char** arg_names, const uint8_t* arg_types,
38     const uint64_t* arg_values,
39     std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables,
40     unsigned int flags, int64_t timestamp, int64_t cpu_timestamp) {
41   pid_ = base::OS::GetCurrentProcessId();
42   tid_ = base::OS::GetCurrentThreadId();
43   phase_ = phase;
44   category_enabled_flag_ = category_enabled_flag;
45   name_ = name;
46   scope_ = scope;
47   id_ = id;
48   bind_id_ = bind_id;
49   flags_ = flags;
50   ts_ = timestamp;
51   tts_ = cpu_timestamp;
52   duration_ = 0;
53   cpu_duration_ = 0;
54 
55   // Clamp num_args since it may have been set by a third-party library.
56   num_args_ = (num_args > kTraceMaxNumArgs) ? kTraceMaxNumArgs : num_args;
57   for (int i = 0; i < num_args_; ++i) {
58     arg_names_[i] = arg_names[i];
59     arg_values_[i].as_uint = arg_values[i];
60     arg_types_[i] = arg_types[i];
61     if (arg_types[i] == TRACE_VALUE_TYPE_CONVERTABLE)
62       arg_convertables_[i] = std::move(arg_convertables[i]);
63   }
64 
65   bool copy = !!(flags & TRACE_EVENT_FLAG_COPY);
66   // Allocate a long string to fit all string copies.
67   size_t alloc_size = 0;
68   if (copy) {
69     alloc_size += GetAllocLength(name) + GetAllocLength(scope);
70     for (int i = 0; i < num_args_; ++i) {
71       alloc_size += GetAllocLength(arg_names_[i]);
72       if (arg_types_[i] == TRACE_VALUE_TYPE_STRING)
73         arg_types_[i] = TRACE_VALUE_TYPE_COPY_STRING;
74     }
75   }
76 
77   bool arg_is_copy[kTraceMaxNumArgs];
78   for (int i = 0; i < num_args_; ++i) {
79     // We only take a copy of arg_vals if they are of type COPY_STRING.
80     arg_is_copy[i] = (arg_types_[i] == TRACE_VALUE_TYPE_COPY_STRING);
81     if (arg_is_copy[i]) alloc_size += GetAllocLength(arg_values_[i].as_string);
82   }
83 
84   if (alloc_size) {
85     // Since TraceObject can be initialized multiple times, we might need
86     // to free old memory.
87     delete[] parameter_copy_storage_;
88     char* ptr = parameter_copy_storage_ = new char[alloc_size];
89     if (copy) {
90       CopyTraceObjectParameter(&ptr, &name_);
91       CopyTraceObjectParameter(&ptr, &scope_);
92       for (int i = 0; i < num_args_; ++i) {
93         CopyTraceObjectParameter(&ptr, &arg_names_[i]);
94       }
95     }
96     for (int i = 0; i < num_args_; ++i) {
97       if (arg_is_copy[i]) {
98         CopyTraceObjectParameter(&ptr, &arg_values_[i].as_string);
99       }
100     }
101   }
102 }
103 
~TraceObject()104 TraceObject::~TraceObject() { delete[] parameter_copy_storage_; }
105 
UpdateDuration(int64_t timestamp,int64_t cpu_timestamp)106 void TraceObject::UpdateDuration(int64_t timestamp, int64_t cpu_timestamp) {
107   duration_ = timestamp - ts_;
108   cpu_duration_ = cpu_timestamp - tts_;
109 }
110 
InitializeForTesting(char phase,const uint8_t * category_enabled_flag,const char * name,const char * scope,uint64_t id,uint64_t bind_id,int num_args,const char ** arg_names,const uint8_t * arg_types,const uint64_t * arg_values,std::unique_ptr<v8::ConvertableToTraceFormat> * arg_convertables,unsigned int flags,int pid,int tid,int64_t ts,int64_t tts,uint64_t duration,uint64_t cpu_duration)111 void TraceObject::InitializeForTesting(
112     char phase, const uint8_t* category_enabled_flag, const char* name,
113     const char* scope, uint64_t id, uint64_t bind_id, int num_args,
114     const char** arg_names, const uint8_t* arg_types,
115     const uint64_t* arg_values,
116     std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables,
117     unsigned int flags, int pid, int tid, int64_t ts, int64_t tts,
118     uint64_t duration, uint64_t cpu_duration) {
119   pid_ = pid;
120   tid_ = tid;
121   phase_ = phase;
122   category_enabled_flag_ = category_enabled_flag;
123   name_ = name;
124   scope_ = scope;
125   id_ = id;
126   bind_id_ = bind_id;
127   num_args_ = num_args;
128   flags_ = flags;
129   ts_ = ts;
130   tts_ = tts;
131   duration_ = duration;
132   cpu_duration_ = cpu_duration;
133 }
134 
135 }  // namespace tracing
136 }  // namespace platform
137 }  // namespace v8
138