LCOV - code coverage report
Current view: top level - src/libplatform/tracing - tracing-controller.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 84 84 100.0 %
Date: 2019-04-17 Functions: 16 16 100.0 %

          Line data    Source code
       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 <stdio.h>
       6             : #include <stdlib.h>
       7             : #include <string.h>
       8             : 
       9             : #include "include/libplatform/v8-tracing.h"
      10             : 
      11             : #include "src/base/atomicops.h"
      12             : #include "src/base/platform/mutex.h"
      13             : #include "src/base/platform/time.h"
      14             : 
      15             : namespace v8 {
      16             : namespace platform {
      17             : namespace tracing {
      18             : 
      19             : static const size_t kMaxCategoryGroups = 200;
      20             : 
      21             : // Parallel arrays g_category_groups and g_category_group_enabled are separate
      22             : // so that a pointer to a member of g_category_group_enabled can be easily
      23             : // converted to an index into g_category_groups. This allows macros to deal
      24             : // only with char enabled pointers from g_category_group_enabled, and we can
      25             : // convert internally to determine the category name from the char enabled
      26             : // pointer.
      27             : const char* g_category_groups[kMaxCategoryGroups] = {
      28             :     "toplevel",
      29             :     "tracing categories exhausted; must increase kMaxCategoryGroups",
      30             :     "__metadata"};
      31             : 
      32             : // The enabled flag is char instead of bool so that the API can be used from C.
      33             : unsigned char g_category_group_enabled[kMaxCategoryGroups] = {0};
      34             : // Indexes here have to match the g_category_groups array indexes above.
      35             : const int g_category_categories_exhausted = 1;
      36             : // Metadata category not used in V8.
      37             : // const int g_category_metadata = 2;
      38             : const int g_num_builtin_categories = 3;
      39             : 
      40             : // Skip default categories.
      41             : v8::base::AtomicWord g_category_index = g_num_builtin_categories;
      42             : 
      43             : TracingController::TracingController() = default;
      44             : 
      45      231864 : TracingController::~TracingController() {
      46       57966 :   StopTracing();
      47             : 
      48             :   {
      49             :     // Free memory for category group names allocated via strdup.
      50             :     base::MutexGuard lock(mutex_.get());
      51      265202 :     for (size_t i = g_category_index - 1; i >= g_num_builtin_categories; --i) {
      52      207236 :       const char* group = g_category_groups[i];
      53      207236 :       g_category_groups[i] = nullptr;
      54      207236 :       free(const_cast<char*>(group));
      55             :     }
      56       57966 :     g_category_index = g_num_builtin_categories;
      57             :   }
      58      115932 : }
      59             : 
      60       61069 : void TracingController::Initialize(TraceBuffer* trace_buffer) {
      61             :   trace_buffer_.reset(trace_buffer);
      62       61069 :   mutex_.reset(new base::Mutex());
      63       61069 : }
      64             : 
      65        1407 : int64_t TracingController::CurrentTimestampMicroseconds() {
      66        2814 :   return base::TimeTicks::HighResolutionNow().ToInternalValue();
      67             : }
      68             : 
      69        1831 : int64_t TracingController::CurrentCpuTimestampMicroseconds() {
      70        3662 :   return base::ThreadTicks::Now().ToInternalValue();
      71             : }
      72             : 
      73        5578 : uint64_t TracingController::AddTraceEvent(
      74             :     char phase, const uint8_t* category_enabled_flag, const char* name,
      75             :     const char* scope, uint64_t id, uint64_t bind_id, int num_args,
      76             :     const char** arg_names, const uint8_t* arg_types,
      77             :     const uint64_t* arg_values,
      78             :     std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables,
      79             :     unsigned int flags) {
      80        5578 :   uint64_t handle = 0;
      81        5578 :   if (recording_.load(std::memory_order_acquire)) {
      82        1002 :     TraceObject* trace_object = trace_buffer_->AddTraceEvent(&handle);
      83        1002 :     if (trace_object) {
      84             :       {
      85             :         base::MutexGuard lock(mutex_.get());
      86        2004 :         trace_object->Initialize(
      87             :             phase, category_enabled_flag, name, scope, id, bind_id, num_args,
      88             :             arg_names, arg_types, arg_values, arg_convertables, flags,
      89        3006 :             CurrentTimestampMicroseconds(), CurrentCpuTimestampMicroseconds());
      90             :       }
      91             :     }
      92             :   }
      93        5578 :   return handle;
      94             : }
      95             : 
      96        5000 : uint64_t TracingController::AddTraceEventWithTimestamp(
      97             :     char phase, const uint8_t* category_enabled_flag, const char* name,
      98             :     const char* scope, uint64_t id, uint64_t bind_id, int num_args,
      99             :     const char** arg_names, const uint8_t* arg_types,
     100             :     const uint64_t* arg_values,
     101             :     std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables,
     102             :     unsigned int flags, int64_t timestamp) {
     103        5000 :   uint64_t handle = 0;
     104        5000 :   if (recording_.load(std::memory_order_acquire)) {
     105         424 :     TraceObject* trace_object = trace_buffer_->AddTraceEvent(&handle);
     106         424 :     if (trace_object) {
     107             :       {
     108             :         base::MutexGuard lock(mutex_.get());
     109         424 :         trace_object->Initialize(phase, category_enabled_flag, name, scope, id,
     110             :                                  bind_id, num_args, arg_names, arg_types,
     111             :                                  arg_values, arg_convertables, flags, timestamp,
     112         848 :                                  CurrentCpuTimestampMicroseconds());
     113             :       }
     114             :     }
     115             :   }
     116        5000 :   return handle;
     117             : }
     118             : 
     119         419 : void TracingController::UpdateTraceEventDuration(
     120             :     const uint8_t* category_enabled_flag, const char* name, uint64_t handle) {
     121         419 :   TraceObject* trace_object = trace_buffer_->GetEventByHandle(handle);
     122         419 :   if (!trace_object) return;
     123         405 :   trace_object->UpdateDuration(CurrentTimestampMicroseconds(),
     124         810 :                                CurrentCpuTimestampMicroseconds());
     125             : }
     126             : 
     127         150 : const char* TracingController::GetCategoryGroupName(
     128             :     const uint8_t* category_group_enabled) {
     129             :   // Calculate the index of the category group by finding
     130             :   // category_group_enabled in g_category_group_enabled array.
     131             :   uintptr_t category_begin =
     132         150 :       reinterpret_cast<uintptr_t>(g_category_group_enabled);
     133         150 :   uintptr_t category_ptr = reinterpret_cast<uintptr_t>(category_group_enabled);
     134             :   // Check for out of bounds category pointers.
     135             :   DCHECK(category_ptr >= category_begin &&
     136             :          category_ptr < reinterpret_cast<uintptr_t>(g_category_group_enabled +
     137             :                                                     kMaxCategoryGroups));
     138             :   uintptr_t category_index =
     139         150 :       (category_ptr - category_begin) / sizeof(g_category_group_enabled[0]);
     140         150 :   return g_category_groups[category_index];
     141             : }
     142             : 
     143          41 : void TracingController::StartTracing(TraceConfig* trace_config) {
     144          41 :   trace_config_.reset(trace_config);
     145             :   std::unordered_set<v8::TracingController::TraceStateObserver*> observers_copy;
     146             :   {
     147             :     base::MutexGuard lock(mutex_.get());
     148             :     recording_.store(true, std::memory_order_release);
     149          41 :     UpdateCategoryGroupEnabledFlags();
     150             :     observers_copy = observers_;
     151             :   }
     152          58 :   for (auto o : observers_copy) {
     153          17 :     o->OnTraceEnabled();
     154             :   }
     155          41 : }
     156             : 
     157       58006 : void TracingController::StopTracing() {
     158       58006 :   bool expected = true;
     159       58006 :   if (!recording_.compare_exchange_strong(expected, false)) {
     160       57965 :     return;
     161             :   }
     162             :   DCHECK(trace_buffer_);
     163          41 :   UpdateCategoryGroupEnabledFlags();
     164             :   std::unordered_set<v8::TracingController::TraceStateObserver*> observers_copy;
     165             :   {
     166             :     base::MutexGuard lock(mutex_.get());
     167             :     observers_copy = observers_;
     168             :   }
     169          56 :   for (auto o : observers_copy) {
     170          15 :     o->OnTraceDisabled();
     171             :   }
     172             :   {
     173             :     base::MutexGuard lock(mutex_.get());
     174          41 :     trace_buffer_->Flush();
     175             :   }
     176             : }
     177             : 
     178      209879 : void TracingController::UpdateCategoryGroupEnabledFlag(size_t category_index) {
     179             :   unsigned char enabled_flag = 0;
     180      209879 :   const char* category_group = g_category_groups[category_index];
     181      210094 :   if (recording_.load(std::memory_order_acquire) &&
     182         215 :       trace_config_->IsCategoryGroupEnabled(category_group)) {
     183             :     enabled_flag |= ENABLED_FOR_RECORDING;
     184             :   }
     185             : 
     186             :   // TODO(fmeawad): EventCallback and ETW modes are not yet supported in V8.
     187             :   // TODO(primiano): this is a temporary workaround for catapult:#2341,
     188             :   // to guarantee that metadata events are always added even if the category
     189             :   // filter is "-*". See crbug.com/618054 for more details and long-term fix.
     190      210094 :   if (recording_.load(std::memory_order_acquire) &&
     191         215 :       !strcmp(category_group, "__metadata")) {
     192             :     enabled_flag |= ENABLED_FOR_RECORDING;
     193             :   }
     194             : 
     195      209879 :   base::Relaxed_Store(reinterpret_cast<base::Atomic8*>(
     196             :                           g_category_group_enabled + category_index),
     197             :                       enabled_flag);
     198      209879 : }
     199             : 
     200          82 : void TracingController::UpdateCategoryGroupEnabledFlags() {
     201             :   size_t category_index = base::Acquire_Load(&g_category_index);
     202         432 :   for (size_t i = 0; i < category_index; i++) UpdateCategoryGroupEnabledFlag(i);
     203          82 : }
     204             : 
     205     2181662 : const uint8_t* TracingController::GetCategoryGroupEnabled(
     206             :     const char* category_group) {
     207             :   // Check that category group does not contain double quote
     208             :   DCHECK(!strchr(category_group, '"'));
     209             : 
     210             :   // The g_category_groups is append only, avoid using a lock for the fast path.
     211             :   size_t category_index = base::Acquire_Load(&g_category_index);
     212             : 
     213             :   // Search for pre-existing category group.
     214    21338698 :   for (size_t i = 0; i < category_index; ++i) {
     215    11550399 :     if (strcmp(g_category_groups[i], category_group) == 0) {
     216     1971881 :       return &g_category_group_enabled[i];
     217             :     }
     218             :   }
     219             : 
     220             :   // Slow path. Grab the lock.
     221             :   base::MutexGuard lock(mutex_.get());
     222             : 
     223             :   // Check the list again with lock in hand.
     224             :   unsigned char* category_group_enabled = nullptr;
     225             :   category_index = base::Acquire_Load(&g_category_index);
     226     2101912 :   for (size_t i = 0; i < category_index; ++i) {
     227      946320 :     if (strcmp(g_category_groups[i], category_group) == 0) {
     228         257 :       return &g_category_group_enabled[i];
     229             :     }
     230             :   }
     231             : 
     232             :   // Create a new category group.
     233             :   // Check that there is a slot for the new category_group.
     234             :   DCHECK(category_index < kMaxCategoryGroups);
     235      209529 :   if (category_index < kMaxCategoryGroups) {
     236             :     // Don't hold on to the category_group pointer, so that we can create
     237             :     // category groups with strings not known at compile time (this is
     238             :     // required by SetWatchEvent).
     239      209529 :     const char* new_group = strdup(category_group);
     240      209529 :     g_category_groups[category_index] = new_group;
     241             :     DCHECK(!g_category_group_enabled[category_index]);
     242             :     // Note that if both included and excluded patterns in the
     243             :     // TraceConfig are empty, we exclude nothing,
     244             :     // thereby enabling this category group.
     245      209529 :     UpdateCategoryGroupEnabledFlag(category_index);
     246      209529 :     category_group_enabled = &g_category_group_enabled[category_index];
     247             :     // Update the max index now.
     248      209529 :     base::Release_Store(&g_category_index, category_index + 1);
     249             :   } else {
     250             :     category_group_enabled =
     251             :         &g_category_group_enabled[g_category_categories_exhausted];
     252             :   }
     253             :   return category_group_enabled;
     254             : }
     255             : 
     256      123420 : void TracingController::AddTraceStateObserver(
     257             :     v8::TracingController::TraceStateObserver* observer) {
     258             :   {
     259             :     base::MutexGuard lock(mutex_.get());
     260             :     observers_.insert(observer);
     261      123420 :     if (!recording_.load(std::memory_order_acquire)) return;
     262             :   }
     263             :   // Fire the observer if recording is already in progress.
     264           5 :   observer->OnTraceEnabled();
     265             : }
     266             : 
     267      122255 : void TracingController::RemoveTraceStateObserver(
     268             :     v8::TracingController::TraceStateObserver* observer) {
     269             :   base::MutexGuard lock(mutex_.get());
     270             :   DCHECK(observers_.find(observer) != observers_.end());
     271             :   observers_.erase(observer);
     272      122256 : }
     273             : 
     274             : }  // namespace tracing
     275             : }  // namespace platform
     276             : }  // namespace v8

Generated by: LCOV version 1.10