Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OTS Statistics by kondra for TFS 1.6+ #4874

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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 @@ -97,6 +97,13 @@ if (BUILD_TESTING)
enable_testing()
endif()

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

# Option to disable unity builds
option(ENABLE_UNITY_BUILD "Enable unity build" ON)

Expand Down
16 changes: 16 additions & 0 deletions config.lua.dist
Original file line number Diff line number Diff line change
Expand Up @@ -168,3 +168,19 @@ 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
-- normal stats reports all Lua addEvents as '(Unknown scriptfile)'
-- with this option enabled, it will generate special.log with addEvent CPU usage
-- it will also generate special_slow/very_slow.log with addEvent stack backtrace
statsTrackLuaAddEvents = false
-- statsTrackLuaAddEvents reports all scripts in special.log with name 'LuaAddEvent'
-- if you want to track CPU usage of individual addEvent scripts, enable this option - IT WILL USE A LOT MORE CPU!
-- hashID = stack backtrace will be printed in server console, so you must log server output to some file
statsTrackLuaAddEventsHashes = false
5 changes: 5 additions & 0 deletions data/cpplinter.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2137,6 +2137,8 @@ configKeys = {
MANASHIELD_BREAKABLE = 36,
CHECK_DUPLICATE_STORAGE_KEYS = 37,
MONSTER_OVERSPAWN = 38,
STATS_TRACK_LUA_ADD_EVENTS = 39,
STATS_TRACK_LUA_ADD_EVENTS_HASHES = 40,

-- ConfigKeysString
MAP_NAME = 0,
Expand Down Expand Up @@ -2203,6 +2205,9 @@ configKeys = {
QUEST_TRACKER_PREMIUM_LIMIT = 42,
STAMINA_REGEN_MINUTE = 43,
STAMINA_REGEN_PREMIUM = 44,
STATS_DUMP_INTERVAL = 45,
STATS_SLOW_LOG_TIME = 46,
STATS_VERY_SLOW_LOG_TIME = 47,
}

ITEM_TYPE_NONE = 0
Expand Down
2 changes: 2 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,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 Expand Up @@ -152,6 +153,7 @@ set(tfs_HDR
${CMAKE_CURRENT_LIST_DIR}/spawn.h
${CMAKE_CURRENT_LIST_DIR}/spectators.h
${CMAKE_CURRENT_LIST_DIR}/spells.h
${CMAKE_CURRENT_LIST_DIR}/stats.h
${CMAKE_CURRENT_LIST_DIR}/storeinbox.h
${CMAKE_CURRENT_LIST_DIR}/talkaction.h
${CMAKE_CURRENT_LIST_DIR}/tasks.h
Expand Down
5 changes: 5 additions & 0 deletions src/configmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,8 @@ bool ConfigManager::load()
boolean[TWO_FACTOR_AUTH] = getGlobalBoolean(L, "enableTwoFactorAuth", true);
boolean[CHECK_DUPLICATE_STORAGE_KEYS] = getGlobalBoolean(L, "checkDuplicateStorageKeys", false);
boolean[MONSTER_OVERSPAWN] = getGlobalBoolean(L, "monsterOverspawn", false);
boolean[STATS_TRACK_LUA_ADD_EVENTS] = getGlobalBoolean(L, "statsTrackLuaAddEvents", false);
boolean[STATS_TRACK_LUA_ADD_EVENTS_HASHES] = getGlobalBoolean(L, "statsTrackLuaAddEventsHashes", false);

string[DEFAULT_PRIORITY] = getGlobalString(L, "defaultPriority", "high");
string[SERVER_NAME] = getGlobalString(L, "serverName", "");
Expand Down Expand Up @@ -292,6 +294,9 @@ bool ConfigManager::load()
integer[QUEST_TRACKER_PREMIUM_LIMIT] = getGlobalNumber(L, "questTrackerPremiumLimit", 15);
integer[STAMINA_REGEN_MINUTE] = getGlobalNumber(L, "timeToRegenMinuteStamina", 3 * 60);
integer[STAMINA_REGEN_PREMIUM] = getGlobalNumber(L, "timeToRegenMinutePremiumStamina", 6 * 60);
integer[STATS_DUMP_INTERVAL] = getGlobalNumber(L, "statsDumpInterval", 30);
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
5 changes: 5 additions & 0 deletions src/configmanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ enum boolean_config_t
MANASHIELD_BREAKABLE,
CHECK_DUPLICATE_STORAGE_KEYS,
MONSTER_OVERSPAWN,
STATS_TRACK_LUA_ADD_EVENTS,
STATS_TRACK_LUA_ADD_EVENTS_HASHES,

LAST_BOOLEAN_CONFIG /* this must be the last one */
};
Expand Down Expand Up @@ -121,6 +123,9 @@ enum integer_config_t
QUEST_TRACKER_PREMIUM_LIMIT,
STAMINA_REGEN_MINUTE,
STAMINA_REGEN_PREMIUM,
STATS_DUMP_INTERVAL,
STATS_SLOW_LOG_TIME,
STATS_VERY_SLOW_LOG_TIME,

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

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

#include <mysql/errmsg.h>

Expand Down Expand Up @@ -49,6 +50,10 @@ static bool isLostConnectionError(const unsigned error)

static bool executeQuery(tfs::detail::Mysql_ptr& handle, std::string_view query, const bool retryIfLostConnection)
{
#ifdef STATS_ENABLED
std::chrono::high_resolution_clock::time_point time_point = std::chrono::high_resolution_clock::now();
#endif

while (mysql_real_query(handle.get(), query.data(), query.length()) != 0) {
std::cout << "[Error - mysql_real_query] Query: " << query.substr(0, 256) << std::endl
<< "Message: " << mysql_error(handle.get()) << std::endl;
Expand All @@ -58,6 +63,15 @@ static bool executeQuery(tfs::detail::Mysql_ptr& handle, std::string_view query,
}
handle = connectToDatabase(true);
}

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

return true;
}

Expand Down
11 changes: 11 additions & 0 deletions src/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "server.h"
#include "spectators.h"
#include "spells.h"
#include "stats.h"
#include "storeinbox.h"
#include "talkaction.h"
#include "weapons.h"
Expand Down Expand Up @@ -117,6 +118,9 @@ void Game::setGameState(GameState_t newState)
g_scheduler.stop();
g_databaseTasks.stop();
g_dispatcher.stop();
#ifdef STATS_ENABLED
g_stats.stop();
#endif
tfs::http::stop();
break;
}
Expand Down Expand Up @@ -3882,6 +3886,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 @@ -4800,6 +4808,9 @@ void Game::shutdown()
g_scheduler.shutdown();
g_databaseTasks.shutdown();
g_dispatcher.shutdown();
#ifdef STATS_ENABLED
g_stats.shutdown();
#endif
map.spawns.clear();

cleanup();
Expand Down
77 changes: 77 additions & 0 deletions src/luascript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "script.h"
#include "spectators.h"
#include "spells.h"
#include "stats.h"
#include "storeinbox.h"
#include "teleport.h"
#include "weapons.h"
Expand Down Expand Up @@ -489,12 +490,27 @@ bool LuaScriptInterface::reInitState()
/// Same as lua_pcall, but adds stack trace to error strings in called function.
int tfs::lua::protectedCall(lua_State* L, int nargs, int nresults)
{
#ifdef STATS_ENABLED
auto [scriptId, scriptInterface, callbackId, timerEvent] = getScriptEnv()->getEventInfo();
std::chrono::high_resolution_clock::time_point time_point = std::chrono::high_resolution_clock::now();
#endif

int error_index = lua_gettop(L) - nargs;
lua_pushcfunction(L, luaErrorHandler);
lua_insert(L, error_index);

int ret = lua_pcall(L, nargs, nresults, error_index);
lua_remove(L, error_index);

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

return ret;
}

Expand Down Expand Up @@ -633,6 +649,35 @@ const std::string& LuaScriptInterface::getFileById(int32_t scriptId)
return it->second;
}

#ifdef STATS_ENABLED
const std::string& LuaScriptInterface::getAddEventStackTracebackHash(const std::string& addEventStackBacktrace)
{
if (!getBoolean(ConfigManager::STATS_TRACK_LUA_ADD_EVENTS_HASHES)) {
static const std::string& hashesDisabledText = "LuaAddEvent";
return hashesDisabledText;
}

if (auto it{addEventStackTracebackHashCache.find(addEventStackBacktrace)};
it != std::end(addEventStackTracebackHashCache)) {
return it->second;
}

std::chrono::high_resolution_clock::time_point time_point = std::chrono::high_resolution_clock::now();
auto* hash = new std::string(
fmt::format("LuaAddEvent-{:d}", adlerChecksum(reinterpret_cast<const uint8_t*>(addEventStackBacktrace.c_str()),
addEventStackBacktrace.length())));
uint64_t ns =
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - time_point)
.count();

addEventStackTracebackHashCache[addEventStackBacktrace] = *hash;

std::cout << "Generated new addEvent hash (" << ns << "): " << *hash << "=" << addEventStackBacktrace << std::endl;

return *hash;
}
#endif

void tfs::lua::reportError(std::string_view function, std::string_view error_desc, lua_State* L /*= nullptr*/,
bool stack_trace /*= false*/)
{
Expand Down Expand Up @@ -696,6 +741,9 @@ bool LuaScriptInterface::closeState()
}

cacheFiles.clear();
#ifdef STATS_ENABLED
addEventStackTracebackHashCache.clear();
#endif
if (eventTableRef != -1) {
luaL_unref(L, LUA_REGISTRYINDEX, eventTableRef);
eventTableRef = -1;
Expand Down Expand Up @@ -2285,6 +2333,8 @@ void LuaScriptInterface::registerFunctions()
registerEnumIn(L, "configKeys", ConfigManager::SERVER_SAVE_SHUTDOWN);
registerEnumIn(L, "configKeys", ConfigManager::ONLINE_OFFLINE_CHARLIST);
registerEnumIn(L, "configKeys", ConfigManager::CHECK_DUPLICATE_STORAGE_KEYS);
registerEnumIn(L, "configKeys", ConfigManager::STATS_TRACK_LUA_ADD_EVENTS);
registerEnumIn(L, "configKeys", ConfigManager::STATS_TRACK_LUA_ADD_EVENTS_HASHES);

registerEnumIn(L, "configKeys", ConfigManager::MAP_NAME);
registerEnumIn(L, "configKeys", ConfigManager::HOUSE_RENT_PERIOD);
Expand Down Expand Up @@ -2342,6 +2392,9 @@ void LuaScriptInterface::registerFunctions()
registerEnumIn(L, "configKeys", ConfigManager::STAMINA_REGEN_PREMIUM);
registerEnumIn(L, "configKeys", ConfigManager::HOUSE_DOOR_SHOW_PRICE);
registerEnumIn(L, "configKeys", ConfigManager::MONSTER_OVERSPAWN);
registerEnumIn(L, "configKeys", ConfigManager::STATS_DUMP_INTERVAL);
registerEnumIn(L, "configKeys", ConfigManager::STATS_SLOW_LOG_TIME);
registerEnumIn(L, "configKeys", ConfigManager::STATS_VERY_SLOW_LOG_TIME);

registerEnumIn(L, "configKeys", ConfigManager::QUEST_TRACKER_FREE_LIMIT);
registerEnumIn(L, "configKeys", ConfigManager::QUEST_TRACKER_PREMIUM_LIMIT);
Expand Down Expand Up @@ -3983,6 +4036,14 @@ int LuaScriptInterface::luaAddEvent(lua_State* L)
eventDesc.function = luaL_ref(L, LUA_REGISTRYINDEX);
eventDesc.scriptId = tfs::lua::getScriptEnv()->getScriptId();

#ifdef STATS_ENABLED
if (getBoolean(ConfigManager::STATS_TRACK_LUA_ADD_EVENTS)) {
std::string trackLuaAddEventLog = getStackTrace(L, "");
replaceString(trackLuaAddEventLog, "\n", " ");
eventDesc.stackTraceback = trackLuaAddEventLog;
}
#endif

auto& lastTimerEventId = g_luaEnvironment.lastEventTimerId;
eventDesc.eventId = g_scheduler.addEvent(
createSchedulerTask(delay, [=]() { g_luaEnvironment.executeTimerEvent(lastTimerEventId); }));
Expand Down Expand Up @@ -18707,6 +18768,9 @@ bool LuaEnvironment::closeState()
areaIdMap.clear();
timerEvents.clear();
cacheFiles.clear();
#ifdef STATS_ENABLED
addEventStackTracebackHashCache.clear();
#endif

lua_close(L);
L = nullptr;
Expand Down Expand Up @@ -18808,10 +18872,23 @@ void LuaEnvironment::executeTimerEvent(uint32_t eventIndex)

// call the function
if (tfs::lua::reserveScriptEnv()) {
#ifdef STATS_ENABLED
std::chrono::high_resolution_clock::time_point time_point = std::chrono::high_resolution_clock::now();
#endif
ScriptEnvironment* env = tfs::lua::getScriptEnv();
env->setTimerEvent();
env->setScriptId(timerEventDesc.scriptId, this);
callFunction(timerEventDesc.parameters.size());

#ifdef STATS_ENABLED
uint64_t ns =
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - time_point)
.count();
if (getBoolean(ConfigManager::STATS_TRACK_LUA_ADD_EVENTS)) {
g_stats.addSpecialStats(new Stat(ns, getAddEventStackTracebackHash(timerEventDesc.stackTraceback),
timerEventDesc.stackTraceback));
}
#endif
} else {
std::cout << "[Error - LuaScriptInterface::executeTimerEvent] Call stack overflow\n";
}
Expand Down
9 changes: 9 additions & 0 deletions src/luascript.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ struct LuaTimerEventDesc
int32_t function = -1;
std::vector<int32_t> parameters;
uint32_t eventId = 0;
#ifdef STATS_ENABLED
std::string stackTraceback;
#endif

LuaTimerEventDesc() = default;
LuaTimerEventDesc(LuaTimerEventDesc&& other) = default;
Expand Down Expand Up @@ -133,6 +136,9 @@ class LuaScriptInterface
int32_t loadFile(const std::string& file, Npc* npc = nullptr);

const std::string& getFileById(int32_t scriptId);
#ifdef STATS_ENABLED
const std::string& getAddEventStackTracebackHash(const std::string& addEventStackBacktrace);
#endif
int32_t getEvent(std::string_view eventName);
int32_t getEvent();
int32_t getMetaEvent(const std::string& globalName, const std::string& eventName);
Expand Down Expand Up @@ -166,6 +172,9 @@ class LuaScriptInterface

// script file cache
std::map<int32_t, std::string> cacheFiles;
#ifdef STATS_ENABLED
std::map<std::string, std::string> addEventStackTracebackHashCache;
#endif

private:
// lua functions
Expand Down
Loading
Loading