OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 The Chromium 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 #ifndef BASE_DEBUG_BLAME_CONTEXT_H_ |
| 6 #define BASE_DEBUG_BLAME_CONTEXT_H_ |
| 7 |
| 8 #include <inttypes.h> |
| 9 |
| 10 #include "base/macros.h" |
| 11 #include "base/strings/stringprintf.h" |
| 12 #include "base/trace_event/trace_event.h" |
| 13 #include "base/trace_event/trace_event_argument.h" |
| 14 |
| 15 namespace base { |
| 16 namespace debug { |
| 17 |
| 18 // A blame context represents a logical unit to which we want to attribute |
| 19 // different costs (CPU, network usage, memory, etc.). An example of a blame |
| 20 // context is an <iframe> element on a web page. Different subsystems can |
| 21 // "enter" and "leave" blame contexts to indicate that they are doing work which |
| 22 // should be accounted against this blame context. |
| 23 // |
| 24 // Each blame context can optionally have a parent blame context, forming a |
| 25 // blame context tree. When work is attributed to a particular blame context, it |
| 26 // is considered to count against all of that context's children too. This is |
| 27 // useful when work cannot be exactly attributed into a more specific context. |
| 28 // For example, Javascript garbage collection generally needs to inspect all |
| 29 // objects on a page instead looking at each <iframe> individually. In this case |
| 30 // the work should be attributed to a blame context which is the parent of all |
| 31 // <iframe> blame contexts. |
| 32 |
| 33 // Abstract blame context base class which can be used for attributing work. |
| 34 class BlameContextBase { |
| 35 public: |
| 36 // Indicate that the current thread is now doing work which should count |
| 37 // against this blame context. |
| 38 virtual void Enter() = 0; |
| 39 |
| 40 // Leave and stop doing work for a previously entered blame context. If |
| 41 // another blame context of the same type was entered prior to this one, it |
| 42 // becomes the active blame context for this thread again. |
| 43 virtual void Leave() = 0; |
| 44 |
| 45 protected: |
| 46 BlameContextBase() {} |
| 47 virtual ~BlameContextBase() {} |
| 48 |
| 49 DISALLOW_COPY_AND_ASSIGN(BlameContextBase); |
| 50 }; |
| 51 |
| 52 // A concrete instance of a blame context which emits blame context trace |
| 53 // events. |category| is the tracing category this context belongs to and |name| |
| 54 // identifies the type of the blame context. |scope| defines the name space for |
| 55 // the |id| parameter (identical ids in different scopes are considered separate |
| 56 // blame context objects). Each string parameter must be a pointer to a constant |
| 57 // string with application lifetime. |
| 58 // |
| 59 // Note that the blame context is templatized to work around a trace event |
| 60 // limitation which prohibits a single trace event macro instantiation to be |
| 61 // used with more than one trace category. |
| 62 // TODO(skyostil): De-templatize this class. |
| 63 template <const char* category, const char* name, const char* scope> |
| 64 class BlameContext : public BlameContextBase, |
| 65 public trace_event::TraceLog::EnabledStateObserver { |
| 66 public: |
| 67 // Construct a blame context with the given |id| belonging to the |scope| |
| 68 // namespace. The blame context will not have a parent. |
| 69 explicit BlameContext(int64_t id) |
| 70 : id_(id), parent_id_(0), parent_scope_(nullptr) { |
| 71 Initialize(); |
| 72 } |
| 73 |
| 74 // Construct a blame context with the given |id| belonging to the |scope| |
| 75 // namespace. |parent_context| identifies the parent for this blame context. |
| 76 // It must belong to the same blame context tree as this context, i.e., |name| |
| 77 // must equal |parent_name|. |
| 78 template <const char* parent_category, |
| 79 const char* parent_name, |
| 80 const char* parent_scope> |
| 81 BlameContext(int64_t id, |
| 82 const BlameContext<parent_category, parent_name, parent_scope>& |
| 83 parent_context) |
| 84 : id_(id), parent_id_(parent_context.id()), parent_scope_(parent_scope) { |
| 85 DCHECK(!strcmp(name, parent_name)) |
| 86 << "parent blame context must be of the same type"; |
| 87 Initialize(); |
| 88 } |
| 89 |
| 90 // BlameContextBase implementation: |
| 91 void Enter() override { |
| 92 TRACE_EVENT_ENTER_CONTEXT(category, name, TRACE_ID_WITH_SCOPE(scope, id_)); |
| 93 } |
| 94 |
| 95 void Leave() override { |
| 96 TRACE_EVENT_LEAVE_CONTEXT(category, name, TRACE_ID_WITH_SCOPE(scope, id_)); |
| 97 } |
| 98 |
| 99 // Record a snapshot of the blame context. This is normally only needed if a |
| 100 // blame context subclass defines custom properties (see AsValueInto) and one |
| 101 // or more of the properties have changed. |
| 102 void TakeSnapshot() { |
| 103 bool is_tracing = false; |
| 104 TRACE_EVENT_CATEGORY_GROUP_ENABLED(category, &is_tracing); |
| 105 if (!is_tracing) |
| 106 return; |
| 107 scoped_ptr<trace_event::TracedValue> snapshot(new trace_event::TracedValue); |
| 108 AsValueInto(snapshot.get()); |
| 109 scoped_ptr<trace_event::ConvertableToTraceFormat> snapshot_data( |
| 110 std::move(snapshot)); |
| 111 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(category, name, |
| 112 TRACE_ID_WITH_SCOPE(scope, id_), |
| 113 std::move(snapshot_data)); |
| 114 } |
| 115 |
| 116 int64_t id() const { return id_; } |
| 117 |
| 118 // trace_event::TraceLog::EnabledStateObserver implementation: |
| 119 void OnTraceLogEnabled() override { TakeSnapshot(); } |
| 120 |
| 121 void OnTraceLogDisabled() override {} |
| 122 |
| 123 protected: |
| 124 virtual ~BlameContext() { |
| 125 TRACE_EVENT_OBJECT_DELETED_WITH_ID(category, name, |
| 126 TRACE_ID_WITH_SCOPE(scope, id_)); |
| 127 trace_event::TraceLog::GetInstance()->RemoveEnabledStateObserver(this); |
| 128 } |
| 129 |
| 130 // Serialize the properties of this blame context into |state|. Subclasses can |
| 131 // override this method to record additional properties (e.g, the URL for an |
| 132 // <iframe> blame context). Note that an overriden implementation must still |
| 133 // call this base method. |
| 134 virtual void AsValueInto(trace_event::TracedValue* state) { |
| 135 if (!parent_id_) |
| 136 return; |
| 137 state->BeginDictionary("parent"); |
| 138 state->SetString("id_ref", StringPrintf("0x%" PRIx64, parent_id_)); |
| 139 state->SetString("scope", parent_scope_); |
| 140 state->EndDictionary(); |
| 141 } |
| 142 |
| 143 private: |
| 144 void Initialize() { |
| 145 TRACE_EVENT_OBJECT_CREATED_WITH_ID(category, name, |
| 146 TRACE_ID_WITH_SCOPE(scope, id_)); |
| 147 trace_event::TraceLog::GetInstance()->AddEnabledStateObserver(this); |
| 148 } |
| 149 |
| 150 const int64_t id_; |
| 151 const int64_t parent_id_; |
| 152 const char* parent_scope_; |
| 153 |
| 154 DISALLOW_COPY_AND_ASSIGN(BlameContext); |
| 155 }; |
| 156 |
| 157 } // namespace debug |
| 158 } // namespace base |
| 159 |
| 160 #endif // BASE_DEBUG_BLAME_CONTEXT_H_ |
OLD | NEW |