| // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // Tracer objects uresed to record an annotated timeline of events for use in |
| // gathering performance data. It wraps a TraceBuffer which is the raw data |
| // for a trace. Tracer is threadsafe. |
| // |
| // TraceContext is a singleton that is used to give information for the current |
| // trace. Clients should query TraceContext to find the current tracer and then |
| // use that for logging annotations. TraceContext is threadsafe. |
| // |
| // ScopedTracer pushes a new Tracer on the TraceContext. It's scoped in that |
| // this tracer is popped off the context when ScopedTracer goes out of scope. |
| // However, if a call to NewTracedMethod is made while the ScopedTracer is in |
| // scope, then a reference to the Tracer will be kept in the resulting Task and |
| // repushed onto the stack when the Task is run. Conceptually, this simulates |
| // the current context being continued when the Task is invoked. You usually |
| // will want to declare a ScopedTracer at the start of a logical flow of |
| // operations. |
| // |
| // Example Usage: |
| // |
| // void Decoder::StartDecode() { |
| // ScopedTracer tracer("decode_start"); |
| // |
| // TraceContext::tracer()->PrintString("Decode starting"); |
| // |
| // // DoDecode takes 2 parameters. The first is a callback invoked for each |
| // // finished frame of output. The second is invoked when the task is done. |
| // DoDecode(NewTracedMethod(this, &Decoder::OnFrameOutput), |
| // NewTracedMethod(this, &Decoder::DecodeDone)); |
| // } |
| // } |
| // |
| // void Decoder::OnFrameOutput() { |
| // TraceContext::tracer()->PrintString("Frame outputed"); |
| // ... |
| // } |
| // |
| // void Decoder::DecodeDone() { |
| // TraceContext::tracer()->PrintString("decode done"); |
| // ... |
| // } |
| // |
| // For each call of StartDecode(), the related calls to OnFrameOutput() and |
| // DecodeDone() will be annotated to the Tracer created by the ScopedTracer |
| // declaration allowing for creating of timing information over the related |
| // asynchronous Task invocations. |
| |
| #ifndef REMOTING_BASE_TRACER_H_ |
| #define REMOTING_BASE_TRACER_H_ |
| |
| #include <string> |
| |
| #include "base/lock.h" |
| #include "base/ref_counted.h" |
| #include "base/singleton.h" |
| #include "base/task.h" |
| #include "base/scoped_ptr.h" |
| #include "remoting/proto/trace.pb.h" |
| |
| namespace remoting { |
| |
| class Tracer : public base::RefCountedThreadSafe<Tracer> { |
| public: |
| // The |name| is just a label for the given tracer. It is recorder into the |
| // trace buffer and printed at the end. Use it specify one logical flow such |
| // as "Host Update Request". The sample_percent is to allow for gathering a |
| // random sampling of the traces. This allows the tracer to be used in a |
| // high-frequency code path without spamming the log, or putting undo load on |
| // the system. Use 0.0 to disable the tracer completely, and 1.0 to log |
| // everything. |
| Tracer(const std::string& name, double sample_percent); |
| |
| // TODO(ajwong): Consider using an ostream interface similar to DLOG. |
| void PrintString(const std::string& s); |
| |
| void OutputTrace(); |
| |
| private: |
| friend class base::RefCountedThreadSafe<Tracer>; |
| virtual ~Tracer(); |
| |
| Lock lock_; |
| scoped_ptr<TraceBuffer> buffer_; |
| |
| DISALLOW_COPY_AND_ASSIGN(Tracer); |
| }; |
| |
| class TraceContext { |
| public: |
| // Get the current tracer. |
| static Tracer* tracer(); |
| |
| static void PushTracer(Tracer* tracer); |
| |
| static void PopTracer(); |
| |
| static TraceContext* Get(); |
| |
| private: |
| TraceContext(); |
| |
| ~TraceContext(); |
| |
| void PushTracerInternal(Tracer* tracer); |
| |
| void PopTracerInternal(); |
| |
| Tracer* GetTracerInternal(); |
| |
| std::vector<scoped_refptr<Tracer> > tracers_; |
| |
| DISALLOW_COPY_AND_ASSIGN(TraceContext); |
| }; |
| |
| // Used to create a new tracer that NewRunnableMethod can propogate from. |
| // |
| // Declare this at the logical start of a "trace." Calls to NewTracedMethod |
| // that are done with the ScopedTracer object is alive will take a reference |
| // to this tracer. When such a method is invoked, it will push the trace back |
| // onto the top of the TraceContext stack. The result is that all asynchronous |
| // tasks that are part of one logical flow will share the same trace. |
| class ScopedTracer { |
| public: |
| ScopedTracer(const std::string& name) { |
| #if defined(USE_TRACE) |
| scoped_refptr<Tracer> tracer = new Tracer(name, 1.00); |
| TraceContext::PushTracer(tracer); |
| #endif |
| } |
| |
| ~ScopedTracer() { |
| #if defined(USE_TRACE) |
| TraceContext::PopTracer(); |
| #endif |
| } |
| }; |
| |
| // This is experimental code. I'm creating a set of analogues to |
| // the NewRunnableMethod functions called NewTracedMethod, which should be |
| // API equivalent to the former. In fact, they must be enabled by setting |
| // USE_TRACE 1 for now. |
| // |
| // The idea is to add hooks for performance traces into the Task/Callback |
| // mechanisms. If it works well enough, will think about generalizing into the |
| // original NewRunnableMethod and NewCallback systems. |
| #if defined(USE_TRACE) |
| |
| template <class T, class Method, class Params> |
| class TracedMethod : public RunnableMethod<T, Method, Params> { |
| public: |
| TracedMethod(T* obj, Method meth, const Params& params) |
| : RunnableMethod<T, Method, Params>(obj, meth, params), |
| tracer_(TraceContext::tracer()) { |
| } |
| |
| virtual ~TracedMethod() { |
| } |
| |
| virtual void Run() { |
| TraceContext::PushTracer(tracer_); |
| RunnableMethod<T, Method, Params>::Run(); |
| TraceContext::PopTracer(); |
| } |
| |
| private: |
| scoped_refptr<Tracer> tracer_; |
| }; |
| |
| template <class T, class Method> |
| inline CancelableTask* NewTracedMethod(T* object, Method method) { |
| return new TracedMethod<T, Method, Tuple0>(object, method, MakeTuple()); |
| } |
| |
| template <class T, class Method, class A> |
| inline CancelableTask* NewTracedMethod(T* object, Method method, const A& a) { |
| return new TracedMethod<T, Method, Tuple1<A> >(object, |
| method, |
| MakeTuple(a)); |
| } |
| |
| template <class T, class Method, class A, class B> |
| inline CancelableTask* NewTracedMethod(T* object, Method method, |
| const A& a, const B& b) { |
| return new TracedMethod<T, Method, Tuple2<A, B> >(object, method, |
| MakeTuple(a, b)); |
| } |
| |
| template <class T, class Method, class A, class B, class C> |
| inline CancelableTask* NewTracedMethod(T* object, Method method, |
| const A& a, const B& b, const C& c) { |
| return new TracedMethod<T, Method, Tuple3<A, B, C> >(object, method, |
| MakeTuple(a, b, c)); |
| } |
| |
| template <class T, class Method, class A, class B, class C, class D> |
| inline CancelableTask* NewTracedMethod(T* object, Method method, |
| const A& a, const B& b, |
| const C& c, const D& d) { |
| return new TracedMethod<T, Method, Tuple4<A, B, C, D> >(object, method, |
| MakeTuple(a, b, |
| c, d)); |
| } |
| |
| template <class T, class Method, class A, class B, class C, class D, class E> |
| inline CancelableTask* NewTracedMethod(T* object, Method method, |
| const A& a, const B& b, |
| const C& c, const D& d, const E& e) { |
| return new TracedMethod<T, |
| Method, |
| Tuple5<A, B, C, D, E> >(object, |
| method, |
| MakeTuple(a, b, c, d, e)); |
| } |
| |
| template <class T, class Method, class A, class B, class C, class D, class E, |
| class F> |
| inline CancelableTask* NewTracedMethod(T* object, Method method, |
| const A& a, const B& b, |
| const C& c, const D& d, |
| const E& e, const F& f) { |
| return new TracedMethod<T, |
| Method, |
| Tuple6<A, B, C, D, E, F> >(object, |
| method, |
| MakeTuple(a, b, c, d, e, |
| f)); |
| } |
| |
| template <class T, class Method, class A, class B, class C, class D, class E, |
| class F, class G> |
| inline CancelableTask* NewTracedMethod(T* object, Method method, |
| const A& a, const B& b, |
| const C& c, const D& d, const E& e, |
| const F& f, const G& g) { |
| return new TracedMethod<T, |
| Method, |
| Tuple7<A, B, C, D, E, F, G> >(object, |
| method, |
| MakeTuple(a, b, c, d, |
| e, f, g)); |
| } |
| |
| #else |
| # define NewTracedMethod NewRunnableMethod |
| #endif |
| |
| } // namespace remoting |
| |
| #endif // REMOTING_BASE_TRACER_H_ |