slow messags
This commit is contained in:
@@ -876,7 +876,7 @@ typedef struct {
|
||||
#define ACTOR_SLOW 5
|
||||
#define ACTOR_REFRESHED 6
|
||||
|
||||
#define ACTOR_FAST_TIMER_NS (10ULL * 1000000)
|
||||
#define ACTOR_FAST_TIMER_NS (1000ULL * 1000000)
|
||||
#define ACTOR_SLOW_TIMER_NS (60000ULL * 1000000)
|
||||
#define ACTOR_SLOW_STRIKES_MAX 3
|
||||
#define ACTOR_MEMORY_LIMIT (1024ULL * 1024 * 1024)
|
||||
|
||||
@@ -1915,12 +1915,13 @@ int ctx_gc (JSContext *ctx, int allow_grow, size_t alloc_size) {
|
||||
if (ctx->trace_hook && (ctx->trace_type & JS_HOOK_GC))
|
||||
ctx->trace_hook(ctx, JS_HOOK_GC, NULL, ctx->trace_data);
|
||||
|
||||
/* Check memory limit — kill actor if heap exceeds cap */
|
||||
/* Check memory limit — kill actor if heap exceeds cap.
|
||||
Use JS_Log "memory" channel which always fprintf's (safe during GC). */
|
||||
if (ctx->heap_memory_limit > 0 && ctx->current_block_size > ctx->heap_memory_limit) {
|
||||
#ifdef ACTOR_TRACE
|
||||
fprintf(stderr, "[ACTOR_TRACE] heap %zu > limit %zu, OOM\n",
|
||||
ctx->current_block_size, ctx->heap_memory_limit);
|
||||
#endif
|
||||
JS_Log(ctx, "memory", "%s: heap %zuKB exceeds limit %zuMB, killing",
|
||||
ctx->name ? ctx->name : ctx->id,
|
||||
ctx->current_block_size / 1024,
|
||||
ctx->heap_memory_limit / (1024 * 1024));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -3283,19 +3284,18 @@ JS_RaiseDisrupt (JSContext *ctx, const char *fmt, ...) {
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
|
||||
/* Log to "memory" channel + disrupt. Skips JS callback (can't allocate). */
|
||||
/* Log to "memory" channel + disrupt. Skips JS callback (can't allocate).
|
||||
Uses fprintf directly — safe even during OOM. */
|
||||
JSValue JS_RaiseOOM (JSContext *ctx) {
|
||||
size_t used = (size_t)((uint8_t *)ctx->heap_free - (uint8_t *)ctx->heap_base);
|
||||
size_t block = ctx->current_block_size;
|
||||
size_t limit = ctx->heap_memory_limit;
|
||||
const char *name = ctx->name ? ctx->name : ctx->id;
|
||||
const char *label = ctx->actor_label;
|
||||
if (limit > 0) {
|
||||
fprintf(stderr, "out of memory: heap %zuKB / %zuKB block, limit %zuMB",
|
||||
used / 1024, block / 1024, limit / (1024 * 1024));
|
||||
} else {
|
||||
fprintf(stderr, "out of memory: heap %zuKB / %zuKB block, no limit",
|
||||
used / 1024, block / 1024);
|
||||
}
|
||||
fprintf(stderr, "[memory] %s: out of memory — heap %zuKB / %zuKB block",
|
||||
name ? name : "?", used / 1024, block / 1024);
|
||||
if (limit > 0)
|
||||
fprintf(stderr, ", limit %zuMB", limit / (1024 * 1024));
|
||||
if (label)
|
||||
fprintf(stderr, " [%s]", label);
|
||||
fprintf(stderr, "\n");
|
||||
@@ -12009,7 +12009,7 @@ void JS_CrashPrintStack(JSContext *ctx) {
|
||||
if (!ctx) return;
|
||||
if (JS_IsNull(ctx->reg_current_frame)) return;
|
||||
|
||||
static const char hdr[] = "\n--- JS Stack at crash ---\n";
|
||||
static const char hdr[] = "\n--- JS Stack ---\n";
|
||||
write(STDERR_FILENO, hdr, sizeof(hdr) - 1);
|
||||
|
||||
JSFrameRegister *frame = (JSFrameRegister *)JS_VALUE_GET_PTR(ctx->reg_current_frame);
|
||||
|
||||
@@ -293,9 +293,15 @@ void *timer_thread_func(void *arg) {
|
||||
/* Only fire if turn_gen still matches (stale timers are ignored) */
|
||||
uint32_t cur = atomic_load_explicit(&t.actor->turn_gen, memory_order_relaxed);
|
||||
if (cur == t.turn_gen) {
|
||||
/* Can't call JS_Log from timer thread — use fprintf */
|
||||
const char *name = t.actor->name ? t.actor->name : t.actor->id;
|
||||
if (t.type == TIMER_PAUSE) {
|
||||
fprintf(stderr, "[slow] %s: pausing (turn exceeded %llums)\n",
|
||||
name, (unsigned long long)(ACTOR_FAST_TIMER_NS / 1000000));
|
||||
JS_SetPauseFlag(t.actor, 1);
|
||||
} else {
|
||||
fprintf(stderr, "[slow] %s: kill timer fired (turn exceeded %llus)\n",
|
||||
name, (unsigned long long)(ACTOR_SLOW_TIMER_NS / 1000000000));
|
||||
t.actor->disrupt = 1;
|
||||
JS_SetPauseFlag(t.actor, 2);
|
||||
}
|
||||
@@ -577,17 +583,11 @@ int actor_exists(const char *id)
|
||||
void set_actor_state(JSContext *actor)
|
||||
{
|
||||
if (actor->disrupt) {
|
||||
#ifdef SCHEDULER_DEBUG
|
||||
fprintf(stderr, "set_actor_state: %s disrupted, freeing\n", actor->name ? actor->name : actor->id);
|
||||
#endif
|
||||
actor_free(actor);
|
||||
return;
|
||||
}
|
||||
pthread_mutex_lock(actor->msg_mutex);
|
||||
|
||||
#ifdef SCHEDULER_DEBUG
|
||||
fprintf(stderr, "set_actor_state: %s state=%d letters=%ld\n", actor->name ? actor->name : actor->id, actor->state, (long)arrlen(actor->letters));
|
||||
#endif
|
||||
switch(actor->state) {
|
||||
case ACTOR_RUNNING:
|
||||
case ACTOR_READY:
|
||||
@@ -601,9 +601,6 @@ void set_actor_state(JSContext *actor)
|
||||
actor->is_quiescent = 0;
|
||||
atomic_fetch_sub(&engine.quiescent_count, 1);
|
||||
}
|
||||
#ifdef SCHEDULER_DEBUG
|
||||
fprintf(stderr, "set_actor_state: %s IDLE->READY, enqueueing (main=%d)\n", actor->name ? actor->name : actor->id, actor->main_thread_only);
|
||||
#endif
|
||||
actor->state = ACTOR_READY;
|
||||
actor->ar = 0;
|
||||
enqueue_actor_priority(actor);
|
||||
@@ -846,6 +843,8 @@ void actor_turn(JSContext *actor)
|
||||
|
||||
if (JS_IsSuspended(result)) {
|
||||
/* Still suspended after kill timer — shouldn't happen, kill it */
|
||||
fprintf(stderr, "[slow] %s: still suspended after resume, killing\n",
|
||||
actor->name ? actor->name : actor->id);
|
||||
actor->disrupt = 1;
|
||||
goto ENDTURN;
|
||||
}
|
||||
@@ -854,16 +853,12 @@ void actor_turn(JSContext *actor)
|
||||
actor->disrupt = 1;
|
||||
}
|
||||
actor->slow_strikes++;
|
||||
#ifdef ACTOR_TRACE
|
||||
fprintf(stderr, "[ACTOR_TRACE] %s: slow strike %d/%d\n",
|
||||
actor->name ? actor->name : actor->id,
|
||||
actor->slow_strikes, ACTOR_SLOW_STRIKES_MAX);
|
||||
#endif
|
||||
JS_Log(actor, "slow", "%s: slow strike %d/%d",
|
||||
actor->name ? actor->name : actor->id,
|
||||
actor->slow_strikes, ACTOR_SLOW_STRIKES_MAX);
|
||||
if (actor->slow_strikes >= ACTOR_SLOW_STRIKES_MAX) {
|
||||
#ifdef ACTOR_TRACE
|
||||
fprintf(stderr, "[ACTOR_TRACE] %s: %d slow strikes, killing\n",
|
||||
actor->name ? actor->name : actor->id, actor->slow_strikes);
|
||||
#endif
|
||||
JS_Log(actor, "slow", "%s: killed after %d consecutive slow turns",
|
||||
actor->name ? actor->name : actor->id, actor->slow_strikes);
|
||||
actor->disrupt = 1;
|
||||
}
|
||||
goto ENDTURN;
|
||||
@@ -876,10 +871,6 @@ void actor_turn(JSContext *actor)
|
||||
pthread_mutex_unlock(actor->msg_mutex);
|
||||
goto ENDTURN;
|
||||
}
|
||||
#ifdef SCHEDULER_DEBUG
|
||||
fprintf(stderr, "actor_turn: %s has %d letters, type=%d\n",
|
||||
actor->name ? actor->name : actor->id, pending, actor->letters[0].type);
|
||||
#endif
|
||||
letter l = actor->letters[0];
|
||||
arrdel(actor->letters, 0);
|
||||
pthread_mutex_unlock(actor->msg_mutex);
|
||||
@@ -937,29 +928,22 @@ ENDTURN:
|
||||
actor->actor_trace_hook(actor, CELL_HOOK_EXIT);
|
||||
|
||||
if (actor->disrupt) {
|
||||
#ifdef SCHEDULER_DEBUG
|
||||
fprintf(stderr, "actor_turn ENDTURN: %s disrupted, freeing\n",
|
||||
actor->name ? actor->name : actor->id);
|
||||
#endif
|
||||
pthread_mutex_unlock(actor->mutex);
|
||||
actor_free(actor);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef SCHEDULER_DEBUG
|
||||
fprintf(stderr, "actor_turn ENDTURN: %s has %ld letters, calling set_actor_state\n",
|
||||
actor->name ? actor->name : actor->id, (long)arrlen(actor->letters));
|
||||
#endif
|
||||
set_actor_state(actor);
|
||||
pthread_mutex_unlock(actor->mutex);
|
||||
return;
|
||||
|
||||
ENDTURN_SLOW:
|
||||
g_crash_ctx = NULL;
|
||||
#ifdef ACTOR_TRACE
|
||||
fprintf(stderr, "[ACTOR_TRACE] %s: suspended mid-turn -> SLOW\n",
|
||||
actor->name ? actor->name : actor->id);
|
||||
#endif
|
||||
/* VM suspended mid-turn — can't call JS_Log, use fprintf.
|
||||
Print stack trace while frames are still intact. */
|
||||
fprintf(stderr, "[slow] %s: suspended mid-turn, entering slow queue (strike %d/%d)\n",
|
||||
actor->name ? actor->name : actor->id,
|
||||
actor->slow_strikes + 1, ACTOR_SLOW_STRIKES_MAX);
|
||||
if (actor->actor_trace_hook)
|
||||
actor->actor_trace_hook(actor, CELL_HOOK_EXIT);
|
||||
enqueue_actor_priority(actor);
|
||||
|
||||
Reference in New Issue
Block a user