diff options
author | Michaël Zasso <targos@protonmail.com> | 2016-09-06 22:49:51 +0200 |
---|---|---|
committer | Michaël Zasso <targos@protonmail.com> | 2016-09-22 09:51:19 +0200 |
commit | ec02b811a8a5c999bab4de312be2d732b7d9d50b (patch) | |
tree | ca3068017254f238cf413a451c57a803572983a4 /deps/v8/src/libplatform/tracing | |
parent | d2eb7ce0105369a9cad82787cb33a665e9bd00ad (diff) | |
download | node-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.cc | 109 | ||||
-rw-r--r-- | deps/v8/src/libplatform/tracing/trace-buffer.h | 48 | ||||
-rw-r--r-- | deps/v8/src/libplatform/tracing/trace-config.cc | 42 | ||||
-rw-r--r-- | deps/v8/src/libplatform/tracing/trace-object.cc | 130 | ||||
-rw-r--r-- | deps/v8/src/libplatform/tracing/trace-writer.cc | 163 | ||||
-rw-r--r-- | deps/v8/src/libplatform/tracing/trace-writer.h | 32 | ||||
-rw-r--r-- | deps/v8/src/libplatform/tracing/tracing-controller.cc | 177 |
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 |