Chromium Code Reviews

Unified Diff: remoting/base/tracer.h

Issue 3169047: Add in some infrastructure to make tracing of logical requests broken over async callbacks easier. (Closed) Base URL: git://codf21.jail.google.com/chromium.git
Patch Set: sent Created 10 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
« no previous file with comments | « remoting/base/protocol/trace.proto ('k') | remoting/base/tracer.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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_
« no previous file with comments | « remoting/base/protocol/trace.proto ('k') | remoting/base/tracer.cc » ('j') | no next file with comments »

Powered by Google App Engine