Index: remoting/base/tracer.h |
diff --git a/remoting/base/tracer.h b/remoting/base/tracer.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..739648dca0d18557f62c2d8784eb92d219d960e1 |
--- /dev/null |
+++ b/remoting/base/tracer.h |
@@ -0,0 +1,265 @@ |
+// 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::current()->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::current()->PrintString("Frame outputed"); |
+// ... |
+// } |
+// |
+// void Decoder::DecodeDone() { |
+// TraceContext::current()->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 "base/thread_local.h" |
+#include "remoting/base/protocol/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: |
+ // Set the current tracer. |
+ static Tracer* tracer() { |
+ return Get()->GetTracerInternal(); |
+ } |
+ |
+ static void PushTracer(Tracer* tracer) { |
+ Get()->PushTracerInternal(tracer); |
+ } |
+ |
+ static void PopTracer() { |
+ Get()->PopTracerInternal(); |
+ } |
+ |
+ static TraceContext* Get() { |
+ TraceContext* context = |
+ Singleton<base::ThreadLocalPointer<TraceContext> >::get()->Get(); |
+ if (context == NULL) { |
+ context = new TraceContext(); |
+ context->PushTracerInternal(new Tracer("default", 0.0)); |
+ Singleton<base::ThreadLocalPointer<TraceContext> >::get()->Set(context); |
+ } |
+ return context; |
+ } |
+ |
+ private: |
+ TraceContext() { |
+ } |
+ |
+ ~TraceContext() {} |
+ |
+ void PushTracerInternal(Tracer* tracer) { tracers_.push_back(tracer); } |
+ |
+ void PopTracerInternal() { tracers_.pop_back(); } |
+ |
+ Tracer* GetTracerInternal() { return tracers_.back(); } |
+ |
+ 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) { |
+ scoped_refptr<Tracer> tracer = new Tracer(name, 1.00); |
+ TraceContext::PushTracer(tracer); |
+ } |
+ |
+ ~ScopedTracer() { |
+ TraceContext::PopTracer(); |
+ } |
+}; |
+ |
+// 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_ |