1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-07-27 17:28:41 +00:00

Warn if async engine seems stuck (#16010)

This commit is contained in:
sfan5 2025-04-14 17:18:33 +02:00 committed by GitHub
parent 60c47c51e0
commit bdaabad53c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 59 additions and 11 deletions

View file

@ -24,6 +24,11 @@ extern "C" {
#endif #endif
#include "lua_api/l_base.h" #include "lua_api/l_base.h"
// if a job is waiting for this duration, an additional thread will be spawned
static constexpr int AUTOSCALE_DELAY_MS = 1000;
// if jobs are waiting for this duration, a warning is printed
static constexpr int STUCK_DELAY_MS = 11500;
/******************************************************************************/ /******************************************************************************/
AsyncEngine::~AsyncEngine() AsyncEngine::~AsyncEngine()
{ {
@ -156,6 +161,7 @@ void AsyncEngine::step(lua_State *L)
{ {
stepJobResults(L); stepJobResults(L);
stepAutoscale(); stepAutoscale();
stepStuckWarning();
} }
void AsyncEngine::stepJobResults(lua_State *L) void AsyncEngine::stepJobResults(lua_State *L)
@ -203,11 +209,9 @@ void AsyncEngine::stepAutoscale()
if (autoscaleTimer && porting::getTimeMs() >= autoscaleTimer) { if (autoscaleTimer && porting::getTimeMs() >= autoscaleTimer) {
autoscaleTimer = 0; autoscaleTimer = 0;
// Determine overlap with previous snapshot // Determine overlap with previous snapshot
unsigned int n = 0; size_t n = compareJobs(autoscaleSeenJobs);
for (const auto &it : jobQueue) infostream << "AsyncEngine: " << n << " jobs were still waiting after "
n += autoscaleSeenJobs.count(it.id); << AUTOSCALE_DELAY_MS << "ms, adding more threads." << std::endl;
autoscaleSeenJobs.clear();
infostream << "AsyncEngine: " << n << " jobs were still waiting after 1s" << std::endl;
// Start this many new threads // Start this many new threads
while (workerThreads.size() < autoscaleMaxWorkers && n > 0) { while (workerThreads.size() < autoscaleMaxWorkers && n > 0) {
addWorkerThread(); addWorkerThread();
@ -216,13 +220,34 @@ void AsyncEngine::stepAutoscale()
return; return;
} }
// 1) Check if there's anything in the queue // 1) Check queue contents
if (!autoscaleTimer && !jobQueue.empty()) { if (!autoscaleTimer && !jobQueue.empty()) {
// Take a snapshot of all jobs we have seen autoscaleSeenJobs.clear();
for (const auto &it : jobQueue) snapshotJobs(autoscaleSeenJobs);
autoscaleSeenJobs.emplace(it.id); autoscaleTimer = porting::getTimeMs() + AUTOSCALE_DELAY_MS;
// and set a timer for 1 second }
autoscaleTimer = porting::getTimeMs() + 1000; }
void AsyncEngine::stepStuckWarning()
{
MutexAutoLock autolock(jobQueueMutex);
// 2) If the timer elapsed, check again
if (stuckTimer && porting::getTimeMs() >= stuckTimer) {
stuckTimer = 0;
size_t n = compareJobs(stuckSeenJobs);
if (n > 0) {
warningstream << "AsyncEngine: " << n << " jobs seem to be stuck in queue"
" (" << workerThreads.size() << " workers active)" << std::endl;
}
// fallthrough
}
// 1) Check queue contents
if (!stuckTimer && !jobQueue.empty()) {
stuckSeenJobs.clear();
snapshotJobs(stuckSeenJobs);
stuckTimer = porting::getTimeMs() + STUCK_DELAY_MS;
} }
} }

View file

@ -138,6 +138,11 @@ protected:
*/ */
void stepAutoscale(); void stepAutoscale();
/**
* Print warning message if too many jobs are stuck
*/
void stepStuckWarning();
/** /**
* Initialize environment with current registred functions * Initialize environment with current registred functions
* this function adds all functions registred by registerFunction to the * this function adds all functions registred by registerFunction to the
@ -149,6 +154,21 @@ protected:
bool prepareEnvironment(lua_State* L, int top); bool prepareEnvironment(lua_State* L, int top);
private: private:
template <typename T>
inline void snapshotJobs(T &to)
{
for (const auto &it : jobQueue)
to.emplace(it.id);
}
template <typename T>
inline size_t compareJobs(const T &from)
{
size_t overlap = 0;
for (const auto &it : jobQueue)
overlap += from.count(it.id);
return overlap;
}
// Variable locking the engine against further modification // Variable locking the engine against further modification
bool initDone = false; bool initDone = false;
@ -158,6 +178,9 @@ private:
u64 autoscaleTimer = 0; u64 autoscaleTimer = 0;
std::unordered_set<u32> autoscaleSeenJobs; std::unordered_set<u32> autoscaleSeenJobs;
u64 stuckTimer = 0;
std::unordered_set<u32> stuckSeenJobs;
// Only set for the server async environment (duh) // Only set for the server async environment (duh)
Server *server = nullptr; Server *server = nullptr;