| 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_
|
|
|