LCOV - code coverage report
Current view: top level - src/libplatform/tracing - tracing-controller.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 61 66 92.4 %
Date: 2017-04-26 Functions: 13 14 92.9 %

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

Generated by: LCOV version 1.10