summaryrefslogtreecommitdiff
path: root/deps/v8/src/libplatform/tracing
diff options
context:
space:
mode:
authorMichaël Zasso <targos@protonmail.com>2016-09-06 22:49:51 +0200
committerMichaël Zasso <targos@protonmail.com>2016-09-22 09:51:19 +0200
commitec02b811a8a5c999bab4de312be2d732b7d9d50b (patch)
treeca3068017254f238cf413a451c57a803572983a4 /deps/v8/src/libplatform/tracing
parentd2eb7ce0105369a9cad82787cb33a665e9bd00ad (diff)
downloadnode-new-ec02b811a8a5c999bab4de312be2d732b7d9d50b.tar.gz
deps: update V8 to 5.4.500.27
Pick up latest commit from the 5.4-lkgr branch. deps: edit V8 gitignore to allow trace event copy deps: update V8 trace event to 315bf1e2d45be7d53346c31cfcc37424a32c30c8 deps: edit V8 gitignore to allow gtest_prod.h copy deps: update V8 gtest to 6f8a66431cb592dad629028a50b3dd418a408c87 PR-URL: https://github.com/nodejs/node/pull/8317 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Ali Ijaz Sheikh <ofrobots@google.com>
Diffstat (limited to 'deps/v8/src/libplatform/tracing')
-rw-r--r--deps/v8/src/libplatform/tracing/trace-buffer.cc109
-rw-r--r--deps/v8/src/libplatform/tracing/trace-buffer.h48
-rw-r--r--deps/v8/src/libplatform/tracing/trace-config.cc42
-rw-r--r--deps/v8/src/libplatform/tracing/trace-object.cc130
-rw-r--r--deps/v8/src/libplatform/tracing/trace-writer.cc163
-rw-r--r--deps/v8/src/libplatform/tracing/trace-writer.h32
-rw-r--r--deps/v8/src/libplatform/tracing/tracing-controller.cc177
7 files changed, 701 insertions, 0 deletions
diff --git a/deps/v8/src/libplatform/tracing/trace-buffer.cc b/deps/v8/src/libplatform/tracing/trace-buffer.cc
new file mode 100644
index 0000000000..354f0459f6
--- /dev/null
+++ b/deps/v8/src/libplatform/tracing/trace-buffer.cc
@@ -0,0 +1,109 @@
+// Copyright 2016 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/libplatform/tracing/trace-buffer.h"
+
+namespace v8 {
+namespace platform {
+namespace tracing {
+
+TraceBufferRingBuffer::TraceBufferRingBuffer(size_t max_chunks,
+ TraceWriter* trace_writer)
+ : max_chunks_(max_chunks) {
+ trace_writer_.reset(trace_writer);
+ chunks_.resize(max_chunks);
+}
+
+TraceBufferRingBuffer::~TraceBufferRingBuffer() {}
+
+TraceObject* TraceBufferRingBuffer::AddTraceEvent(uint64_t* handle) {
+ base::LockGuard<base::Mutex> guard(&mutex_);
+ if (is_empty_ || chunks_[chunk_index_]->IsFull()) {
+ chunk_index_ = is_empty_ ? 0 : NextChunkIndex(chunk_index_);
+ is_empty_ = false;
+ auto& chunk = chunks_[chunk_index_];
+ if (chunk) {
+ chunk->Reset(current_chunk_seq_++);
+ } else {
+ chunk.reset(new TraceBufferChunk(current_chunk_seq_++));
+ }
+ }
+ auto& chunk = chunks_[chunk_index_];
+ size_t event_index;
+ TraceObject* trace_object = chunk->AddTraceEvent(&event_index);
+ *handle = MakeHandle(chunk_index_, chunk->seq(), event_index);
+ return trace_object;
+}
+
+TraceObject* TraceBufferRingBuffer::GetEventByHandle(uint64_t handle) {
+ base::LockGuard<base::Mutex> guard(&mutex_);
+ size_t chunk_index, event_index;
+ uint32_t chunk_seq;
+ ExtractHandle(handle, &chunk_index, &chunk_seq, &event_index);
+ if (chunk_index >= chunks_.size()) return NULL;
+ auto& chunk = chunks_[chunk_index];
+ if (!chunk || chunk->seq() != chunk_seq) return NULL;
+ return chunk->GetEventAt(event_index);
+}
+
+bool TraceBufferRingBuffer::Flush() {
+ base::LockGuard<base::Mutex> guard(&mutex_);
+ // This flushes all the traces stored in the buffer.
+ if (!is_empty_) {
+ for (size_t i = NextChunkIndex(chunk_index_);; i = NextChunkIndex(i)) {
+ if (auto& chunk = chunks_[i]) {
+ for (size_t j = 0; j < chunk->size(); ++j) {
+ trace_writer_->AppendTraceEvent(chunk->GetEventAt(j));
+ }
+ }
+ if (i == chunk_index_) break;
+ }
+ }
+ trace_writer_->Flush();
+ // This resets the trace buffer.
+ is_empty_ = true;
+ return true;
+}
+
+uint64_t TraceBufferRingBuffer::MakeHandle(size_t chunk_index,
+ uint32_t chunk_seq,
+ size_t event_index) const {
+ return static_cast<uint64_t>(chunk_seq) * Capacity() +
+ chunk_index * TraceBufferChunk::kChunkSize + event_index;
+}
+
+void TraceBufferRingBuffer::ExtractHandle(uint64_t handle, size_t* chunk_index,
+ uint32_t* chunk_seq,
+ size_t* event_index) const {
+ *chunk_seq = static_cast<uint32_t>(handle / Capacity());
+ size_t indices = handle % Capacity();
+ *chunk_index = indices / TraceBufferChunk::kChunkSize;
+ *event_index = indices % TraceBufferChunk::kChunkSize;
+}
+
+size_t TraceBufferRingBuffer::NextChunkIndex(size_t index) const {
+ if (++index >= max_chunks_) index = 0;
+ return index;
+}
+
+TraceBufferChunk::TraceBufferChunk(uint32_t seq) : seq_(seq) {}
+
+void TraceBufferChunk::Reset(uint32_t new_seq) {
+ next_free_ = 0;
+ seq_ = new_seq;
+}
+
+TraceObject* TraceBufferChunk::AddTraceEvent(size_t* event_index) {
+ *event_index = next_free_++;
+ return &chunk_[*event_index];
+}
+
+TraceBuffer* TraceBuffer::CreateTraceBufferRingBuffer(
+ size_t max_chunks, TraceWriter* trace_writer) {
+ return new TraceBufferRingBuffer(max_chunks, trace_writer);
+}
+
+} // namespace tracing
+} // namespace platform
+} // namespace v8
diff --git a/deps/v8/src/libplatform/tracing/trace-buffer.h b/deps/v8/src/libplatform/tracing/trace-buffer.h
new file mode 100644
index 0000000000..16f3b2a12e
--- /dev/null
+++ b/deps/v8/src/libplatform/tracing/trace-buffer.h
@@ -0,0 +1,48 @@
+// Copyright 2016 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SRC_LIBPLATFORM_TRACING_TRACE_BUFFER_H_
+#define SRC_LIBPLATFORM_TRACING_TRACE_BUFFER_H_
+
+#include <memory>
+#include <vector>
+
+#include "include/libplatform/v8-tracing.h"
+#include "src/base/platform/mutex.h"
+
+namespace v8 {
+namespace platform {
+namespace tracing {
+
+class TraceBufferRingBuffer : public TraceBuffer {
+ public:
+ TraceBufferRingBuffer(size_t max_chunks, TraceWriter* trace_writer);
+ ~TraceBufferRingBuffer();
+
+ TraceObject* AddTraceEvent(uint64_t* handle) override;
+ TraceObject* GetEventByHandle(uint64_t handle) override;
+ bool Flush() override;
+
+ private:
+ uint64_t MakeHandle(size_t chunk_index, uint32_t chunk_seq,
+ size_t event_index) const;
+ void ExtractHandle(uint64_t handle, size_t* chunk_index, uint32_t* chunk_seq,
+ size_t* event_index) const;
+ size_t Capacity() const { return max_chunks_ * TraceBufferChunk::kChunkSize; }
+ size_t NextChunkIndex(size_t index) const;
+
+ mutable base::Mutex mutex_;
+ size_t max_chunks_;
+ std::unique_ptr<TraceWriter> trace_writer_;
+ std::vector<std::unique_ptr<TraceBufferChunk>> chunks_;
+ size_t chunk_index_;
+ bool is_empty_ = true;
+ uint32_t current_chunk_seq_ = 1;
+};
+
+} // namespace tracing
+} // namespace platform
+} // namespace v8
+
+#endif // SRC_LIBPLATFORM_TRACING_TRACE_BUFFER_H_
diff --git a/deps/v8/src/libplatform/tracing/trace-config.cc b/deps/v8/src/libplatform/tracing/trace-config.cc
new file mode 100644
index 0000000000..7a824f614e
--- /dev/null
+++ b/deps/v8/src/libplatform/tracing/trace-config.cc
@@ -0,0 +1,42 @@
+// Copyright 2016 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string.h>
+
+#include "include/libplatform/v8-tracing.h"
+#include "src/base/logging.h"
+
+namespace v8 {
+
+class Isolate;
+
+namespace platform {
+namespace tracing {
+
+TraceConfig* TraceConfig::CreateDefaultTraceConfig() {
+ TraceConfig* trace_config = new TraceConfig();
+ trace_config->included_categories_.push_back("v8");
+ return trace_config;
+}
+
+bool TraceConfig::IsCategoryGroupEnabled(const char* category_group) const {
+ for (auto included_category : included_categories_) {
+ if (strcmp(included_category.data(), category_group) == 0) return true;
+ }
+ return false;
+}
+
+void TraceConfig::AddIncludedCategory(const char* included_category) {
+ DCHECK(included_category != NULL && strlen(included_category) > 0);
+ included_categories_.push_back(included_category);
+}
+
+void TraceConfig::AddExcludedCategory(const char* excluded_category) {
+ DCHECK(excluded_category != NULL && strlen(excluded_category) > 0);
+ excluded_categories_.push_back(excluded_category);
+}
+
+} // namespace tracing
+} // namespace platform
+} // namespace v8
diff --git a/deps/v8/src/libplatform/tracing/trace-object.cc b/deps/v8/src/libplatform/tracing/trace-object.cc
new file mode 100644
index 0000000000..55be8921cb
--- /dev/null
+++ b/deps/v8/src/libplatform/tracing/trace-object.cc
@@ -0,0 +1,130 @@
+// Copyright 2016 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "include/libplatform/v8-tracing.h"
+
+#include "base/trace_event/common/trace_event_common.h"
+#include "src/base/platform/platform.h"
+#include "src/base/platform/time.h"
+
+namespace v8 {
+namespace platform {
+namespace tracing {
+
+// We perform checks for NULL strings since it is possible that a string arg
+// value is NULL.
+V8_INLINE static size_t GetAllocLength(const char* str) {
+ return str ? strlen(str) + 1 : 0;
+}
+
+// Copies |*member| into |*buffer|, sets |*member| to point to this new
+// location, and then advances |*buffer| by the amount written.
+V8_INLINE static void CopyTraceObjectParameter(char** buffer,
+ const char** member) {
+ if (*member) {
+ size_t length = strlen(*member) + 1;
+ strncpy(*buffer, *member, length);
+ *member = *buffer;
+ *buffer += length;
+ }
+}
+
+void TraceObject::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, unsigned int flags) {
+ pid_ = base::OS::GetCurrentProcessId();
+ tid_ = base::OS::GetCurrentThreadId();
+ phase_ = phase;
+ category_enabled_flag_ = category_enabled_flag;
+ name_ = name;
+ scope_ = scope;
+ id_ = id;
+ bind_id_ = bind_id;
+ flags_ = flags;
+ ts_ = base::TimeTicks::HighResolutionNow().ToInternalValue();
+ tts_ = base::ThreadTicks::Now().ToInternalValue();
+ duration_ = 0;
+ cpu_duration_ = 0;
+
+ // Clamp num_args since it may have been set by a third-party library.
+ num_args_ = (num_args > kTraceMaxNumArgs) ? kTraceMaxNumArgs : num_args;
+ for (int i = 0; i < num_args_; ++i) {
+ arg_names_[i] = arg_names[i];
+ arg_values_[i].as_uint = arg_values[i];
+ arg_types_[i] = arg_types[i];
+ }
+
+ bool copy = !!(flags & TRACE_EVENT_FLAG_COPY);
+ // Allocate a long string to fit all string copies.
+ size_t alloc_size = 0;
+ if (copy) {
+ alloc_size += GetAllocLength(name) + GetAllocLength(scope);
+ for (int i = 0; i < num_args_; ++i) {
+ alloc_size += GetAllocLength(arg_names_[i]);
+ if (arg_types_[i] == TRACE_VALUE_TYPE_STRING)
+ arg_types_[i] = TRACE_VALUE_TYPE_COPY_STRING;
+ }
+ }
+
+ bool arg_is_copy[kTraceMaxNumArgs];
+ for (int i = 0; i < num_args_; ++i) {
+ // We only take a copy of arg_vals if they are of type COPY_STRING.
+ arg_is_copy[i] = (arg_types_[i] == TRACE_VALUE_TYPE_COPY_STRING);
+ if (arg_is_copy[i]) alloc_size += GetAllocLength(arg_values_[i].as_string);
+ }
+
+ if (alloc_size) {
+ // Since TraceObject can be initialized multiple times, we might need
+ // to free old memory.
+ delete[] parameter_copy_storage_;
+ char* ptr = parameter_copy_storage_ = new char[alloc_size];
+ if (copy) {
+ CopyTraceObjectParameter(&ptr, &name_);
+ CopyTraceObjectParameter(&ptr, &scope_);
+ for (int i = 0; i < num_args_; ++i) {
+ CopyTraceObjectParameter(&ptr, &arg_names_[i]);
+ }
+ }
+ for (int i = 0; i < num_args_; ++i) {
+ if (arg_is_copy[i]) {
+ CopyTraceObjectParameter(&ptr, &arg_values_[i].as_string);
+ }
+ }
+ }
+}
+
+TraceObject::~TraceObject() { delete[] parameter_copy_storage_; }
+
+void TraceObject::UpdateDuration() {
+ duration_ = base::TimeTicks::HighResolutionNow().ToInternalValue() - ts_;
+ cpu_duration_ = base::ThreadTicks::Now().ToInternalValue() - tts_;
+}
+
+void TraceObject::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, unsigned int flags, int pid, int tid,
+ int64_t ts, int64_t tts, uint64_t duration, uint64_t cpu_duration) {
+ pid_ = pid;
+ tid_ = tid;
+ phase_ = phase;
+ category_enabled_flag_ = category_enabled_flag;
+ name_ = name;
+ scope_ = scope;
+ id_ = id;
+ bind_id_ = bind_id;
+ num_args_ = num_args;
+ flags_ = flags;
+ ts_ = ts;
+ tts_ = tts;
+ duration_ = duration;
+ cpu_duration_ = cpu_duration;
+}
+
+} // namespace tracing
+} // namespace platform
+} // namespace v8
diff --git a/deps/v8/src/libplatform/tracing/trace-writer.cc b/deps/v8/src/libplatform/tracing/trace-writer.cc
new file mode 100644
index 0000000000..ec95527d5f
--- /dev/null
+++ b/deps/v8/src/libplatform/tracing/trace-writer.cc
@@ -0,0 +1,163 @@
+// Copyright 2016 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/libplatform/tracing/trace-writer.h"
+
+#include <cmath>
+
+#include "base/trace_event/common/trace_event_common.h"
+#include "src/base/platform/platform.h"
+
+namespace v8 {
+namespace platform {
+namespace tracing {
+
+// Writes the given string to a stream, taking care to escape characters
+// when necessary.
+V8_INLINE static void WriteJSONStringToStream(const char* str,
+ std::ostream& stream) {
+ size_t len = strlen(str);
+ stream << "\"";
+ for (size_t i = 0; i < len; ++i) {
+ // All of the permitted escape sequences in JSON strings, as per
+ // https://mathiasbynens.be/notes/javascript-escapes
+ switch (str[i]) {
+ case '\b':
+ stream << "\\b";
+ break;
+ case '\f':
+ stream << "\\f";
+ break;
+ case '\n':
+ stream << "\\n";
+ break;
+ case '\r':
+ stream << "\\r";
+ break;
+ case '\t':
+ stream << "\\t";
+ break;
+ case '\"':
+ stream << "\\\"";
+ break;
+ case '\\':
+ stream << "\\\\";
+ break;
+ // Note that because we use double quotes for JSON strings,
+ // we don't need to escape single quotes.
+ default:
+ stream << str[i];
+ break;
+ }
+ }
+ stream << "\"";
+}
+
+void JSONTraceWriter::AppendArgValue(uint8_t type,
+ TraceObject::ArgValue value) {
+ switch (type) {
+ case TRACE_VALUE_TYPE_BOOL:
+ stream_ << (value.as_bool ? "true" : "false");
+ break;
+ case TRACE_VALUE_TYPE_UINT:
+ stream_ << value.as_uint;
+ break;
+ case TRACE_VALUE_TYPE_INT:
+ stream_ << value.as_int;
+ break;
+ case TRACE_VALUE_TYPE_DOUBLE: {
+ std::string real;
+ double val = value.as_double;
+ if (std::isfinite(val)) {
+ std::ostringstream convert_stream;
+ convert_stream << val;
+ real = convert_stream.str();
+ // Ensure that the number has a .0 if there's no decimal or 'e'. This
+ // makes sure that when we read the JSON back, it's interpreted as a
+ // real rather than an int.
+ if (real.find('.') == std::string::npos &&
+ real.find('e') == std::string::npos &&
+ real.find('E') == std::string::npos) {
+ real += ".0";
+ }
+ } else if (std::isnan(val)) {
+ // The JSON spec doesn't allow NaN and Infinity (since these are
+ // objects in EcmaScript). Use strings instead.
+ real = "\"NaN\"";
+ } else if (val < 0) {
+ real = "\"-Infinity\"";
+ } else {
+ real = "\"Infinity\"";
+ }
+ stream_ << real;
+ break;
+ }
+ case TRACE_VALUE_TYPE_POINTER:
+ // JSON only supports double and int numbers.
+ // So as not to lose bits from a 64-bit pointer, output as a hex string.
+ stream_ << "\"" << value.as_pointer << "\"";
+ break;
+ case TRACE_VALUE_TYPE_STRING:
+ case TRACE_VALUE_TYPE_COPY_STRING:
+ if (value.as_string == nullptr) {
+ stream_ << "\"NULL\"";
+ } else {
+ WriteJSONStringToStream(value.as_string, stream_);
+ }
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+}
+
+JSONTraceWriter::JSONTraceWriter(std::ostream& stream) : stream_(stream) {
+ stream_ << "{\"traceEvents\":[";
+}
+
+JSONTraceWriter::~JSONTraceWriter() { stream_ << "]}"; }
+
+void JSONTraceWriter::AppendTraceEvent(TraceObject* trace_event) {
+ if (append_comma_) stream_ << ",";
+ append_comma_ = true;
+ stream_ << "{\"pid\":" << trace_event->pid()
+ << ",\"tid\":" << trace_event->tid()
+ << ",\"ts\":" << trace_event->ts()
+ << ",\"tts\":" << trace_event->tts() << ",\"ph\":\""
+ << trace_event->phase() << "\",\"cat\":\""
+ << TracingController::GetCategoryGroupName(
+ trace_event->category_enabled_flag())
+ << "\",\"name\":\"" << trace_event->name()
+ << "\",\"dur\":" << trace_event->duration()
+ << ",\"tdur\":" << trace_event->cpu_duration();
+ if (trace_event->flags() & TRACE_EVENT_FLAG_HAS_ID) {
+ if (trace_event->scope() != nullptr) {
+ stream_ << ",\"scope\":\"" << trace_event->scope() << "\"";
+ }
+ // So as not to lose bits from a 64-bit integer, output as a hex string.
+ stream_ << ",\"id\":\"0x" << std::hex << trace_event->id() << "\""
+ << std::dec;
+ }
+ stream_ << ",\"args\":{";
+ const char** arg_names = trace_event->arg_names();
+ const uint8_t* arg_types = trace_event->arg_types();
+ TraceObject::ArgValue* arg_values = trace_event->arg_values();
+ for (int i = 0; i < trace_event->num_args(); ++i) {
+ if (i > 0) stream_ << ",";
+ stream_ << "\"" << arg_names[i] << "\":";
+ AppendArgValue(arg_types[i], arg_values[i]);
+ }
+ stream_ << "}}";
+ // TODO(fmeawad): Add support for Flow Events.
+}
+
+void JSONTraceWriter::Flush() {}
+
+TraceWriter* TraceWriter::CreateJSONTraceWriter(std::ostream& stream) {
+ return new JSONTraceWriter(stream);
+}
+
+} // namespace tracing
+} // namespace platform
+} // namespace v8
diff --git a/deps/v8/src/libplatform/tracing/trace-writer.h b/deps/v8/src/libplatform/tracing/trace-writer.h
new file mode 100644
index 0000000000..963fc6a64d
--- /dev/null
+++ b/deps/v8/src/libplatform/tracing/trace-writer.h
@@ -0,0 +1,32 @@
+// Copyright 2016 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SRC_LIBPLATFORM_TRACING_TRACE_WRITER_H_
+#define SRC_LIBPLATFORM_TRACING_TRACE_WRITER_H_
+
+#include "include/libplatform/v8-tracing.h"
+
+namespace v8 {
+namespace platform {
+namespace tracing {
+
+class JSONTraceWriter : public TraceWriter {
+ public:
+ explicit JSONTraceWriter(std::ostream& stream);
+ ~JSONTraceWriter();
+ void AppendTraceEvent(TraceObject* trace_event) override;
+ void Flush() override;
+
+ private:
+ void AppendArgValue(uint8_t type, TraceObject::ArgValue value);
+
+ std::ostream& stream_;
+ bool append_comma_ = false;
+};
+
+} // namespace tracing
+} // namespace platform
+} // namespace v8
+
+#endif // SRC_LIBPLATFORM_TRACING_TRACE_WRITER_H_
diff --git a/deps/v8/src/libplatform/tracing/tracing-controller.cc b/deps/v8/src/libplatform/tracing/tracing-controller.cc
new file mode 100644
index 0000000000..e9a21725e2
--- /dev/null
+++ b/deps/v8/src/libplatform/tracing/tracing-controller.cc
@@ -0,0 +1,177 @@
+// Copyright 2016 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdio.h>
+#include <string.h>
+
+#include "include/libplatform/v8-tracing.h"
+
+#include "src/base/platform/mutex.h"
+
+namespace v8 {
+namespace platform {
+namespace tracing {
+
+#define MAX_CATEGORY_GROUPS 200
+
+// Parallel arrays g_category_groups and g_category_group_enabled are separate
+// so that a pointer to a member of g_category_group_enabled can be easily
+// converted to an index into g_category_groups. This allows macros to deal
+// only with char enabled pointers from g_category_group_enabled, and we can
+// convert internally to determine the category name from the char enabled
+// pointer.
+const char* g_category_groups[MAX_CATEGORY_GROUPS] = {
+ "toplevel", "tracing already shutdown",
+ "tracing categories exhausted; must increase MAX_CATEGORY_GROUPS",
+ "__metadata"};
+
+// The enabled flag is char instead of bool so that the API can be used from C.
+unsigned char g_category_group_enabled[MAX_CATEGORY_GROUPS] = {0};
+// Indexes here have to match the g_category_groups array indexes above.
+const int g_category_already_shutdown = 1;
+const int g_category_categories_exhausted = 2;
+// Metadata category not used in V8.
+// const int g_category_metadata = 3;
+const int g_num_builtin_categories = 4;
+
+// Skip default categories.
+v8::base::AtomicWord g_category_index = g_num_builtin_categories;
+
+void TracingController::Initialize(TraceBuffer* trace_buffer) {
+ trace_buffer_.reset(trace_buffer);
+}
+
+uint64_t TracingController::AddTraceEvent(
+ 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, unsigned int flags) {
+ uint64_t handle;
+ TraceObject* trace_object = trace_buffer_->AddTraceEvent(&handle);
+ if (trace_object) {
+ trace_object->Initialize(phase, category_enabled_flag, name, scope, id,
+ bind_id, num_args, arg_names, arg_types,
+ arg_values, flags);
+ }
+ return handle;
+}
+
+void TracingController::UpdateTraceEventDuration(
+ const uint8_t* category_enabled_flag, const char* name, uint64_t handle) {
+ TraceObject* trace_object = trace_buffer_->GetEventByHandle(handle);
+ if (!trace_object) return;
+ trace_object->UpdateDuration();
+}
+
+const uint8_t* TracingController::GetCategoryGroupEnabled(
+ const char* category_group) {
+ if (!trace_buffer_) {
+ DCHECK(!g_category_group_enabled[g_category_already_shutdown]);
+ return &g_category_group_enabled[g_category_already_shutdown];
+ }
+ return GetCategoryGroupEnabledInternal(category_group);
+}
+
+const char* TracingController::GetCategoryGroupName(
+ const uint8_t* category_group_enabled) {
+ // Calculate the index of the category group by finding
+ // category_group_enabled in g_category_group_enabled array.
+ uintptr_t category_begin =
+ reinterpret_cast<uintptr_t>(g_category_group_enabled);
+ uintptr_t category_ptr = reinterpret_cast<uintptr_t>(category_group_enabled);
+ // Check for out of bounds category pointers.
+ DCHECK(category_ptr >= category_begin &&
+ category_ptr < reinterpret_cast<uintptr_t>(g_category_group_enabled +
+ MAX_CATEGORY_GROUPS));
+ uintptr_t category_index =
+ (category_ptr - category_begin) / sizeof(g_category_group_enabled[0]);
+ return g_category_groups[category_index];
+}
+
+void TracingController::StartTracing(TraceConfig* trace_config) {
+ trace_config_.reset(trace_config);
+ mode_ = RECORDING_MODE;
+ UpdateCategoryGroupEnabledFlags();
+}
+
+void TracingController::StopTracing() {
+ mode_ = DISABLED;
+ UpdateCategoryGroupEnabledFlags();
+ trace_buffer_->Flush();
+}
+
+void TracingController::UpdateCategoryGroupEnabledFlag(size_t category_index) {
+ unsigned char enabled_flag = 0;
+ const char* category_group = g_category_groups[category_index];
+ if (mode_ == RECORDING_MODE &&
+ trace_config_->IsCategoryGroupEnabled(category_group)) {
+ enabled_flag |= ENABLED_FOR_RECORDING;
+ }
+
+ // TODO(fmeawad): EventCallback and ETW modes are not yet supported in V8.
+ // TODO(primiano): this is a temporary workaround for catapult:#2341,
+ // to guarantee that metadata events are always added even if the category
+ // filter is "-*". See crbug.com/618054 for more details and long-term fix.
+ if (mode_ == RECORDING_MODE && !strcmp(category_group, "__metadata")) {
+ enabled_flag |= ENABLED_FOR_RECORDING;
+ }
+
+ g_category_group_enabled[category_index] = enabled_flag;
+}
+
+void TracingController::UpdateCategoryGroupEnabledFlags() {
+ size_t category_index = base::NoBarrier_Load(&g_category_index);
+ for (size_t i = 0; i < category_index; i++) UpdateCategoryGroupEnabledFlag(i);
+}
+
+const uint8_t* TracingController::GetCategoryGroupEnabledInternal(
+ const char* category_group) {
+ // Check that category groups does not contain double quote
+ DCHECK(!strchr(category_group, '"'));
+
+ // The g_category_groups is append only, avoid using a lock for the fast path.
+ size_t current_category_index = v8::base::Acquire_Load(&g_category_index);
+
+ // Search for pre-existing category group.
+ for (size_t i = 0; i < current_category_index; ++i) {
+ if (strcmp(g_category_groups[i], category_group) == 0) {
+ return &g_category_group_enabled[i];
+ }
+ }
+
+ unsigned char* category_group_enabled = NULL;
+ size_t category_index = base::Acquire_Load(&g_category_index);
+ for (size_t i = 0; i < category_index; ++i) {
+ if (strcmp(g_category_groups[i], category_group) == 0) {
+ return &g_category_group_enabled[i];
+ }
+ }
+
+ // Create a new category group.
+ // Check that there is a slot for the new category_group.
+ DCHECK(category_index < MAX_CATEGORY_GROUPS);
+ if (category_index < MAX_CATEGORY_GROUPS) {
+ // Don't hold on to the category_group pointer, so that we can create
+ // category groups with strings not known at compile time (this is
+ // required by SetWatchEvent).
+ const char* new_group = strdup(category_group);
+ g_category_groups[category_index] = new_group;
+ DCHECK(!g_category_group_enabled[category_index]);
+ // Note that if both included and excluded patterns in the
+ // TraceConfig are empty, we exclude nothing,
+ // thereby enabling this category group.
+ UpdateCategoryGroupEnabledFlag(category_index);
+ category_group_enabled = &g_category_group_enabled[category_index];
+ // Update the max index now.
+ base::Release_Store(&g_category_index, category_index + 1);
+ } else {
+ category_group_enabled =
+ &g_category_group_enabled[g_category_categories_exhausted];
+ }
+ return category_group_enabled;
+}
+
+} // namespace tracing
+} // namespace platform
+} // namespace v8