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 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 
     58 // Profiling could be switched via a build flag, but for now, it's always on.
     59 #define ENABLE_PROFILING
     60 
     61 #ifdef ENABLE_PROFILING
     62 
     63 #define UV_HELPER2(x) _uv_ ## x
     64 #define UV_HELPER(x) UV_HELPER2(x)
     65 #define UNIQUE_VAR UV_HELPER(__LINE__)
     66 
     67 // Profiles the current scope.
     68 #define PROFILE(msg) talk_base::ProfilerScope UNIQUE_VAR(msg)
     69 // When placed at the start of a function, profiles the current function.
     70 #define PROFILE_F() PROFILE(__FUNCTION__)
     71 // Reports current timings to the log at severity |sev|.
     72 #define PROFILE_DUMP_ALL(sev) \
     73   talk_base::Profiler::Instance()->ReportAllToLog(__FILE__, __LINE__, sev)
     74 // Reports current timings for all events whose names are prefixed by |prefix|
     75 // to the log at severity |sev|. Using a unique event name as |prefix| will
     76 // report only that event.
     77 #define PROFILE_DUMP(sev, prefix) \
     78   talk_base::Profiler::Instance()->ReportToLog(__FILE__, __LINE__, sev, prefix)
     79 // Starts and stops a profile event. Useful when an event is not easily
     80 // captured within a scope (eg, an async call with a callback when done).
     81 #define PROFILE_START(msg) talk_base::Profiler::Instance()->StartEvent(msg)
     82 #define PROFILE_STOP(msg) talk_base::Profiler::Instance()->StopEvent(msg)
     83 // TODO(ryanpetrie): Consider adding PROFILE_DUMP_EVERY(sev, iterations)
     84 
     85 #undef UV_HELPER2
     86 #undef UV_HELPER
     87 #undef UNIQUE_VAR
     88 
     89 #else  // ENABLE_PROFILING
     90 
     91 #define PROFILE(msg) (void)0
     92 #define PROFILE_F() (void)0
     93 #define PROFILE_DUMP_ALL(sev) (void)0
     94 #define PROFILE_DUMP(sev, prefix) (void)0
     95 #define PROFILE_START(msg) (void)0
     96 #define PROFILE_STOP(msg) (void)0
     97 
     98 #endif  // ENABLE_PROFILING
     99 
    100 namespace talk_base {
    101 
    102 // Tracks information for one profiler event.
    103 class ProfilerEvent {
    104  public:
    105   ProfilerEvent();
    106   void Start();
    107   void Stop();
    108   double standard_deviation() const;
    109   double total_time() const { return total_time_; }
    110   double mean() const { return mean_; }
    111   double minimum() const { return minimum_; }
    112   double maximum() const { return maximum_; }
    113   int event_count() const { return event_count_; }
    114   bool is_started() const { return start_count_ > 0; }
    115 
    116  private:
    117   uint64 current_start_time_;
    118   double total_time_;
    119   double mean_;
    120   double sum_of_squared_differences_;
    121   double minimum_;
    122   double maximum_;
    123   int start_count_;
    124   int event_count_;
    125 };
    126 
    127 // Singleton that owns ProfilerEvents and reports results. Prefer to use
    128 // macros, defined above, rather than directly calling Profiler methods.
    129 class Profiler {
    130  public:
    131   void StartEvent(const std::string& event_name);
    132   void StopEvent(const std::string& event_name);
    133   void ReportToLog(const char* file, int line, LoggingSeverity severity_to_use,
    134                    const std::string& event_prefix);
    135   void ReportAllToLog(const char* file, int line,
    136                       LoggingSeverity severity_to_use);
    137   const ProfilerEvent* GetEvent(const std::string& event_name) const;
    138   // Clears all _stopped_ events. Returns true if _all_ events were cleared.
    139   bool Clear();
    140 
    141   static Profiler* Instance();
    142  private:
    143   Profiler() {}
    144 
    145   std::map<std::string, ProfilerEvent> events_;
    146 
    147   DISALLOW_COPY_AND_ASSIGN(Profiler);
    148 };
    149 
    150 // Starts an event on construction and stops it on destruction.
    151 // Used by PROFILE macro.
    152 class ProfilerScope {
    153  public:
    154   explicit ProfilerScope(const std::string& event_name)
    155       : event_name_(event_name) {
    156     Profiler::Instance()->StartEvent(event_name_);
    157   }
    158   ~ProfilerScope() {
    159     Profiler::Instance()->StopEvent(event_name_);
    160   }
    161  private:
    162   std::string event_name_;
    163 
    164   DISALLOW_COPY_AND_ASSIGN(ProfilerScope);
    165 };
    166 
    167 }  // namespace talk_base
    168 
    169 #endif  // TALK_BASE_PROFILER_H_
    170