OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2010 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 // Tracer objects uresed to record an annotated timeline of events for use in |
| 6 // gathering performance data. It wraps a TraceBuffer which is the raw data |
| 7 // for a trace. Tracer is threadsafe. |
| 8 // |
| 9 // TraceContext is a singleton that is used to give information for the current |
| 10 // trace. Clients should query TraceContext to find the current tracer and then |
| 11 // use that for logging annotations. TraceContext is threadsafe. |
| 12 // |
| 13 // ScopedTracer pushes a new Tracer on the TraceContext. It's scoped in that |
| 14 // this tracer is popped off the context when ScopedTracer goes out of scope. |
| 15 // However, if a call to NewTracedMethod is made while the ScopedTracer is in |
| 16 // scope, then a reference to the Tracer will be kept in the resulting Task and |
| 17 // repushed onto the stack when the Task is run. Conceptually, this simulates |
| 18 // the current context being continued when the Task is invoked. You usually |
| 19 // will want to declare a ScopedTracer at the start of a logical flow of |
| 20 // operations. |
| 21 // |
| 22 // Example Usage: |
| 23 // |
| 24 // void Decoder::StartDecode() { |
| 25 // ScopedTracer tracer("decode_start"); |
| 26 // |
| 27 // TraceContext::current()->PrintString("Decode starting"); |
| 28 // |
| 29 // // DoDecode takes 2 parameters. The first is a callback invoked for each |
| 30 // // finished frame of output. The second is invoked when the task is done. |
| 31 // DoDecode(NewTracedMethod(this, &Decoder::OnFrameOutput), |
| 32 // NewTracedMethod(this, &Decoder::DecodeDone)); |
| 33 // } |
| 34 // } |
| 35 // |
| 36 // void Decoder::OnFrameOutput() { |
| 37 // TraceContext::current()->PrintString("Frame outputed"); |
| 38 // ... |
| 39 // } |
| 40 // |
| 41 // void Decoder::DecodeDone() { |
| 42 // TraceContext::current()->PrintString("decode done"); |
| 43 // ... |
| 44 // } |
| 45 // |
| 46 // For each call of StartDecode(), the related calls to OnFrameOutput() and |
| 47 // DecodeDone() will be annotated to the Tracer created by the ScopedTracer |
| 48 // declaration allowing for creating of timing information over the related |
| 49 // asynchronous Task invocations. |
| 50 |
| 51 #ifndef REMOTING_BASE_TRACER_H_ |
| 52 #define REMOTING_BASE_TRACER_H_ |
| 53 |
| 54 #include <string> |
| 55 |
| 56 #include "base/lock.h" |
| 57 #include "base/ref_counted.h" |
| 58 #include "base/singleton.h" |
| 59 #include "base/task.h" |
| 60 #include "base/scoped_ptr.h" |
| 61 #include "base/thread_local.h" |
| 62 #include "remoting/base/protocol/trace.pb.h" |
| 63 |
| 64 namespace remoting { |
| 65 |
| 66 class Tracer : public base::RefCountedThreadSafe<Tracer> { |
| 67 public: |
| 68 // The |name| is just a label for the given tracer. It is recorder into the |
| 69 // trace buffer and printed at the end. Use it specify one logical flow such |
| 70 // as "Host Update Request". The sample_percent is to allow for gathering a |
| 71 // random sampling of the traces. This allows the tracer to be used in a |
| 72 // high-frequency code path without spamming the log, or putting undo load on |
| 73 // the system. Use 0.0 to disable the tracer completely, and 1.0 to log |
| 74 // everything. |
| 75 Tracer(const std::string& name, double sample_percent); |
| 76 |
| 77 // TODO(ajwong): Consider using an ostream interface similar to DLOG. |
| 78 void PrintString(const std::string& s); |
| 79 |
| 80 void OutputTrace(); |
| 81 |
| 82 private: |
| 83 friend class base::RefCountedThreadSafe<Tracer>; |
| 84 virtual ~Tracer(); |
| 85 |
| 86 Lock lock_; |
| 87 scoped_ptr<TraceBuffer> buffer_; |
| 88 |
| 89 DISALLOW_COPY_AND_ASSIGN(Tracer); |
| 90 }; |
| 91 |
| 92 class TraceContext { |
| 93 public: |
| 94 // Set the current tracer. |
| 95 static Tracer* tracer() { |
| 96 return Get()->GetTracerInternal(); |
| 97 } |
| 98 |
| 99 static void PushTracer(Tracer* tracer) { |
| 100 Get()->PushTracerInternal(tracer); |
| 101 } |
| 102 |
| 103 static void PopTracer() { |
| 104 Get()->PopTracerInternal(); |
| 105 } |
| 106 |
| 107 static TraceContext* Get() { |
| 108 TraceContext* context = |
| 109 Singleton<base::ThreadLocalPointer<TraceContext> >::get()->Get(); |
| 110 if (context == NULL) { |
| 111 context = new TraceContext(); |
| 112 context->PushTracerInternal(new Tracer("default", 0.0)); |
| 113 Singleton<base::ThreadLocalPointer<TraceContext> >::get()->Set(context); |
| 114 } |
| 115 return context; |
| 116 } |
| 117 |
| 118 private: |
| 119 TraceContext() { |
| 120 } |
| 121 |
| 122 ~TraceContext() {} |
| 123 |
| 124 void PushTracerInternal(Tracer* tracer) { tracers_.push_back(tracer); } |
| 125 |
| 126 void PopTracerInternal() { tracers_.pop_back(); } |
| 127 |
| 128 Tracer* GetTracerInternal() { return tracers_.back(); } |
| 129 |
| 130 std::vector<scoped_refptr<Tracer> > tracers_; |
| 131 |
| 132 DISALLOW_COPY_AND_ASSIGN(TraceContext); |
| 133 }; |
| 134 |
| 135 // Used to create a new tracer that NewRunnableMethod can propogate from. |
| 136 // |
| 137 // Declare this at the logical start of a "trace." Calls to NewTracedMethod |
| 138 // that are done with the ScopedTracer object is alive will take a reference |
| 139 // to this tracer. When such a method is invoked, it will push the trace back |
| 140 // onto the top of the TraceContext stack. The result is that all asynchronous |
| 141 // tasks that are part of one logical flow will share the same trace. |
| 142 class ScopedTracer { |
| 143 public: |
| 144 ScopedTracer(const std::string& name) { |
| 145 scoped_refptr<Tracer> tracer = new Tracer(name, 1.00); |
| 146 TraceContext::PushTracer(tracer); |
| 147 } |
| 148 |
| 149 ~ScopedTracer() { |
| 150 TraceContext::PopTracer(); |
| 151 } |
| 152 }; |
| 153 |
| 154 // This is experimental code. I'm creating a set of analogues to |
| 155 // the NewRunnableMethod functions called NewTracedMethod, which should be |
| 156 // API equivalent to the former. In fact, they must be enabled by setting |
| 157 // USE_TRACE 1 for now. |
| 158 // |
| 159 // The idea is to add hooks for performance traces into the Task/Callback |
| 160 // mechanisms. If it works well enough, will think about generalizing into the |
| 161 // original NewRunnableMethod and NewCallback systems. |
| 162 #if defined(USE_TRACE) |
| 163 |
| 164 template <class T, class Method, class Params> |
| 165 class TracedMethod : public RunnableMethod<T, Method, Params> { |
| 166 public: |
| 167 TracedMethod(T* obj, Method meth, const Params& params) |
| 168 : RunnableMethod<T, Method, Params>(obj, meth, params), |
| 169 tracer_(TraceContext::tracer()) { |
| 170 } |
| 171 |
| 172 virtual ~TracedMethod() { |
| 173 } |
| 174 |
| 175 virtual void Run() { |
| 176 TraceContext::PushTracer(tracer_); |
| 177 RunnableMethod<T, Method, Params>::Run(); |
| 178 TraceContext::PopTracer(); |
| 179 } |
| 180 |
| 181 private: |
| 182 scoped_refptr<Tracer> tracer_; |
| 183 }; |
| 184 |
| 185 template <class T, class Method> |
| 186 inline CancelableTask* NewTracedMethod(T* object, Method method) { |
| 187 return new TracedMethod<T, Method, Tuple0>(object, method, MakeTuple()); |
| 188 } |
| 189 |
| 190 template <class T, class Method, class A> |
| 191 inline CancelableTask* NewTracedMethod(T* object, Method method, const A& a) { |
| 192 return new TracedMethod<T, Method, Tuple1<A> >(object, |
| 193 method, |
| 194 MakeTuple(a)); |
| 195 } |
| 196 |
| 197 template <class T, class Method, class A, class B> |
| 198 inline CancelableTask* NewTracedMethod(T* object, Method method, |
| 199 const A& a, const B& b) { |
| 200 return new TracedMethod<T, Method, Tuple2<A, B> >(object, method, |
| 201 MakeTuple(a, b)); |
| 202 } |
| 203 |
| 204 template <class T, class Method, class A, class B, class C> |
| 205 inline CancelableTask* NewTracedMethod(T* object, Method method, |
| 206 const A& a, const B& b, const C& c) { |
| 207 return new TracedMethod<T, Method, Tuple3<A, B, C> >(object, method, |
| 208 MakeTuple(a, b, c)); |
| 209 } |
| 210 |
| 211 template <class T, class Method, class A, class B, class C, class D> |
| 212 inline CancelableTask* NewTracedMethod(T* object, Method method, |
| 213 const A& a, const B& b, |
| 214 const C& c, const D& d) { |
| 215 return new TracedMethod<T, Method, Tuple4<A, B, C, D> >(object, method, |
| 216 MakeTuple(a, b, |
| 217 c, d)); |
| 218 } |
| 219 |
| 220 template <class T, class Method, class A, class B, class C, class D, class E> |
| 221 inline CancelableTask* NewTracedMethod(T* object, Method method, |
| 222 const A& a, const B& b, |
| 223 const C& c, const D& d, const E& e) { |
| 224 return new TracedMethod<T, |
| 225 Method, |
| 226 Tuple5<A, B, C, D, E> >(object, |
| 227 method, |
| 228 MakeTuple(a, b, c, d, e)); |
| 229 } |
| 230 |
| 231 template <class T, class Method, class A, class B, class C, class D, class E, |
| 232 class F> |
| 233 inline CancelableTask* NewTracedMethod(T* object, Method method, |
| 234 const A& a, const B& b, |
| 235 const C& c, const D& d, |
| 236 const E& e, const F& f) { |
| 237 return new TracedMethod<T, |
| 238 Method, |
| 239 Tuple6<A, B, C, D, E, F> >(object, |
| 240 method, |
| 241 MakeTuple(a, b, c, d, e, |
| 242 f)); |
| 243 } |
| 244 |
| 245 template <class T, class Method, class A, class B, class C, class D, class E, |
| 246 class F, class G> |
| 247 inline CancelableTask* NewTracedMethod(T* object, Method method, |
| 248 const A& a, const B& b, |
| 249 const C& c, const D& d, const E& e, |
| 250 const F& f, const G& g) { |
| 251 return new TracedMethod<T, |
| 252 Method, |
| 253 Tuple7<A, B, C, D, E, F, G> >(object, |
| 254 method, |
| 255 MakeTuple(a, b, c, d, |
| 256 e, f, g)); |
| 257 } |
| 258 |
| 259 #else |
| 260 # define NewTracedMethod NewRunnableMethod |
| 261 #endif |
| 262 |
| 263 } // namespace remoting |
| 264 |
| 265 #endif // REMOTING_BASE_TRACER_H_ |
OLD | NEW |