@@ -833,6 +833,19 @@ Tensor {{ embedding_cuda_op }}(
833833#endif
834834 const int used_shared_bytes = used_shared_kb << 10 ;
835835
836+ #ifdef USE_ROCM
837+ {%- if enable_optimized_hip_mixed_D_kernel %}
838+ const bool use_hip_kernel_flag = fbgemm_gpu::config::is_feature_enabled (
839+ fbgemm_gpu::config::FeatureGateName::TBE_ROCM_HIP_BACKWARD_KERNEL );
840+ // Declared here so the dispatch lambdas below can capture it.
841+ // Populated from the pinned buffer after transpose_embedding_input().
842+ struct NumUniqueEntry { at::Tensor pinned_buf; };
843+ static thread_local std::unordered_map<const void *, NumUniqueEntry>
844+ s_num_unique_cache;
845+ int64_t num_unique_prev = 0 ;
846+ {%- endif %}
847+ #endif // USE_ROCM
848+
836849 Tensor linear_indices, linear_indices_sorted, infos_sorted,
837850 sorted_linear_indices_run, sorted_linear_indices_run_lengths,
838851 sorted_linear_indices_num_runs,
@@ -865,6 +878,31 @@ Tensor {{ embedding_cuda_op }}(
865878 {%- endif %}
866879 );
867880
881+ #ifdef USE_ROCM
882+ {%- if enable_optimized_hip_mixed_D_kernel %}
883+ if (use_hip_kernel_flag) {
884+ auto & entry = s_num_unique_cache[hash_size_cumsum.data_ptr ()];
885+ if (entry.pinned_buf .defined ()) {
886+ // Read the exact num_unique from the previous backward call.
887+ num_unique_prev =
888+ static_cast <int64_t >(entry.pinned_buf .data_ptr <int32_t >()[0 ]);
889+ } else {
890+ // First call: allocate pinned buffer.
891+ entry.pinned_buf = at::empty (
892+ {1 },
893+ at::TensorOptions ()
894+ .dtype (at::kInt )
895+ .device (at::kCPU )
896+ .pinned_memory (true ));
897+ }
898+ // Schedule async D2H copy for the next backward call.
899+ entry.pinned_buf .copy_ (
900+ sorted_linear_indices_num_runs.slice (0 , 0 , 1 ),
901+ /* non_blocking=*/ true );
902+ }
903+ {%- endif %}
904+ #endif // USE_ROCM
905+
868906 {%- if not dense %}
869907 Tensor {{ locs_or_addrs_tensor }}_sorted = {{ locs_or_addrs_tensor }};
870908 Tensor table_unique_indices_offsets;
@@ -1348,15 +1386,13 @@ Tensor {{ embedding_cuda_op }}(
13481386 // condition 'use_hip_kernel' is True and "is_optimized_hip_kernel_supported_mode" is True. If no optimization is available for current
13491387 // condition , it will fallback to the default kernel.
13501388 {%- if vbe %}
1351- // Apply the same avg_SL threshold as the non-VBE mixed_D path.
13521389 if (use_hip_kernel &&
1353- total_L <= 2 * static_cast <int64_t >(sorted_linear_indices_num_runs[0 ].item <int32_t >())) {
1390+ num_unique_prev > 0 &&
1391+ total_L <= 2 * num_unique_prev) {
13541392 {%- else %}
1355- // Use hip_mixed_d only when avg segment length <= 2
1356- // (total_L / num_unique_rows <= 2), i.e. when the momentum preload
1357- // benefit outweighs the serial inner-loop serialization cost.
13581393 if (use_hip_kernel && mixed_D &&
1359- total_L <= 2 * static_cast <int64_t >(sorted_linear_indices_num_runs[0 ].item <int32_t >())) {
1394+ num_unique_prev > 0 &&
1395+ total_L <= 2 * num_unique_prev) {
13601396 {%- endif %}
13611397 backward_warp_per_row_kernel =
13621398 {{ hip_mixed_d_warp_kernel }}
0 commit comments