From 3d39b8190f3d90df8600825da603fc02ba704967 Mon Sep 17 00:00:00 2001 From: Aditya Lohia Date: Fri, 17 Apr 2026 10:03:24 -0700 Subject: [PATCH] Fix MXR cache hash collision in MIGraphX EP Two bugs in the cache hash computation cause different input shape configurations (prefill vs decode) to produce identical .mxr cache filenames, leading to unnecessary recompilations. Bug 1: make_hash uses element count instead of byte count. MurmurHash3::x86_128 expects byte length but receives v.size() (element count). For vector, only the first N bytes are hashed instead of N*8, causing shapes like {1,256} and {1,1} to collide. Bug 2: Inconsistent hash iteration in handle_input_shape. The defer_compilation path iterates map_input_name_index (all inputs). The else path iterates param_shapes.names() (current program params, potentially a subset). Different set produces different hash for identical input shapes, preventing cache reuse across prompts. Fix: Use v.size() * sizeof(*v.data()) for byte count. Move input_shapes population to a separate loop over map_input_name_index, consistent with the defer_compilation path. --- .../migraphx/migraphx_execution_provider.cc | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/onnxruntime/core/providers/migraphx/migraphx_execution_provider.cc b/onnxruntime/core/providers/migraphx/migraphx_execution_provider.cc index 5ced07d0a032c..530c69244ba4e 100644 --- a/onnxruntime/core/providers/migraphx/migraphx_execution_provider.cc +++ b/onnxruntime/core/providers/migraphx/migraphx_execution_provider.cc @@ -1771,7 +1771,7 @@ std::string to_hex(const uint64_t v) { template std::string make_hash(T v) { std::array temp{}; - MurmurHash3::x86_128(v.data(), gsl::narrow_cast(v.size()), temp[0], temp.data()); + MurmurHash3::x86_128(v.data(), gsl::narrow_cast(v.size() * sizeof(*v.data())), temp[0], temp.data()); return to_hex(temp[0] | static_cast(temp[1]) << 32); } @@ -2722,12 +2722,20 @@ static InputShapeResult handle_input_shape( cmp_options.set_input_parameter_shape(name, ort_lens); input_shape_match = false; } - - // Include all inputs in cache key (map_input_name_index already filtered to model inputs only) - input_shapes.insert(input_shapes.end(), tensor_shape.begin(), tensor_shape.end()); } } } + + // Compute hash over all model inputs, consistent with the defer_compilation path. + // The shape comparison above iterates param_shapes.names() which may be a subset + // of map_input_name_index. Using map_input_name_index ensures the cache key is + // identical for identical input shapes regardless of which program is currently active. + for (const auto& [name, index] : map_input_name_index) { + auto input_tensor = ctx.GetInput(index); + auto tensor_info = input_tensor.GetTensorTypeAndShapeInfo(); + const auto tensor_shape = tensor_info.GetShape(); + input_shapes.insert(input_shapes.end(), tensor_shape.begin(), tensor_shape.end()); + } } return {input_shape_match, param_shapes, input_shapes};