freeze_dump_policy: unit-test the profile-ring diversity scan

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Matthew Stanley
2026-10-12 04:40:33 -07:00
parent 5279226e90
commit e7d96b68c1
3 changed files with 32 additions and 17 deletions
+15
View File
@@ -98,6 +98,21 @@ int freeze_distinct_add(FreezeDistinct *set, uint32_t value) {
return set->count > FREEZE_WEDGE_SPIN_MAX_FNS;
}
uint32_t freeze_window_fn_diversity(uint64_t lo, uint64_t hi, uint64_t oldest,
int (*get)(uint64_t seq, uint32_t *fn,
int *in_exception)) {
if (lo < oldest) lo = oldest;
FreezeDistinct set = {{0}, 0};
int any = 0;
for (uint64_t seq = lo; seq < hi; seq++) {
uint32_t fn = 0;
int in_exception = 0;
if (!get(seq, &fn, &in_exception) || in_exception) continue;
any = 1;
if (freeze_distinct_add(&set, fn)) break;
}
return any ? set.count : FREEZE_WEDGE_FN_DIVERSITY_UNKNOWN;
}
uint32_t freeze_wedge_classify(const FreezeWedgeSample *window, uint32_t count,
uint32_t fn_diversity,
int (*mdec_recently_active)(uint32_t frames)) {
+8
View File
@@ -73,6 +73,14 @@ typedef struct FreezeDistinct {
* distinct values have been seen (the caller can stop scanning). */
int freeze_distinct_add(FreezeDistinct *set, uint32_t value);
/* Distinct functions entered outside exceptions over profile samples
* [lo, hi), clamped to oldest (the ring's oldest held sample). get() returns
* 0 for an evicted/unavailable sample. Stops counting past
* FREEZE_WEDGE_SPIN_MAX_FNS; FREEZE_WEDGE_FN_DIVERSITY_UNKNOWN when no
* non-exception sample covers the window. */
uint32_t freeze_window_fn_diversity(uint64_t lo, uint64_t hi, uint64_t oldest,
int (*get)(uint64_t seq, uint32_t *fn,
int *in_exception));
/* Classify a window of consecutive samples, oldest first. A spin requires the
* executing function, last store PC and dirty-RAM instruction count to hold
* one value at EVERY sample, AND (when known) at most FREEZE_WEDGE_SPIN_MAX_FNS
+9 -17
View File
@@ -756,24 +756,14 @@ void freeze_heartbeat_fatal_dump(const char *reason) {
sio_get_mc_max_state(), sio_get_tx_writes());
}
/* Distinct guest functions entered outside exceptions in profile samples
* [lo, hi), read from the always-on guest-cycle profile ring. Stops counting
* past FREEZE_WEDGE_SPIN_MAX_FNS; UNKNOWN when no sample covers the window. */
static uint32_t window_fn_diversity(uint64_t lo, uint64_t hi) {
uint64_t oldest = guest_cycle_profile_oldest();
if (lo < oldest) lo = oldest;
FreezeDistinct set = {{0}, 0};
int any = 0;
/* Adapter from the guest-cycle profile ring to freeze_window_fn_diversity. */
static int gcp_sample_fn(uint64_t seq, uint32_t *fn, int *in_exception) {
GcpSample s;
for (uint64_t seq = lo; seq < hi; seq++) {
if (!guest_cycle_profile_get(seq, &s)) continue;
if (s.flags & GCP_FLAG_EXCEPTION) continue;
any = 1;
if (freeze_distinct_add(&set, s.fn)) break;
}
return any ? set.count : FREEZE_WEDGE_FN_DIVERSITY_UNKNOWN;
if (!guest_cycle_profile_get(seq, &s)) return 0;
*fn = s.fn;
*in_exception = (s.flags & GCP_FLAG_EXCEPTION) != 0;
return 1;
}
static void heartbeat_write(void) {
uint64_t cyc = psx_get_cycle_count();
uint64_t frame = s_frame_count;
@@ -866,7 +856,9 @@ static void heartbeat_write(void) {
uint64_t lo = s_ring[(s_ring_head + RING_CAP - WEDGE_WINDOW_TICKS) % RING_CAP].gcp_seq;
uint64_t hi = s_ring[(s_ring_head + RING_CAP - 1u) % RING_CAP].gcp_seq;
wedge_kind = freeze_wedge_classify(window, WEDGE_WINDOW_TICKS,
window_fn_diversity(lo, hi),
freeze_window_fn_diversity(
lo, hi, guest_cycle_profile_oldest(),
gcp_sample_fn),
mdec_recently_active);
}
}