11cb0ef41Sopenharmony_ci// Copyright 2016 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#include <stdio.h>
61cb0ef41Sopenharmony_ci#include <stdlib.h>
71cb0ef41Sopenharmony_ci#include <string.h>
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_ci#include "include/libplatform/v8-tracing.h"
101cb0ef41Sopenharmony_ci#include "src/base/atomicops.h"
111cb0ef41Sopenharmony_ci#include "src/base/platform/mutex.h"
121cb0ef41Sopenharmony_ci#include "src/base/platform/time.h"
131cb0ef41Sopenharmony_ci#include "src/base/platform/wrappers.h"
141cb0ef41Sopenharmony_ci
151cb0ef41Sopenharmony_ci#ifdef V8_USE_PERFETTO
161cb0ef41Sopenharmony_ci#include "perfetto/ext/trace_processor/export_json.h"
171cb0ef41Sopenharmony_ci#include "perfetto/trace_processor/trace_processor.h"
181cb0ef41Sopenharmony_ci#include "perfetto/tracing/tracing.h"
191cb0ef41Sopenharmony_ci#include "protos/perfetto/config/data_source_config.gen.h"
201cb0ef41Sopenharmony_ci#include "protos/perfetto/config/trace_config.gen.h"
211cb0ef41Sopenharmony_ci#include "protos/perfetto/config/track_event/track_event_config.gen.h"
221cb0ef41Sopenharmony_ci#include "src/base/platform/platform.h"
231cb0ef41Sopenharmony_ci#include "src/base/platform/semaphore.h"
241cb0ef41Sopenharmony_ci#include "src/libplatform/tracing/trace-event-listener.h"
251cb0ef41Sopenharmony_ci#endif  // V8_USE_PERFETTO
261cb0ef41Sopenharmony_ci
271cb0ef41Sopenharmony_ci#ifdef V8_USE_PERFETTO
281cb0ef41Sopenharmony_ciclass JsonOutputWriter : public perfetto::trace_processor::json::OutputWriter {
291cb0ef41Sopenharmony_ci public:
301cb0ef41Sopenharmony_ci  explicit JsonOutputWriter(std::ostream* stream) : stream_(stream) {}
311cb0ef41Sopenharmony_ci
321cb0ef41Sopenharmony_ci  perfetto::trace_processor::util::Status AppendString(
331cb0ef41Sopenharmony_ci      const std::string& string) override {
341cb0ef41Sopenharmony_ci    *stream_ << string;
351cb0ef41Sopenharmony_ci    return perfetto::trace_processor::util::OkStatus();
361cb0ef41Sopenharmony_ci  }
371cb0ef41Sopenharmony_ci
381cb0ef41Sopenharmony_ci private:
391cb0ef41Sopenharmony_ci  std::ostream* stream_;
401cb0ef41Sopenharmony_ci};
411cb0ef41Sopenharmony_ci#endif  // V8_USE_PERFETTO
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_cinamespace v8 {
441cb0ef41Sopenharmony_cinamespace platform {
451cb0ef41Sopenharmony_cinamespace tracing {
461cb0ef41Sopenharmony_ci
471cb0ef41Sopenharmony_ci#if !defined(V8_USE_PERFETTO)
481cb0ef41Sopenharmony_cistatic const size_t kMaxCategoryGroups = 200;
491cb0ef41Sopenharmony_ci
501cb0ef41Sopenharmony_ci// Parallel arrays g_category_groups and g_category_group_enabled are separate
511cb0ef41Sopenharmony_ci// so that a pointer to a member of g_category_group_enabled can be easily
521cb0ef41Sopenharmony_ci// converted to an index into g_category_groups. This allows macros to deal
531cb0ef41Sopenharmony_ci// only with char enabled pointers from g_category_group_enabled, and we can
541cb0ef41Sopenharmony_ci// convert internally to determine the category name from the char enabled
551cb0ef41Sopenharmony_ci// pointer.
561cb0ef41Sopenharmony_ciconst char* g_category_groups[kMaxCategoryGroups] = {
571cb0ef41Sopenharmony_ci    "toplevel",
581cb0ef41Sopenharmony_ci    "tracing categories exhausted; must increase kMaxCategoryGroups",
591cb0ef41Sopenharmony_ci    "__metadata"};
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_ci// The enabled flag is char instead of bool so that the API can be used from C.
621cb0ef41Sopenharmony_ciunsigned char g_category_group_enabled[kMaxCategoryGroups] = {0};
631cb0ef41Sopenharmony_ci// Indexes here have to match the g_category_groups array indexes above.
641cb0ef41Sopenharmony_ciconst int g_category_categories_exhausted = 1;
651cb0ef41Sopenharmony_ci// Metadata category not used in V8.
661cb0ef41Sopenharmony_ci// const int g_category_metadata = 2;
671cb0ef41Sopenharmony_ciconst int g_num_builtin_categories = 3;
681cb0ef41Sopenharmony_ci
691cb0ef41Sopenharmony_ci// Skip default categories.
701cb0ef41Sopenharmony_civ8::base::AtomicWord g_category_index = g_num_builtin_categories;
711cb0ef41Sopenharmony_ci#endif  // !defined(V8_USE_PERFETTO)
721cb0ef41Sopenharmony_ci
731cb0ef41Sopenharmony_ciTracingController::TracingController() { mutex_.reset(new base::Mutex()); }
741cb0ef41Sopenharmony_ci
751cb0ef41Sopenharmony_ciTracingController::~TracingController() {
761cb0ef41Sopenharmony_ci  StopTracing();
771cb0ef41Sopenharmony_ci
781cb0ef41Sopenharmony_ci#if !defined(V8_USE_PERFETTO)
791cb0ef41Sopenharmony_ci  {
801cb0ef41Sopenharmony_ci    // Free memory for category group names allocated via strdup.
811cb0ef41Sopenharmony_ci    base::MutexGuard lock(mutex_.get());
821cb0ef41Sopenharmony_ci    for (size_t i = g_category_index - 1; i >= g_num_builtin_categories; --i) {
831cb0ef41Sopenharmony_ci      const char* group = g_category_groups[i];
841cb0ef41Sopenharmony_ci      g_category_groups[i] = nullptr;
851cb0ef41Sopenharmony_ci      free(const_cast<char*>(group));
861cb0ef41Sopenharmony_ci    }
871cb0ef41Sopenharmony_ci    g_category_index = g_num_builtin_categories;
881cb0ef41Sopenharmony_ci  }
891cb0ef41Sopenharmony_ci#endif  // !defined(V8_USE_PERFETTO)
901cb0ef41Sopenharmony_ci}
911cb0ef41Sopenharmony_ci
921cb0ef41Sopenharmony_ci#ifdef V8_USE_PERFETTO
931cb0ef41Sopenharmony_civoid TracingController::InitializeForPerfetto(std::ostream* output_stream) {
941cb0ef41Sopenharmony_ci  output_stream_ = output_stream;
951cb0ef41Sopenharmony_ci  DCHECK_NOT_NULL(output_stream);
961cb0ef41Sopenharmony_ci  DCHECK(output_stream->good());
971cb0ef41Sopenharmony_ci}
981cb0ef41Sopenharmony_ci
991cb0ef41Sopenharmony_civoid TracingController::SetTraceEventListenerForTesting(
1001cb0ef41Sopenharmony_ci    TraceEventListener* listener) {
1011cb0ef41Sopenharmony_ci  listener_for_testing_ = listener;
1021cb0ef41Sopenharmony_ci}
1031cb0ef41Sopenharmony_ci#else   // !V8_USE_PERFETTO
1041cb0ef41Sopenharmony_civoid TracingController::Initialize(TraceBuffer* trace_buffer) {
1051cb0ef41Sopenharmony_ci  trace_buffer_.reset(trace_buffer);
1061cb0ef41Sopenharmony_ci}
1071cb0ef41Sopenharmony_ci
1081cb0ef41Sopenharmony_ciint64_t TracingController::CurrentTimestampMicroseconds() {
1091cb0ef41Sopenharmony_ci  return base::TimeTicks::Now().ToInternalValue();
1101cb0ef41Sopenharmony_ci}
1111cb0ef41Sopenharmony_ci
1121cb0ef41Sopenharmony_ciint64_t TracingController::CurrentCpuTimestampMicroseconds() {
1131cb0ef41Sopenharmony_ci  return base::ThreadTicks::Now().ToInternalValue();
1141cb0ef41Sopenharmony_ci}
1151cb0ef41Sopenharmony_ci
1161cb0ef41Sopenharmony_ciuint64_t TracingController::AddTraceEvent(
1171cb0ef41Sopenharmony_ci    char phase, const uint8_t* category_enabled_flag, const char* name,
1181cb0ef41Sopenharmony_ci    const char* scope, uint64_t id, uint64_t bind_id, int num_args,
1191cb0ef41Sopenharmony_ci    const char** arg_names, const uint8_t* arg_types,
1201cb0ef41Sopenharmony_ci    const uint64_t* arg_values,
1211cb0ef41Sopenharmony_ci    std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables,
1221cb0ef41Sopenharmony_ci    unsigned int flags) {
1231cb0ef41Sopenharmony_ci  int64_t now_us = CurrentTimestampMicroseconds();
1241cb0ef41Sopenharmony_ci
1251cb0ef41Sopenharmony_ci  return AddTraceEventWithTimestamp(
1261cb0ef41Sopenharmony_ci      phase, category_enabled_flag, name, scope, id, bind_id, num_args,
1271cb0ef41Sopenharmony_ci      arg_names, arg_types, arg_values, arg_convertables, flags, now_us);
1281cb0ef41Sopenharmony_ci}
1291cb0ef41Sopenharmony_ci
1301cb0ef41Sopenharmony_ciuint64_t TracingController::AddTraceEventWithTimestamp(
1311cb0ef41Sopenharmony_ci    char phase, const uint8_t* category_enabled_flag, const char* name,
1321cb0ef41Sopenharmony_ci    const char* scope, uint64_t id, uint64_t bind_id, int num_args,
1331cb0ef41Sopenharmony_ci    const char** arg_names, const uint8_t* arg_types,
1341cb0ef41Sopenharmony_ci    const uint64_t* arg_values,
1351cb0ef41Sopenharmony_ci    std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables,
1361cb0ef41Sopenharmony_ci    unsigned int flags, int64_t timestamp) {
1371cb0ef41Sopenharmony_ci  int64_t cpu_now_us = CurrentCpuTimestampMicroseconds();
1381cb0ef41Sopenharmony_ci
1391cb0ef41Sopenharmony_ci  uint64_t handle = 0;
1401cb0ef41Sopenharmony_ci  if (recording_.load(std::memory_order_acquire)) {
1411cb0ef41Sopenharmony_ci    TraceObject* trace_object = trace_buffer_->AddTraceEvent(&handle);
1421cb0ef41Sopenharmony_ci    if (trace_object) {
1431cb0ef41Sopenharmony_ci      {
1441cb0ef41Sopenharmony_ci        base::MutexGuard lock(mutex_.get());
1451cb0ef41Sopenharmony_ci        trace_object->Initialize(phase, category_enabled_flag, name, scope, id,
1461cb0ef41Sopenharmony_ci                                 bind_id, num_args, arg_names, arg_types,
1471cb0ef41Sopenharmony_ci                                 arg_values, arg_convertables, flags, timestamp,
1481cb0ef41Sopenharmony_ci                                 cpu_now_us);
1491cb0ef41Sopenharmony_ci      }
1501cb0ef41Sopenharmony_ci    }
1511cb0ef41Sopenharmony_ci  }
1521cb0ef41Sopenharmony_ci  return handle;
1531cb0ef41Sopenharmony_ci}
1541cb0ef41Sopenharmony_ci
1551cb0ef41Sopenharmony_civoid TracingController::UpdateTraceEventDuration(
1561cb0ef41Sopenharmony_ci    const uint8_t* category_enabled_flag, const char* name, uint64_t handle) {
1571cb0ef41Sopenharmony_ci  int64_t now_us = CurrentTimestampMicroseconds();
1581cb0ef41Sopenharmony_ci  int64_t cpu_now_us = CurrentCpuTimestampMicroseconds();
1591cb0ef41Sopenharmony_ci
1601cb0ef41Sopenharmony_ci  TraceObject* trace_object = trace_buffer_->GetEventByHandle(handle);
1611cb0ef41Sopenharmony_ci  if (!trace_object) return;
1621cb0ef41Sopenharmony_ci  trace_object->UpdateDuration(now_us, cpu_now_us);
1631cb0ef41Sopenharmony_ci}
1641cb0ef41Sopenharmony_ci
1651cb0ef41Sopenharmony_ciconst char* TracingController::GetCategoryGroupName(
1661cb0ef41Sopenharmony_ci    const uint8_t* category_group_enabled) {
1671cb0ef41Sopenharmony_ci  // Calculate the index of the category group by finding
1681cb0ef41Sopenharmony_ci  // category_group_enabled in g_category_group_enabled array.
1691cb0ef41Sopenharmony_ci  uintptr_t category_begin =
1701cb0ef41Sopenharmony_ci      reinterpret_cast<uintptr_t>(g_category_group_enabled);
1711cb0ef41Sopenharmony_ci  uintptr_t category_ptr = reinterpret_cast<uintptr_t>(category_group_enabled);
1721cb0ef41Sopenharmony_ci  // Check for out of bounds category pointers.
1731cb0ef41Sopenharmony_ci  DCHECK(category_ptr >= category_begin &&
1741cb0ef41Sopenharmony_ci         category_ptr < reinterpret_cast<uintptr_t>(g_category_group_enabled +
1751cb0ef41Sopenharmony_ci                                                    kMaxCategoryGroups));
1761cb0ef41Sopenharmony_ci  uintptr_t category_index =
1771cb0ef41Sopenharmony_ci      (category_ptr - category_begin) / sizeof(g_category_group_enabled[0]);
1781cb0ef41Sopenharmony_ci  return g_category_groups[category_index];
1791cb0ef41Sopenharmony_ci}
1801cb0ef41Sopenharmony_ci#endif  // !defined(V8_USE_PERFETTO)
1811cb0ef41Sopenharmony_ci
1821cb0ef41Sopenharmony_civoid TracingController::StartTracing(TraceConfig* trace_config) {
1831cb0ef41Sopenharmony_ci#ifdef V8_USE_PERFETTO
1841cb0ef41Sopenharmony_ci  DCHECK_NOT_NULL(output_stream_);
1851cb0ef41Sopenharmony_ci  DCHECK(output_stream_->good());
1861cb0ef41Sopenharmony_ci  perfetto::trace_processor::Config processor_config;
1871cb0ef41Sopenharmony_ci  trace_processor_ =
1881cb0ef41Sopenharmony_ci      perfetto::trace_processor::TraceProcessorStorage::CreateInstance(
1891cb0ef41Sopenharmony_ci          processor_config);
1901cb0ef41Sopenharmony_ci
1911cb0ef41Sopenharmony_ci  ::perfetto::TraceConfig perfetto_trace_config;
1921cb0ef41Sopenharmony_ci  perfetto_trace_config.add_buffers()->set_size_kb(4096);
1931cb0ef41Sopenharmony_ci  auto ds_config = perfetto_trace_config.add_data_sources()->mutable_config();
1941cb0ef41Sopenharmony_ci  ds_config->set_name("track_event");
1951cb0ef41Sopenharmony_ci  perfetto::protos::gen::TrackEventConfig te_config;
1961cb0ef41Sopenharmony_ci  te_config.add_disabled_categories("*");
1971cb0ef41Sopenharmony_ci  for (const auto& category : trace_config->GetEnabledCategories())
1981cb0ef41Sopenharmony_ci    te_config.add_enabled_categories(category);
1991cb0ef41Sopenharmony_ci  ds_config->set_track_event_config_raw(te_config.SerializeAsString());
2001cb0ef41Sopenharmony_ci
2011cb0ef41Sopenharmony_ci  tracing_session_ =
2021cb0ef41Sopenharmony_ci      perfetto::Tracing::NewTrace(perfetto::BackendType::kUnspecifiedBackend);
2031cb0ef41Sopenharmony_ci  tracing_session_->Setup(perfetto_trace_config);
2041cb0ef41Sopenharmony_ci  tracing_session_->StartBlocking();
2051cb0ef41Sopenharmony_ci
2061cb0ef41Sopenharmony_ci#endif  // V8_USE_PERFETTO
2071cb0ef41Sopenharmony_ci
2081cb0ef41Sopenharmony_ci  trace_config_.reset(trace_config);
2091cb0ef41Sopenharmony_ci  std::unordered_set<v8::TracingController::TraceStateObserver*> observers_copy;
2101cb0ef41Sopenharmony_ci  {
2111cb0ef41Sopenharmony_ci    base::MutexGuard lock(mutex_.get());
2121cb0ef41Sopenharmony_ci    recording_.store(true, std::memory_order_release);
2131cb0ef41Sopenharmony_ci#ifndef V8_USE_PERFETTO
2141cb0ef41Sopenharmony_ci    UpdateCategoryGroupEnabledFlags();
2151cb0ef41Sopenharmony_ci#endif
2161cb0ef41Sopenharmony_ci    observers_copy = observers_;
2171cb0ef41Sopenharmony_ci  }
2181cb0ef41Sopenharmony_ci  for (auto o : observers_copy) {
2191cb0ef41Sopenharmony_ci    o->OnTraceEnabled();
2201cb0ef41Sopenharmony_ci  }
2211cb0ef41Sopenharmony_ci}
2221cb0ef41Sopenharmony_ci
2231cb0ef41Sopenharmony_civoid TracingController::StopTracing() {
2241cb0ef41Sopenharmony_ci  bool expected = true;
2251cb0ef41Sopenharmony_ci  if (!recording_.compare_exchange_strong(expected, false)) {
2261cb0ef41Sopenharmony_ci    return;
2271cb0ef41Sopenharmony_ci  }
2281cb0ef41Sopenharmony_ci#ifndef V8_USE_PERFETTO
2291cb0ef41Sopenharmony_ci  UpdateCategoryGroupEnabledFlags();
2301cb0ef41Sopenharmony_ci#endif
2311cb0ef41Sopenharmony_ci  std::unordered_set<v8::TracingController::TraceStateObserver*> observers_copy;
2321cb0ef41Sopenharmony_ci  {
2331cb0ef41Sopenharmony_ci    base::MutexGuard lock(mutex_.get());
2341cb0ef41Sopenharmony_ci    observers_copy = observers_;
2351cb0ef41Sopenharmony_ci  }
2361cb0ef41Sopenharmony_ci  for (auto o : observers_copy) {
2371cb0ef41Sopenharmony_ci    o->OnTraceDisabled();
2381cb0ef41Sopenharmony_ci  }
2391cb0ef41Sopenharmony_ci
2401cb0ef41Sopenharmony_ci#ifdef V8_USE_PERFETTO
2411cb0ef41Sopenharmony_ci  tracing_session_->StopBlocking();
2421cb0ef41Sopenharmony_ci
2431cb0ef41Sopenharmony_ci  std::vector<char> trace = tracing_session_->ReadTraceBlocking();
2441cb0ef41Sopenharmony_ci  std::unique_ptr<uint8_t[]> trace_bytes(new uint8_t[trace.size()]);
2451cb0ef41Sopenharmony_ci  std::copy(&trace[0], &trace[0] + trace.size(), &trace_bytes[0]);
2461cb0ef41Sopenharmony_ci  trace_processor_->Parse(std::move(trace_bytes), trace.size());
2471cb0ef41Sopenharmony_ci  trace_processor_->NotifyEndOfFile();
2481cb0ef41Sopenharmony_ci  JsonOutputWriter output_writer(output_stream_);
2491cb0ef41Sopenharmony_ci  auto status = perfetto::trace_processor::json::ExportJson(
2501cb0ef41Sopenharmony_ci      trace_processor_.get(), &output_writer, nullptr, nullptr, nullptr);
2511cb0ef41Sopenharmony_ci  DCHECK(status.ok());
2521cb0ef41Sopenharmony_ci
2531cb0ef41Sopenharmony_ci  if (listener_for_testing_) listener_for_testing_->ParseFromArray(trace);
2541cb0ef41Sopenharmony_ci
2551cb0ef41Sopenharmony_ci  trace_processor_.reset();
2561cb0ef41Sopenharmony_ci#else
2571cb0ef41Sopenharmony_ci
2581cb0ef41Sopenharmony_ci  {
2591cb0ef41Sopenharmony_ci    base::MutexGuard lock(mutex_.get());
2601cb0ef41Sopenharmony_ci    DCHECK(trace_buffer_);
2611cb0ef41Sopenharmony_ci    trace_buffer_->Flush();
2621cb0ef41Sopenharmony_ci  }
2631cb0ef41Sopenharmony_ci#endif  // V8_USE_PERFETTO
2641cb0ef41Sopenharmony_ci}
2651cb0ef41Sopenharmony_ci
2661cb0ef41Sopenharmony_ci#if !defined(V8_USE_PERFETTO)
2671cb0ef41Sopenharmony_civoid TracingController::UpdateCategoryGroupEnabledFlag(size_t category_index) {
2681cb0ef41Sopenharmony_ci  unsigned char enabled_flag = 0;
2691cb0ef41Sopenharmony_ci  const char* category_group = g_category_groups[category_index];
2701cb0ef41Sopenharmony_ci  if (recording_.load(std::memory_order_acquire) &&
2711cb0ef41Sopenharmony_ci      trace_config_->IsCategoryGroupEnabled(category_group)) {
2721cb0ef41Sopenharmony_ci    enabled_flag |= ENABLED_FOR_RECORDING;
2731cb0ef41Sopenharmony_ci  }
2741cb0ef41Sopenharmony_ci
2751cb0ef41Sopenharmony_ci  // TODO(fmeawad): EventCallback and ETW modes are not yet supported in V8.
2761cb0ef41Sopenharmony_ci  // TODO(primiano): this is a temporary workaround for catapult:#2341,
2771cb0ef41Sopenharmony_ci  // to guarantee that metadata events are always added even if the category
2781cb0ef41Sopenharmony_ci  // filter is "-*". See crbug.com/618054 for more details and long-term fix.
2791cb0ef41Sopenharmony_ci  if (recording_.load(std::memory_order_acquire) &&
2801cb0ef41Sopenharmony_ci      !strcmp(category_group, "__metadata")) {
2811cb0ef41Sopenharmony_ci    enabled_flag |= ENABLED_FOR_RECORDING;
2821cb0ef41Sopenharmony_ci  }
2831cb0ef41Sopenharmony_ci
2841cb0ef41Sopenharmony_ci  base::Relaxed_Store(reinterpret_cast<base::Atomic8*>(
2851cb0ef41Sopenharmony_ci                          g_category_group_enabled + category_index),
2861cb0ef41Sopenharmony_ci                      enabled_flag);
2871cb0ef41Sopenharmony_ci}
2881cb0ef41Sopenharmony_ci
2891cb0ef41Sopenharmony_civoid TracingController::UpdateCategoryGroupEnabledFlags() {
2901cb0ef41Sopenharmony_ci  size_t category_index = base::Acquire_Load(&g_category_index);
2911cb0ef41Sopenharmony_ci  for (size_t i = 0; i < category_index; i++) UpdateCategoryGroupEnabledFlag(i);
2921cb0ef41Sopenharmony_ci}
2931cb0ef41Sopenharmony_ci
2941cb0ef41Sopenharmony_ciconst uint8_t* TracingController::GetCategoryGroupEnabled(
2951cb0ef41Sopenharmony_ci    const char* category_group) {
2961cb0ef41Sopenharmony_ci  // Check that category group does not contain double quote
2971cb0ef41Sopenharmony_ci  DCHECK(!strchr(category_group, '"'));
2981cb0ef41Sopenharmony_ci
2991cb0ef41Sopenharmony_ci  // The g_category_groups is append only, avoid using a lock for the fast path.
3001cb0ef41Sopenharmony_ci  size_t category_index = base::Acquire_Load(&g_category_index);
3011cb0ef41Sopenharmony_ci
3021cb0ef41Sopenharmony_ci  // Search for pre-existing category group.
3031cb0ef41Sopenharmony_ci  for (size_t i = 0; i < category_index; ++i) {
3041cb0ef41Sopenharmony_ci    if (strcmp(g_category_groups[i], category_group) == 0) {
3051cb0ef41Sopenharmony_ci      return &g_category_group_enabled[i];
3061cb0ef41Sopenharmony_ci    }
3071cb0ef41Sopenharmony_ci  }
3081cb0ef41Sopenharmony_ci
3091cb0ef41Sopenharmony_ci  // Slow path. Grab the lock.
3101cb0ef41Sopenharmony_ci  base::MutexGuard lock(mutex_.get());
3111cb0ef41Sopenharmony_ci
3121cb0ef41Sopenharmony_ci  // Check the list again with lock in hand.
3131cb0ef41Sopenharmony_ci  unsigned char* category_group_enabled = nullptr;
3141cb0ef41Sopenharmony_ci  category_index = base::Acquire_Load(&g_category_index);
3151cb0ef41Sopenharmony_ci  for (size_t i = 0; i < category_index; ++i) {
3161cb0ef41Sopenharmony_ci    if (strcmp(g_category_groups[i], category_group) == 0) {
3171cb0ef41Sopenharmony_ci      return &g_category_group_enabled[i];
3181cb0ef41Sopenharmony_ci    }
3191cb0ef41Sopenharmony_ci  }
3201cb0ef41Sopenharmony_ci
3211cb0ef41Sopenharmony_ci  // Create a new category group.
3221cb0ef41Sopenharmony_ci  // Check that there is a slot for the new category_group.
3231cb0ef41Sopenharmony_ci  DCHECK(category_index < kMaxCategoryGroups);
3241cb0ef41Sopenharmony_ci  if (category_index < kMaxCategoryGroups) {
3251cb0ef41Sopenharmony_ci    // Don't hold on to the category_group pointer, so that we can create
3261cb0ef41Sopenharmony_ci    // category groups with strings not known at compile time (this is
3271cb0ef41Sopenharmony_ci    // required by SetWatchEvent).
3281cb0ef41Sopenharmony_ci    const char* new_group = base::Strdup(category_group);
3291cb0ef41Sopenharmony_ci    g_category_groups[category_index] = new_group;
3301cb0ef41Sopenharmony_ci    DCHECK(!g_category_group_enabled[category_index]);
3311cb0ef41Sopenharmony_ci    // Note that if both included and excluded patterns in the
3321cb0ef41Sopenharmony_ci    // TraceConfig are empty, we exclude nothing,
3331cb0ef41Sopenharmony_ci    // thereby enabling this category group.
3341cb0ef41Sopenharmony_ci    UpdateCategoryGroupEnabledFlag(category_index);
3351cb0ef41Sopenharmony_ci    category_group_enabled = &g_category_group_enabled[category_index];
3361cb0ef41Sopenharmony_ci    // Update the max index now.
3371cb0ef41Sopenharmony_ci    base::Release_Store(&g_category_index, category_index + 1);
3381cb0ef41Sopenharmony_ci  } else {
3391cb0ef41Sopenharmony_ci    category_group_enabled =
3401cb0ef41Sopenharmony_ci        &g_category_group_enabled[g_category_categories_exhausted];
3411cb0ef41Sopenharmony_ci  }
3421cb0ef41Sopenharmony_ci  return category_group_enabled;
3431cb0ef41Sopenharmony_ci}
3441cb0ef41Sopenharmony_ci#endif  // !defined(V8_USE_PERFETTO)
3451cb0ef41Sopenharmony_ci
3461cb0ef41Sopenharmony_civoid TracingController::AddTraceStateObserver(
3471cb0ef41Sopenharmony_ci    v8::TracingController::TraceStateObserver* observer) {
3481cb0ef41Sopenharmony_ci  {
3491cb0ef41Sopenharmony_ci    base::MutexGuard lock(mutex_.get());
3501cb0ef41Sopenharmony_ci    observers_.insert(observer);
3511cb0ef41Sopenharmony_ci    if (!recording_.load(std::memory_order_acquire)) return;
3521cb0ef41Sopenharmony_ci  }
3531cb0ef41Sopenharmony_ci  // Fire the observer if recording is already in progress.
3541cb0ef41Sopenharmony_ci  observer->OnTraceEnabled();
3551cb0ef41Sopenharmony_ci}
3561cb0ef41Sopenharmony_ci
3571cb0ef41Sopenharmony_civoid TracingController::RemoveTraceStateObserver(
3581cb0ef41Sopenharmony_ci    v8::TracingController::TraceStateObserver* observer) {
3591cb0ef41Sopenharmony_ci  base::MutexGuard lock(mutex_.get());
3601cb0ef41Sopenharmony_ci  DCHECK(observers_.find(observer) != observers_.end());
3611cb0ef41Sopenharmony_ci  observers_.erase(observer);
3621cb0ef41Sopenharmony_ci}
3631cb0ef41Sopenharmony_ci
3641cb0ef41Sopenharmony_ci}  // namespace tracing
3651cb0ef41Sopenharmony_ci}  // namespace platform
3661cb0ef41Sopenharmony_ci}  // namespace v8
367