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