2013-07-10 02:45:36 +02:00
|
|
|
/*
|
|
|
|
* libjingle
|
|
|
|
* Copyright 2013, Google Inc.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions are met:
|
|
|
|
*
|
|
|
|
* 1. Redistributions of source code must retain the above copyright notice,
|
|
|
|
* this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
|
|
* and/or other materials provided with the distribution.
|
|
|
|
* 3. The name of the author may not be used to endorse or promote products
|
|
|
|
* derived from this software without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
|
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
|
|
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
|
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
|
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
|
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
// A simple wall-clock profiler for instrumented code.
|
|
|
|
// Example:
|
|
|
|
// void MyLongFunction() {
|
|
|
|
// PROFILE_F(); // Time the execution of this function.
|
|
|
|
// // Do something
|
|
|
|
// { // Time just what is in this scope.
|
|
|
|
// PROFILE("My event");
|
|
|
|
// // Do something else
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// Another example:
|
|
|
|
// void StartAsyncProcess() {
|
|
|
|
// PROFILE_START("My event");
|
|
|
|
// DoSomethingAsyncAndThenCall(&Callback);
|
|
|
|
// }
|
|
|
|
// void Callback() {
|
|
|
|
// PROFILE_STOP("My async event");
|
|
|
|
// // Handle callback.
|
|
|
|
// }
|
|
|
|
|
|
|
|
#ifndef TALK_BASE_PROFILER_H_
|
|
|
|
#define TALK_BASE_PROFILER_H_
|
|
|
|
|
|
|
|
#include <map>
|
|
|
|
#include <string>
|
|
|
|
|
|
|
|
#include "talk/base/basictypes.h"
|
|
|
|
#include "talk/base/common.h"
|
|
|
|
#include "talk/base/logging.h"
|
|
|
|
|
|
|
|
// Profiling could be switched via a build flag, but for now, it's always on.
|
|
|
|
#define ENABLE_PROFILING
|
|
|
|
|
|
|
|
#ifdef ENABLE_PROFILING
|
|
|
|
|
|
|
|
#define UV_HELPER2(x) _uv_ ## x
|
|
|
|
#define UV_HELPER(x) UV_HELPER2(x)
|
|
|
|
#define UNIQUE_VAR UV_HELPER(__LINE__)
|
|
|
|
|
|
|
|
// Profiles the current scope.
|
|
|
|
#define PROFILE(msg) talk_base::ProfilerScope UNIQUE_VAR(msg)
|
|
|
|
// When placed at the start of a function, profiles the current function.
|
|
|
|
#define PROFILE_F() PROFILE(__FUNCTION__)
|
|
|
|
// Reports current timings to the log at severity |sev|.
|
|
|
|
#define PROFILE_DUMP_ALL(sev) \
|
|
|
|
talk_base::Profiler::Instance()->ReportAllToLog(__FILE__, __LINE__, sev)
|
|
|
|
// Reports current timings for all events whose names are prefixed by |prefix|
|
|
|
|
// to the log at severity |sev|. Using a unique event name as |prefix| will
|
|
|
|
// report only that event.
|
|
|
|
#define PROFILE_DUMP(sev, prefix) \
|
|
|
|
talk_base::Profiler::Instance()->ReportToLog(__FILE__, __LINE__, sev, prefix)
|
|
|
|
// Starts and stops a profile event. Useful when an event is not easily
|
|
|
|
// captured within a scope (eg, an async call with a callback when done).
|
|
|
|
#define PROFILE_START(msg) talk_base::Profiler::Instance()->StartEvent(msg)
|
|
|
|
#define PROFILE_STOP(msg) talk_base::Profiler::Instance()->StopEvent(msg)
|
|
|
|
// TODO(ryanpetrie): Consider adding PROFILE_DUMP_EVERY(sev, iterations)
|
|
|
|
|
|
|
|
#undef UV_HELPER2
|
|
|
|
#undef UV_HELPER
|
|
|
|
#undef UNIQUE_VAR
|
|
|
|
|
|
|
|
#else // ENABLE_PROFILING
|
|
|
|
|
|
|
|
#define PROFILE(msg) (void)0
|
|
|
|
#define PROFILE_F() (void)0
|
|
|
|
#define PROFILE_DUMP_ALL(sev) (void)0
|
|
|
|
#define PROFILE_DUMP(sev, prefix) (void)0
|
|
|
|
#define PROFILE_START(msg) (void)0
|
|
|
|
#define PROFILE_STOP(msg) (void)0
|
|
|
|
|
|
|
|
#endif // ENABLE_PROFILING
|
|
|
|
|
|
|
|
namespace talk_base {
|
|
|
|
|
|
|
|
// Tracks information for one profiler event.
|
|
|
|
class ProfilerEvent {
|
|
|
|
public:
|
|
|
|
ProfilerEvent();
|
|
|
|
void Start();
|
|
|
|
void Stop();
|
|
|
|
double standard_deviation() const;
|
|
|
|
double total_time() const { return total_time_; }
|
|
|
|
double mean() const { return mean_; }
|
|
|
|
double minimum() const { return minimum_; }
|
|
|
|
double maximum() const { return maximum_; }
|
|
|
|
int event_count() const { return event_count_; }
|
|
|
|
bool is_started() const { return start_count_ > 0; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
uint64 current_start_time_;
|
|
|
|
double total_time_;
|
|
|
|
double mean_;
|
|
|
|
double sum_of_squared_differences_;
|
|
|
|
double minimum_;
|
|
|
|
double maximum_;
|
|
|
|
int start_count_;
|
|
|
|
int event_count_;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Singleton that owns ProfilerEvents and reports results. Prefer to use
|
|
|
|
// macros, defined above, rather than directly calling Profiler methods.
|
|
|
|
class Profiler {
|
|
|
|
public:
|
|
|
|
void StartEvent(const std::string& event_name);
|
|
|
|
void StopEvent(const std::string& event_name);
|
|
|
|
void ReportToLog(const char* file, int line, LoggingSeverity severity_to_use,
|
|
|
|
const std::string& event_prefix);
|
|
|
|
void ReportAllToLog(const char* file, int line,
|
|
|
|
LoggingSeverity severity_to_use);
|
|
|
|
const ProfilerEvent* GetEvent(const std::string& event_name) const;
|
|
|
|
// Clears all _stopped_ events. Returns true if _all_ events were cleared.
|
|
|
|
bool Clear();
|
|
|
|
|
|
|
|
static Profiler* Instance();
|
|
|
|
private:
|
|
|
|
Profiler() {}
|
|
|
|
|
|
|
|
std::map<std::string, ProfilerEvent> events_;
|
|
|
|
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(Profiler);
|
|
|
|
};
|
|
|
|
|
|
|
|
// Starts an event on construction and stops it on destruction.
|
|
|
|
// Used by PROFILE macro.
|
|
|
|
class ProfilerScope {
|
|
|
|
public:
|
|
|
|
explicit ProfilerScope(const std::string& event_name)
|
|
|
|
: event_name_(event_name) {
|
|
|
|
Profiler::Instance()->StartEvent(event_name_);
|
|
|
|
}
|
|
|
|
~ProfilerScope() {
|
|
|
|
Profiler::Instance()->StopEvent(event_name_);
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
std::string event_name_;
|
|
|
|
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(ProfilerScope);
|
|
|
|
};
|
|
|
|
|
2013-10-08 01:32:02 +02:00
|
|
|
std::ostream& operator<<(std::ostream& stream,
|
|
|
|
const ProfilerEvent& profiler_event);
|
|
|
|
|
2013-07-10 02:45:36 +02:00
|
|
|
} // namespace talk_base
|
|
|
|
|
|
|
|
#endif // TALK_BASE_PROFILER_H_
|