blob: 95d4e9c3dab9a52dd82baad6c3c12ce3ea7f1d5e [file] [log] [blame]
// 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_