Skip to content

Commit 63abcd3

Browse files
committed
Improve adaptive DFlash draft depth selection
1 parent 80fd61b commit 63abcd3

2 files changed

Lines changed: 340 additions & 70 deletions

File tree

tests/test-adaptive-dm.cpp

Lines changed: 103 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -65,21 +65,30 @@ int main() {
6565

6666
{
6767
server_adaptive_dm_state explore;
68-
assert(explore.profit_explore_depth_for_step(15, 15, 1) == 1);
69-
assert(explore.profit_explore_depth_for_step(15, 15, 2) == 2);
70-
assert(explore.profit_explore_depth_for_step(15, 15, 3) == 3);
71-
assert(explore.profit_explore_depth_for_step(15, 15, 4) == 4);
72-
assert(explore.profit_explore_depth_for_step(15, 15, 14) == 14);
73-
assert(explore.profit_explore_depth_for_step(15, 15, 15) == 1);
74-
assert(explore.profit_explore_depth_for_step(8, 15, 1) == 9);
75-
assert(explore.profit_explore_depth_for_step(8, 15, 7) == 15);
76-
assert(explore.profit_explore_depth_for_step(8, 15, 8) == 1);
68+
assert(explore.profit_explore_depth_for_step(15, 15, 1) == 14);
69+
assert(explore.profit_explore_depth_for_step(15, 15, 2) == 13);
70+
assert(explore.profit_explore_depth_for_step(15, 15, 3) == 12);
71+
assert(explore.profit_explore_depth_for_step(15, 15, 4) == 11);
72+
assert(explore.profit_explore_depth_for_step(15, 15, 5) == 10);
73+
assert(explore.profit_explore_depth_for_step(15, 15, 8) == 14);
74+
assert(explore.profit_explore_depth_for_step(8, 15, 1) == 7);
75+
assert(explore.profit_explore_depth_for_step(8, 15, 2) == 9);
76+
assert(explore.profit_explore_depth_for_step(8, 15, 7) == 4);
77+
78+
int active_order[SERVER_ADAPTIVE_DM_PROFIT_CANDIDATES];
79+
const int n_active = explore.profit_active_explore_depths(
80+
15, 15, active_order, SERVER_ADAPTIVE_DM_PROFIT_CANDIDATES);
81+
assert(n_active > 0);
82+
assert(n_active <= 7);
83+
for (int i = 0; i < n_active; ++i) {
84+
assert(active_order[i] >= 4);
85+
}
7786
}
7887

7988
{
8089
server_adaptive_dm_state explore_ready;
8190
explore_ready.dm_profit_min_samples = 1;
82-
assert(explore_ready.profit_next_unready_explore_depth(10, 15, 1) == 11);
91+
assert(explore_ready.profit_next_unready_explore_depth(10, 15, 1) == 9);
8392
const int ready_depths[] = {1, 2, 3, 4, 5, 6, 7, 8,
8493
9, 10, 11, 12, 13, 14, 15};
8594
for (const int depth : ready_depths) {
@@ -90,6 +99,45 @@ int main() {
9099
assert(explore_ready.profit_next_unready_explore_depth(10, 15, 1) == 0);
91100
}
92101

102+
{
103+
server_adaptive_dm_state strong_max;
104+
strong_max.dm_profit_min_samples = 1;
105+
strong_max.adaptive_n_max = 15;
106+
strong_max.profit_last_recommended_n = 15;
107+
108+
strong_max.observe_profit_timing(0, 0, 0, 0.0f, 30.0f, 0.0f, 30.0f);
109+
for (int i = 0; i < 6; ++i) {
110+
observe_profit_cycle(strong_max, 15, 15, 10, 60.0f);
111+
}
112+
assert(strong_max.profit_next_unready_explore_depth(15, 15, 1) == 0);
113+
}
114+
115+
{
116+
server_adaptive_dm_state weak_max;
117+
weak_max.dm_profit_min_samples = 1;
118+
weak_max.adaptive_n_max = 15;
119+
weak_max.profit_last_recommended_n = 15;
120+
121+
weak_max.observe_profit_timing(0, 0, 0, 0.0f, 30.0f, 0.0f, 30.0f);
122+
for (int i = 0; i < 6; ++i) {
123+
observe_profit_cycle(weak_max, 15, 15, 1, 95.0f);
124+
}
125+
assert(weak_max.profit_next_unready_explore_depth(15, 15, 1) == 14);
126+
}
127+
128+
{
129+
server_adaptive_dm_state strong_mid;
130+
strong_mid.dm_profit_min_samples = 1;
131+
strong_mid.adaptive_n_max = 8;
132+
strong_mid.profit_last_recommended_n = 8;
133+
134+
strong_mid.observe_profit_timing(0, 0, 0, 0.0f, 30.0f, 0.0f, 30.0f);
135+
for (int i = 0; i < 6; ++i) {
136+
observe_profit_cycle(strong_mid, 8, 8, 7, 50.0f);
137+
}
138+
assert(strong_mid.profit_next_unready_explore_depth(8, 15, 1) == 9);
139+
}
140+
93141
{
94142
server_adaptive_dm_state initial_large;
95143
initial_large.dm_profit_min_samples = 1;
@@ -761,9 +809,39 @@ int main() {
761809

762810
assert(preserved_challenger.decide_profit_n_max(15) == 15);
763811
observe_profit_cycle(preserved_challenger, 12, 12, 10, 70.0f);
812+
assert(preserved_challenger.decide_profit_n_max(15) == 15);
813+
for (int i = 0; i < 5; ++i) {
814+
observe_profit_cycle(preserved_challenger, 12, 12, 10, 70.0f);
815+
}
764816
assert(preserved_challenger.decide_profit_n_max(15) == 13);
765817
}
766818

819+
// A preserved max-depth run must actively collect fresh local challenger
820+
// evidence. Stale global stats can rank a lower challenger, but they cannot
821+
// replace a same-request probe, and active mode should not sweep the low end.
822+
{
823+
server_adaptive_dm_state preserved_probe;
824+
preserved_probe.dm_profit_min_samples = 1;
825+
preserved_probe.adaptive_n_max = 15;
826+
preserved_probe.profit_last_recommended_n = 15;
827+
preserved_probe.profit_has_key = true;
828+
preserved_probe.profit_key = {};
829+
preserved_probe.profit_key.base_n_max = 15;
830+
831+
preserved_probe.observe_profit_timing(0, 0, 0, 0.0f, 30.0f, 0.0f, 30.0f);
832+
observe_profit_cycle(preserved_probe, 12, 12, 10, 70.0f);
833+
observe_profit_cycle(preserved_probe, 15, 15, 10, 90.0f);
834+
835+
preserved_probe.reset_request_state(true);
836+
assert(preserved_probe.profit_next_unready_explore_depth(15, 15, 1) == 14);
837+
observe_profit_cycle(preserved_probe, 14, 14, 10, 70.0f);
838+
assert(preserved_probe.profit_next_unready_explore_depth(15, 15, 1) == 14);
839+
for (int i = 0; i < 5; ++i) {
840+
observe_profit_cycle(preserved_probe, 14, 14, 10, 70.0f);
841+
}
842+
assert(preserved_probe.profit_next_unready_explore_depth(15, 15, 1) == 13);
843+
}
844+
767845
// test lower acceptance can still be faster; controller must optimize TPS,
768846
// not raw acceptance rate.
769847
{
@@ -988,34 +1066,37 @@ int main() {
9881066
assert(recent_acceptance.decide_profit_n_max(15) == 10);
9891067
}
9901068

991-
// Off-state probes must sweep through every low-end depth before backing
992-
// off, so a marginal prompt can still discover depth 1/2/3 instead of
993-
// treating depth 4 as the minimum viable speculative horizon.
1069+
// Off-state probes should try useful anchors first, then fill nearby low
1070+
// depths. Dense candidate scoring is separate; recovery probes should not
1071+
// spend an entire sweep walking 1,2,3,... before testing the known productive
1072+
// mid/high range.
9941073
{
9951074
server_adaptive_dm_state sweep;
9961075
sweep.dm_profit_min_samples = 1;
9971076
sweep.dm_probe_interval = 4;
9981077
sweep.adaptive_n_max = 0;
9991078
sweep.observe_profit_timing(0, 0, 0, 0.0f, 30.0f, 0.0f, 30.0f);
10001079

1001-
assert(sweep.profit_next_off_probe_depth(15, 3) == 1);
1002-
for (int depth = 1; depth <= 14; ++depth) {
1080+
const int expected_order[] = {4, 8, 12, 15, 2, 3, 1, 5, 7, 9, 11, 13, 14, 6, 10};
1081+
for (int i = 0; i < 14; ++i) {
1082+
const int depth = expected_order[i];
1083+
assert(sweep.profit_next_off_probe_depth(15, 3) == depth);
10031084
observe_profit_cycle(sweep, depth, depth, 0, 60.0f + (float) depth);
10041085
sweep.profit_note_off_probe_result(depth, 15, false);
1005-
assert(sweep.profit_next_off_probe_depth(15, 3) == depth + 1);
1086+
assert(sweep.profit_next_off_probe_depth(15, 3) == expected_order[i + 1]);
10061087
assert(sweep.profit_off_probe_failures == 0);
10071088
assert(sweep.profit_off_probe_interval() == 4);
10081089
}
10091090

1010-
observe_profit_cycle(sweep, 15, 15, 0, 80.0f);
1011-
sweep.profit_note_off_probe_result(15, 15, false);
1012-
assert(sweep.profit_next_off_probe_depth(15, 3) == 1);
1091+
observe_profit_cycle(sweep, expected_order[14], expected_order[14], 0, 80.0f);
1092+
sweep.profit_note_off_probe_result(expected_order[14], 15, false);
1093+
assert(sweep.profit_next_off_probe_depth(15, 3) == expected_order[0]);
10131094
assert(sweep.profit_off_probe_failures == 1);
10141095
assert(sweep.profit_off_probe_interval() == 8);
10151096

1016-
sweep.profit_note_off_probe_result(1, 15, true);
1097+
sweep.profit_note_off_probe_result(expected_order[0], 15, true);
10171098
assert(sweep.profit_off_probe_failures == 0);
1018-
assert(sweep.profit_next_off_probe_depth(15, 3) == 1);
1099+
assert(sweep.profit_next_off_probe_depth(15, 3) == expected_order[0]);
10191100
}
10201101

10211102
// Failed wake probes advance the off-state sweep instead of retrying the
@@ -1034,7 +1115,7 @@ int main() {
10341115
assert(failed.profit_off_probe_interval() == 4);
10351116
assert(failed.decide_profit_n_max(8) == 0);
10361117
assert(failed.profit_off_probe_failures == 0);
1037-
assert(failed.profit_next_off_probe_depth(8, 2) == 5);
1118+
assert(failed.profit_next_off_probe_depth(8, 2) == 8);
10381119
assert(failed.profit_off_probe_interval() == 4);
10391120
}
10401121

0 commit comments

Comments
 (0)