Home | History | Annotate | Download | only in base
      1 /*
      2  * libjingle
      3  * Copyright 2013, Google Inc.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are met:
      7  *
      8  *  1. Redistributions of source code must retain the above copyright notice,
      9  *     this list of conditions and the following disclaimer.
     10  *  2. Redistributions in binary form must reproduce the above copyright notice,
     11  *     this list of conditions and the following disclaimer in the documentation
     12  *     and/or other materials provided with the distribution.
     13  *  3. The name of the author may not be used to endorse or promote products
     14  *     derived from this software without specific prior written permission.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
     17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
     19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 // A simple wall-clock profiler for instrumented code.
     29 // Example:
     30 //   void MyLongFunction() {
     31 //     PROFILE_F();  // Time the execution of this function.
     32 //     // Do something
     33 //     {  // Time just what is in this scope.
     34 //       PROFILE("My event");
     35 //       // Do something else
     36 //     }
     37 //   }
     38 // Another example:
     39 //   void StartAsyncProcess() {
     40 //     PROFILE_START("My async event");
     41 //     DoSomethingAsyncAndThenCall(&Callback);
     42 //   }
     43 //   void Callback() {
     44 //     PROFILE_STOP("My async event");
     45 //     // Handle callback.
     46 //   }
     47 
     48 #ifndef TALK_BASE_PROFILER_H_
     49 #define TALK_BASE_PROFILER_H_
     50 
     51 #include <map>
     52 #include <string>
     53 
     54 #include "talk/base/basictypes.h"
     55 #include "talk/base/common.h"
     56 #include "talk/base/logging.h"
     57 #include "talk/base/sharedexclusivelock.h"
     58 
     59 // Profiling could be switched via a build flag, but for now, it's always on.
     60 #define ENABLE_PROFILING
     61 
     62 #ifdef ENABLE_PROFILING
     63 
     64 #define UV_HELPER2(x) _uv_ ## x
     65 #define UV_HELPER(x) UV_HELPER2(x)
     66 #define UNIQUE_VAR UV_HELPER(__LINE__)
     67 
     68 // Profiles the current scope.
     69 #define PROFILE(msg) talk_base::ProfilerScope UNIQUE_VAR(msg)
     70 // When placed at the start of a function, profiles the current function.
     71 #define PROFILE_F() PROFILE(__FUNCTION__)
     72 // Reports current timings to the log at severity |sev|.
     73 #define PROFILE_DUMP_ALL(sev) \
     74   talk_base::Profiler::Instance()->ReportAllToLog(__FILE__, __LINE__, sev)
     75 // Reports current timings for all events whose names are prefixed by |prefix|
     76 // to the log at severity |sev|. Using a unique event name as |prefix| will
     77 // report only that event.
     78 #define PROFILE_DUMP(sev, prefix) \
     79   talk_base::Profiler::Instance()->ReportToLog(__FILE__, __LINE__, sev, prefix)
     80 // Starts and stops a profile event. Useful when an event is not easily
     81 // captured within a scope (eg, an async call with a callback when done).
     82 #define PROFILE_START(msg) talk_base::Profiler::Instance()->StartEvent(msg)
     83 #define PROFILE_STOP(msg) talk_base::Profiler::Instance()->StopEvent(msg)
     84 // TODO(ryanpetrie): Consider adding PROFILE_DUMP_EVERY(sev, iterations)
     85 
     86 #undef UV_HELPER2
     87 #undef UV_HELPER
     88 #undef UNIQUE_VAR
     89 
     90 #else  // ENABLE_PROFILING
     91 
     92 #define PROFILE(msg) (void)0
     93 #define PROFILE_F() (void)0
     94 #define PROFILE_DUMP_ALL(sev) (void)0
     95 #define PROFILE_DUMP(sev, prefix) (void)0
     96 #define PROFILE_START(msg) (void)0
     97 #define PROFILE_STOP(msg) (void)0
     98 
     99 #endif  // ENABLE_PROFILING
    100 
    101 namespace talk_base {
    102 
    103 // Tracks information for one profiler event.
    104 class ProfilerEvent {
    105  public:
    106   ProfilerEvent();
    107   void Start();
    108   void Stop();
    109   void Stop(uint64 stop_time);
    110   double standard_deviation() const;
    111   double total_time() const { return total_time_; }
    112   double mean() const { return mean_; }
    113   double minimum() const { return minimum_; }
    114   double maximum() const { return maximum_; }
    115   int event_count() const { return event_count_; }
    116   bool is_started() const { return start_count_ > 0; }
    117 
    118  private:
    119   uint64 current_start_time_;
    120   double total_time_;
    121   double mean_;
    122   double sum_of_squared_differences_;
    123   double minimum_;
    124   double maximum_;
    125   int start_count_;
    126   int event_count_;
    127 };
    128 
    129 // Singleton that owns ProfilerEvents and reports results. Prefer to use
    130 // macros, defined above, rather than directly calling Profiler methods.
    131 class Profiler {
    132  public:
    133   void StartEvent(const std::string& event_name);
    134   void StopEvent(const std::string& event_name);
    135   void ReportToLog(const char* file, int line, LoggingSeverity severity_to_use,
    136                    const std::string& event_prefix);
    137   void ReportAllToLog(const char* file, int line,
    138                       LoggingSeverity severity_to_use);
    139   const ProfilerEvent* GetEvent(const std::string& event_name) const;
    140   // Clears all _stopped_ events. Returns true if _all_ events were cleared.
    141   bool Clear();
    142 
    143   static Profiler* Instance();
    144  private:
    145   Profiler() {}
    146 
    147   typedef std::map<std::string, ProfilerEvent> EventMap;
    148   EventMap events_;
    149   mutable SharedExclusiveLock lock_;
    150 
    151   DISALLOW_COPY_AND_ASSIGN(Profiler);
    152 };
    153 
    154 // Starts an event on construction and stops it on destruction.
    155 // Used by PROFILE macro.
    156 class ProfilerScope {
    157  public:
    158   explicit ProfilerScope(const std::string& event_name)
    159       : event_name_(event_name) {
    160     Profiler::Instance()->StartEvent(event_name_);
    161   }
    162   ~ProfilerScope() {
    163     Profiler::Instance()->StopEvent(event_name_);
    164   }
    165  private:
    166   std::string event_name_;
    167 
    168   DISALLOW_COPY_AND_ASSIGN(ProfilerScope);
    169 };
    170 
    171 std::ostream& operator<<(std::ostream& stream,
    172                          const ProfilerEvent& profiler_event);
    173 
    174 }  // namespace talk_base
    175 
    176 #endif  // TALK_BASE_PROFILER_H_
    177