feat(scheduler-core): implement clock virtualization and session timing (task 4.5)
Adds xce_core_now() (new core_clock.c, kept separate from core.c so test_core_isolation.c's wall-clock scan still enforces zero direct clock_gettime()/time() calls elsewhere in the core): the two-anchor plus speed formula (virtual_clock_base + (elapsed * speed_num) / speed_den), covering all four modes (normal, discrete/real-time/fast- slow simulation) via four new atomic fields on xce_sched_core_t, defaulted to normal-mode (1/1 speed) in xce_sched_core_init(). requirements.md's literal tlog_reg_format_func(fn, core_ptr) call shape doesn't exist in the real vendored tlog library (registration takes only the callback; userptr is per-call-site, not bindable at registration) -- resolved with a module-level active-core pointer read by a new core-scoped format function, not wired into mylog_init()/ main.c yet. xce_core_go()/xce_core_end_session() (task 4.4) now stamp session_start/compute session_duration_ns via xce_core_now(), with their existing session-active/reentrancy behavior untouched. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019dw5WnN3DXStaEaPYfACU1
This commit is contained in:
parent
de69b6288d
commit
c5432f7786
9 changed files with 849 additions and 5 deletions
|
|
@ -23,6 +23,19 @@
|
|||
* testsuite/test_core_isolation.c (source-text scan + an nm(1) undefined-
|
||||
* symbol audit of core.c's compiled object, the build-time proof this
|
||||
* task's Observable requires).
|
||||
*
|
||||
* One documented exception (task 4.5, Req 5 AC 3): the core's single
|
||||
* sanctioned wall-clock call -- clock_gettime(CLOCK_MONOTONIC) inside
|
||||
* xce_core_now() -- and its tlog format-function integration live in
|
||||
* core_clock.c, a SEPARATE file from core.c, specifically so
|
||||
* test_core_isolation.c's core.c-scoped "zero wall-clock calls" text scan
|
||||
* keeps proving what it has always proven (core.c itself never reads real
|
||||
* time) without needing to special-case the one legitimate call site AC 3
|
||||
* mandates. tlog (tinylog) is likewise an allowed core dependency as of
|
||||
* this task -- AC 3's own "Third-party library constraint" section
|
||||
* discusses the core registering a tlog format function -- distinct from
|
||||
* the forbidden client.h/netio.h/xceapi.h/delay.h/idgen.h/xce/cluster.h
|
||||
* list above, none of which tlog is part of.
|
||||
*/
|
||||
|
||||
#include <pthread.h>
|
||||
|
|
@ -102,6 +115,55 @@ struct xce_sched_core_s {
|
|||
_Atomic int staging_merge_complete; /* 1 after staging merge completes */
|
||||
select_eval_ctx_t* sel_eval_ctx; /* session-level memoisation context; NULL
|
||||
between sessions */
|
||||
/*
|
||||
* Clock virtualization (Req 5 AC 3, scheduler-core spec, task 4.5): the
|
||||
* core's ONLY sanctioned time source is xce_core_now() (core_clock.c),
|
||||
* which computes virtual time from these four fields via the
|
||||
* two-anchor + speed formula:
|
||||
*
|
||||
* wall_ns = clock_gettime(CLOCK_MONOTONIC) // the one wall-clock
|
||||
* // call in the whole
|
||||
* // core -- lives in
|
||||
* // core_clock.c, NOT
|
||||
* // core.c (core.c's own
|
||||
* // zero-wall-clock
|
||||
* // guarantee, enforced
|
||||
* // by
|
||||
* // test_core_isolation.c,
|
||||
* // stays intact)
|
||||
* elapsed = wall_ns - real_clock_base
|
||||
* xce_core_now() = virtual_clock_base + (elapsed * speed_num) / speed_den
|
||||
*
|
||||
* Atomically updated by the driver AS A GROUP before each event
|
||||
* dispatch (design.md's State Management note) -- xce_core_now() reads
|
||||
* them lock-free, no mutex, safe from both the picker and allocator
|
||||
* threads. xce_sched_core_init() seeds these to AC 3's Normal-mode row
|
||||
* (virtual_clock_base=0, real_clock_base=0, speed_num=1, speed_den=1):
|
||||
* degraded-to-real-wall-clock default, today's existing production
|
||||
* behavior, preserved until a future simulation driver (Phase 3)
|
||||
* explicitly reconfigures them.
|
||||
*/
|
||||
_Atomic uint64_t virtual_clock_base;
|
||||
_Atomic uint64_t real_clock_base;
|
||||
_Atomic uint64_t speed_num;
|
||||
_Atomic uint64_t speed_den;
|
||||
/*
|
||||
* Session response-time diagnostics (Req 5 AC 12, task 4.5). Plain
|
||||
* (non-atomic) fields -- touched only by the driver thread, inside
|
||||
* xce_core_go()/xce_core_end_session() (core_session.c), the same
|
||||
* single-writer discipline core->sel_eval_ctx above already follows.
|
||||
* session_start is stamped at the top of xce_core_go(); the field name
|
||||
* matches requirements.md's own pseudocode verbatim
|
||||
* ("session_start = xce_core_now()"). session_duration_ns is computed
|
||||
* at the top of xce_core_end_session() as xce_core_now() -
|
||||
* session_start. Both are diagnostics only -- nothing in the
|
||||
* scheduling/decision path reads them. The ReplaySession.summary
|
||||
* SessionSummary wire struct these values eventually feed is explicitly
|
||||
* OUT of this task's scope (Phase 3, recording/replay-format tasks
|
||||
* 7.x) -- this struct only holds the plain numeric tracking.
|
||||
*/
|
||||
uint64_t session_start;
|
||||
uint64_t session_duration_ns;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -302,4 +364,40 @@ extern int xce_core_go(xce_sched_core_t*);
|
|||
*/
|
||||
extern int xce_core_end_session(xce_sched_core_t*);
|
||||
|
||||
/*
|
||||
* xce_core_now - Req 5 AC 3 (scheduler-core spec, task 4.5): the core's
|
||||
* virtualized clock accessor, and the ONLY place inside the scheduler-core
|
||||
* module family that calls clock_gettime() (implemented in core_clock.c,
|
||||
* deliberately NOT core.c -- see this header's own top-of-file boundary
|
||||
* comment and xce_sched_core_t's clock-field doc comment above for why).
|
||||
* Computes virtual time via the two-anchor + speed formula from
|
||||
* virtual_clock_base/real_clock_base/speed_num/speed_den, reading all four
|
||||
* atomically (lock-free, safe from any thread). Returns 0 if core is NULL.
|
||||
*/
|
||||
extern uint64_t xce_core_now(xce_sched_core_t*);
|
||||
|
||||
/*
|
||||
* xce_core_set_active_for_logging / xce_core_register_tlog_format - Req 5
|
||||
* AC 3's tlog integration (task 4.5). See core_clock.c's own file header
|
||||
* comment for the full reasoning behind this exact mechanism, including why
|
||||
* it deliberately does NOT match AC 3's literal
|
||||
* `tlog_reg_format_func(fn, core_ptr)` pseudocode -- that call shape does
|
||||
* not exist in the real vendored tlog.h (`tlog_reg_format_func()` takes
|
||||
* only the callback, no userptr-binding parameter; userptr is a per-call-
|
||||
* site argument that flows through tlog_ext()/tlog_vext(), not something
|
||||
* bindable once at registration time).
|
||||
*
|
||||
* xce_core_set_active_for_logging(core) sets (or, passed NULL, clears) a
|
||||
* module-level "active core for logging" pointer that core_clock.c's
|
||||
* registered tlog_format_func reads via xce_core_now() instead of
|
||||
* info->time. xce_core_register_tlog_format() registers that format
|
||||
* function with tlog via the real tlog_reg_format_func(). Neither is
|
||||
* called from mylog_init()/main.c by this task -- wiring the live
|
||||
* scheduler process over to this mechanism is a later task's job,
|
||||
* consistent with tasks 4.1-4.4's additive-only, unwired-until-a-driver-
|
||||
* exists pattern.
|
||||
*/
|
||||
extern void xce_core_set_active_for_logging(xce_sched_core_t*);
|
||||
extern int xce_core_register_tlog_format(void);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue