Skip to content

Commit 3dbb8c9

Browse files
kmbandyclaude
andcommitted
feat(dsws): pool-economy offline machinery (Tasks 1-6) — GPU gate BRICKED, needs offline root-cause
Offline pool-economy implementation, all review-clean, all offline gates green (assemble matrix, RGA 0-spill, CONV=0 .text byte-identical to Phase A, CPU model, dry-print): - T1 CPU model: role_dispatch/cooldown_step/pool_fits_lean/quiesce_ready_pool - T2 seed s59 in the lean partition arms + BUDGET headroom knob (no launch grow) - T3 .Ldispatch trampoline unifying entry + re-dispatch (targets _follow, scalar-only) - T4 cooldown K on s66 (default 0; prologue-dead scalar, liveness verified) - T5 DSWS2_FORCE deterministic bring-up hook (all 4 dirs assemble) - T6 offline integration gate: green KNOWN BUG (found on first-ever CONV=1 silicon dispatch, Pool-T7 inert-safe gate): CONV=1 with conversions PROVABLY DORMANT (CTRL_LOW=0/HIGH_A=6/HIGH_B=4, every watermark branch unreachable) HUNG the GPU -> MODE1 reset. Phase-A CONV=0 ran clean across all mixes, so the hang is in the always-active Phase-B machinery (the .Ldispatch trampoline and/or the snapshot/quiesce handshake), NOT the conversion logic. Prime suspect: the claimer's snapshot-sized quiesce sentinels spin forever. Root-cause is OFFLINE-ONLY from here (extend the CPU control model to simulate the multi-wave quiesce/dispatch handshake); no further gfx1201 dispatch until both the deadlock is understood AND the compositor is isolated from the card. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0132aDSBLwusCJ4KzHQTnvdu
1 parent f6f4c6e commit 3dbb8c9

4 files changed

Lines changed: 209 additions & 5 deletions

File tree

ggml/src/ggml-cuda/aiter-integration/rdna4_fp8_gemm/spike/dvgpr_occ/build_dsws.sh

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,18 @@ mk() { # $1=NCOMP $2=NAFEED $3=NBFEED $4=RINGD $5=DYN
2121

2222
mk2() { # $1=NCOMP $2=NAFEED $3=NBFEED (DSWS2 v2 substrate, occ_kernel_dsws.s; G=6 SEGK=64 FM=2 FN=4)
2323
local tag="occ_dsws2_${1}c${2}a${3}b_gd"
24+
# BUDGET passthrough: default mirrors the in-file .ifndef launch-footprint conservation ceiling
25+
# (NCOMP*NFV + (NAFEED+NBFEED)*VLEAN, with NFV=112/VLEAN=32 at this file's fixed FM=2 FN=4) so an
26+
# unset $BUDGET reproduces the existing default exactly; set $BUDGET to give real per-SIMD headroom.
27+
local budget="${BUDGET:-$(( $1 * 112 + ($2 + $3) * 32 ))}"
28+
# DSWS2_FORCE* passthrough (Task 5): defaults mirror the in-file .ifndef values exactly, so an
29+
# unset env leaves every existing mk2 call byte-identical (DSWS2_FORCE=0 emits zero bytes).
2430
nice -19 ionice -c3 "$L/clang" -x assembler -target amdgcn-amd-amdhsa -mcpu=gfx1201 \
2531
-Wa,-defsym,DSWS2=1 -Wa,-defsym,FM=2 -Wa,-defsym,FN=4 -Wa,-defsym,G=6 -Wa,-defsym,SEGK=64 \
26-
-Wa,-defsym,SAFEPROBE=1 -Wa,-defsym,DIAG=${DIAG:-1} \
32+
-Wa,-defsym,SAFEPROBE=1 -Wa,-defsym,DIAG=${DIAG:-1} -Wa,-defsym,BUDGET=$budget \
2733
-Wa,-defsym,NCOMP=$1 -Wa,-defsym,NAFEED=$2 -Wa,-defsym,NBFEED=$3 \
34+
-Wa,-defsym,DSWS2_FORCE=${DSWS2_FORCE:-0} -Wa,-defsym,DSWS2_FORCE_WID=${DSWS2_FORCE_WID:-0} \
35+
-Wa,-defsym,DSWS2_FORCE_DIR=${DSWS2_FORCE_DIR:-0} -Wa,-defsym,DSWS2_FORCE_EPOCH=${DSWS2_FORCE_EPOCH:-1} \
2836
-c occ_kernel_dsws.s -o "$tag.o" 2>/tmp/dsws2_build.err \
2937
&& { "$L/llvm-objcopy" -O binary --only-section=.text "$tag.o" "$tag.bin"; echo " OK $tag.bin ($(wc -c < "$tag.bin")B)"; } \
3038
|| { echo " FAIL $tag"; sed -n '1,15p' /tmp/dsws2_build.err; fail=1; }

ggml/src/ggml-cuda/aiter-integration/rdna4_fp8_gemm/spike/dvgpr_occ/dsws_ctrl_model.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,23 @@ static inline bool quiesce_ready(uint32_t rowblk_next, uint32_t bfrag_next,
7373
static inline bool quiesce_ready_nm1(uint32_t quiesce_cnt, uint32_t N) {
7474
return quiesce_cnt >= (N - 1);
7575
}
76+
77+
// ---- Task 1: dispatch, cooldown, pool invariants ----
78+
79+
enum Role { COMPUTE, AFEED, BFEED };
80+
81+
inline Role role_dispatch(uint32_t slot_id) {
82+
return slot_id == 24 ? COMPUTE : (slot_id == 28 ? AFEED : BFEED);
83+
}
84+
85+
inline uint32_t cooldown_step(uint32_t cd) { return cd ? cd - 1 : 0; }
86+
87+
inline bool in_cooldown(uint32_t cd) { return cd > 0; }
88+
89+
inline bool pool_fits_lean(uint32_t n_pool, uint32_t vlean, uint32_t budget) {
90+
return (uint64_t)n_pool * vlean <= budget;
91+
}
92+
93+
inline bool quiesce_ready_pool(uint32_t quiesce_cnt, uint32_t n_pool) {
94+
return quiesce_cnt >= n_pool - 1;
95+
}

ggml/src/ggml-cuda/aiter-integration/rdna4_fp8_gemm/spike/dvgpr_occ/occ_kernel_dsws.s

Lines changed: 166 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,27 @@
128128
.ifndef DSWS2_TICKET_SELFTEST
129129
.set DSWS2_TICKET_SELFTEST, 0 // DIAG-only try_gate single-winner smoke (Task 4 Step 3); default 0 = no bytes
130130
.endif
131+
.ifndef CONV_COOLDOWN
132+
.set CONV_COOLDOWN, 0 // Task 4: per-wave post-conversion cooldown epochs. 0 = spec-faithful (no
133+
// cooldown, byte-identical to pre-Task-4); >0 damps thrash (skip N epochs
134+
// of watermark decision after a wave converts role).
135+
.endif
136+
// Task 5: deterministic bring-up hook. DSWS2_FORCE=1 makes exactly wave DSWS2_FORCE_WID convert
137+
// direction DSWS2_FORCE_DIR at epoch DSWS2_FORCE_EPOCH, watermarks bypassed -- a reproducible,
138+
// single-wave/single-epoch GPU proof of role conversion. Default DSWS2_FORCE=0 emits ZERO bytes
139+
// (byte-identical to pre-Task-5).
140+
.ifndef DSWS2_FORCE
141+
.set DSWS2_FORCE, 0
142+
.endif
143+
.ifndef DSWS2_FORCE_WID
144+
.set DSWS2_FORCE_WID, 0
145+
.endif
146+
.ifndef DSWS2_FORCE_DIR
147+
.set DSWS2_FORCE_DIR, 0 // 0/1 = compute->A/B ; 2/3 = A/B->compute
148+
.endif
149+
.ifndef DSWS2_FORCE_EPOCH
150+
.set DSWS2_FORCE_EPOCH, 1
151+
.endif
131152
.set SNAP_BASE, (INITFLAG_OFF + 4) // u32[6]: [parity*3 + {0:nC,1:nA,2:nB}] role-mix snapshots
132153
.set QUIESCE_CNT_OFF,(SNAP_BASE + 6*4) // u32 role-agnostic bail counter
133154
.set DSWS2_STATE_END,(QUIESCE_CNT_OFF + 4)
@@ -404,6 +425,13 @@
404425
.set BUDGET, (NCOMP*NFV + (NAFEED+NBFEED)*VLEAN) // = VRESV_OFF init (conservation ceiling)
405426
.endif
406427

428+
.if DSWS2_CONV
429+
// compile-time no-parking invariant: every launched wave must fit lean at once
430+
.if (WAVES * VLEAN) > BUDGET
431+
.error "WAVES*VLEAN exceeds BUDGET — pool cannot stay all-lean (parking is out of scope)"
432+
.endif
433+
.endif
434+
407435
// try_gate: the lock-free single-winner conversion ticket (transcribed VERBATIM from occ_kernel_coop.s,
408436
// which transcribes dsws_ctrl_model.cpp gate_try_win + epoch_of EXACTLY). E = segcnt>>EPOCH_SHIFT.
409437
// gate[dir] holds the last epoch dir fired. Among many waves racing the same (g<E), exactly ONE wins
@@ -550,6 +578,9 @@
550578
.Lca_commit\@:
551579
lds_fetch_add s52, \dst_slot, 1 // (c) inc dest slot (unbounded -> plain atomic add)
552580
s_mov_b32 s59, \dst_slot // flip private current-role reg (records new role slot id)
581+
.if CONV_COOLDOWN > 0
582+
s_mov_b32 s66, CONV_COOLDOWN // Task 4: committed conversion -> arm cooldown
583+
.endif
553584
// ---- s_alloc_vgpr resize: THE pre-grow OOR window closes here; all reads above were <=v15 ----
554585
.Lca_alloc\@:
555586
s_alloc_vgpr \alloc_sz // GROW(NFV) / SHRINK(32); SCC-retry (brick-class rule)
@@ -622,11 +653,29 @@ occ_kernel:
622653
.Ltg_selftest_skip:
623654
s_mov_b32 exec_lo, s16
624655
.endif
656+
.if DSWS2_CONV
657+
.if CONV_COOLDOWN > 0
658+
s_mov_b32 s66, 0 // Task 4: init cooldown ctr (un-cooled at entry)
659+
.endif
660+
s_cmp_lt_u32 s24, NBFEED
661+
s_cbranch_scc1 .Lseed_bfeed
662+
s_cmp_lt_u32 s24, (NBFEED+NAFEED)
663+
s_cbranch_scc1 .Lseed_afeed
664+
s_mov_b32 s59, NCOMP_SLOT
665+
s_branch .Ldispatch
666+
.Lseed_afeed:
667+
s_mov_b32 s59, NAFEED_SLOT
668+
s_branch .Ldispatch
669+
.Lseed_bfeed:
670+
s_mov_b32 s59, NBFEED_SLOT
671+
s_branch .Ldispatch
672+
.else
625673
s_cmp_lt_u32 s24, NBFEED
626674
s_cbranch_scc1 .Lbfeed
627675
s_cmp_lt_u32 s24, (NBFEED+NAFEED)
628676
s_cbranch_scc1 .Lafeed
629677
s_branch .Lcompute
678+
.endif
630679

631680
// ============================================================================================
632681
// A3 -- .Lclaimer : pinned wid-0. Owns the super-tile claim+broadcast, the SEGCNT clock, the
@@ -894,17 +943,46 @@ occ_kernel:
894943
// Lean-32 -> PRE-GROW window (the feed->compute GROW closes it inside conv_apply, post all <=v15
895944
// reads). If the B-ring is OVER-SERVED (occ_B>CTRL_HIGH_B) grow one B-feed->compute (dir 3):
896945
// reserve delta +(NFV-VLEAN) (may abort over BUDGET -> stay B-feed).
946+
.if CONV_COOLDOWN > 0
947+
s_cmp_eq_u32 s66, 0
948+
s_cbranch_scc0 .Lbfeed_cooldn // Task 4: s66!=0 -> in cooldown, skip decision
949+
.endif
950+
.if DSWS2_FORCE
951+
.if DSWS2_FORCE_DIR == 3
952+
// Task 5: deterministic forced conversion (dir 3: B-feed -> compute), watermark bypassed.
953+
// Convert iff wid(s24)==DSWS2_FORCE_WID AND current epoch(s35)==DSWS2_FORCE_EPOCH.
954+
s_mov_b32 s58, 0
955+
s_cmp_eq_u32 s24, DSWS2_FORCE_WID
956+
s_cbranch_scc0 .Lbfeed_cooldn
957+
s_cmp_eq_u32 s35, DSWS2_FORCE_EPOCH
958+
s_cbranch_scc0 .Lbfeed_cooldn
959+
s_mov_b32 s57, 3 // dir 3: B-feed -> compute (forced)
960+
try_gate 3, s58
961+
conv_apply NBFEED_SLOT, NCOMP_SLOT, +(NFV-VLEAN), NFV
962+
.endif
963+
.else
897964
s_mov_b32 s58, 0
898965
occ_sample s55, s56 // s55=occ_A, s56=occ_B
899966
s_cmp_gt_u32 s56, CTRL_HIGH_B
900-
s_cbranch_scc0 .Lbfeed_quiesce
967+
s_cbranch_scc0 .Lbfeed_cooldn
901968
s_mov_b32 s57, 3 // dir 3: B-feed -> compute
902969
try_gate 3, s58
903970
conv_apply NBFEED_SLOT, NCOMP_SLOT, +(NFV-VLEAN), NFV
971+
.endif
972+
.Lbfeed_cooldn:
973+
.if CONV_COOLDOWN > 0
974+
s_cmp_eq_u32 s66, 0 // Task 4: decrement once per epoch (saturating)
975+
s_cbranch_scc1 .Lbfeed_quiesce
976+
s_sub_i32 s66, s66, 1
977+
.endif
904978
.Lbfeed_quiesce:
905979
lds_fetch_add s61, QUIESCE_CNT_OFF, 1 // commit-before-bump ordering (SPEC 3.4 decision 2)
906980
.endif
981+
.if DSWS2_CONV
982+
s_branch .Ldispatch
983+
.else
907984
s_branch .Lbfeed_follow
985+
.endif
908986

909987
// ============================================================================================
910988
// A5 -- .Lafeed : A-feed wave. Follows EPOCH/STI, decodes (mblk,ksi), stages its claimed A rowblks.
@@ -938,17 +1016,46 @@ occ_kernel:
9381016
// (feed->compute, s_alloc_vgpr NFV) is the ONLY grow and closes the window inside conv_apply, after
9391017
// all <=v15 LDS/atomic reads. If the A-ring is OVER-SERVED (occ_A>CTRL_HIGH_A) grow one A-feed->
9401018
// compute (dir 2): reserve delta +(NFV-VLEAN) (may abort over BUDGET -> stay A-feed).
1019+
.if CONV_COOLDOWN > 0
1020+
s_cmp_eq_u32 s66, 0
1021+
s_cbranch_scc0 .Lafeed_cooldn // Task 4: s66!=0 -> in cooldown, skip decision
1022+
.endif
1023+
.if DSWS2_FORCE
1024+
.if DSWS2_FORCE_DIR == 2
1025+
// Task 5: deterministic forced conversion (dir 2: A-feed -> compute), watermark bypassed.
1026+
// Convert iff wid(s24)==DSWS2_FORCE_WID AND current epoch(s35)==DSWS2_FORCE_EPOCH.
1027+
s_mov_b32 s58, 0
1028+
s_cmp_eq_u32 s24, DSWS2_FORCE_WID
1029+
s_cbranch_scc0 .Lafeed_cooldn
1030+
s_cmp_eq_u32 s35, DSWS2_FORCE_EPOCH
1031+
s_cbranch_scc0 .Lafeed_cooldn
1032+
s_mov_b32 s57, 2 // dir 2: A-feed -> compute (forced)
1033+
try_gate 2, s58
1034+
conv_apply NAFEED_SLOT, NCOMP_SLOT, +(NFV-VLEAN), NFV
1035+
.endif
1036+
.else
9411037
s_mov_b32 s58, 0
9421038
occ_sample s55, s56 // s55=occ_A, s56=occ_B
9431039
s_cmp_gt_u32 s55, CTRL_HIGH_A
944-
s_cbranch_scc0 .Lafeed_quiesce
1040+
s_cbranch_scc0 .Lafeed_cooldn
9451041
s_mov_b32 s57, 2 // dir 2: A-feed -> compute
9461042
try_gate 2, s58
9471043
conv_apply NAFEED_SLOT, NCOMP_SLOT, +(NFV-VLEAN), NFV
1044+
.endif
1045+
.Lafeed_cooldn:
1046+
.if CONV_COOLDOWN > 0
1047+
s_cmp_eq_u32 s66, 0 // Task 4: decrement once per epoch (saturating)
1048+
s_cbranch_scc1 .Lafeed_quiesce
1049+
s_sub_i32 s66, s66, 1
1050+
.endif
9481051
.Lafeed_quiesce:
9491052
lds_fetch_add s61, QUIESCE_CNT_OFF, 1 // commit-before-bump ordering (SPEC 3.4 decision 2)
9501053
.endif
1054+
.if DSWS2_CONV
1055+
s_branch .Ldispatch
1056+
.else
9511057
s_branch .Lafeed_follow
1058+
.endif
9521059

9531060
// ============================================================================================
9541061
// A6 -- .Lcompute : compute wave. Follows EPOCH/STI, decodes (mblk,tcol,ksi), waits resident A/B
@@ -1075,26 +1182,81 @@ occ_kernel:
10751182
// else if starved for B, compute->B-feed (dir 1). Both are SHRINKs: reserve delta -(NFV-VLEAN),
10761183
// s_alloc_vgpr 32 (already lean -> no-op). Persistent: s57=dir, s58=s_win, s59=new-role (all outside
10771184
// s60..s65 so occ_sample/try_gate/reserve_try/conv_* cannot clobber them while live).
1185+
.if CONV_COOLDOWN > 0
1186+
s_cmp_eq_u32 s66, 0
1187+
s_cbranch_scc0 .Lcmp_cooldn // Task 4: s66!=0 -> in cooldown, skip decision
1188+
.endif
1189+
.if DSWS2_FORCE
1190+
.if DSWS2_FORCE_DIR == 0 || DSWS2_FORCE_DIR == 1
1191+
// Task 5: deterministic forced conversion (compute is the source role for dir 0 and dir 1).
1192+
// Watermark bypassed: convert iff wid(s24)==DSWS2_FORCE_WID AND current epoch(s35)==
1193+
// DSWS2_FORCE_EPOCH. try_gate still runs (sets s58=s_win, conv_apply's precondition).
1194+
s_mov_b32 s58, 0 // s_win = 0 default (compares below may bail early)
1195+
s_cmp_eq_u32 s24, DSWS2_FORCE_WID
1196+
s_cbranch_scc0 .Lcmp_cooldn
1197+
s_cmp_eq_u32 s35, DSWS2_FORCE_EPOCH
1198+
s_cbranch_scc0 .Lcmp_cooldn
1199+
.if DSWS2_FORCE_DIR == 0
1200+
s_mov_b32 s57, 0 // dir 0: compute -> A-feed (forced)
1201+
try_gate 0, s58
1202+
conv_apply NCOMP_SLOT, NAFEED_SLOT, -(NFV-VLEAN), 32
1203+
.else
1204+
s_mov_b32 s57, 1 // dir 1: compute -> B-feed (forced)
1205+
try_gate 1, s58
1206+
conv_apply NCOMP_SLOT, NBFEED_SLOT, -(NFV-VLEAN), 32
1207+
.endif
1208+
.endif
1209+
.else
10781210
s_mov_b32 s58, 0 // s_win = 0 (default: raced no ticket)
10791211
occ_sample s55, s56 // s55=occ_A in [0,G], s56=occ_B in [0,FN] (clob s60,s61)
10801212
s_cmp_lt_u32 s55, CTRL_LOW
10811213
s_cbranch_scc0 .Lcmp_try_b
10821214
s_mov_b32 s57, 0 // dir 0: compute -> A-feed
10831215
try_gate 0, s58 // s58 = s_win (single-winner per (dir,epoch))
10841216
conv_apply NCOMP_SLOT, NAFEED_SLOT, -(NFV-VLEAN), 32
1085-
s_branch .Lcmp_quiesce
1217+
s_branch .Lcmp_cooldn
10861218
.Lcmp_try_b:
10871219
s_cmp_lt_u32 s56, CTRL_LOW
1088-
s_cbranch_scc0 .Lcmp_quiesce
1220+
s_cbranch_scc0 .Lcmp_cooldn
10891221
s_mov_b32 s57, 1 // dir 1: compute -> B-feed
10901222
try_gate 1, s58
10911223
conv_apply NCOMP_SLOT, NBFEED_SLOT, -(NFV-VLEAN), 32
1224+
.endif
1225+
.Lcmp_cooldn:
1226+
.if CONV_COOLDOWN > 0
1227+
s_cmp_eq_u32 s66, 0 // Task 4: decrement once per epoch (saturating)
1228+
s_cbranch_scc1 .Lcmp_quiesce
1229+
s_sub_i32 s66, s66, 1
1230+
.endif
10921231
.Lcmp_quiesce:
10931232
// ORDERING (SPEC 3.4 decision 2): the commit above fully completed (role-slot CAS + reservation +
10941233
// s_alloc_vgpr) BEFORE this QUIESCE_CNT bump -- the bump is the snapshot handshake the claimer reads.
10951234
lds_fetch_add s61, QUIESCE_CNT_OFF, 1 // exactly one bump per non-claimer wave / super-tile
10961235
.endif
1236+
.if DSWS2_CONV
1237+
s_branch .Ldispatch
1238+
.else
10971239
s_branch .Lcompute_follow // this super-tile's compute drained -> re-check epoch/terminal
1240+
.endif
1241+
1242+
.if DSWS2_CONV
1243+
// ============================================================================================
1244+
// Universal role dispatcher (Task 3): scalar-only trampoline. Reads the role register s59
1245+
// (seeded at entry / flipped by conv_apply on a role conversion) and branches to the matching
1246+
// role's per-epoch _follow loop. Lands on _follow (NOT _alloc/_init): the wave's VGPR footprint
1247+
// is already correct (seed or conv_apply set it) and INIT already ran once -- re-entering
1248+
// _alloc would wrongly resize, and _init would deadlock on the already-consumed INITFLAG.
1249+
// s35 (last-seen-epoch) is untouched here, which is what makes a re-dispatched wave wait for
1250+
// the NEXT epoch at the top of its new role's _follow loop. Scalar-only (s59 read + s_branch) ->
1251+
// adds ZERO OOR/VGPR exposure.
1252+
// ============================================================================================
1253+
.Ldispatch:
1254+
s_cmp_eq_u32 s59, NCOMP_SLOT
1255+
s_cbranch_scc1 .Lcompute_follow
1256+
s_cmp_eq_u32 s59, NAFEED_SLOT
1257+
s_cbranch_scc1 .Lafeed_follow
1258+
s_branch .Lbfeed_follow
1259+
.endif
10981260

10991261
// ---- A7 role-agnostic terminal (followers): retire. (Claimer retires via .Lclaimer_terminal.) ----
11001262
.Lretire:

ggml/src/ggml-cuda/aiter-integration/rdna4_fp8_gemm/spike/dvgpr_occ/test_dsws_ctrl_model.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,20 @@ int main() {
8181
}
8282
}
8383

84+
// ---- Task 1: dispatch + cooldown + pool invariants ----
85+
assert(role_dispatch(24) == COMPUTE);
86+
assert(role_dispatch(28) == AFEED);
87+
assert(role_dispatch(32) == BFEED);
88+
// cooldown counts down and saturates at 0; in_cooldown true iff >0
89+
assert(cooldown_step(3) == 2 && cooldown_step(1) == 0 && cooldown_step(0) == 0);
90+
assert(in_cooldown(1) && !in_cooldown(0));
91+
// no-parking budget invariant: 16 lean waves fit iff budget >= 512
92+
assert( pool_fits_lean(16, 32, 512));
93+
assert(!pool_fits_lean(16, 32, 511));
94+
// quiesce cross-check generalizes WAVES-1 -> N_POOL-1
95+
assert( quiesce_ready_pool(11, 12) && !quiesce_ready_pool(10, 12));
96+
printf("dsws_ctrl_model: dispatch/cooldown/pool OK\n");
97+
8498
printf("dsws_ctrl_model: ALL PASS\n");
8599
return 0;
86100
}

0 commit comments

Comments
 (0)