// Copyright (c) 2011 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 #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/memory/singleton.h" #include "base/synchronization/lock.h" #include "base/task.h" #include "remoting/proto/trace.pb.h" namespace remoting { class Tracer : public base::RefCountedThreadSafe { 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; virtual ~Tracer(); base::Lock lock_; scoped_ptr 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 > tracers_; DISALLOW_COPY_AND_ASSIGN(TraceContext); }; // Used to create a new tracer that NewRunnableMethod can propagate 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 = 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 TracedMethod : public RunnableMethod { public: TracedMethod(T* obj, Method meth, const Params& params) : RunnableMethod(obj, meth, params), tracer_(TraceContext::tracer()) { } virtual ~TracedMethod() { } virtual void Run() { TraceContext::PushTracer(tracer_); RunnableMethod::Run(); TraceContext::PopTracer(); } private: scoped_refptr tracer_; }; template inline CancelableTask* NewTracedMethod(T* object, Method method) { return new TracedMethod(object, method, MakeTuple()); } template inline CancelableTask* NewTracedMethod(T* object, Method method, const A& a) { return new TracedMethod >(object, method, MakeTuple(a)); } template inline CancelableTask* NewTracedMethod(T* object, Method method, const A& a, const B& b) { return new TracedMethod >(object, method, MakeTuple(a, b)); } template inline CancelableTask* NewTracedMethod(T* object, Method method, const A& a, const B& b, const C& c) { return new TracedMethod >(object, method, MakeTuple(a, b, c)); } template inline CancelableTask* NewTracedMethod(T* object, Method method, const A& a, const B& b, const C& c, const D& d) { return new TracedMethod >(object, method, MakeTuple(a, b, c, d)); } template 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 >(object, method, MakeTuple(a, b, c, d, e)); } template 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 >(object, method, MakeTuple(a, b, c, d, e, f)); } template 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 >(object, method, MakeTuple(a, b, c, d, e, f, g)); } #else # define NewTracedMethod NewRunnableMethod #endif } // namespace remoting #endif // REMOTING_BASE_TRACER_H_