diff --git a/CMakeLists.txt b/CMakeLists.txt index 494959cbc..00557ccae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,6 +31,7 @@ #EQEMU_SANITIZE_LUA_LIBS #EQEMU_BUILD_CLIENT_FILES #EQEMU_MAP_DIR +#EQEMU_ENABLE_PROFILING #We set a fairly new version (as of 2013) because I found finding perl was a bit... buggy on older ones #Can change this if you really want but you should upgrade! @@ -257,6 +258,7 @@ OPTION(EQEMU_BUILD_TESTS "Build utility tests." OFF) OPTION(EQEMU_BUILD_PERL "Build Perl parser." ON) OPTION(EQEMU_BUILD_LUA "Build Lua parser." ON) OPTION(EQEMU_BUILD_CLIENT_FILES "Build Client Import/Export Data Programs." ON) +OPTION(EQEMU_ENABLE_PROFILING "Enable CPU profiler. Note: will slow down execution time." OFF) #C++11 stuff IF(NOT MSVC) @@ -331,6 +333,15 @@ IF(EQEMU_BUILD_LUA) ADD_SUBDIRECTORY(luabind) ENDIF(EQEMU_BUILD_LUA) +IF(EQEMU_ENABLE_PROFILING) + ADD_DEFINITIONS(-DEQPERF_ENABLED) + INCLUDE_DIRECTORIES("eqperf") + ADD_SUBDIRECTORY(eqperf) + SET(PERF_LIBS eqperf) +ELSE(EQEMU_ENABLE_PROFILING) + SET(PERF_LIBS "") +ENDIF(EQEMU_ENABLE_PROFILING) + IF(EQEMU_BUILD_SERVER OR EQEMU_BUILD_LOGIN OR EQEMU_BUILD_TESTS) ADD_SUBDIRECTORY(common) ENDIF(EQEMU_BUILD_SERVER OR EQEMU_BUILD_LOGIN OR EQEMU_BUILD_TESTS) diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index f847957db..4ee46a41f 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -158,7 +158,6 @@ SET(common_headers packet_functions.h platform.h proc_launcher.h - profiler.h ptimer.h queue.h races.h diff --git a/common/profiler.h b/common/profiler.h deleted file mode 100644 index a66e3ac88..000000000 --- a/common/profiler.h +++ /dev/null @@ -1,92 +0,0 @@ -/* EQEMu: Everquest Server Emulator - Copyright (C) 2001-2004 EQEMu Development Team (http://eqemulator.net) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY except by those people which sell it, which - are required to give you total support for your newly bought product; - without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ -#ifndef PROFILER_H -#define PROFILER_H - -#ifdef EQPROFILE - -#include "../common/rdtsc.h" -#include "../common/types.h" - -class ScopedProfiler; - -class GeneralProfiler { - friend class ScopedProfiler; -public: - inline GeneralProfiler(unsigned int _count) { - count = _count; - timers = new RDTSC_Collector[count]; - } - inline virtual ~GeneralProfiler() { - safe_delete_array(timers); - } - - inline double getTotalDuration(unsigned int id) { - return(idreset(); - } - - RDTSC_Collector *timers; - unsigned int count; -}; - -class ScopedProfiler { -public: - inline ScopedProfiler(RDTSC_Collector *c) { - _it = c; - c->start(); - } - inline ~ScopedProfiler() { - _it->stop(); - } -protected: - RDTSC_Collector *_it; -}; - - -#define _GP(obj, pkg, name) ScopedProfiler __eqemu_profiler(&obj.timers[pkg::name]) - -#else // else !EQPROFILE - //no profiling, dummy functions -#define _GP(obj, pkg, name) ; - -#endif - -#endif diff --git a/common/types.h b/common/types.h index 9064b67e0..786f774ea 100644 --- a/common/types.h +++ b/common/types.h @@ -18,6 +18,7 @@ #ifndef TYPES_H #define TYPES_H +#include #include typedef uint8_t byte; typedef uint8_t uint8; diff --git a/eqperf/CMakeLists.txt b/eqperf/CMakeLists.txt new file mode 100644 index 000000000..3a59573ba --- /dev/null +++ b/eqperf/CMakeLists.txt @@ -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) diff --git a/eqperf/eqp_profile_event.cpp b/eqperf/eqp_profile_event.cpp new file mode 100644 index 000000000..1e84cfc2b --- /dev/null +++ b/eqperf/eqp_profile_event.cpp @@ -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_); +} diff --git a/eqperf/eqp_profile_event.h b/eqperf/eqp_profile_event.h new file mode 100644 index 000000000..24a7cc9bf --- /dev/null +++ b/eqperf/eqp_profile_event.h @@ -0,0 +1,41 @@ +#pragma once + +#include +#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 + diff --git a/eqperf/eqp_profile_function.h b/eqperf/eqp_profile_function.h new file mode 100644 index 000000000..2e4a26634 --- /dev/null +++ b/eqperf/eqp_profile_function.h @@ -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 diff --git a/eqperf/eqp_profile_timer.cpp b/eqperf/eqp_profile_timer.cpp new file mode 100644 index 000000000..9b415968b --- /dev/null +++ b/eqperf/eqp_profile_timer.cpp @@ -0,0 +1,24 @@ +#include "eqp_profile_timer.h" + +#ifdef _MSC_VER +#include +#else +#include +#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 +} diff --git a/eqperf/eqp_profile_timer.h b/eqperf/eqp_profile_timer.h new file mode 100644 index 000000000..3e6b03b42 --- /dev/null +++ b/eqperf/eqp_profile_timer.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +namespace EQP +{ + uint64_t GetCurrentTimer(); +} // EQP + diff --git a/eqperf/eqp_profiler.cpp b/eqperf/eqp_profiler.cpp new file mode 100644 index 000000000..90f75e8d0 --- /dev/null +++ b/eqperf/eqp_profiler.cpp @@ -0,0 +1,194 @@ +#include "eqp_profiler.h" +#include +#include +#include +#include +#include + +EQP::CPU::ST::Profiler st_profiler; +EQP::CPU::MT::Profiler mt_profiler; + +struct EQP::CPU::MT::Profiler::impl +{ + std::mutex lock_; + std::unordered_map 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 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 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(); +} + diff --git a/eqperf/eqp_profiler.h b/eqperf/eqp_profiler.h new file mode 100644 index 000000000..ae01e8e7c --- /dev/null +++ b/eqperf/eqp_profiler.h @@ -0,0 +1,78 @@ +#pragma once + +#ifdef EQPERF_ENABLED + +#include +#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 + diff --git a/eqperf/eqp_profiler_node.cpp b/eqperf/eqp_profiler_node.cpp new file mode 100644 index 000000000..315a27648 --- /dev/null +++ b/eqperf/eqp_profiler_node.cpp @@ -0,0 +1,54 @@ +#include "eqp_profiler_node.h" +#include +#include +#include + +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(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 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); + } +} diff --git a/eqperf/eqp_profiler_node.h b/eqperf/eqp_profiler_node.h new file mode 100644 index 000000000..5f3dfe6b9 --- /dev/null +++ b/eqperf/eqp_profiler_node.h @@ -0,0 +1,43 @@ +#pragma once + +#include +#include +#include + +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& 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 nodes_; + }; + + struct ProfilerNodeDump + { + std::string name; + ProfilerNode *node; + }; + } // CPU +} // EQP + diff --git a/loginserver/CMakeLists.txt b/loginserver/CMakeLists.txt index f588cbc48..d5b91854c 100644 --- a/loginserver/CMakeLists.txt +++ b/loginserver/CMakeLists.txt @@ -43,7 +43,7 @@ ADD_EXECUTABLE(loginserver ${eqlogin_sources} ${eqlogin_headers}) INSTALL(TARGETS loginserver RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}) -TARGET_LINK_LIBRARIES(loginserver common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE}) +TARGET_LINK_LIBRARIES(loginserver common ${PERF_LIBS} debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE}) IF(MSVC) SET_TARGET_PROPERTIES(loginserver PROPERTIES LINK_FLAGS_RELEASE "/OPT:REF /OPT:ICF") diff --git a/loginserver/client.cpp b/loginserver/client.cpp index fe43e6675..4b1deb2ef 100644 --- a/loginserver/client.cpp +++ b/loginserver/client.cpp @@ -26,6 +26,7 @@ extern LoginServer server; Client::Client(std::shared_ptr c, LSClientVersion v) { + _eqp connection = c; version = v; status = cs_not_sent_session_ready; @@ -36,6 +37,7 @@ Client::Client(std::shared_ptr c, LSClientVersion v) bool Client::Process() { + _eqp EQApplicationPacket *app = connection->PopPacket(); while(app) { @@ -114,6 +116,7 @@ bool Client::Process() void Client::Handle_SessionReady(const char* data, unsigned int size) { + _eqp if(status != cs_not_sent_session_ready) { server_log->Log(log_network_error, "Session ready received again after already being received."); @@ -175,6 +178,7 @@ void Client::Handle_SessionReady(const char* data, unsigned int size) void Client::Handle_Login(const char* data, unsigned int size) { + _eqp if(status != cs_waiting_for_login) { server_log->Log(log_network_error, "Login received after already having logged in."); @@ -329,6 +333,7 @@ void Client::Handle_Login(const char* data, unsigned int size) void Client::Handle_Play(const char* data) { + _eqp if(status != cs_logged_in) { server_log->Log(log_client_error, "Client sent a play request when they either were not logged in, discarding."); @@ -352,6 +357,7 @@ void Client::Handle_Play(const char* data) void Client::SendServerListPacket() { + _eqp EQApplicationPacket *outapp = server.SM->CreateServerListPacket(this); if(server.options.IsDumpOutPacketsOn()) @@ -365,6 +371,7 @@ void Client::SendServerListPacket() void Client::SendPlayResponse(EQApplicationPacket *outapp) { + _eqp if(server.options.IsTraceOn()) { server_log->Log(log_network_trace, "Sending play response for %s.", GetAccountName().c_str()); @@ -376,6 +383,7 @@ void Client::SendPlayResponse(EQApplicationPacket *outapp) void Client::GenerateKey() { + _eqp key.clear(); int count = 0; while(count < 10) diff --git a/loginserver/client_manager.cpp b/loginserver/client_manager.cpp index eb982f613..309067a79 100644 --- a/loginserver/client_manager.cpp +++ b/loginserver/client_manager.cpp @@ -25,6 +25,7 @@ extern bool run_server; ClientManager::ClientManager() { + _eqp int titanium_port = atoi(server.config->GetVariable("Titanium", "port").c_str()); titanium_stream = new EQStreamFactory(LoginStream, titanium_port); titanium_ops = new RegularOpcodeManager; @@ -68,6 +69,7 @@ ClientManager::ClientManager() ClientManager::~ClientManager() { + _eqp if(titanium_stream) { titanium_stream->Close(); @@ -93,6 +95,7 @@ ClientManager::~ClientManager() void ClientManager::Process() { + _eqp ProcessDisconnect(); std::shared_ptr cur = titanium_stream->Pop(); while(cur) @@ -138,6 +141,7 @@ void ClientManager::Process() void ClientManager::ProcessDisconnect() { + _eqp list::iterator iter = clients.begin(); while(iter != clients.end()) { @@ -157,6 +161,7 @@ void ClientManager::ProcessDisconnect() void ClientManager::UpdateServerList() { + _eqp list::iterator iter = clients.begin(); while(iter != clients.end()) { @@ -167,6 +172,7 @@ void ClientManager::UpdateServerList() void ClientManager::RemoveExistingClient(unsigned int account_id) { + _eqp list::iterator iter = clients.begin(); while(iter != clients.end()) { @@ -185,6 +191,7 @@ void ClientManager::RemoveExistingClient(unsigned int account_id) Client *ClientManager::GetClient(unsigned int account_id) { + _eqp Client *cur = nullptr; int count = 0; list::iterator iter = clients.begin(); diff --git a/loginserver/config.cpp b/loginserver/config.cpp index 96a4c8568..633e51c26 100644 --- a/loginserver/config.cpp +++ b/loginserver/config.cpp @@ -27,6 +27,7 @@ extern ErrorLog *server_log; */ std::string Config::GetVariable(std::string title, std::string parameter) { + _eqp std::map >::iterator iter = vars.find(title); if(iter != vars.end()) { @@ -46,6 +47,7 @@ std::string Config::GetVariable(std::string title, std::string parameter) */ void Config::Parse(const char *file_name) { + _eqp if(file_name == nullptr) { server_log->Log(log_error, "Config::Parse(), file_name passed was null."); @@ -144,6 +146,7 @@ void Config::Parse(const char *file_name) */ void Config::Tokenize(FILE *input, std::list &tokens) { + _eqp char c = fgetc(input); std::string lexeme; diff --git a/loginserver/database_mysql.cpp b/loginserver/database_mysql.cpp index 9cf08563b..29f006077 100644 --- a/loginserver/database_mysql.cpp +++ b/loginserver/database_mysql.cpp @@ -30,6 +30,7 @@ extern LoginServer server; DatabaseMySQL::DatabaseMySQL(string user, string pass, string host, string port, string name) { + _eqp this->user = user; this->pass = pass; this->host = host; @@ -55,6 +56,7 @@ DatabaseMySQL::DatabaseMySQL(string user, string pass, string host, string port, DatabaseMySQL::~DatabaseMySQL() { + _eqp if(db) { mysql_close(db); @@ -63,6 +65,7 @@ DatabaseMySQL::~DatabaseMySQL() bool DatabaseMySQL::GetLoginDataFromAccountName(string name, string &password, unsigned int &id) { + _eqp if(!db) { return false; @@ -101,6 +104,7 @@ bool DatabaseMySQL::GetLoginDataFromAccountName(string name, string &password, u bool DatabaseMySQL::GetWorldRegistration(string long_name, string short_name, unsigned int &id, string &desc, unsigned int &list_id, unsigned int &trusted, string &list_desc, string &account, string &password) { + _eqp if(!db) { return false; @@ -176,6 +180,7 @@ bool DatabaseMySQL::GetWorldRegistration(string long_name, string short_name, un void DatabaseMySQL::UpdateLSAccountData(unsigned int id, string ip_address) { + _eqp if(!db) { return; @@ -195,6 +200,7 @@ void DatabaseMySQL::UpdateLSAccountData(unsigned int id, string ip_address) void DatabaseMySQL::UpdateLSAccountInfo(unsigned int id, string name, string password, string email) { + _eqp if(!db) { return; @@ -214,6 +220,7 @@ void DatabaseMySQL::UpdateLSAccountInfo(unsigned int id, string name, string pas void DatabaseMySQL::UpdateWorldRegistration(unsigned int id, string long_name, string ip_address) { + _eqp if(!db) { return; @@ -239,6 +246,7 @@ void DatabaseMySQL::UpdateWorldRegistration(unsigned int id, string long_name, s bool DatabaseMySQL::CreateWorldRegistration(string long_name, string short_name, unsigned int &id) { + _eqp if(!db) { return false; diff --git a/loginserver/database_postgresql.cpp b/loginserver/database_postgresql.cpp index 3dc20d3f3..eaa10e6ca 100644 --- a/loginserver/database_postgresql.cpp +++ b/loginserver/database_postgresql.cpp @@ -30,6 +30,7 @@ extern LoginServer server; DatabasePostgreSQL::DatabasePostgreSQL(string user, string pass, string host, string port, string name) { + _eqp db = nullptr; db = PQsetdbLogin(host.c_str(), port.c_str(), nullptr, nullptr, name.c_str(), user.c_str(), pass.c_str()); if(!db) @@ -47,6 +48,7 @@ DatabasePostgreSQL::DatabasePostgreSQL(string user, string pass, string host, st DatabasePostgreSQL::~DatabasePostgreSQL() { + _eqp if(db) { PQfinish(db); @@ -55,6 +57,7 @@ DatabasePostgreSQL::~DatabasePostgreSQL() bool DatabasePostgreSQL::GetLoginDataFromAccountName(string name, string &password, unsigned int &id) { + _eqp if(!db) { return false; @@ -103,6 +106,7 @@ bool DatabasePostgreSQL::GetLoginDataFromAccountName(string name, string &passwo bool DatabasePostgreSQL::GetWorldRegistration(string long_name, string short_name, unsigned int &id, string &desc, unsigned int &list_id, unsigned int &trusted, string &list_desc, string &account, string &password) { + _eqp if(!db) { return false; @@ -160,6 +164,7 @@ bool DatabasePostgreSQL::GetWorldRegistration(string long_name, string short_nam void DatabasePostgreSQL::UpdateLSAccountData(unsigned int id, string ip_address) { + _eqp if(!db) { return; @@ -195,6 +200,7 @@ void DatabasePostgreSQL::UpdateLSAccountData(unsigned int id, string ip_address) void DatabasePostgreSQL::UpdateWorldRegistration(unsigned int id, string long_name, string ip_address) { + _eqp if(!db) { return; diff --git a/loginserver/encryption.cpp b/loginserver/encryption.cpp index b00f5e88b..ebbb6a35d 100644 --- a/loginserver/encryption.cpp +++ b/loginserver/encryption.cpp @@ -24,6 +24,7 @@ extern ErrorLog *server_log; bool Encryption::LoadCrypto(std::string name) { + _eqp if(!Load(name.c_str())) { server_log->Log(log_error, "Failed to load %s from the operating system.", name.c_str()); @@ -58,6 +59,7 @@ bool Encryption::LoadCrypto(std::string name) char *Encryption::DecryptUsernamePassword(const char* encrypted_buffer, unsigned int buffer_size, int mode) { + _eqp if(decrypt_func) { return decrypt_func(encrypted_buffer, buffer_size, mode); @@ -67,6 +69,7 @@ char *Encryption::DecryptUsernamePassword(const char* encrypted_buffer, unsigned char *Encryption::Encrypt(const char* buffer, unsigned int buffer_size, unsigned int &out_size) { + _eqp if(encrypt_func) { return encrypt_func(buffer, buffer_size, out_size); @@ -76,6 +79,7 @@ char *Encryption::Encrypt(const char* buffer, unsigned int buffer_size, unsigned void Encryption::DeleteHeap(char *buffer) { + _eqp if(delete_func) { delete_func(buffer); @@ -84,6 +88,7 @@ void Encryption::DeleteHeap(char *buffer) bool Encryption::Load(const char *name) { + _eqp SetLastError(0); #ifdef UNICODE int name_length = strlen(name); @@ -111,6 +116,7 @@ bool Encryption::Load(const char *name) void Encryption::Unload() { + _eqp if(h_dll) { FreeLibrary(h_dll); @@ -120,6 +126,7 @@ void Encryption::Unload() bool Encryption::GetSym(const char *name, void **sym) { + _eqp if(Loaded()) { *sym = GetProcAddress(h_dll, name); @@ -133,6 +140,7 @@ bool Encryption::GetSym(const char *name, void **sym) void *Encryption::GetSym(const char *name) { + _eqp if(Loaded()) { return GetProcAddress(h_dll, name); diff --git a/loginserver/error_log.cpp b/loginserver/error_log.cpp index 03021f6c7..cee8b1fde 100644 --- a/loginserver/error_log.cpp +++ b/loginserver/error_log.cpp @@ -34,12 +34,14 @@ const char *eqLogTypes[_log_largest_type] = ErrorLog::ErrorLog(const char* file_name) { + _eqp log_mutex = new Mutex(); error_log = fopen(file_name, "w"); } ErrorLog::~ErrorLog() { + _eqp log_mutex->lock(); if(error_log) { @@ -51,6 +53,7 @@ ErrorLog::~ErrorLog() void ErrorLog::Log(eqLogType type, const char *message, ...) { + _eqp if(type >= _log_largest_type) { return; @@ -98,6 +101,7 @@ void ErrorLog::Log(eqLogType type, const char *message, ...) void ErrorLog::LogPacket(eqLogType type, const char *data, size_t size) { + _eqp if(type >= _log_largest_type) { return; diff --git a/loginserver/main.cpp b/loginserver/main.cpp index 0d51a69ff..687f053bc 100644 --- a/loginserver/main.cpp +++ b/loginserver/main.cpp @@ -26,8 +26,10 @@ #include "login_server.h" #include #include +#include #include #include +#include TimeoutManager timeout_manager; LoginServer server; @@ -37,6 +39,20 @@ bool run_server = true; void CatchSignal(int sig_num) { +#ifdef EQPERF_ENABLED + char time_str[128]; + time_t result = time(nullptr); + strftime(time_str, sizeof(time_str), "%Y_%m_%d__%H_%M_%S", localtime(&result)); + + std::string prof_name = "./profile/login_"; + prof_name += time_str; + prof_name += ".log"; + + std::ofstream profile_out(prof_name, std::ofstream::out); + if(profile_out.good()) { + EQP::CPU::ST::GetProfiler().Dump(profile_out); + } +#endif } int main() @@ -47,14 +63,23 @@ int main() //Create our error log, is of format login_.log time_t current_time = time(nullptr); std::stringstream log_name(std::stringstream::in | std::stringstream::out); -#ifdef WIN32 - log_name << ".\\logs\\login_" << (unsigned int)current_time << ".log"; -#else log_name << "./logs/login_" << (unsigned int)current_time << ".log"; -#endif server_log = new ErrorLog(log_name.str().c_str()); server_log->Log(log_debug, "Logging System Init."); + if(signal(SIGINT, CatchSignal) == SIG_ERR) { + server_log->Log(log_error, "Could not set signal handler"); + return 1; + } + if(signal(SIGTERM, CatchSignal) == SIG_ERR) { + server_log->Log(log_error, "Could not set signal handler"); + return 1; + } + if(signal(SIGBREAK, CatchSignal) == SIG_ERR) { + server_log->Log(log_error, "Could not set signal handler"); + return 1; + } + //Create our subsystem and parse the ini file. server.config = new Config(); server_log->Log(log_debug, "Config System Init."); diff --git a/loginserver/server_manager.cpp b/loginserver/server_manager.cpp index 6a1b57d6f..07e88f4f6 100644 --- a/loginserver/server_manager.cpp +++ b/loginserver/server_manager.cpp @@ -27,6 +27,7 @@ extern bool run_server; ServerManager::ServerManager() { + _eqp char error_buffer[TCPConnection_ErrorBufferSize]; int listen_port = atoi(server.config->GetVariable("options", "listen_port").c_str()); @@ -44,6 +45,7 @@ ServerManager::ServerManager() ServerManager::~ServerManager() { + _eqp if(tcps) { tcps->Close(); @@ -53,6 +55,7 @@ ServerManager::~ServerManager() void ServerManager::Process() { + _eqp ProcessDisconnect(); EmuTCPConnection *tcp_c = nullptr; while(tcp_c = tcps->NewQueuePop()) @@ -94,6 +97,7 @@ void ServerManager::Process() void ServerManager::ProcessDisconnect() { + _eqp list::iterator iter = world_servers.begin(); while(iter != world_servers.end()) { @@ -116,6 +120,7 @@ void ServerManager::ProcessDisconnect() WorldServer* ServerManager::GetServerByAddress(unsigned int address) { + _eqp list::iterator iter = world_servers.begin(); while(iter != world_servers.end()) { @@ -131,6 +136,7 @@ WorldServer* ServerManager::GetServerByAddress(unsigned int address) EQApplicationPacket *ServerManager::CreateServerListPacket(Client *c) { + _eqp unsigned int packet_size = sizeof(ServerListHeader_Struct); unsigned int server_count = 0; in_addr in; @@ -268,6 +274,7 @@ EQApplicationPacket *ServerManager::CreateServerListPacket(Client *c) void ServerManager::SendUserToWorldRequest(unsigned int server_id, unsigned int client_account_id) { + _eqp list::iterator iter = world_servers.begin(); bool found = false; while(iter != world_servers.end()) @@ -298,6 +305,7 @@ void ServerManager::SendUserToWorldRequest(unsigned int server_id, unsigned int bool ServerManager::ServerExists(string l_name, string s_name, WorldServer *ignore) { + _eqp list::iterator iter = world_servers.begin(); while(iter != world_servers.end()) { @@ -319,6 +327,7 @@ bool ServerManager::ServerExists(string l_name, string s_name, WorldServer *igno void ServerManager::DestroyServerByName(string l_name, string s_name, WorldServer *ignore) { + _eqp list::iterator iter = world_servers.begin(); while(iter != world_servers.end()) { diff --git a/loginserver/world_server.cpp b/loginserver/world_server.cpp index c91f1b702..12a9e5a48 100644 --- a/loginserver/world_server.cpp +++ b/loginserver/world_server.cpp @@ -25,6 +25,7 @@ extern LoginServer server; WorldServer::WorldServer(EmuTCPConnection *c) { + _eqp connection = c; zones_booted = 0; players_online = 0; @@ -39,6 +40,7 @@ WorldServer::WorldServer(EmuTCPConnection *c) WorldServer::~WorldServer() { + _eqp if(connection) { connection->Free(); @@ -47,6 +49,7 @@ WorldServer::~WorldServer() void WorldServer::Reset() { + _eqp zones_booted = 0; players_online = 0; status = 0; @@ -59,6 +62,7 @@ void WorldServer::Reset() bool WorldServer::Process() { + _eqp ServerPacket *app = nullptr; while(app = connection->PopPacket()) { @@ -237,6 +241,7 @@ bool WorldServer::Process() void WorldServer::Handle_NewLSInfo(ServerNewLSInfo_Struct* i) { + _eqp if(logged_in) { server_log->Log(log_network_error, "WorldServer::Handle_NewLSInfo called but the login server was already marked as logged in, aborting."); @@ -501,6 +506,7 @@ void WorldServer::Handle_NewLSInfo(ServerNewLSInfo_Struct* i) void WorldServer::Handle_LSStatus(ServerLSStatus_Struct *s) { + _eqp players_online = s->num_players; zones_booted = s->num_zones; status = s->status; @@ -508,6 +514,7 @@ void WorldServer::Handle_LSStatus(ServerLSStatus_Struct *s) void WorldServer::SendClientAuth(unsigned int ip, string account, string key, unsigned int account_id) { + _eqp ServerPacket *outapp = new ServerPacket(ServerOP_LSClientAuth, sizeof(ServerLSClientAuth)); ServerLSClientAuth* slsca = (ServerLSClientAuth*)outapp->pBuffer; diff --git a/zone/command.cpp b/zone/command.cpp index f54db9a75..1fbfc81d3 100644 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -153,10 +153,6 @@ int command_init(void) { #ifdef PACKET_PROFILER command_add("packetprofile", "- Dump packet profile for target or self.", 250, command_packetprofile) || #endif -#ifdef EQPROFILE - command_add("profiledump", "- Dump profiling info to logs", 250, command_profiledump) || - command_add("profilereset", "- Reset profiling info", 250, command_profilereset) || -#endif #ifdef BOTS command_add("bot", "- Type \"#bot help\" to the see the list of available commands for bots.", 0, command_bot) || #endif @@ -6611,16 +6607,6 @@ void command_packetprofile(Client *c, const Seperator *sep) { } #endif -#ifdef EQPROFILE -void command_profiledump(Client *c, const Seperator *sep) { - DumpZoneProfile(); -} - -void command_profilereset(Client *c, const Seperator *sep) { - ResetZoneProfile(); -} -#endif - void command_opcode(Client *c, const Seperator *sep) { if(!strcasecmp(sep->arg[1], "reload" )) { ReloadAllPatches(); diff --git a/zone/command.h b/zone/command.h index 0560b8eff..13f718f7a 100644 --- a/zone/command.h +++ b/zone/command.h @@ -325,11 +325,6 @@ void command_tune(Client *c, const Seperator *sep); void command_logtest(Client *c, const Seperator *sep); void command_mysqltest(Client *c, const Seperator *sep); void command_logs(Client *c, const Seperator *sep); - -#ifdef EQPROFILE -void command_profiledump(Client *c, const Seperator *sep); -void command_profilereset(Client *c, const Seperator *sep); -#endif #ifdef PACKET_PROFILER void command_packetprofile(Client *c, const Seperator *sep); diff --git a/zone/net.cpp b/zone/net.cpp index 92f568af0..9e4b5eed3 100644 --- a/zone/net.cpp +++ b/zone/net.cpp @@ -308,12 +308,6 @@ int main(int argc, char** argv) { } Timer InterserverTimer(INTERSERVER_TIMER); // does MySQL pings and auto-reconnect -#ifdef EQPROFILE -#ifdef PROFILE_DUMP_TIME - Timer profile_dump_timer(PROFILE_DUMP_TIME*1000); - profile_dump_timer.Start(); -#endif -#endif if (!strlen(zone_name) || !strcmp(zone_name,".")) { Log.Out(Logs::General, Logs::Zone_Server, "Entering sleep mode"); } else if (!Zone::Bootup(database.GetZoneID(zone_name), 0, true)) { //todo: go above and fix this to allow cmd line instance @@ -444,13 +438,6 @@ int main(int argc, char** argv) { worldserver.AsyncConnect(); } -#ifdef EQPROFILE -#ifdef PROFILE_DUMP_TIME - if(profile_dump_timer.Check()) { - DumpZoneProfile(); - } -#endif -#endif } //end extra profiler block Sleep(ZoneTimerResolution); }