LCOV - code coverage report
Current view: top level - src/libplatform/tracing - tracing-controller.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 62 67 92.5 %
Date: 2017-10-20 Functions: 14 15 93.3 %

          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 <string.h>
       7             : 
       8             : #include "include/libplatform/v8-tracing.h"
       9             : 
      10             : #include "src/base/atomicops.h"
      11             : #include "src/base/platform/mutex.h"
      12             : 
      13             : namespace v8 {
      14             : namespace platform {
      15             : namespace tracing {
      16             : 
      17             : #define MAX_CATEGORY_GROUPS 200
      18             : 
      19             : // Parallel arrays g_category_groups and g_category_group_enabled are separate
      20             : // so that a pointer to a member of g_category_group_enabled can be easily
      21             : // converted to an index into g_category_groups. This allows macros to deal
      22             : // only with char enabled pointers from g_category_group_enabled, and we can
      23             : // convert internally to determine the category name from the char enabled
      24             : // pointer.
      25             : const char* g_category_groups[MAX_CATEGORY_GROUPS] = {
      26             :     "toplevel", "tracing already shutdown",
      27             :     "tracing categories exhausted; must increase MAX_CATEGORY_GROUPS",
      28             :     "__metadata"};
      29             : 
      30             : // The enabled flag is char instead of bool so that the API can be used from C.
      31             : unsigned char g_category_group_enabled[MAX_CATEGORY_GROUPS] = {0};
      32             : // Indexes here have to match the g_category_groups array indexes above.
      33             : const int g_category_already_shutdown = 1;
      34             : const int g_category_categories_exhausted = 2;
      35             : // Metadata category not used in V8.
      36             : // const int g_category_metadata = 3;
      37             : const int g_num_builtin_categories = 4;
      38             : 
      39             : // Skip default categories.
      40             : v8::base::AtomicWord g_category_index = g_num_builtin_categories;
      41             : 
      42      162123 : TracingController::TracingController() {}
      43             : 
      44      159616 : TracingController::~TracingController() { StopTracing(); }
      45             : 
      46       54041 : void TracingController::Initialize(TraceBuffer* trace_buffer) {
      47             :   trace_buffer_.reset(trace_buffer);
      48       54041 :   mutex_.reset(new base::Mutex());
      49       54041 : }
      50             : 
      51         161 : uint64_t TracingController::AddTraceEvent(
      52             :     char phase, const uint8_t* category_enabled_flag, const char* name,
      53             :     const char* scope, uint64_t id, uint64_t bind_id, int num_args,
      54             :     const char** arg_names, const uint8_t* arg_types,
      55             :     const uint64_t* arg_values,
      56             :     std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables,
      57             :     unsigned int flags) {
      58             :   uint64_t handle;
      59         161 :   TraceObject* trace_object = trace_buffer_->AddTraceEvent(&handle);
      60         161 :   if (trace_object) {
      61             :     trace_object->Initialize(phase, category_enabled_flag, name, scope, id,
      62             :                              bind_id, num_args, arg_names, arg_types,
      63         161 :                              arg_values, arg_convertables, flags);
      64             :   }
      65         161 :   return handle;
      66             : }
      67             : 
      68           0 : void TracingController::UpdateTraceEventDuration(
      69             :     const uint8_t* category_enabled_flag, const char* name, uint64_t handle) {
      70           0 :   TraceObject* trace_object = trace_buffer_->GetEventByHandle(handle);
      71           0 :   if (!trace_object) return;
      72           0 :   trace_object->UpdateDuration();
      73             : }
      74             : 
      75     1487004 : const uint8_t* TracingController::GetCategoryGroupEnabled(
      76             :     const char* category_group) {
      77     1487004 :   if (!trace_buffer_) {
      78             :     DCHECK(!g_category_group_enabled[g_category_already_shutdown]);
      79             :     return &g_category_group_enabled[g_category_already_shutdown];
      80             :   }
      81         274 :   return GetCategoryGroupEnabledInternal(category_group);
      82             : }
      83             : 
      84         156 : const char* TracingController::GetCategoryGroupName(
      85             :     const uint8_t* category_group_enabled) {
      86             :   // Calculate the index of the category group by finding
      87             :   // category_group_enabled in g_category_group_enabled array.
      88             :   uintptr_t category_begin =
      89         156 :       reinterpret_cast<uintptr_t>(g_category_group_enabled);
      90         156 :   uintptr_t category_ptr = reinterpret_cast<uintptr_t>(category_group_enabled);
      91             :   // Check for out of bounds category pointers.
      92             :   DCHECK(category_ptr >= category_begin &&
      93             :          category_ptr < reinterpret_cast<uintptr_t>(g_category_group_enabled +
      94             :                                                     MAX_CATEGORY_GROUPS));
      95             :   uintptr_t category_index =
      96         156 :       (category_ptr - category_begin) / sizeof(g_category_group_enabled[0]);
      97         156 :   return g_category_groups[category_index];
      98             : }
      99             : 
     100          35 : void TracingController::StartTracing(TraceConfig* trace_config) {
     101             :   trace_config_.reset(trace_config);
     102          35 :   std::unordered_set<v8::TracingController::TraceStateObserver*> observers_copy;
     103             :   {
     104             :     base::LockGuard<base::Mutex> lock(mutex_.get());
     105          35 :     mode_ = RECORDING_MODE;
     106          35 :     UpdateCategoryGroupEnabledFlags();
     107             :     observers_copy = observers_;
     108             :   }
     109          76 :   for (auto o : observers_copy) {
     110           6 :     o->OnTraceEnabled();
     111             :   }
     112          35 : }
     113             : 
     114       53250 : void TracingController::StopTracing() {
     115       53250 :   if (mode_ == DISABLED) {
     116       53215 :     return;
     117             :   }
     118             :   DCHECK(trace_buffer_);
     119          35 :   mode_ = DISABLED;
     120          35 :   UpdateCategoryGroupEnabledFlags();
     121          35 :   std::unordered_set<v8::TracingController::TraceStateObserver*> observers_copy;
     122             :   {
     123             :     base::LockGuard<base::Mutex> lock(mutex_.get());
     124             :     observers_copy = observers_;
     125             :   }
     126          81 :   for (auto o : observers_copy) {
     127          11 :     o->OnTraceDisabled();
     128             :   }
     129          35 :   trace_buffer_->Flush();
     130             : }
     131             : 
     132         376 : void TracingController::UpdateCategoryGroupEnabledFlag(size_t category_index) {
     133             :   unsigned char enabled_flag = 0;
     134         376 :   const char* category_group = g_category_groups[category_index];
     135         561 :   if (mode_ == RECORDING_MODE &&
     136         185 :       trace_config_->IsCategoryGroupEnabled(category_group)) {
     137             :     enabled_flag |= ENABLED_FOR_RECORDING;
     138             :   }
     139             : 
     140             :   // TODO(fmeawad): EventCallback and ETW modes are not yet supported in V8.
     141             :   // TODO(primiano): this is a temporary workaround for catapult:#2341,
     142             :   // to guarantee that metadata events are always added even if the category
     143             :   // filter is "-*". See crbug.com/618054 for more details and long-term fix.
     144         376 :   if (mode_ == RECORDING_MODE && !strcmp(category_group, "__metadata")) {
     145             :     enabled_flag |= ENABLED_FOR_RECORDING;
     146             :   }
     147             : 
     148             :   base::Relaxed_Store(reinterpret_cast<base::Atomic8*>(
     149             :                           g_category_group_enabled + category_index),
     150         376 :                       enabled_flag);
     151         376 : }
     152             : 
     153          70 : void TracingController::UpdateCategoryGroupEnabledFlags() {
     154             :   size_t category_index = base::Relaxed_Load(&g_category_index);
     155          70 :   for (size_t i = 0; i < category_index; i++) UpdateCategoryGroupEnabledFlag(i);
     156          70 : }
     157             : 
     158         274 : const uint8_t* TracingController::GetCategoryGroupEnabledInternal(
     159             :     const char* category_group) {
     160             :   // Check that category groups does not contain double quote
     161             :   DCHECK(!strchr(category_group, '"'));
     162             : 
     163             :   // The g_category_groups is append only, avoid using a lock for the fast path.
     164             :   size_t current_category_index = v8::base::Acquire_Load(&g_category_index);
     165             : 
     166             :   // Search for pre-existing category group.
     167        1564 :   for (size_t i = 0; i < current_category_index; ++i) {
     168        1519 :     if (strcmp(g_category_groups[i], category_group) == 0) {
     169         229 :       return &g_category_group_enabled[i];
     170             :     }
     171             :   }
     172             : 
     173             :   unsigned char* category_group_enabled = nullptr;
     174             :   size_t category_index = base::Acquire_Load(&g_category_index);
     175         265 :   for (size_t i = 0; i < category_index; ++i) {
     176         220 :     if (strcmp(g_category_groups[i], category_group) == 0) {
     177           0 :       return &g_category_group_enabled[i];
     178             :     }
     179             :   }
     180             : 
     181             :   // Create a new category group.
     182             :   // Check that there is a slot for the new category_group.
     183             :   DCHECK(category_index < MAX_CATEGORY_GROUPS);
     184          45 :   if (category_index < MAX_CATEGORY_GROUPS) {
     185             :     // Don't hold on to the category_group pointer, so that we can create
     186             :     // category groups with strings not known at compile time (this is
     187             :     // required by SetWatchEvent).
     188          45 :     const char* new_group = strdup(category_group);
     189          45 :     g_category_groups[category_index] = new_group;
     190             :     DCHECK(!g_category_group_enabled[category_index]);
     191             :     // Note that if both included and excluded patterns in the
     192             :     // TraceConfig are empty, we exclude nothing,
     193             :     // thereby enabling this category group.
     194          45 :     UpdateCategoryGroupEnabledFlag(category_index);
     195          45 :     category_group_enabled = &g_category_group_enabled[category_index];
     196             :     // Update the max index now.
     197          45 :     base::Release_Store(&g_category_index, category_index + 1);
     198             :   } else {
     199             :     category_group_enabled =
     200             :         &g_category_group_enabled[g_category_categories_exhausted];
     201             :   }
     202          45 :   return category_group_enabled;
     203             : }
     204             : 
     205       53994 : void TracingController::AddTraceStateObserver(
     206             :     v8::TracingController::TraceStateObserver* observer) {
     207             :   {
     208             :     base::LockGuard<base::Mutex> lock(mutex_.get());
     209             :     observers_.insert(observer);
     210      107988 :     if (mode_ != RECORDING_MODE) return;
     211             :   }
     212             :   // Fire the observer if recording is already in progress.
     213          11 :   observer->OnTraceEnabled();
     214             : }
     215             : 
     216       53168 : void TracingController::RemoveTraceStateObserver(
     217             :     v8::TracingController::TraceStateObserver* observer) {
     218             :   base::LockGuard<base::Mutex> lock(mutex_.get());
     219             :   DCHECK(observers_.find(observer) != observers_.end());
     220             :   observers_.erase(observer);
     221       53168 : }
     222             : 
     223             : }  // namespace tracing
     224             : }  // namespace platform
     225             : }  // namespace v8

Generated by: LCOV version 1.10