mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-24 13:42:50 +00:00
feat(servers): time the main loops' phases and the known heavy spots
Frames and phase scopes in the world, auth, chat and UGC loops (packets per type, entities, physics, ghosting, replica, spawners, log flush, saves, web requests by route). Scopes at LoadPlayer, CreateEntity, each component's construction, InventoryComponent::LoadXml, script timers and a world's zone load; game database queries in the query helpers; CDClient statements timed through sqlite3_trace_v2 as CDClient <table> (CppSQLite3DB gets a handle accessor). Task 96. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,7 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
//DLU Includes:
|
//DLU Includes:
|
||||||
|
#include "Profiler.h"
|
||||||
#include "dCommonVars.h"
|
#include "dCommonVars.h"
|
||||||
#include "ConfigSync.h"
|
#include "ConfigSync.h"
|
||||||
#include "dServer.h"
|
#include "dServer.h"
|
||||||
@@ -117,6 +118,7 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
Game::logger->Flush(); // once immediately before main loop
|
Game::logger->Flush(); // once immediately before main loop
|
||||||
while (!Game::ShouldShutdown()) {
|
while (!Game::ShouldShutdown()) {
|
||||||
|
Profiler::BeginFrame();
|
||||||
//Check if we're still connected to master:
|
//Check if we're still connected to master:
|
||||||
if (!Game::server->GetIsConnectedToMaster()) {
|
if (!Game::server->GetIsConnectedToMaster()) {
|
||||||
framesSinceMasterDisconnect++;
|
framesSinceMasterDisconnect++;
|
||||||
@@ -130,9 +132,13 @@ int main(int argc, char** argv) {
|
|||||||
//In world we'd update our other systems here.
|
//In world we'd update our other systems here.
|
||||||
|
|
||||||
//Check for packets here:
|
//Check for packets here:
|
||||||
Game::server->ReceiveFromMaster(); //ReceiveFromMaster also handles the master packets if needed.
|
{
|
||||||
|
Profiler::Scope scope("Master packets", Profiler::Phase::PACKETS);
|
||||||
|
Game::server->ReceiveFromMaster(); //ReceiveFromMaster also handles the master packets if needed.
|
||||||
|
}
|
||||||
packet = Game::server->Receive();
|
packet = Game::server->Receive();
|
||||||
if (packet) {
|
if (packet) {
|
||||||
|
Profiler::PacketScope scope(packet->data, packet->length);
|
||||||
HandlePacket(packet);
|
HandlePacket(packet);
|
||||||
Game::server->DeallocatePacket(packet);
|
Game::server->DeallocatePacket(packet);
|
||||||
packet = nullptr;
|
packet = nullptr;
|
||||||
@@ -140,6 +146,7 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
//Push our log every 30s:
|
//Push our log every 30s:
|
||||||
if (framesSinceLastFlush >= logFlushTime) {
|
if (framesSinceLastFlush >= logFlushTime) {
|
||||||
|
Profiler::Scope scope("Log flush", Profiler::Phase::LOG_FLUSH);
|
||||||
Game::logger->Flush();
|
Game::logger->Flush();
|
||||||
framesSinceLastFlush = 0;
|
framesSinceLastFlush = 0;
|
||||||
} else framesSinceLastFlush++;
|
} else framesSinceLastFlush++;
|
||||||
@@ -158,6 +165,7 @@ int main(int argc, char** argv) {
|
|||||||
framesSinceLastSQLPing = 0;
|
framesSinceLastSQLPing = 0;
|
||||||
} else framesSinceLastSQLPing++;
|
} else framesSinceLastSQLPing++;
|
||||||
|
|
||||||
|
Profiler::EndFrame();
|
||||||
//Sleep our thread since auth can afford to.
|
//Sleep our thread since auth can afford to.
|
||||||
t += std::chrono::milliseconds(authFrameDelta); //Auth can run at a lower "fps"
|
t += std::chrono::milliseconds(authFrameDelta); //Auth can run at a lower "fps"
|
||||||
std::this_thread::sleep_until(t);
|
std::this_thread::sleep_until(t);
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
//DLU Includes:
|
//DLU Includes:
|
||||||
|
#include "Profiler.h"
|
||||||
|
#include <optional>
|
||||||
#include "dCommonVars.h"
|
#include "dCommonVars.h"
|
||||||
#include "ConfigSync.h"
|
#include "ConfigSync.h"
|
||||||
#include "dServer.h"
|
#include "dServer.h"
|
||||||
@@ -149,6 +151,7 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
Game::logger->Flush(); // once immediately before main loop
|
Game::logger->Flush(); // once immediately before main loop
|
||||||
while (!Game::ShouldShutdown()) {
|
while (!Game::ShouldShutdown()) {
|
||||||
|
Profiler::BeginFrame();
|
||||||
//Check if we're still connected to master:
|
//Check if we're still connected to master:
|
||||||
if (!Game::server->GetIsConnectedToMaster()) {
|
if (!Game::server->GetIsConnectedToMaster()) {
|
||||||
framesSinceMasterDisconnect++;
|
framesSinceMasterDisconnect++;
|
||||||
@@ -161,16 +164,26 @@ int main(int argc, char** argv) {
|
|||||||
const float deltaTime = std::chrono::duration<float>(currentTime - lastTime).count();
|
const float deltaTime = std::chrono::duration<float>(currentTime - lastTime).count();
|
||||||
lastTime = currentTime;
|
lastTime = currentTime;
|
||||||
|
|
||||||
Game::playerContainer.Update(deltaTime);
|
{
|
||||||
|
Profiler::Scope scope("Player container update", Profiler::Phase::ENTITIES);
|
||||||
|
Game::playerContainer.Update(deltaTime);
|
||||||
|
}
|
||||||
|
|
||||||
//Check for packets here:
|
//Check for packets here:
|
||||||
//ReceiveFromMaster also handles the master packets if needed; it hands back the ones for us.
|
//ReceiveFromMaster also handles the master packets if needed; it hands back the ones for us.
|
||||||
|
std::optional<Profiler::Scope> masterScope;
|
||||||
|
masterScope.emplace("Master packets", Profiler::Phase::PACKETS);
|
||||||
if (auto* masterPacket = Game::server->ReceiveFromMaster()) {
|
if (auto* masterPacket = Game::server->ReceiveFromMaster()) {
|
||||||
HandleMasterPacket(masterPacket);
|
{
|
||||||
|
Profiler::PacketScope scope(masterPacket->data, masterPacket->length);
|
||||||
|
HandleMasterPacket(masterPacket);
|
||||||
|
}
|
||||||
Game::server->DeallocateMasterPacket(masterPacket);
|
Game::server->DeallocateMasterPacket(masterPacket);
|
||||||
}
|
}
|
||||||
|
masterScope.reset();
|
||||||
packet = Game::server->Receive();
|
packet = Game::server->Receive();
|
||||||
if (packet) {
|
if (packet) {
|
||||||
|
Profiler::PacketScope scope(packet->data, packet->length);
|
||||||
HandlePacket(packet);
|
HandlePacket(packet);
|
||||||
Game::server->DeallocatePacket(packet);
|
Game::server->DeallocatePacket(packet);
|
||||||
packet = nullptr;
|
packet = nullptr;
|
||||||
@@ -179,6 +192,7 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
//Push our log every 30s:
|
//Push our log every 30s:
|
||||||
if (framesSinceLastFlush >= logFlushTime) {
|
if (framesSinceLastFlush >= logFlushTime) {
|
||||||
|
Profiler::Scope scope("Log flush", Profiler::Phase::LOG_FLUSH);
|
||||||
Game::logger->Flush();
|
Game::logger->Flush();
|
||||||
framesSinceLastFlush = 0;
|
framesSinceLastFlush = 0;
|
||||||
} else framesSinceLastFlush++;
|
} else framesSinceLastFlush++;
|
||||||
@@ -198,6 +212,7 @@ int main(int argc, char** argv) {
|
|||||||
framesSinceLastSQLPing = 0;
|
framesSinceLastSQLPing = 0;
|
||||||
} else framesSinceLastSQLPing++;
|
} else framesSinceLastSQLPing++;
|
||||||
|
|
||||||
|
Profiler::EndFrame();
|
||||||
//Sleep our thread since auth can afford to.
|
//Sleep our thread since auth can afford to.
|
||||||
t += std::chrono::milliseconds(chatFrameDelta); //Chat can run at a lower "fps"
|
t += std::chrono::milliseconds(chatFrameDelta); //Chat can run at a lower "fps"
|
||||||
std::this_thread::sleep_until(t);
|
std::this_thread::sleep_until(t);
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
#include "CDClientDatabase.h"
|
#include "CDClientDatabase.h"
|
||||||
#include "CDComponentsRegistryTable.h"
|
#include "CDComponentsRegistryTable.h"
|
||||||
|
#include "Profiler.h"
|
||||||
|
|
||||||
|
#include <cctype>
|
||||||
|
#include <string_view>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
// Static Variables
|
// Static Variables
|
||||||
static CppSQLite3DB* conn = new CppSQLite3DB();
|
static CppSQLite3DB* conn = new CppSQLite3DB();
|
||||||
@@ -7,10 +13,58 @@ static CppSQLite3DB* conn = new CppSQLite3DB();
|
|||||||
// Status Variables
|
// Status Variables
|
||||||
bool CDClientDatabase::isConnected = false;
|
bool CDClientDatabase::isConnected = false;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// Frame timing (Profiler.h): each CDClient statement the main thread runs, timed from its first step to its end,
|
||||||
|
// counted under the scope that ran it as "CDClient <table>" (the first table after FROM)
|
||||||
|
std::vector<std::pair<sqlite3_stmt*, int64_t>> g_Running;
|
||||||
|
|
||||||
|
const char* TableScope(const char* sql) {
|
||||||
|
if (!sql) return "CDClient";
|
||||||
|
const std::string_view text(sql);
|
||||||
|
for (size_t i = 0; i + 5 < text.size(); i++) {
|
||||||
|
const bool from = (text[i] == 'F' || text[i] == 'f') && (text[i + 1] == 'R' || text[i + 1] == 'r') && (text[i + 2] == 'O' || text[i + 2] == 'o') &&
|
||||||
|
(text[i + 3] == 'M' || text[i + 3] == 'm') && std::isspace(static_cast<unsigned char>(text[i + 4])) && (i == 0 || std::isspace(static_cast<unsigned char>(text[i - 1])));
|
||||||
|
if (!from) continue;
|
||||||
|
size_t start = i + 5;
|
||||||
|
while (start < text.size() && std::isspace(static_cast<unsigned char>(text[start]))) start++;
|
||||||
|
size_t end = start;
|
||||||
|
while (end < text.size() && (std::isalnum(static_cast<unsigned char>(text[end])) || text[end] == '_')) end++;
|
||||||
|
if (end > start) return Profiler::Intern("CDClient " + std::string(text.substr(start, end - start)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return "CDClient";
|
||||||
|
}
|
||||||
|
|
||||||
|
int Trace(unsigned type, void*, void* p, void* x) {
|
||||||
|
if (!Profiler::IsMainThread()) return 0;
|
||||||
|
auto* statement = static_cast<sqlite3_stmt*>(p);
|
||||||
|
const auto now = Profiler::NowNs();
|
||||||
|
if (type == SQLITE_TRACE_STMT) {
|
||||||
|
for (auto& [running, start] : g_Running) {
|
||||||
|
if (running == statement) { start = now; return 0; }
|
||||||
|
}
|
||||||
|
if (g_Running.size() < 64) g_Running.emplace_back(statement, now);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (type != SQLITE_TRACE_PROFILE) return 0;
|
||||||
|
// SQLite's own time as a fallback (coarse on some platforms)
|
||||||
|
int64_t duration = x ? static_cast<int64_t>(*static_cast<sqlite3_int64*>(x)) : 0;
|
||||||
|
for (size_t i = 0; i < g_Running.size(); i++) {
|
||||||
|
if (g_Running[i].first != statement) continue;
|
||||||
|
duration = now - g_Running[i].second;
|
||||||
|
g_Running.erase(g_Running.begin() + static_cast<std::ptrdiff_t>(i));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Profiler::Local().Record(TableScope(sqlite3_sql(statement)), 0, duration, Profiler::Phase::CDCLIENT, now);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//! Opens a connection with the CDClient
|
//! Opens a connection with the CDClient
|
||||||
void CDClientDatabase::Connect(const std::string& filename) {
|
void CDClientDatabase::Connect(const std::string& filename) {
|
||||||
conn->open(filename.c_str());
|
conn->open(filename.c_str());
|
||||||
isConnected = true;
|
isConnected = true;
|
||||||
|
sqlite3_trace_v2(conn->handle(), SQLITE_TRACE_STMT | SQLITE_TRACE_PROFILE, Trace, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Queries the CDClient
|
//! Queries the CDClient
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#ifndef __MYSQLDATABASE__H__
|
#ifndef __MYSQLDATABASE__H__
|
||||||
#define __MYSQLDATABASE__H__
|
#define __MYSQLDATABASE__H__
|
||||||
|
|
||||||
|
#include "Profiler.h"
|
||||||
#include <conncpp.hpp>
|
#include <conncpp.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@@ -518,6 +519,7 @@ private:
|
|||||||
// The return type is a PreparedStmtResultSet which keeps the PreparedStatement alive alongside the ResultSet.
|
// The return type is a PreparedStmtResultSet which keeps the PreparedStatement alive alongside the ResultSet.
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
inline PreparedStmtResultSet ExecuteSelect(const std::string& query, Args&&... args) {
|
inline PreparedStmtResultSet ExecuteSelect(const std::string& query, Args&&... args) {
|
||||||
|
Profiler::Scope profile("Database query", Profiler::Phase::DATABASE);
|
||||||
PreparedStmtResultSet toReturn;
|
PreparedStmtResultSet toReturn;
|
||||||
toReturn.m_stmt.reset(CreatePreppedStmt(query));
|
toReturn.m_stmt.reset(CreatePreppedStmt(query));
|
||||||
SetParams(toReturn.m_stmt, std::forward<Args>(args)...);
|
SetParams(toReturn.m_stmt, std::forward<Args>(args)...);
|
||||||
@@ -528,6 +530,7 @@ private:
|
|||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
inline void ExecuteDelete(const std::string& query, Args&&... args) {
|
inline void ExecuteDelete(const std::string& query, Args&&... args) {
|
||||||
|
Profiler::Scope profile("Database query", Profiler::Phase::DATABASE);
|
||||||
std::unique_ptr<sql::PreparedStatement> preppedStmt(CreatePreppedStmt(query));
|
std::unique_ptr<sql::PreparedStatement> preppedStmt(CreatePreppedStmt(query));
|
||||||
SetParams(preppedStmt, std::forward<Args>(args)...);
|
SetParams(preppedStmt, std::forward<Args>(args)...);
|
||||||
DLU_SQL_TRY_CATCH_RETHROW(preppedStmt->execute());
|
DLU_SQL_TRY_CATCH_RETHROW(preppedStmt->execute());
|
||||||
@@ -535,6 +538,7 @@ private:
|
|||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
inline int32_t ExecuteUpdate(const std::string& query, Args&&... args) {
|
inline int32_t ExecuteUpdate(const std::string& query, Args&&... args) {
|
||||||
|
Profiler::Scope profile("Database query", Profiler::Phase::DATABASE);
|
||||||
std::unique_ptr<sql::PreparedStatement> preppedStmt(CreatePreppedStmt(query));
|
std::unique_ptr<sql::PreparedStatement> preppedStmt(CreatePreppedStmt(query));
|
||||||
SetParams(preppedStmt, std::forward<Args>(args)...);
|
SetParams(preppedStmt, std::forward<Args>(args)...);
|
||||||
DLU_SQL_TRY_CATCH_RETHROW(return preppedStmt->executeUpdate());
|
DLU_SQL_TRY_CATCH_RETHROW(return preppedStmt->executeUpdate());
|
||||||
@@ -542,6 +546,7 @@ private:
|
|||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
inline bool ExecuteInsert(const std::string& query, Args&&... args) {
|
inline bool ExecuteInsert(const std::string& query, Args&&... args) {
|
||||||
|
Profiler::Scope profile("Database query", Profiler::Phase::DATABASE);
|
||||||
std::unique_ptr<sql::PreparedStatement> preppedStmt(CreatePreppedStmt(query));
|
std::unique_ptr<sql::PreparedStatement> preppedStmt(CreatePreppedStmt(query));
|
||||||
SetParams(preppedStmt, std::forward<Args>(args)...);
|
SetParams(preppedStmt, std::forward<Args>(args)...);
|
||||||
DLU_SQL_TRY_CATCH_RETHROW(return preppedStmt->execute());
|
DLU_SQL_TRY_CATCH_RETHROW(return preppedStmt->execute());
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#ifndef SQLITEDATABASE_H
|
#ifndef SQLITEDATABASE_H
|
||||||
#define SQLITEDATABASE_H
|
#define SQLITEDATABASE_H
|
||||||
|
|
||||||
|
#include "Profiler.h"
|
||||||
#include "CppSQLite3.h"
|
#include "CppSQLite3.h"
|
||||||
|
|
||||||
#include "GameDatabase.h"
|
#include "GameDatabase.h"
|
||||||
@@ -502,6 +503,7 @@ private:
|
|||||||
// The return type is a unique_ptr to the result set, which is deleted automatically when it goes out of scope
|
// The return type is a unique_ptr to the result set, which is deleted automatically when it goes out of scope
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
inline std::pair<CppSQLite3Statement, CppSQLite3Query> ExecuteSelect(const std::string& query, Args&&... args) {
|
inline std::pair<CppSQLite3Statement, CppSQLite3Query> ExecuteSelect(const std::string& query, Args&&... args) {
|
||||||
|
Profiler::Scope profile("Database query", Profiler::Phase::DATABASE);
|
||||||
std::pair<CppSQLite3Statement, CppSQLite3Query> toReturn;
|
std::pair<CppSQLite3Statement, CppSQLite3Query> toReturn;
|
||||||
toReturn.first = CreatePreppedStmt(query);
|
toReturn.first = CreatePreppedStmt(query);
|
||||||
SetParams(toReturn.first, std::forward<Args>(args)...);
|
SetParams(toReturn.first, std::forward<Args>(args)...);
|
||||||
@@ -511,6 +513,7 @@ private:
|
|||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
inline void ExecuteDelete(const std::string& query, Args&&... args) {
|
inline void ExecuteDelete(const std::string& query, Args&&... args) {
|
||||||
|
Profiler::Scope profile("Database query", Profiler::Phase::DATABASE);
|
||||||
auto preppedStmt = CreatePreppedStmt(query);
|
auto preppedStmt = CreatePreppedStmt(query);
|
||||||
SetParams(preppedStmt, std::forward<Args>(args)...);
|
SetParams(preppedStmt, std::forward<Args>(args)...);
|
||||||
DLU_SQL_TRY_CATCH_RETHROW(preppedStmt.execDML());
|
DLU_SQL_TRY_CATCH_RETHROW(preppedStmt.execDML());
|
||||||
@@ -518,6 +521,7 @@ private:
|
|||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
inline int32_t ExecuteUpdate(const std::string& query, Args&&... args) {
|
inline int32_t ExecuteUpdate(const std::string& query, Args&&... args) {
|
||||||
|
Profiler::Scope profile("Database query", Profiler::Phase::DATABASE);
|
||||||
auto preppedStmt = CreatePreppedStmt(query);
|
auto preppedStmt = CreatePreppedStmt(query);
|
||||||
SetParams(preppedStmt, std::forward<Args>(args)...);
|
SetParams(preppedStmt, std::forward<Args>(args)...);
|
||||||
DLU_SQL_TRY_CATCH_RETHROW(return preppedStmt.execDML());
|
DLU_SQL_TRY_CATCH_RETHROW(return preppedStmt.execDML());
|
||||||
@@ -525,6 +529,7 @@ private:
|
|||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
inline int ExecuteInsert(const std::string& query, Args&&... args) {
|
inline int ExecuteInsert(const std::string& query, Args&&... args) {
|
||||||
|
Profiler::Scope profile("Database query", Profiler::Phase::DATABASE);
|
||||||
auto preppedStmt = CreatePreppedStmt(query);
|
auto preppedStmt = CreatePreppedStmt(query);
|
||||||
SetParams(preppedStmt, std::forward<Args>(args)...);
|
SetParams(preppedStmt, std::forward<Args>(args)...);
|
||||||
DLU_SQL_TRY_CATCH_RETHROW(return preppedStmt.execDML());
|
DLU_SQL_TRY_CATCH_RETHROW(return preppedStmt.execDML());
|
||||||
|
|||||||
@@ -1152,6 +1152,7 @@ void Entity::Update(const float deltaTime) {
|
|||||||
// Remove the timer from the list of timers first so that scripts and events can remove timers without causing iterator invalidation
|
// Remove the timer from the list of timers first so that scripts and events can remove timers without causing iterator invalidation
|
||||||
auto timerName = timer.GetName();
|
auto timerName = timer.GetName();
|
||||||
m_Timers.erase(m_Timers.begin() + timerPosition);
|
m_Timers.erase(m_Timers.begin() + timerPosition);
|
||||||
|
Profiler::Scope profile("Script timer", Profiler::Phase::SCRIPTS);
|
||||||
GetScript()->OnTimerDone(this, timerName);
|
GetScript()->OnTimerDone(this, timerName);
|
||||||
VanityUtilities::OnTimerDone(this, timerName);
|
VanityUtilities::OnTimerDone(this, timerName);
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
#include "LDFFormat.h"
|
#include "LDFFormat.h"
|
||||||
#include "eKillType.h"
|
#include "eKillType.h"
|
||||||
#include "Observable.h"
|
#include "Observable.h"
|
||||||
|
#include "Profiler.h"
|
||||||
|
|
||||||
namespace GameMessages {
|
namespace GameMessages {
|
||||||
struct GameMsg;
|
struct GameMsg;
|
||||||
@@ -589,6 +590,8 @@ T Entity::GetNetworkVar(const std::u16string& name) {
|
|||||||
template<typename ComponentType, typename... VaArgs>
|
template<typename ComponentType, typename... VaArgs>
|
||||||
inline ComponentType* Entity::AddComponent(VaArgs... args) {
|
inline ComponentType* Entity::AddComponent(VaArgs... args) {
|
||||||
static_assert(std::is_base_of_v<Component, ComponentType>, "ComponentType must be a Component");
|
static_assert(std::is_base_of_v<Component, ComponentType>, "ComponentType must be a Component");
|
||||||
|
// Frame timing: each component type's construction (loading a character's XML is in some of them)
|
||||||
|
Profiler::Scope profile(Profiler::COMPONENT, static_cast<uint64_t>(ComponentType::ComponentType));
|
||||||
|
|
||||||
// Get the component if it already exists, or default construct a nullptr
|
// Get the component if it already exists, or default construct a nullptr
|
||||||
auto*& componentToReturn = m_Components[ComponentType::ComponentType];
|
auto*& componentToReturn = m_Components[ComponentType::ComponentType];
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "EntityManager.h"
|
#include "EntityManager.h"
|
||||||
|
#include "Profiler.h"
|
||||||
#include "RakNetTypes.h"
|
#include "RakNetTypes.h"
|
||||||
#include "Game.h"
|
#include "Game.h"
|
||||||
#include "User.h"
|
#include "User.h"
|
||||||
@@ -117,6 +118,7 @@ void EntityManager::Initialize() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Entity* EntityManager::CreateEntity(EntityInfo info, User* user, Entity* parentEntity, const bool controller, const LWOOBJID explicitId) {
|
Entity* EntityManager::CreateEntity(EntityInfo info, User* user, Entity* parentEntity, const bool controller, const LWOOBJID explicitId) {
|
||||||
|
Profiler::Scope profile("CreateEntity");
|
||||||
|
|
||||||
// Determine the objectID for the new entity
|
// Determine the objectID for the new entity
|
||||||
LWOOBJID id;
|
LWOOBJID id;
|
||||||
@@ -286,11 +288,18 @@ void EntityManager::DeleteEntities() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void EntityManager::UpdateEntities(const float deltaTime) {
|
void EntityManager::UpdateEntities(const float deltaTime) {
|
||||||
for (auto* entity : m_Entities | std::views::values) {
|
{
|
||||||
entity->Update(deltaTime);
|
Profiler::Scope profile("Entity updates");
|
||||||
|
for (auto* entity : m_Entities | std::views::values) {
|
||||||
|
entity->Update(deltaTime);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SerializeEntities();
|
{
|
||||||
|
Profiler::Scope profile("Serialize entities", Profiler::Phase::REPLICA);
|
||||||
|
SerializeEntities();
|
||||||
|
}
|
||||||
|
Profiler::Scope profile("Kill and delete entities");
|
||||||
KillEntities();
|
KillEntities();
|
||||||
DeleteEntities();
|
DeleteEntities();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "InventoryComponent.h"
|
#include "InventoryComponent.h"
|
||||||
|
#include "Profiler.h"
|
||||||
#include "BrickByBrick.h"
|
#include "BrickByBrick.h"
|
||||||
#include "Contraband.h"
|
#include "Contraband.h"
|
||||||
#include "EconomyLedger.h"
|
#include "EconomyLedger.h"
|
||||||
@@ -668,6 +669,7 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void InventoryComponent::LoadXml(const tinyxml2::XMLDocument& document) {
|
void InventoryComponent::LoadXml(const tinyxml2::XMLDocument& document) {
|
||||||
|
Profiler::Scope profile("InventoryComponent::LoadXml");
|
||||||
LoadPetXml(document);
|
LoadPetXml(document);
|
||||||
|
|
||||||
auto* inventoryElement = document.FirstChildElement("obj")->FirstChildElement("inv");
|
auto* inventoryElement = document.FirstChildElement("obj")->FirstChildElement("inv");
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include <set>
|
#include <set>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
|
#include "Profiler.h"
|
||||||
#include "AssetManager.h"
|
#include "AssetManager.h"
|
||||||
#include "BinaryPathFinder.h"
|
#include "BinaryPathFinder.h"
|
||||||
#include "CDClientDatabase.h"
|
#include "CDClientDatabase.h"
|
||||||
@@ -802,6 +803,7 @@ int main(int argc, char** argv) {
|
|||||||
const auto now = std::chrono::steady_clock::now();
|
const auto now = std::chrono::steady_clock::now();
|
||||||
if (now - lastTick < std::chrono::milliseconds(16)) continue;
|
if (now - lastTick < std::chrono::milliseconds(16)) continue;
|
||||||
lastTick = now;
|
lastTick = now;
|
||||||
|
Profiler::FrameScope frame;
|
||||||
|
|
||||||
Packet* packet = g_Server->ReceiveFromMaster();
|
Packet* packet = g_Server->ReceiveFromMaster();
|
||||||
while (packet) {
|
while (packet) {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include "Profiler.h"
|
||||||
#include "Web.h"
|
#include "Web.h"
|
||||||
#include "Game.h"
|
#include "Game.h"
|
||||||
#include "magic_enum.hpp"
|
#include "magic_enum.hpp"
|
||||||
@@ -499,6 +500,8 @@ void HandleHTTPMessage(mg_connection* connection, const mg_http_message* http_ms
|
|||||||
// Call handler only if all middleware passed. A failing handler (e.g. a database error) answers 500
|
// Call handler only if all middleware passed. A failing handler (e.g. a database error) answers 500
|
||||||
// instead of taking the whole server down.
|
// instead of taking the whole server down.
|
||||||
if (chainPassed) {
|
if (chainPassed) {
|
||||||
|
// Frame timing: a handler runs on the main thread, between ticks or inside one
|
||||||
|
Profiler::Scope profile(Profiler::Intern(trafficRoute), Profiler::Phase::WEB);
|
||||||
try {
|
try {
|
||||||
route.handle(reply, context);
|
route.handle(reply, context);
|
||||||
} catch (const std::exception& ex) {
|
} catch (const std::exception& ex) {
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
#include "DashboardActions.h"
|
#include "DashboardActions.h"
|
||||||
|
#include "Profiler.h"
|
||||||
|
#include <optional>
|
||||||
#include "ConfigSync.h"
|
#include "ConfigSync.h"
|
||||||
#include "EconomyLedger.h"
|
#include "EconomyLedger.h"
|
||||||
#include "DashboardNotify.h"
|
#include "DashboardNotify.h"
|
||||||
@@ -383,7 +385,11 @@ int main(int argc, char** argv) {
|
|||||||
Game::zoneManager = new dZoneManager();
|
Game::zoneManager = new dZoneManager();
|
||||||
//Load our level:
|
//Load our level:
|
||||||
if (zoneID != 0) {
|
if (zoneID != 0) {
|
||||||
dpWorld::Initialize(zoneID);
|
Profiler::Scope zoneLoad("Zone load");
|
||||||
|
{
|
||||||
|
Profiler::Scope navmesh("Navmesh and physics load", Profiler::Phase::PHYSICS);
|
||||||
|
dpWorld::Initialize(zoneID);
|
||||||
|
}
|
||||||
Game::zoneManager->Initialize(LWOZONEID(zoneID, g_InstanceID, cloneID));
|
Game::zoneManager->Initialize(LWOZONEID(zoneID, g_InstanceID, cloneID));
|
||||||
g_CloneID = cloneID;
|
g_CloneID = cloneID;
|
||||||
} else {
|
} else {
|
||||||
@@ -438,6 +444,7 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
Game::logger->Flush(); // once immediately before the main loop
|
Game::logger->Flush(); // once immediately before the main loop
|
||||||
while (true) {
|
while (true) {
|
||||||
|
Profiler::BeginFrame();
|
||||||
Metrics::StartMeasurement(MetricVariable::Frame);
|
Metrics::StartMeasurement(MetricVariable::Frame);
|
||||||
Metrics::StartMeasurement(MetricVariable::GameLoop);
|
Metrics::StartMeasurement(MetricVariable::GameLoop);
|
||||||
|
|
||||||
@@ -508,15 +515,22 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
if (zoneID != 0 && deltaTime > 0.0f) {
|
if (zoneID != 0 && deltaTime > 0.0f) {
|
||||||
Metrics::StartMeasurement(MetricVariable::UpdateEntities);
|
Metrics::StartMeasurement(MetricVariable::UpdateEntities);
|
||||||
Game::entityManager->UpdateEntities(deltaTime);
|
{
|
||||||
|
Profiler::Scope scope("Entities", Profiler::Phase::ENTITIES);
|
||||||
|
Game::entityManager->UpdateEntities(deltaTime);
|
||||||
|
}
|
||||||
Metrics::EndMeasurement(MetricVariable::UpdateEntities);
|
Metrics::EndMeasurement(MetricVariable::UpdateEntities);
|
||||||
|
|
||||||
Metrics::StartMeasurement(MetricVariable::Physics);
|
Metrics::StartMeasurement(MetricVariable::Physics);
|
||||||
dpWorld::StepWorld(deltaTime);
|
{
|
||||||
|
Profiler::Scope scope("Physics step", Profiler::Phase::PHYSICS);
|
||||||
|
dpWorld::StepWorld(deltaTime);
|
||||||
|
}
|
||||||
Metrics::EndMeasurement(MetricVariable::Physics);
|
Metrics::EndMeasurement(MetricVariable::Physics);
|
||||||
|
|
||||||
Metrics::StartMeasurement(MetricVariable::Ghosting);
|
Metrics::StartMeasurement(MetricVariable::Ghosting);
|
||||||
if (std::chrono::duration<float>(currentTime - ghostingLastTime).count() >= 1.0f) {
|
if (std::chrono::duration<float>(currentTime - ghostingLastTime).count() >= 1.0f) {
|
||||||
|
Profiler::Scope scope("Ghosting", Profiler::Phase::REPLICA);
|
||||||
Game::entityManager->UpdateGhosting();
|
Game::entityManager->UpdateGhosting();
|
||||||
ghostingLastTime = currentTime;
|
ghostingLastTime = currentTime;
|
||||||
}
|
}
|
||||||
@@ -534,7 +548,10 @@ int main(int argc, char** argv) {
|
|||||||
UgcManifest::Update();
|
UgcManifest::Update();
|
||||||
|
|
||||||
Metrics::StartMeasurement(MetricVariable::UpdateSpawners);
|
Metrics::StartMeasurement(MetricVariable::UpdateSpawners);
|
||||||
Game::zoneManager->Update(deltaTime);
|
{
|
||||||
|
Profiler::Scope scope("Spawners", Profiler::Phase::ENTITIES);
|
||||||
|
Game::zoneManager->Update(deltaTime);
|
||||||
|
}
|
||||||
Metrics::EndMeasurement(MetricVariable::UpdateSpawners);
|
Metrics::EndMeasurement(MetricVariable::UpdateSpawners);
|
||||||
|
|
||||||
WorldMigration::Update(deltaTime);
|
WorldMigration::Update(deltaTime);
|
||||||
@@ -545,21 +562,33 @@ int main(int argc, char** argv) {
|
|||||||
Metrics::StartMeasurement(MetricVariable::PacketHandling);
|
Metrics::StartMeasurement(MetricVariable::PacketHandling);
|
||||||
|
|
||||||
//Check for packets here:
|
//Check for packets here:
|
||||||
|
std::optional<Profiler::Scope> packetScope;
|
||||||
|
packetScope.emplace("Master packets", Profiler::Phase::PACKETS);
|
||||||
packet = Game::server->ReceiveFromMaster();
|
packet = Game::server->ReceiveFromMaster();
|
||||||
while (packet) { //We can get messages not handle-able by the dServer class, so handle them if we returned anything.
|
while (packet) { //We can get messages not handle-able by the dServer class, so handle them if we returned anything.
|
||||||
HandleMasterPacket(packet);
|
{
|
||||||
|
Profiler::PacketScope scope(packet->data, packet->length);
|
||||||
|
HandleMasterPacket(packet);
|
||||||
|
}
|
||||||
Game::server->DeallocateMasterPacket(packet);
|
Game::server->DeallocateMasterPacket(packet);
|
||||||
packet = Game::server->ReceiveFromMaster();
|
packet = Game::server->ReceiveFromMaster();
|
||||||
}
|
}
|
||||||
|
|
||||||
//Handle our chat packets:
|
//Handle our chat packets:
|
||||||
|
packetScope.reset();
|
||||||
|
packetScope.emplace("Chat packets", Profiler::Phase::PACKETS);
|
||||||
packet = Game::chatServer->Receive();
|
packet = Game::chatServer->Receive();
|
||||||
while (packet) {
|
while (packet) {
|
||||||
ChatServerLink::CountReceived(packet->data, packet->length);
|
ChatServerLink::CountReceived(packet->data, packet->length);
|
||||||
HandlePacketChat(packet);
|
{
|
||||||
|
Profiler::PacketScope scope(packet->data, packet->length);
|
||||||
|
HandlePacketChat(packet);
|
||||||
|
}
|
||||||
Game::chatServer->DeallocatePacket(packet);
|
Game::chatServer->DeallocatePacket(packet);
|
||||||
packet = Game::chatServer->Receive();
|
packet = Game::chatServer->Receive();
|
||||||
}
|
}
|
||||||
|
packetScope.reset();
|
||||||
|
packetScope.emplace("Client packets", Profiler::Phase::PACKETS);
|
||||||
|
|
||||||
//Handle world-specific packets:
|
//Handle world-specific packets:
|
||||||
float timeSpent = 0.0f;
|
float timeSpent = 0.0f;
|
||||||
@@ -570,7 +599,10 @@ int main(int argc, char** argv) {
|
|||||||
packet = Game::server->Receive();
|
packet = Game::server->Receive();
|
||||||
if (packet) {
|
if (packet) {
|
||||||
auto t1 = std::chrono::high_resolution_clock::now();
|
auto t1 = std::chrono::high_resolution_clock::now();
|
||||||
HandlePacket(packet);
|
{
|
||||||
|
Profiler::PacketScope scope(packet->data, packet->length);
|
||||||
|
HandlePacket(packet);
|
||||||
|
}
|
||||||
auto t2 = std::chrono::high_resolution_clock::now();
|
auto t2 = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
timeSpent += std::chrono::duration_cast<std::chrono::duration<float>>(t2 - t1).count();
|
timeSpent += std::chrono::duration_cast<std::chrono::duration<float>>(t2 - t1).count();
|
||||||
@@ -581,17 +613,22 @@ int main(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
packetScope.reset();
|
||||||
Metrics::EndMeasurement(MetricVariable::PacketHandling);
|
Metrics::EndMeasurement(MetricVariable::PacketHandling);
|
||||||
|
|
||||||
Metrics::StartMeasurement(MetricVariable::UpdateReplica);
|
Metrics::StartMeasurement(MetricVariable::UpdateReplica);
|
||||||
|
|
||||||
//Update our replica objects:
|
//Update our replica objects:
|
||||||
Game::server->UpdateReplica();
|
{
|
||||||
|
Profiler::Scope scope("Replica update", Profiler::Phase::REPLICA);
|
||||||
|
Game::server->UpdateReplica();
|
||||||
|
}
|
||||||
|
|
||||||
Metrics::EndMeasurement(MetricVariable::UpdateReplica);
|
Metrics::EndMeasurement(MetricVariable::UpdateReplica);
|
||||||
|
|
||||||
//Push our log every 15s:
|
//Push our log every 15s:
|
||||||
if (framesSinceLastFlush >= logFlushTime) {
|
if (framesSinceLastFlush >= logFlushTime) {
|
||||||
|
Profiler::Scope scope("Log flush", Profiler::Phase::LOG_FLUSH);
|
||||||
Game::logger->Flush();
|
Game::logger->Flush();
|
||||||
framesSinceLastFlush = 0;
|
framesSinceLastFlush = 0;
|
||||||
} else framesSinceLastFlush++;
|
} else framesSinceLastFlush++;
|
||||||
@@ -612,6 +649,7 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
//Save all connected users every 10 minutes:
|
//Save all connected users every 10 minutes:
|
||||||
if (framesSinceLastUsersSave >= saveTime && zoneID != 0) {
|
if (framesSinceLastUsersSave >= saveTime && zoneID != 0) {
|
||||||
|
Profiler::Scope scope("Save all characters", Profiler::Phase::DATABASE);
|
||||||
UserManager::Instance()->SaveAllActiveCharacters();
|
UserManager::Instance()->SaveAllActiveCharacters();
|
||||||
framesSinceLastUsersSave = 0;
|
framesSinceLastUsersSave = 0;
|
||||||
|
|
||||||
@@ -635,6 +673,7 @@ int main(int argc, char** argv) {
|
|||||||
} else framesSinceLastSQLPing++;
|
} else framesSinceLastSQLPing++;
|
||||||
|
|
||||||
Metrics::EndMeasurement(MetricVariable::GameLoop);
|
Metrics::EndMeasurement(MetricVariable::GameLoop);
|
||||||
|
Profiler::EndFrame();
|
||||||
|
|
||||||
Metrics::StartMeasurement(MetricVariable::Sleep);
|
Metrics::StartMeasurement(MetricVariable::Sleep);
|
||||||
|
|
||||||
@@ -930,6 +969,7 @@ void HandleMasterPacket(Packet* packet) {
|
|||||||
// Creates the player's entity and sends the client everything in the world: after the client loaded the zone
|
// Creates the player's entity and sends the client everything in the world: after the client loaded the zone
|
||||||
// (LEVEL_LOAD_COMPLETE), or at once when it kept its scene (an experimental seamless migration)
|
// (LEVEL_LOAD_COMPLETE), or at once when it kept its scene (an experimental seamless migration)
|
||||||
void LoadPlayer(const SystemAddress& sysAddr) {
|
void LoadPlayer(const SystemAddress& sysAddr) {
|
||||||
|
Profiler::Scope scope("LoadPlayer");
|
||||||
User* user = UserManager::Instance()->GetUser(sysAddr);
|
User* user = UserManager::Instance()->GetUser(sysAddr);
|
||||||
if (user) {
|
if (user) {
|
||||||
Character* c = user->GetLastUsedChar();
|
Character* c = user->GetLastUsedChar();
|
||||||
|
|||||||
3
thirdparty/SQLite/CppSQLite3.h
vendored
3
thirdparty/SQLite/CppSQLite3.h
vendored
@@ -314,6 +314,9 @@ public:
|
|||||||
|
|
||||||
void interrupt() { sqlite3_interrupt(mpDB); }
|
void interrupt() { sqlite3_interrupt(mpDB); }
|
||||||
|
|
||||||
|
// The connection, for sqlite3_* calls this wrapper has no method for (e.g. sqlite3_trace_v2)
|
||||||
|
sqlite3* handle() { return mpDB; }
|
||||||
|
|
||||||
void setBusyTimeout(int nMillisecs);
|
void setBusyTimeout(int nMillisecs);
|
||||||
|
|
||||||
static const char* SQLiteVersion() { return SQLITE_VERSION; }
|
static const char* SQLiteVersion() { return SQLITE_VERSION; }
|
||||||
|
|||||||
Reference in New Issue
Block a user