Added profiler to loginserver as initial work cause it's the smallest service or one of the smallest

This commit is contained in:
KimLS
2015-01-31 14:52:27 -08:00
parent 0bdbc5f5c9
commit e135f46711
28 changed files with 629 additions and 130 deletions
+22
View File
@@ -0,0 +1,22 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
SET(eqperf_sources
eqp_profile_event.cpp
eqp_profile_timer.cpp
eqp_profiler.cpp
eqp_profiler_node.cpp
)
SET(eqperf_headers
eqp_profile_event.h
eqp_profile_function.h
eqp_profile_timer.h
eqp_profiler.h
eqp_profiler_node.h
)
ADD_LIBRARY(eqperf SHARED ${eqperf_sources} ${eqperf_headers})
INSTALL(TARGETS eqperf RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX})
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
+47
View File
@@ -0,0 +1,47 @@
#include "eqp_profile_event.h"
#include "eqp_profile_timer.h"
#include "eqp_profiler.h"
EQP::CPU::ST::Event::Event(const char *function_name) {
function_name_ = function_name;
name_ = nullptr;
start_ = GetCurrentTimer();
EQP::CPU::ST::GetProfiler().EventStarted(function_name_, name_);
}
EQP::CPU::ST::Event::Event(const char *function_name, const char *name) {
function_name_ = function_name;
name_ = name;
start_ = GetCurrentTimer();
EQP::CPU::ST::GetProfiler().EventStarted(function_name_, name_);
}
EQP::CPU::ST::Event::~Event() {
uint64_t end = GetCurrentTimer();
EQP::CPU::ST::GetProfiler().EventFinished(end - start_);
}
EQP::CPU::MT::Event::Event(const char *function_name) {
function_name_ = function_name;
name_ = nullptr;
start_ = GetCurrentTimer();
EQP::CPU::MT::GetProfiler().EventStarted(function_name_, name_);
}
EQP::CPU::MT::Event::Event(const char *function_name, const char *name) {
function_name_ = function_name;
name_ = name;
start_ = GetCurrentTimer();
EQP::CPU::MT::GetProfiler().EventStarted(function_name_, name_);
}
EQP::CPU::MT::Event::~Event() {
uint64_t end = GetCurrentTimer();
EQP::CPU::MT::GetProfiler().EventFinished(end - start_);
}
+41
View File
@@ -0,0 +1,41 @@
#pragma once
#include <stdint.h>
#include "eqp_profile_function.h"
namespace EQP
{
namespace CPU
{
namespace ST
{
class EQP_EXPORT Event
{
public:
Event(const char *function_name);
Event(const char *function_name, const char *name);
~Event();
private:
const char *function_name_;
const char *name_;
uint64_t start_;
};
}
namespace MT
{
class EQP_EXPORT Event
{
public:
Event(const char *function_name);
Event(const char *function_name, const char *name);
~Event();
private:
const char *function_name_;
const char *name_;
uint64_t start_;
};
}
}
} // Profile
+15
View File
@@ -0,0 +1,15 @@
#pragma once
#ifndef __PRETTY_FUNCTION__
#ifdef _MSC_VER
#define __PRETTY_FUNCTION__ __FUNCSIG__
#else
#define __PRETTY_FUNCTION__ __FUNCTION__
#endif
#endif
#ifdef _MSC_VER
#define EQP_EXPORT __declspec(dllexport)
#else
#define EQP_EXPORT
#endif
+24
View File
@@ -0,0 +1,24 @@
#include "eqp_profile_timer.h"
#ifdef _MSC_VER
#include <Windows.h>
#else
#include <time.h>
#endif
uint64_t EQP::GetCurrentTimer()
{
#ifdef _MSC_VER
LARGE_INTEGER qpt_i;
QueryPerformanceCounter(&qpt_i);
return qpt_i.QuadPart;
#else
timespec tp;
if(clock_gettime(CLOCK_MONOTONIC, &tp) == 0) {
uint64_t res = tp.tv_sec * 1000000000;
res += tp.tv_nsec;
return res;
}
return 0;
#endif
}
+9
View File
@@ -0,0 +1,9 @@
#pragma once
#include <stdint.h>
namespace EQP
{
uint64_t GetCurrentTimer();
} // EQP
+194
View File
@@ -0,0 +1,194 @@
#include "eqp_profiler.h"
#include <iostream>
#include <thread>
#include <mutex>
#include <vector>
#include <algorithm>
EQP::CPU::ST::Profiler st_profiler;
EQP::CPU::MT::Profiler mt_profiler;
struct EQP::CPU::MT::Profiler::impl
{
std::mutex lock_;
std::unordered_map<std::thread::id, ThreadInfo*> nodes_;
};
EQP::CPU::ST::Profiler &EQP::CPU::ST::GetProfiler() {
return st_profiler;
}
EQP::CPU::MT::Profiler &EQP::CPU::MT::GetProfiler() {
return mt_profiler;
}
EQP::CPU::ST::Profiler::Profiler() {
root_ = new ProfilerNode;
root_->SetParent(root_);
current_ = root_;
}
EQP::CPU::ST::Profiler::~Profiler() {
delete root_;
}
void EQP::CPU::ST::Profiler::EventStarted(const char *func, const char *name) {
std::string cur_name = func;
if(name) {
cur_name += " - ";
cur_name += name;
}
auto search = current_->GetNodes().find(cur_name);
if(search != current_->GetNodes().end()) {
current_ = search->second;
} else {
ProfilerNode *t = new ProfilerNode;
t->SetParent(current_);
current_->GetNodes()[cur_name] = t;
current_ = t;
}
}
void EQP::CPU::ST::Profiler::EventFinished(uint64_t time) {
current_->GetTime() += time;
current_->GetCount()++;
current_ = current_->GetParent();
}
void EQP::CPU::ST::Profiler::Clear() {
for(auto &iter : root_->GetNodes()) {
delete iter.second;
}
root_->GetNodes().clear();
root_->SetTime(0);
root_->SetCount(0);
current_ = root_;
}
void EQP::CPU::ST::Profiler::Dump(std::ostream &stream) {
uint64_t total = 0;
std::vector<ProfilerNodeDump> sorted_vec;
sorted_vec.reserve(root_->GetNodes().size() + 1);
for(auto &iter : root_->GetNodes()) {
ProfilerNodeDump n;
n.name = iter.first;
n.node = iter.second;
sorted_vec.push_back(n);
total += iter.second->GetTime();
}
std::sort(sorted_vec.begin(), sorted_vec.end(),
[](const ProfilerNodeDump& a, const ProfilerNodeDump& b) { return a.node->GetTime() > b.node->GetTime(); });
for(auto &iter : sorted_vec) {
iter.node->Dump(stream, iter.name, total, 0);
}
}
EQP::CPU::MT::Profiler::ThreadInfo::ThreadInfo() {
root_ = new ProfilerNode;
root_->SetParent(root_);
current_ = root_;
}
EQP::CPU::MT::Profiler::ThreadInfo::~ThreadInfo() {
delete root_;
}
EQP::CPU::MT::Profiler::Profiler() {
imp_ = new impl;
}
EQP::CPU::MT::Profiler::~Profiler() {
delete imp_;
}
void EQP::CPU::MT::Profiler::EventStarted(const char *func, const char *name) {
std::string cur_name = func;
if(name) {
cur_name += " - ";
cur_name += name;
}
ThreadInfo *ti = nullptr;
imp_->lock_.lock();
auto ti_search = imp_->nodes_.find(std::this_thread::get_id());
if(ti_search == imp_->nodes_.end()) {
ti = new ThreadInfo;
imp_->nodes_[std::this_thread::get_id()] = ti;
} else {
ti = ti_search->second;
}
imp_->lock_.unlock();
auto search = ti->current_->GetNodes().find(cur_name);
if(search != ti->current_->GetNodes().end()) {
ti->current_ = search->second;
}
else {
ProfilerNode *t = new ProfilerNode;
t->SetParent(ti->current_);
ti->current_->GetNodes()[cur_name] = t;
ti->current_ = t;
}
}
void EQP::CPU::MT::Profiler::EventFinished(uint64_t time) {
ThreadInfo *ti = nullptr;
imp_->lock_.lock();
auto ti_search = imp_->nodes_.find(std::this_thread::get_id());
if(ti_search == imp_->nodes_.end()) {
imp_->lock_.unlock();
return;
}
else {
ti = ti_search->second;
}
imp_->lock_.unlock();
ti->current_->GetTime() += time;
ti->current_->GetCount()++;
ti->current_ = ti->current_->GetParent();
}
void EQP::CPU::MT::Profiler::Clear() {
imp_->lock_.lock();
for(auto &iter : imp_->nodes_) {
delete iter.second;
}
imp_->nodes_.clear();
imp_->lock_.unlock();
}
void EQP::CPU::MT::Profiler::Dump(std::ostream &stream) {
imp_->lock_.lock();
for(auto &iter : imp_->nodes_) {
stream << "Thread: " << iter.first << std::endl;
uint64_t total = 0;
std::vector<ProfilerNodeDump> sorted_vec;
sorted_vec.reserve(iter.second->root_->GetNodes().size() + 1);
for(auto &t_iter : iter.second->root_->GetNodes()) {
ProfilerNodeDump n;
n.name = t_iter.first;
n.node = t_iter.second;
sorted_vec.push_back(n);
total += t_iter.second->GetTime();
}
std::sort(sorted_vec.begin(), sorted_vec.end(),
[](const ProfilerNodeDump& a, const ProfilerNodeDump& b) { return a.node->GetTime() > b.node->GetTime(); });
for(auto &t_iter : sorted_vec) {
t_iter.node->Dump(stream, t_iter.name, total, 1);
}
stream << std::endl;
}
imp_->lock_.unlock();
}
+78
View File
@@ -0,0 +1,78 @@
#pragma once
#ifdef EQPERF_ENABLED
#include <string>
#include "eqp_profile_event.h"
#include "eqp_profiler_node.h"
#define eqp_comb_fin(x, y) x##y
#define eqp_comb(x, y) eqp_comb_fin(x, y)
#define _eqp EQP::CPU::ST::Event eqp_comb(eq_perf_event_, __LINE__) (__PRETTY_FUNCTION__);
#define _eqpn(x) EQP::CPU::ST::Event eqp_comb(eq_perf_event_, __LINE__) (__PRETTY_FUNCTION__, x);
#define _eqp_mt EQP::CPU::MT::Event eqp_comb(eq_perf_event_, __LINE__) (__PRETTY_FUNCTION__);
#define _eqpn_mt(x) EQP::CPU::MT::Event eqp_comb(eq_perf_event_, __LINE__) (__PRETTY_FUNCTION__, x);
namespace EQP
{
namespace CPU
{
namespace ST
{
class EQP_EXPORT Profiler
{
typedef EQP::CPU::ProfilerNode Node;
public:
Profiler();
~Profiler();
void EventStarted(const char *func, const char *name);
void EventFinished(uint64_t time);
void Clear();
void Dump(std::ostream &stream);
private:
Node *root_;
Node *current_;
};
EQP_EXPORT Profiler &GetProfiler();
}
namespace MT
{
class EQP_EXPORT Profiler
{
typedef EQP::CPU::ProfilerNode Node;
class ThreadInfo {
public:
ThreadInfo();
~ThreadInfo();
Node *root_;
Node *current_;
};
public:
Profiler();
~Profiler();
void EventStarted(const char *func, const char *name);
void EventFinished(uint64_t time);
void Clear();
void Dump(std::ostream &stream);
private:
struct impl;
impl *imp_;
};
EQP_EXPORT Profiler &GetProfiler();
}
} // CPU
} // EQP
#else
#define _eqp
#define _eqpn(x)
#define _eqp_mt
#define _eqpn_mt(x)
#endif
+54
View File
@@ -0,0 +1,54 @@
#include "eqp_profiler_node.h"
#include <iostream>
#include <iomanip>
#include <algorithm>
EQP::CPU::ProfilerNode::ProfilerNode() {
count_ = 0;
time_ = 0;
parent_ = nullptr;;
}
EQP::CPU::ProfilerNode::~ProfilerNode() {
for(auto &iter : nodes_) {
delete iter.second;
}
}
void EQP::CPU::ProfilerNode::Dump(std::ostream &stream, const std::string &func, uint64_t total_time, int node_level) {
if(node_level >= 1) {
stream << std::setw(node_level * 2) << " ";
}
double m_cycles = time_ / 1000000.0;
double m_avg_cycles = m_cycles / count_;
double percentage = time_ * 100 / static_cast<double>(total_time);
std::streamsize p = stream.precision();
stream << std::fixed;
stream.precision(2);
stream << m_cycles << "M cycles, " << count_ << " calls, " << m_avg_cycles << "M cycles avg, ";
stream << func.c_str() << " ";
stream << percentage << "%";
stream << std::endl;
stream.precision(p);
std::vector<ProfilerNodeDump> sorted_vec;
sorted_vec.reserve(nodes_.size() + 1);
for(auto &iter : nodes_) {
ProfilerNodeDump n;
n.name = iter.first;
n.node = iter.second;
sorted_vec.push_back(n);
}
std::sort(sorted_vec.begin(), sorted_vec.end(),
[](const ProfilerNodeDump& a, const ProfilerNodeDump& b) { return a.node->GetTime() > b.node->GetTime(); });
for(auto &iter : sorted_vec) {
iter.node->Dump(stream, iter.name, total_time, node_level + 1);
}
}
+43
View File
@@ -0,0 +1,43 @@
#pragma once
#include <unordered_map>
#include <string>
#include <stdint.h>
namespace EQP
{
namespace CPU
{
class ProfilerNode
{
public:
ProfilerNode();
~ProfilerNode();
inline void SetCount(uint64_t c) { count_ = c; }
inline uint64_t& GetCount() { return count_; }
inline void SetTime(uint64_t t) { time_ = t; }
inline uint64_t& GetTime() { return time_; }
inline void SetParent(ProfilerNode *p) { parent_ = p; }
inline ProfilerNode* GetParent() { return parent_; }
inline std::unordered_map<std::string, ProfilerNode*>& GetNodes() { return nodes_; }
void Dump(std::ostream &stream, const std::string &func, uint64_t total_time, int node_level);
private:
uint64_t count_;
uint64_t time_;
ProfilerNode *parent_;
std::unordered_map<std::string, ProfilerNode*> nodes_;
};
struct ProfilerNodeDump
{
std::string name;
ProfilerNode *node;
};
} // CPU
} // EQP