LCOV - code coverage report
Current view: top level - src/libplatform/tracing - tracing-controller.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 74 86 86.0 %
Date: 2019-01-20 Functions: 15 17 88.2 %

          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             : #define MAX_CATEGORY_GROUPS 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[MAX_CATEGORY_GROUPS] = {
      28             :     "toplevel",
      29             :     "tracing categories exhausted; must increase MAX_CATEGORY_GROUPS",
      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[MAX_CATEGORY_GROUPS] = {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      116620 : TracingController::~TracingController() {
      46       58310 :   StopTracing();
      47             : 
      48             :   {
      49             :     // Free memory for category group names allocated via strdup.
      50             :     base::MutexGuard lock(mutex_.get());
      51      225989 :     for (size_t i = g_category_index - 1; i >= g_num_builtin_categories; --i) {
      52      167679 :       const char* group = g_category_groups[i];
      53      167679 :       g_category_groups[i] = nullptr;
      54      167679 :       free(const_cast<char*>(group));
      55             :     }
      56       58310 :     g_category_index = g_num_builtin_categories;
      57             :   }
      58      116620 : }
      59             : 
      60       61342 : void TracingController::Initialize(TraceBuffer* trace_buffer) {
      61             :   trace_buffer_.reset(trace_buffer);
      62       61342 :   mutex_.reset(new base::Mutex());
      63       61342 : }
      64             : 
      65         140 : int64_t TracingController::CurrentTimestampMicroseconds() {
      66         280 :   return base::TimeTicks::HighResolutionNow().ToInternalValue();
      67             : }
      68             : 
      69         140 : int64_t TracingController::CurrentCpuTimestampMicroseconds() {
      70         280 :   return base::ThreadTicks::Now().ToInternalValue();
      71             : }
      72             : 
      73         140 : 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         140 :   uint64_t handle = 0;
      81         140 :   if (mode_ != DISABLED) {
      82         140 :     TraceObject* trace_object = trace_buffer_->AddTraceEvent(&handle);
      83         140 :     if (trace_object) {
      84             :       trace_object->Initialize(
      85             :           phase, category_enabled_flag, name, scope, id, bind_id, num_args,
      86             :           arg_names, arg_types, arg_values, arg_convertables, flags,
      87         140 :           CurrentTimestampMicroseconds(), CurrentCpuTimestampMicroseconds());
      88             :     }
      89             :   }
      90         140 :   return handle;
      91             : }
      92             : 
      93           0 : uint64_t TracingController::AddTraceEventWithTimestamp(
      94             :     char phase, const uint8_t* category_enabled_flag, const char* name,
      95             :     const char* scope, uint64_t id, uint64_t bind_id, int num_args,
      96             :     const char** arg_names, const uint8_t* arg_types,
      97             :     const uint64_t* arg_values,
      98             :     std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables,
      99             :     unsigned int flags, int64_t timestamp) {
     100           0 :   uint64_t handle = 0;
     101           0 :   if (mode_ != DISABLED) {
     102           0 :     TraceObject* trace_object = trace_buffer_->AddTraceEvent(&handle);
     103           0 :     if (trace_object) {
     104             :       trace_object->Initialize(phase, category_enabled_flag, name, scope, id,
     105             :                                bind_id, num_args, arg_names, arg_types,
     106             :                                arg_values, arg_convertables, flags, timestamp,
     107           0 :                                CurrentCpuTimestampMicroseconds());
     108             :     }
     109             :   }
     110           0 :   return handle;
     111             : }
     112             : 
     113           0 : void TracingController::UpdateTraceEventDuration(
     114             :     const uint8_t* category_enabled_flag, const char* name, uint64_t handle) {
     115           0 :   TraceObject* trace_object = trace_buffer_->GetEventByHandle(handle);
     116           0 :   if (!trace_object) return;
     117           0 :   trace_object->UpdateDuration(CurrentTimestampMicroseconds(),
     118           0 :                                CurrentCpuTimestampMicroseconds());
     119             : }
     120             : 
     121     1789196 : const uint8_t* TracingController::GetCategoryGroupEnabled(
     122             :     const char* category_group) {
     123     1789196 :   return GetCategoryGroupEnabledInternal(category_group);
     124             : }
     125             : 
     126         150 : const char* TracingController::GetCategoryGroupName(
     127             :     const uint8_t* category_group_enabled) {
     128             :   // Calculate the index of the category group by finding
     129             :   // category_group_enabled in g_category_group_enabled array.
     130             :   uintptr_t category_begin =
     131         150 :       reinterpret_cast<uintptr_t>(g_category_group_enabled);
     132         150 :   uintptr_t category_ptr = reinterpret_cast<uintptr_t>(category_group_enabled);
     133             :   // Check for out of bounds category pointers.
     134             :   DCHECK(category_ptr >= category_begin &&
     135             :          category_ptr < reinterpret_cast<uintptr_t>(g_category_group_enabled +
     136             :                                                     MAX_CATEGORY_GROUPS));
     137             :   uintptr_t category_index =
     138         150 :       (category_ptr - category_begin) / sizeof(g_category_group_enabled[0]);
     139         150 :   return g_category_groups[category_index];
     140             : }
     141             : 
     142          31 : void TracingController::StartTracing(TraceConfig* trace_config) {
     143             :   trace_config_.reset(trace_config);
     144          31 :   std::unordered_set<v8::TracingController::TraceStateObserver*> observers_copy;
     145             :   {
     146             :     base::MutexGuard lock(mutex_.get());
     147          31 :     mode_ = RECORDING_MODE;
     148          31 :     UpdateCategoryGroupEnabledFlags();
     149             :     observers_copy = observers_;
     150             :   }
     151          69 :   for (auto o : observers_copy) {
     152           7 :     o->OnTraceEnabled();
     153             :   }
     154          31 : }
     155             : 
     156       58340 : void TracingController::StopTracing() {
     157       58340 :   if (mode_ == DISABLED) {
     158       58309 :     return;
     159             :   }
     160             :   DCHECK(trace_buffer_);
     161          31 :   mode_ = DISABLED;
     162          31 :   UpdateCategoryGroupEnabledFlags();
     163          31 :   std::unordered_set<v8::TracingController::TraceStateObserver*> observers_copy;
     164             :   {
     165             :     base::MutexGuard lock(mutex_.get());
     166             :     observers_copy = observers_;
     167             :   }
     168          67 :   for (auto o : observers_copy) {
     169           5 :     o->OnTraceDisabled();
     170             :   }
     171          31 :   trace_buffer_->Flush();
     172             : }
     173             : 
     174      168957 : void TracingController::UpdateCategoryGroupEnabledFlag(size_t category_index) {
     175             :   unsigned char enabled_flag = 0;
     176      168957 :   const char* category_group = g_category_groups[category_index];
     177      169083 :   if (mode_ == RECORDING_MODE &&
     178         126 :       trace_config_->IsCategoryGroupEnabled(category_group)) {
     179             :     enabled_flag |= ENABLED_FOR_RECORDING;
     180             :   }
     181             : 
     182             :   // TODO(fmeawad): EventCallback and ETW modes are not yet supported in V8.
     183             :   // TODO(primiano): this is a temporary workaround for catapult:#2341,
     184             :   // to guarantee that metadata events are always added even if the category
     185             :   // filter is "-*". See crbug.com/618054 for more details and long-term fix.
     186      168957 :   if (mode_ == RECORDING_MODE && !strcmp(category_group, "__metadata")) {
     187             :     enabled_flag |= ENABLED_FOR_RECORDING;
     188             :   }
     189             : 
     190             :   base::Relaxed_Store(reinterpret_cast<base::Atomic8*>(
     191             :                           g_category_group_enabled + category_index),
     192      168957 :                       enabled_flag);
     193      168957 : }
     194             : 
     195          62 : void TracingController::UpdateCategoryGroupEnabledFlags() {
     196             :   size_t category_index = base::Relaxed_Load(&g_category_index);
     197          62 :   for (size_t i = 0; i < category_index; i++) UpdateCategoryGroupEnabledFlag(i);
     198          62 : }
     199             : 
     200     1786946 : const uint8_t* TracingController::GetCategoryGroupEnabledInternal(
     201             :     const char* category_group) {
     202             :   // Check that category groups does not contain double quote
     203             :   DCHECK(!strchr(category_group, '"'));
     204             : 
     205             :   // The g_category_groups is append only, avoid using a lock for the fast path.
     206             :   size_t category_index = base::Acquire_Load(&g_category_index);
     207             : 
     208             :   // Search for pre-existing category group.
     209     9417641 :   for (size_t i = 0; i < category_index; ++i) {
     210     9248797 :     if (strcmp(g_category_groups[i], category_group) == 0) {
     211     1618102 :       return &g_category_group_enabled[i];
     212             :     }
     213             :   }
     214             : 
     215             :   // Slow path. Grab the lock.
     216             :   base::MutexGuard lock(mutex_.get());
     217             : 
     218             :   // Check the list again with lock in hand.
     219             :   unsigned char* category_group_enabled = nullptr;
     220             :   category_index = base::Acquire_Load(&g_category_index);
     221      871507 :   for (size_t i = 0; i < category_index; ++i) {
     222      702769 :     if (strcmp(g_category_groups[i], category_group) == 0) {
     223         108 :       return &g_category_group_enabled[i];
     224             :     }
     225             :   }
     226             : 
     227             :   // Create a new category group.
     228             :   // Check that there is a slot for the new category_group.
     229             :   DCHECK(category_index < MAX_CATEGORY_GROUPS);
     230      168738 :   if (category_index < MAX_CATEGORY_GROUPS) {
     231             :     // Don't hold on to the category_group pointer, so that we can create
     232             :     // category groups with strings not known at compile time (this is
     233             :     // required by SetWatchEvent).
     234      168738 :     const char* new_group = strdup(category_group);
     235      168738 :     g_category_groups[category_index] = new_group;
     236             :     DCHECK(!g_category_group_enabled[category_index]);
     237             :     // Note that if both included and excluded patterns in the
     238             :     // TraceConfig are empty, we exclude nothing,
     239             :     // thereby enabling this category group.
     240      168738 :     UpdateCategoryGroupEnabledFlag(category_index);
     241      168738 :     category_group_enabled = &g_category_group_enabled[category_index];
     242             :     // Update the max index now.
     243      168738 :     base::Release_Store(&g_category_index, category_index + 1);
     244             :   } else {
     245             :     category_group_enabled =
     246             :         &g_category_group_enabled[g_category_categories_exhausted];
     247             :   }
     248      168738 :   return category_group_enabled;
     249             : }
     250             : 
     251      124174 : void TracingController::AddTraceStateObserver(
     252             :     v8::TracingController::TraceStateObserver* observer) {
     253             :   {
     254             :     base::MutexGuard lock(mutex_.get());
     255             :     observers_.insert(observer);
     256      248348 :     if (mode_ != RECORDING_MODE) return;
     257             :   }
     258             :   // Fire the observer if recording is already in progress.
     259           5 :   observer->OnTraceEnabled();
     260             : }
     261             : 
     262      123028 : void TracingController::RemoveTraceStateObserver(
     263             :     v8::TracingController::TraceStateObserver* observer) {
     264             :   base::MutexGuard lock(mutex_.get());
     265             :   DCHECK(observers_.find(observer) != observers_.end());
     266             :   observers_.erase(observer);
     267      123029 : }
     268             : 
     269             : }  // namespace tracing
     270             : }  // namespace platform
     271             : }  // namespace v8

Generated by: LCOV version 1.10