Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@ endif ()

find_package(Boost 1.66.0 REQUIRED COMPONENTS date_time system filesystem iostreams)

if (NOT DEFINED DISABLE_STATS OR NOT DISABLE_STATS)
message(STATUS "OTS stats enabled. Run 'cmake -DDISABLE_STATS=1 ..' to disable")
ADD_DEFINITIONS(-DSTATS_ENABLED)
else ()
message(STATUS "OTS stats disabled. Run 'cmake -DDISABLE_STATS=0 ..' to enable")
endif ()

include_directories(${Boost_INCLUDE_DIRS} ${Crypto++_INCLUDE_DIR} ${LUA_INCLUDE_DIR} ${MYSQL_INCLUDE_DIR} ${PUGIXML_INCLUDE_DIR})
target_link_libraries(tfs PRIVATE
Boost::date_time
Expand Down
8 changes: 8 additions & 0 deletions config.lua.dist
Original file line number Diff line number Diff line change
Expand Up @@ -165,3 +165,11 @@ ownerName = ""
ownerEmail = ""
url = "https://otland.net/"
location = "Sweden"

-- Server Statistics
-- time in seconds: 30 = 30 seconds, 0 = disabled
statsDumpInterval = 30
-- time in milliseconds: 10 = 0.01 sec, 0 = disabled
statsSlowLogTime = 10
-- time in milliseconds: 50 = 0.05 sec, 0 = disabled
statsVerySlowLogTime = 50
1 change: 1 addition & 0 deletions data/logs/stats/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.log
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ set(tfs_SRC
${CMAKE_CURRENT_LIST_DIR}/signals.cpp
${CMAKE_CURRENT_LIST_DIR}/spawn.cpp
${CMAKE_CURRENT_LIST_DIR}/spells.cpp
${CMAKE_CURRENT_LIST_DIR}/stats.cpp
${CMAKE_CURRENT_LIST_DIR}/storeinbox.cpp
${CMAKE_CURRENT_LIST_DIR}/talkaction.cpp
${CMAKE_CURRENT_LIST_DIR}/tasks.cpp
Expand Down
3 changes: 3 additions & 0 deletions src/configmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,9 @@ bool ConfigManager::load()
integer[VIP_PREMIUM_LIMIT] = getGlobalNumber(L, "vipPremiumLimit", 100);
integer[DEPOT_FREE_LIMIT] = getGlobalNumber(L, "depotFreeLimit", 2000);
integer[DEPOT_PREMIUM_LIMIT] = getGlobalNumber(L, "depotPremiumLimit", 10000);
integer[STATS_DUMP_INTERVAL] = getGlobalNumber(L, "statsDumpInterval", 30000);
integer[STATS_SLOW_LOG_TIME] = getGlobalNumber(L, "statsSlowLogTime", 10);
integer[STATS_VERY_SLOW_LOG_TIME] = getGlobalNumber(L, "statsVerySlowLogTime", 50);

expStages = loadXMLStages();
if (expStages.empty()) {
Expand Down
3 changes: 3 additions & 0 deletions src/configmanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ class ConfigManager
VIP_PREMIUM_LIMIT,
DEPOT_FREE_LIMIT,
DEPOT_PREMIUM_LIMIT,
STATS_DUMP_INTERVAL,
STATS_SLOW_LOG_TIME,
STATS_VERY_SLOW_LOG_TIME,

LAST_INTEGER_CONFIG /* this must be the last one */
};
Expand Down
21 changes: 21 additions & 0 deletions src/database.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include "configmanager.h"
#include "database.h"
#include "stats.h"

#include <mysql/errmsg.h>

Expand Down Expand Up @@ -84,6 +85,10 @@ bool Database::executeQuery(const std::string& query)
// executes the query
databaseLock.lock();

#ifdef STATS_ENABLED
std::chrono::high_resolution_clock::time_point time_point = std::chrono::high_resolution_clock::now();
#endif

while (mysql_real_query(handle, query.c_str(), query.length()) != 0) {
std::cout << "[Error - mysql_real_query] Query: " << query.substr(0, 256) << std::endl << "Message: " << mysql_error(handle) << std::endl;
auto error = mysql_errno(handle);
Expand All @@ -95,6 +100,12 @@ bool Database::executeQuery(const std::string& query)
}

MYSQL_RES* m_res = mysql_store_result(handle);

#ifdef STATS_ENABLED
uint64_t ns = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - time_point).count();
g_stats.addSqlStats(new Stat(ns, query.substr(0, 100), query.substr(0, 256)));
#endif

databaseLock.unlock();

if (m_res) {
Expand All @@ -108,6 +119,10 @@ DBResult_ptr Database::storeQuery(const std::string& query)
{
databaseLock.lock();

#ifdef STATS_ENABLED
std::chrono::high_resolution_clock::time_point time_point = std::chrono::high_resolution_clock::now();
#endif

retry:
while (mysql_real_query(handle, query.c_str(), query.length()) != 0) {
std::cout << "[Error - mysql_real_query] Query: " << query << std::endl << "Message: " << mysql_error(handle) << std::endl;
Expand All @@ -130,6 +145,12 @@ DBResult_ptr Database::storeQuery(const std::string& query)
}
goto retry;
}

#ifdef STATS_ENABLED
uint64_t ns = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - time_point).count();
g_stats.addSqlStats(new Stat(ns, query.substr(0, 100), query.substr(0, 256)));
#endif

databaseLock.unlock();

// retrieving results of query
Expand Down
10 changes: 10 additions & 0 deletions src/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@ void Game::setGameState(GameState_t newState)
g_scheduler.stop();
g_databaseTasks.stop();
g_dispatcher.stop();
#ifdef STATS_ENABLED
g_stats.stop();
#endif
break;
}

Expand Down Expand Up @@ -3739,6 +3742,10 @@ void Game::checkCreatures(size_t index)
}

cleanup();

#ifdef STATS_ENABLED
g_stats.playersOnline = getPlayersOnline();
#endif
}

void Game::changeSpeed(Creature* creature, int32_t varSpeedDelta)
Expand Down Expand Up @@ -4621,6 +4628,9 @@ void Game::shutdown()
g_scheduler.shutdown();
g_databaseTasks.shutdown();
g_dispatcher.shutdown();
#ifdef STATS_ENABLED
g_stats.shutdown();
#endif
map.spawns.clear();
raids.clear();

Expand Down
24 changes: 24 additions & 0 deletions src/luascript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,16 @@ const std::string& LuaScriptInterface::getFileById(int32_t scriptId)
return it->second;
}

const std::string& LuaScriptInterface::getFileByIdForStats(int32_t scriptId)
{
auto it = cacheFiles.find(scriptId);
if (it == cacheFiles.end()) {
static const std::string& unk = "(Unknown scriptfile)";
return unk;
}
return it->second;
}

std::string LuaScriptInterface::getStackTrace(lua_State* L, const std::string& error_desc)
{
lua_getglobal(L, "debug");
Expand Down Expand Up @@ -528,6 +538,15 @@ int LuaScriptInterface::luaErrorHandler(lua_State* L)

bool LuaScriptInterface::callFunction(int params)
{
#ifdef STATS_ENABLED
int32_t scriptId;
int32_t callbackId;
bool timerEvent;
LuaScriptInterface* scriptInterface;
getScriptEnv()->getEventInfo(scriptId, scriptInterface, callbackId, timerEvent);
std::chrono::high_resolution_clock::time_point time_point = std::chrono::high_resolution_clock::now();
#endif

bool result = false;
int size = lua_gettop(luaState);
if (protectedCall(luaState, params, 1) != 0) {
Expand All @@ -541,6 +560,11 @@ bool LuaScriptInterface::callFunction(int params)
LuaScriptInterface::reportError(nullptr, "Stack size changed!");
}

#ifdef STATS_ENABLED
uint64_t ns = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - time_point).count();
g_stats.addLuaStats(new Stat(ns, getFileByIdForStats(scriptId), ""));
#endif

resetScriptEnv();
return result;
}
Expand Down
1 change: 1 addition & 0 deletions src/luascript.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ class LuaScriptInterface
int32_t loadFile(const std::string& file, Npc* npc = nullptr);

const std::string& getFileById(int32_t scriptId);
const std::string& getFileByIdForStats(int32_t scriptId);
int32_t getEvent(const std::string& eventName);
int32_t getEvent();
int32_t getMetaEvent(const std::string& globalName, const std::string& eventName);
Expand Down
10 changes: 10 additions & 0 deletions src/otserv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
DatabaseTasks g_databaseTasks;
Dispatcher g_dispatcher;
Scheduler g_scheduler;
Stats g_stats;

Game g_game;
ConfigManager g_config;
Expand Down Expand Up @@ -71,6 +72,9 @@ int main(int argc, char* argv[])

g_dispatcher.start();
g_scheduler.start();
#ifdef STATS_ENABLED
g_stats.start();
#endif

g_dispatcher.addTask(createTask(std::bind(mainLoader, argc, argv, &serviceManager)));

Expand All @@ -84,11 +88,17 @@ int main(int argc, char* argv[])
g_scheduler.shutdown();
g_databaseTasks.shutdown();
g_dispatcher.shutdown();
#ifdef STATS_ENABLED
g_stats.shutdown();
#endif
}

g_scheduler.join();
g_databaseTasks.join();
g_dispatcher.join();
#ifdef STATS_ENABLED
g_stats.join();
#endif
return 0;
}

Expand Down
8 changes: 4 additions & 4 deletions src/protocolgame.h
Original file line number Diff line number Diff line change
Expand Up @@ -293,13 +293,13 @@ class ProtocolGame final : public Protocol

// Helpers so we don't need to bind every time
template <typename Callable, typename... Args>
void addGameTask(Callable&& function, Args&&... args) {
g_dispatcher.addTask(createTask(std::bind(std::forward<Callable>(function), &g_game, std::forward<Args>(args)...)));
void addGameTaskWithStats(Callable&& function, const std::string& function_str, const std::string& extra_info, Args&&... args) {
g_dispatcher.addTask(createTaskWithStats(std::bind(std::forward<Callable>(function), &g_game, std::forward<Args>(args)...), function_str, extra_info));
}

template <typename Callable, typename... Args>
void addGameTaskTimed(uint32_t delay, Callable&& function, Args&&... args) {
g_dispatcher.addTask(createTask(delay, std::bind(std::forward<Callable>(function), &g_game, std::forward<Args>(args)...)));
void addGameTaskTimedWithStats(uint32_t delay, Callable&& function, const std::string& function_str, const std::string& extra_info, Args&&... args) {
g_dispatcher.addTask(createTaskWithStats(delay, std::bind(std::forward<Callable>(function), &g_game, std::forward<Args>(args)...), function_str, extra_info));
}

std::unordered_set<uint32_t> knownCreatureSet;
Expand Down
4 changes: 2 additions & 2 deletions src/scheduler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ void Scheduler::shutdown()
});
}

SchedulerTask* createSchedulerTask(uint32_t delay, TaskFunc&& f)
SchedulerTask* createSchedulerTaskWithStats(uint32_t delay, TaskFunc&& f, const std::string& description, const std::string& extraDescription)
{
return new SchedulerTask(delay, std::move(f));
return new SchedulerTask(delay, std::move(f), description, extraDescription);
}
7 changes: 4 additions & 3 deletions src/scheduler.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,16 @@ class SchedulerTask : public Task
return delay;
}
private:
SchedulerTask(uint32_t delay, TaskFunc&& f) : Task(std::move(f)), delay(delay) {}
SchedulerTask(uint32_t delay, TaskFunc&& f, const std::string& description, const std::string& extraDescription) :
Task(std::move(f), description, extraDescription), delay(delay) {}

uint32_t eventId = 0;
uint32_t delay = 0;

friend SchedulerTask* createSchedulerTask(uint32_t, TaskFunc&&);
friend SchedulerTask* createSchedulerTaskWithStats(uint32_t, TaskFunc&&, const std::string&, const std::string&);
};

SchedulerTask* createSchedulerTask(uint32_t delay, TaskFunc&& f);
SchedulerTask* createSchedulerTaskWithStats(uint32_t delay, TaskFunc&& f, const std::string& description, const std::string& extraDescription);

class Scheduler : public ThreadHolder<Scheduler>
{
Expand Down
3 changes: 3 additions & 0 deletions src/signals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,9 @@ void dispatchSignalHandler(int signal)
g_scheduler.join();
g_databaseTasks.join();
g_dispatcher.join();
#ifdef STATS_ENABLED
g_stats.join();
#endif
break;
#endif
default:
Expand Down
Loading