@@ -144,169 +144,14 @@ static std::tuple<int, int> get_block_config_for_mega_moe_sm90_fp4(
144144 return {block_m, num_epilogue_warpgroups * 128 };
145145}
146146
147- struct FP4SM90WaveRule {
148- float min_tokens_per_expert;
149- float max_tokens_per_expert;
150- bool include_min;
151- int required_expert_divisor;
152- int num_experts_per_wave;
153- };
154-
155- enum class FP4SM90StageShape {
156- Any,
157- Flash,
158- Pro,
159- NotPro,
160- };
161-
162- struct FP4SM90StageCapRule {
163- float min_tokens_per_expert;
164- float max_tokens_per_expert;
165- bool include_min;
166- bool include_max;
167- FP4SM90StageShape shape;
168- int num_stages_cap;
169- };
170-
171- static bool try_get_num_experts_per_wave_for_sm90_fp4 (
172- const FP4SM90WaveRule* rules, const int & num_rules,
173- const float & expected_tokens_per_expert, const int & num_experts_per_rank,
174- int & num_experts_per_wave) {
175- for (int i = 0 ; i < num_rules; ++ i) {
176- const auto & rule = rules[i];
177- const bool in_lower_bound = rule.include_min
178- ? expected_tokens_per_expert >= rule.min_tokens_per_expert
179- : expected_tokens_per_expert > rule.min_tokens_per_expert ;
180- if (!in_lower_bound or expected_tokens_per_expert >= rule.max_tokens_per_expert )
181- continue ;
182-
183- if (rule.num_experts_per_wave == 0 ) {
184- if (num_experts_per_rank <= 0 )
185- continue ;
186- num_experts_per_wave = num_experts_per_rank;
187- return true ;
188- }
189- DG_HOST_ASSERT (rule.required_expert_divisor > 0 );
190- if (num_experts_per_rank % rule.required_expert_divisor == 0 ) {
191- num_experts_per_wave = rule.num_experts_per_wave ;
192- return true ;
193- }
194- }
195- return false ;
196- }
197-
198- static bool fp4_sm90_stage_shape_matches (
199- const FP4SM90StageShape& shape, const bool & fp4_flash_shape, const bool & fp4_pro_shape) {
200- switch (shape) {
201- case FP4SM90StageShape::Any:
202- return true ;
203- case FP4SM90StageShape::Flash:
204- return fp4_flash_shape;
205- case FP4SM90StageShape::Pro:
206- return fp4_pro_shape;
207- case FP4SM90StageShape::NotPro:
208- return !fp4_pro_shape;
209- }
210- DG_HOST_ASSERT (false );
211- return false ;
212- }
213-
214- static int get_default_num_stages_cap_for_mega_moe_sm90_fp4 (
215- const int & intermediate_hidden, const int & block_m, const int & block_n,
216- const float & expected_tokens_per_expert) {
217- if (!(block_m == 64 and block_n == 128 )) {
218- return 0 ;
219- }
220-
221- const bool fp4_flash_shape = intermediate_hidden <= 2048 ;
222- const bool fp4_pro_shape = intermediate_hidden >= 3072 ;
223- // Ordered first-match rules preserve the historical stage-cap priority.
224- static constexpr FP4SM90StageCapRule stage_cap_rules[] = {
225- {6 .0f , 12 .0f , true , false , FP4SM90StageShape::Flash, 4 },
226- {3 .0f , 6 .0f , false , false , FP4SM90StageShape::Flash, 4 },
227- {0 .0f , 0 .25f , false , false , FP4SM90StageShape::Pro, 5 },
228- {0 .375f , 0 .75f , true , false , FP4SM90StageShape::Pro, 5 },
229- {1 .5f , 3 .0f , true , false , FP4SM90StageShape::Pro, 5 },
230- {1 .0f , 1 .5f , true , false , FP4SM90StageShape::Pro, 5 },
231- {24 .0f , 64 .0f , true , false , FP4SM90StageShape::Pro, 5 },
232- {0 .375f , 0 .75f , true , false , FP4SM90StageShape::Any, 6 },
233- {3 .0f , 6 .0f , false , false , FP4SM90StageShape::Flash, 6 },
234- {1 .5f , 3 .0f , true , false , FP4SM90StageShape::NotPro, 6 },
235- {1 .5f , 24 .0f , true , true , FP4SM90StageShape::Any, 5 },
236- };
237- for (const auto & rule: stage_cap_rules) {
238- const bool in_lower_bound = rule.include_min
239- ? expected_tokens_per_expert >= rule.min_tokens_per_expert
240- : expected_tokens_per_expert > rule.min_tokens_per_expert ;
241- const bool in_upper_bound = rule.include_max
242- ? expected_tokens_per_expert <= rule.max_tokens_per_expert
243- : expected_tokens_per_expert < rule.max_tokens_per_expert ;
244- if (in_lower_bound and in_upper_bound and
245- fp4_sm90_stage_shape_matches (rule.shape , fp4_flash_shape, fp4_pro_shape)) {
246- return rule.num_stages_cap ;
247- }
248- }
249- return 0 ;
250- }
251-
252147static int get_num_experts_per_wave_for_mega_moe_sm90_fp4 (
253148 const int & num_experts_per_rank, const int & num_tokens, const int & num_topk,
254149 const int & intermediate_hidden, const int & block_m, const int & block_n, const int & num_sms,
255150 const int & num_ring_tokens, const int & num_max_tokens_per_rank, const int & num_ranks) {
256- const float expected_tokens_per_expert =
257- static_cast <float >(num_tokens) * num_topk / num_experts_per_rank;
258- const bool fp4_small_block_n_kernel =
259- block_m == 64 and block_n == 128 ;
260- const bool fp4_flash_shape = intermediate_hidden <= 2048 ;
261- const bool fp4_pro_shape = intermediate_hidden >= 3072 ;
262- int fp4_num_experts_per_wave = 0 ;
263- if (fp4_small_block_n_kernel and fp4_flash_shape) {
264- static constexpr FP4SM90WaveRule flash_wave_rules[] = {
265- {0 .75f , 1 .0f , true , 16 , 16 },
266- {1 .5f , 2 .0f , true , 16 , 16 },
267- {3 .0f , 6 .0f , true , 16 , 16 },
268- {6 .0f , 12 .0f , true , 32 , 32 },
269- {6 .0f , 12 .0f , true , 8 , 8 },
270- {24 .0f , 32 .0f , true , 16 , 16 },
271- {12 .0f , 24 .0f , true , 32 , 32 },
272- {12 .0f , 24 .0f , true , 8 , 8 },
273- {32 .0f , 64 .0f , true , 16 , 16 },
274- };
275- if (try_get_num_experts_per_wave_for_sm90_fp4 (
276- flash_wave_rules,
277- static_cast <int >(sizeof (flash_wave_rules) / sizeof (flash_wave_rules[0 ])),
278- expected_tokens_per_expert, num_experts_per_rank,
279- fp4_num_experts_per_wave)) {
280- return fp4_num_experts_per_wave;
281- }
282- }
283- if (fp4_small_block_n_kernel and fp4_pro_shape) {
284- static constexpr FP4SM90WaveRule pro_wave_rules[] = {
285- {0 .0f , 0 .25f , false , 16 , 16 },
286- {0 .25f , 0 .375f , true , 16 , 16 },
287- {0 .375f , 0 .75f , true , 16 , 16 },
288- {0 .25f , 1 .0f , true , 24 , 24 },
289- {1 .0f , 1 .5f , true , 1 , 0 },
290- {1 .5f , 3 .0f , true , 16 , 16 },
291- {3 .0f , 6 .0f , true , 8 , 8 },
292- {6 .0f , 12 .0f , true , 16 , 16 },
293- {6 .0f , 12 .0f , true , 8 , 8 },
294- {12 .0f , 24 .0f , true , 24 , 24 },
295- {12 .0f , 24 .0f , true , 8 , 8 },
296- {24 .0f , 64 .0f , true , 8 , 8 },
297- };
298- if (try_get_num_experts_per_wave_for_sm90_fp4 (
299- pro_wave_rules,
300- static_cast <int >(sizeof (pro_wave_rules) / sizeof (pro_wave_rules[0 ])),
301- expected_tokens_per_expert, num_experts_per_rank,
302- fp4_num_experts_per_wave)) {
303- return fp4_num_experts_per_wave;
304- }
305- }
306- if (expected_tokens_per_expert < 1 .0f or expected_tokens_per_expert > 4 .0f ) {
307- return num_experts_per_rank;
308- }
309- return get_num_experts_per_wave_for_mega_moe (
151+ // Simplified: schedule FP4 expert waves exactly like the FP8 path. The
152+ // historical flash/pro wave tables (9 + 12 first-match rules) were tuned
153+ // point-by-point on benchmark batches and are retired.
154+ return get_num_experts_per_wave_for_mega_moe_sm90 (
310155 num_experts_per_rank, num_tokens, num_topk,
311156 intermediate_hidden, block_m, block_n, num_sms,
312157 num_ring_tokens, num_max_tokens_per_rank, num_ranks);
@@ -319,7 +164,6 @@ static std::pair<int, int> get_pipeline_config_for_mega_moe_sm90_fp4(
319164 const int & num_dispatch_warps, const int & num_epilogue_warps,
320165 const bool & use_early_b_decode = false ,
321166 const bool & use_decode_done_mbarrier = false ,
322- const int & default_num_stages_cap = 0 ,
323167 const bool & use_swap_ab = false ,
324168 const bool & use_swap_ab_fast_amax = false ) {
325169 constexpr int kSmemAlignment = 1024 ;
@@ -380,12 +224,10 @@ static std::pair<int, int> get_pipeline_config_for_mega_moe_sm90_fp4(
380224 const int smem_fixed =
381225 smem_dispatch_size + smem_cd + smem_amax_scratch + smem_barriers_fixed;
382226
383- const int max_num_stages = (smem_capacity - smem_fixed) /
384- (smem_per_stage + smem_barriers_per_stage);
385- int num_stages = max_num_stages;
386- if (default_num_stages_cap > 0 ) {
387- num_stages = std::min (num_stages, default_num_stages_cap);
388- }
227+ // No FP4 stage cap (FP8 parity): always use as many pipeline stages as
228+ // SMEM allows. The historical 11-rule cap table is retired.
229+ const int num_stages = (smem_capacity - smem_fixed) /
230+ (smem_per_stage + smem_barriers_per_stage);
389231 DG_HOST_ASSERT (num_stages >= 2 );
390232 return {num_stages,
391233 smem_fixed + num_stages * (smem_per_stage + smem_barriers_per_stage)};
@@ -461,15 +303,12 @@ static MegaMoESM90Config get_mega_moe_config_sm90_fp4(
461303 num_non_epilogue_threads % 64 == 0 );
462304 DG_HOST_ASSERT ((num_dispatch_threads + num_non_epilogue_threads) % 128 == 0 );
463305
464- const int default_num_stages_cap = get_default_num_stages_cap_for_mega_moe_sm90_fp4 (
465- intermediate_hidden, block_m, block_n, expected_tokens_per_expert);
466-
467306 const auto [num_stages, smem_size] = get_pipeline_config_for_mega_moe_sm90_fp4 (
468307 SM90ArchSpec::smem_capacity,
469308 num_experts, hidden,
470309 block_m, block_n, block_k,
471310 num_dispatch_threads / 32 , fp4_num_epilogue_threads / 32 ,
472- use_early_b_decode, use_decode_done_mbarrier, default_num_stages_cap,
311+ use_early_b_decode, use_decode_done_mbarrier,
473312 use_swap_ab, use_swap_ab_fast_amax);
474313
475314 const auto config = MegaMoESM90Config {
0 commit comments