diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4b18a01803d..87b8d29e9b6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -57,6 +57,7 @@ add_library(migraphx color.cpp common.cpp common_dims.cpp + compile_modes.cpp compile_src.cpp convert_to_json.cpp convolution.cpp @@ -457,5 +458,3 @@ rocm_export_targets( Threads ${MIGRAPHX_CONFIG_DEPENDS} ) - - diff --git a/src/api/api.cpp b/src/api/api.cpp index 736a594f396..0ab1597c715 100644 --- a/src/api/api.cpp +++ b/src/api/api.cpp @@ -190,6 +190,11 @@ static void set_exhaustive_tune_flag(compile_options& options, bool value) options.exhaustive_tune = value; } +static void set_compile_mode(compile_options& options, int8_t value) +{ + options.compile_mode = convert_to_compile_mode(value); +} + // Parse the backend options from `options_json` and merge them into the // compile options. See migraphx::set_backend_options for the merge semantics. static void set_backend_options(compile_options& options, const char* options_json, va_list vlist) @@ -2376,6 +2381,18 @@ migraphx_compile_options_set_exhaustive_tune_flag(migraphx_compile_options_t com return api_error_result; } +extern "C" migraphx_status +migraphx_compile_options_set_compile_mode(migraphx_compile_options_t compile_options, int8_t value) +{ + auto api_error_result = migraphx::try_([&] { + if(compile_options == nullptr) + MIGRAPHX_THROW(migraphx_status_bad_param, + "Bad parameter compile_options: Null pointer"); + migraphx::set_compile_mode((compile_options->object), (value)); + }); + return api_error_result; +} + extern "C" migraphx_status migraphx_compile_options_set_advance_backend_options( migraphx_compile_options_t compile_options, const char* options_json, ...) { diff --git a/src/api/include/migraphx/migraphx.h b/src/api/include/migraphx/migraphx.h index dfaf666f0d6..40eab1e8e02 100644 --- a/src/api/include/migraphx/migraphx.h +++ b/src/api/include/migraphx/migraphx.h @@ -76,6 +76,14 @@ typedef enum } migraphx_shape_datatype_t; #undef MIGRAPHX_SHAPE_GENERATE_ENUM_TYPES +typedef enum +{ + migraphx_compile_mode_eager = 0, + migraphx_compile_mode_balanced = 50, + migraphx_compile_mode_max = 100, + +} migraphx_compile_mode; + typedef struct migraphx_optimals* migraphx_optimals_t; typedef const struct migraphx_optimals* const_migraphx_optimals_t; @@ -627,6 +635,9 @@ migraphx_compile_options_set_fast_math(migraphx_compile_options_t compile_option MIGRAPHX_C_EXPORT migraphx_status migraphx_compile_options_set_exhaustive_tune_flag( migraphx_compile_options_t compile_options, bool value); +MIGRAPHX_C_EXPORT migraphx_status +migraphx_compile_options_set_compile_mode(migraphx_compile_options_t compile_options, int8_t value); + MIGRAPHX_C_EXPORT migraphx_status migraphx_compile_options_set_advance_backend_options( migraphx_compile_options_t compile_options, const char* options_json, ...); diff --git a/src/api/include/migraphx/migraphx.hpp b/src/api/include/migraphx/migraphx.hpp index 45030944b7d..5b22a493c7b 100644 --- a/src/api/include/migraphx/migraphx.hpp +++ b/src/api/include/migraphx/migraphx.hpp @@ -1247,6 +1247,12 @@ struct compile_options : MIGRAPHX_HANDLE_BASE(compile_options) call(&migraphx_compile_options_set_exhaustive_tune_flag, this->get_handle_ptr(), value); } + /// Set compilation mode (0-100). 0 = fast compile, low performance. + /// 100 = best compile with max optimizations, best performance. + void set_compile_mode(int8_t value = migraphx_compile_mode_balanced) + { + call(&migraphx_compile_options_set_compile_mode, this->get_handle_ptr(), value); + } /// Set backend-specific options that targets can read to configure /// compilation. `json_str` is a relaxed JSON object (bare identifiers are /// treated as strings) and accepts printf-style format specifiers followed diff --git a/src/api/migraphx.py b/src/api/migraphx.py index 40b557d3051..d92ac7ff643 100644 --- a/src/api/migraphx.py +++ b/src/api/migraphx.py @@ -462,6 +462,9 @@ def compile_options(h): h.method('set_exhaustive_tune_flag', api.params(value='bool'), invoke='migraphx::set_exhaustive_tune_flag($@)') + h.method('set_compile_mode', + api.params(value='int8_t'), + invoke='migraphx::set_compile_mode($@)') h.method('set_advance_backend_options', api.params(options_json='const char*', vlist='...'), invoke='migraphx::set_backend_options($@)') diff --git a/src/compile_modes.cpp b/src/compile_modes.cpp new file mode 100644 index 00000000000..33bf2d18e2a --- /dev/null +++ b/src/compile_modes.cpp @@ -0,0 +1,78 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +namespace migraphx { +inline namespace MIGRAPHX_INLINE_NS { + +compile_modes convert_to_compile_mode(uint8_t mode) +{ + int clamped = std::clamp(mode, 0, 100); + if(clamped != mode) + log::warn() << "Compile mode value " << mode << " out of range [0, 100], clamping to " + << clamped; + + static const std::array modes = { + compile_modes::eager, compile_modes::balanced, compile_modes::max}; + + // NOLINTNEXTLINE(readability-qualified-auto) + auto it = std::find_if(modes.begin(), modes.end(), [&](compile_modes m) { + return static_cast(m) == clamped; + }); + if(it != modes.end()) + return *it; + + log::warn() << "Compile mode value " << clamped + << " does not match a known mode, using closest match"; + return *std::min_element(modes.begin(), modes.end(), by(std::less<>{}, [&](compile_modes m) { + return std::abs(clamped - static_cast(m)); + })); +} + +compile_modes convert_to_compile_mode(const std::string& mode) +{ + auto lower = to_lower(mode); + if(lower == "eager") + return compile_modes::eager; + if(lower == "balanced") + return compile_modes::balanced; + if(lower == "max") + return compile_modes::max; + + int val = std::stoi(mode); + if(val < 0 or val > 100) + log::warn() << "Compile mode value " << val << " out of range [0, 100], clamping to " + << std::clamp(val, 0, 100); + return convert_to_compile_mode(std::clamp(val, 0, 100)); +} + +} // namespace MIGRAPHX_INLINE_NS +} // namespace migraphx diff --git a/src/driver/main.cpp b/src/driver/main.cpp index d6a55e8d94c..fe351d696c7 100644 --- a/src/driver/main.cpp +++ b/src/driver/main.cpp @@ -839,6 +839,14 @@ struct compiler {"--exhaustive-tune"}, ap.help("Exhastively search for best tuning parameters for kernels"), ap.set_value(true)); + ap(co.compile_mode, + {"--compile-mode"}, + ap.help("Set compilation mode: eager, balanced, max, or an integer 0-100"), + ap.write_action([](auto&, auto& x, const auto& params) { + if(params.empty()) + throw std::runtime_error("Flag with no value."); + x = convert_to_compile_mode(params.back()); + })); ap(to_fp16, {"--fp16"}, ap.help("Quantize for fp16"), ap.set_value(true)); ap(to_bf16, {"--bf16"}, ap.help("Quantize for bf16"), ap.set_value(true)); ap(to_int8, {"--int8"}, ap.help("Quantize for int8"), ap.set_value(true)); diff --git a/src/include/migraphx/compile_modes.hpp b/src/include/migraphx/compile_modes.hpp new file mode 100644 index 00000000000..b21bdf462e7 --- /dev/null +++ b/src/include/migraphx/compile_modes.hpp @@ -0,0 +1,47 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MIGRAPHX_GUARD_MIGRAPHX_COMPILE_MODES_HPP +#define MIGRAPHX_GUARD_MIGRAPHX_COMPILE_MODES_HPP + +#include +#include +#include + +namespace migraphx { +inline namespace MIGRAPHX_INLINE_NS { + +enum class compile_modes +{ + eager = 0, + balanced = 50, + max = 100 +}; + +MIGRAPHX_EXPORT compile_modes convert_to_compile_mode(uint8_t mode); +MIGRAPHX_EXPORT compile_modes convert_to_compile_mode(const std::string& mode); + +} // namespace MIGRAPHX_INLINE_NS +} // namespace migraphx + +#endif // MIGRAPHX_GUARD_MIGRAPHX_COMPILE_MODES_HPP diff --git a/src/include/migraphx/compile_options.hpp b/src/include/migraphx/compile_options.hpp index 50509ba35ef..519a4f39bff 100644 --- a/src/include/migraphx/compile_options.hpp +++ b/src/include/migraphx/compile_options.hpp @@ -25,6 +25,7 @@ #define MIGRAPHX_GUARD_RTGLIB_COMPILE_OPTIONS_HPP #include +#include #include #include #include @@ -44,6 +45,7 @@ struct compile_options bool fast_math = true; bool exhaustive_tune = false; + compile_modes compile_mode = compile_modes::balanced; /** * Backend-specific options keyed by name. Targets can read these to * configure compilation in a way that is opaque to the core engine. diff --git a/src/include/migraphx/output_iterator.hpp b/src/include/migraphx/output_iterator.hpp index 6efd2532396..b7c298ceaec 100644 --- a/src/include/migraphx/output_iterator.hpp +++ b/src/include/migraphx/output_iterator.hpp @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2015-2025 Advanced Micro Devices, Inc. All rights reserved. + * Copyright (c) 2015-2026 Advanced Micro Devices, Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/src/py/migraphx_py.cpp b/src/py/migraphx_py.cpp index a48a9f47787..78c67462212 100644 --- a/src/py/migraphx_py.cpp +++ b/src/py/migraphx_py.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #ifdef HAVE_GPU @@ -609,6 +610,11 @@ MIGRAPHX_PYBIND11_MODULE(migraphx, m) }, py::keep_alive<0, 1>()); + py::enum_(m, "compile_modes") + .value("eager", migraphx::compile_modes::eager) + .value("balanced", migraphx::compile_modes::balanced) + .value("max", migraphx::compile_modes::max); + py::class_(m, "program") .def(py::init([]() { return migraphx::program(); })) .def("get_parameter_names", &migraphx::program::get_parameter_names) @@ -622,11 +628,13 @@ MIGRAPHX_PYBIND11_MODULE(migraphx, m) bool offload_copy, bool fast_math, bool exhaustive_tune, + migraphx::compile_modes compile_mode, const py::dict& advance_backend_options) { migraphx::compile_options options; options.offload_copy = offload_copy; options.fast_math = fast_math; options.exhaustive_tune = exhaustive_tune; + options.compile_mode = compile_mode; for(auto opt : advance_backend_options) { auto key = py::str(opt.first).cast(); @@ -639,6 +647,7 @@ MIGRAPHX_PYBIND11_MODULE(migraphx, m) py::arg("offload_copy") = true, py::arg("fast_math") = true, py::arg("exhaustive_tune") = false, + py::arg("compile_mode") = migraphx::compile_modes::balanced, py::arg("advance_backend_options") = py::dict()) .def( "finalize", diff --git a/src/targets/gpu/compile_ops.cpp b/src/targets/gpu/compile_ops.cpp index 431666fe54c..5840d308802 100644 --- a/src/targets/gpu/compile_ops.cpp +++ b/src/targets/gpu/compile_ops.cpp @@ -337,7 +337,7 @@ struct compile_plan } template - void add_compiles(Vector& compiles) + void add_compiles(Vector& compiles, bool skip_benchmark) { if(config.has_value()) { @@ -359,7 +359,7 @@ struct compile_plan problem_string() + "\n\n" + print_modules()); const bool dump_mxr = not string_value_of(MIGRAPHX_GPU_DUMP_BENCHMARK_MXR{}).empty(); - if(enabled(MIGRAPHX_SKIP_BENCHMARKING{}) or + if(skip_benchmark or enabled(MIGRAPHX_SKIP_BENCHMARKING{}) or (ctx->is_cross_compile() and not dump_mxr) or solutions.size() == 1) { ctx->get_problem_cache().insert(preop.name(), problem, solutions.front()); @@ -547,7 +547,8 @@ static void par_compile(std::size_t n, F f) struct compile_manager { std::vector cps; - bool exhaustive = false; + bool exhaustive = false; + bool skip_benchmark = false; template void add_plan(Ts&&... xs) @@ -565,7 +566,7 @@ struct compile_manager std::vector> compiles; for(auto& cp : cps) { - cp.add_compiles(compiles); + cp.add_compiles(compiles, skip_benchmark); } par_compile(compiles.size(), [&](auto i) { compiles[i](); }); @@ -634,7 +635,8 @@ void compile_ops::apply(module_pass_manager& mpm) const bool is_root = &mpm.get_module() == mpm.get_root_module(); auto& m = mpm.get_module(); compile_manager cm; - cm.exhaustive = exhaustive_tune; + cm.exhaustive = exhaustive_tune; + cm.skip_benchmark = skip_benchmark; // Find all precompile ops for(auto ins : iterator_for(m)) { diff --git a/src/targets/gpu/include/migraphx/gpu/compile_ops.hpp b/src/targets/gpu/include/migraphx/gpu/compile_ops.hpp index 1898899f1b5..8ba232d0219 100644 --- a/src/targets/gpu/include/migraphx/gpu/compile_ops.hpp +++ b/src/targets/gpu/include/migraphx/gpu/compile_ops.hpp @@ -40,6 +40,7 @@ struct MIGRAPHX_GPU_EXPORT compile_ops { context* ctx = nullptr; bool exhaustive_tune = false; + bool skip_benchmark = false; std::string name() const { return "gpu::compile_ops"; } void apply(module_pass_manager& mpm) const; }; diff --git a/src/targets/gpu/target.cpp b/src/targets/gpu/target.cpp index c410808fc25..7d6a4c065de 100644 --- a/src/targets/gpu/target.cpp +++ b/src/targets/gpu/target.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -60,6 +61,7 @@ #include #include #include +#include #include #include #include @@ -251,7 +253,9 @@ struct pipeline_factory adjust_allocation{gpu_allocation_model{}}, dead_code_elimination{}, lower_device_ops{}, - compile_ops{get_context(), options.exhaustive_tune}, + compile_ops{get_context(), + options.exhaustive_tune, + options.compile_mode == compile_modes::eager}, dead_code_elimination{}, promote_literals{}, dead_code_elimination{}, @@ -278,15 +282,37 @@ std::vector target::get_passes(migraphx::context& gctx, const compile_opti ctx.set_exhaustive_tune_flag(options.exhaustive_tune); ctx.load_problem_cache(); // TODO: update load_problem_cache to include gpu arch + if(options.compile_mode == compile_modes::max) + ctx.set_exhaustive_tune_flag(true); + pipeline_factory p{&gctx, options, from_value(value(options.backend_options))}; - std::vector> pipelines = { - p.dynamic_shapes_pipeline(), - p.required_pipeline(), - p.optimize_rewrite_pipeline(), - p.fusion_pipeline(), - p.backend_pipeline(), - }; + std::vector> pipelines; + + if(options.compile_mode == compile_modes::eager) + { + pipelines = { + p.dynamic_shapes_pipeline(), + p.required_pipeline(), + {optimize_module{}, + dead_code_elimination{}, + rewrite_reduce{}, + rewrite_topk{}, + dead_code_elimination{}}, + p.fusion_pipeline(), + p.backend_pipeline(), + }; + } + else + { + pipelines = { + p.dynamic_shapes_pipeline(), + p.required_pipeline(), + p.optimize_rewrite_pipeline(), + p.fusion_pipeline(), + p.backend_pipeline(), + }; + } std::vector passes; std::copy(pipelines.begin(), pipelines.end(), join_back_inserter(passes)); diff --git a/test/api/test_compile_options.cpp b/test/api/test_compile_options.cpp index a43532ceb0b..1a9002ea02b 100644 --- a/test/api/test_compile_options.cpp +++ b/test/api/test_compile_options.cpp @@ -93,4 +93,40 @@ TEST_CASE(compile_options_backend_options_json) run_and_check(p, s); } +TEST_CASE(compile_options_compile_with_eager_mode) +{ + migraphx::api::program p; + auto main_module = p.get_main_module(); + migraphx::api::shape s{migraphx_shape_float_type, {2, 3}}; + auto x = main_module.add_parameter("x", s); + auto y = main_module.add_parameter("y", s); + auto op = migraphx::api::operation("add"); + main_module.add_instruction(op, {x, y}); + + migraphx::api::compile_options options; + options.set_compile_mode(0); + p.compile(migraphx::api::target("ref"), options); + + auto output_shapes = p.get_output_shapes(); + CHECK(output_shapes.size() == 1); +} + +TEST_CASE(compile_options_compile_with_max_mode) +{ + migraphx::api::program p; + auto main_module = p.get_main_module(); + migraphx::api::shape s{migraphx_shape_float_type, {2, 3}}; + auto x = main_module.add_parameter("x", s); + auto y = main_module.add_parameter("y", s); + auto op = migraphx::api::operation("add"); + main_module.add_instruction(op, {x, y}); + + migraphx::api::compile_options options; + options.set_compile_mode(100); + p.compile(migraphx::api::target("ref"), options); + + auto output_shapes = p.get_output_shapes(); + CHECK(output_shapes.size() == 1); +} + int main(int argc, const char* argv[]) { test::run(argc, argv); } diff --git a/test/compile_modes.cpp b/test/compile_modes.cpp new file mode 100644 index 00000000000..5f9c5df59ed --- /dev/null +++ b/test/compile_modes.cpp @@ -0,0 +1,131 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015-2026 Advanced Micro Devices, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include + +TEST_CASE(convert_uint8_eager) +{ + EXPECT(migraphx::convert_to_compile_mode(uint8_t(0)) == migraphx::compile_modes::eager); +} + +TEST_CASE(convert_uint8_balanced) +{ + EXPECT(migraphx::convert_to_compile_mode(uint8_t(50)) == migraphx::compile_modes::balanced); +} + +TEST_CASE(convert_uint8_max) +{ + EXPECT(migraphx::convert_to_compile_mode(uint8_t(100)) == migraphx::compile_modes::max); +} + +TEST_CASE(convert_uint8_closest_to_eager) +{ + EXPECT(migraphx::convert_to_compile_mode(uint8_t(1)) == migraphx::compile_modes::eager); +} + +TEST_CASE(convert_uint8_closest_to_balanced) +{ + EXPECT(migraphx::convert_to_compile_mode(uint8_t(30)) == migraphx::compile_modes::balanced); +} + +TEST_CASE(convert_uint8_closest_to_max) +{ + EXPECT(migraphx::convert_to_compile_mode(uint8_t(99)) == migraphx::compile_modes::max); +} + +TEST_CASE(convert_uint8_midpoint) +{ + auto result = migraphx::convert_to_compile_mode(uint8_t(25)); + EXPECT(result == migraphx::compile_modes::eager or result == migraphx::compile_modes::balanced); +} + +TEST_CASE(convert_string_eager) +{ + EXPECT(migraphx::convert_to_compile_mode("eager") == migraphx::compile_modes::eager); +} + +TEST_CASE(convert_string_balanced) +{ + EXPECT(migraphx::convert_to_compile_mode("balanced") == migraphx::compile_modes::balanced); +} + +TEST_CASE(convert_string_max) +{ + EXPECT(migraphx::convert_to_compile_mode("max") == migraphx::compile_modes::max); +} + +TEST_CASE(convert_string_case_insensitive) +{ + EXPECT(migraphx::convert_to_compile_mode("EAGER") == migraphx::compile_modes::eager); + EXPECT(migraphx::convert_to_compile_mode("Balanced") == migraphx::compile_modes::balanced); + EXPECT(migraphx::convert_to_compile_mode("MAX") == migraphx::compile_modes::max); +} + +TEST_CASE(convert_string_integer) +{ + EXPECT(migraphx::convert_to_compile_mode("0") == migraphx::compile_modes::eager); + EXPECT(migraphx::convert_to_compile_mode("50") == migraphx::compile_modes::balanced); + EXPECT(migraphx::convert_to_compile_mode("100") == migraphx::compile_modes::max); +} + +TEST_CASE(convert_string_integer_closest) +{ + EXPECT(migraphx::convert_to_compile_mode("30") == migraphx::compile_modes::balanced); +} + +TEST_CASE(convert_uint8_out_of_range) +{ + EXPECT(migraphx::convert_to_compile_mode(uint8_t(200)) == migraphx::compile_modes::max); + EXPECT(migraphx::convert_to_compile_mode(uint8_t(101)) == migraphx::compile_modes::max); +} + +TEST_CASE(convert_string_integer_out_of_range) +{ + EXPECT(migraphx::convert_to_compile_mode("-5") == migraphx::compile_modes::eager); + EXPECT(migraphx::convert_to_compile_mode("200") == migraphx::compile_modes::max); +} + +TEST_CASE(convert_string_invalid) +{ + EXPECT(test::throws([&] { migraphx::convert_to_compile_mode("invalid"); })); +} + +TEST_CASE(convert_string_empty_throws) +{ + EXPECT(test::throws([&] { migraphx::convert_to_compile_mode(""); })); +} + +TEST_CASE(convert_uint8_boundary_25) +{ + auto result = migraphx::convert_to_compile_mode(uint8_t(25)); + EXPECT(result == migraphx::compile_modes::eager or result == migraphx::compile_modes::balanced); +} + +TEST_CASE(convert_uint8_boundary_75) +{ + auto result = migraphx::convert_to_compile_mode(uint8_t(75)); + EXPECT(result == migraphx::compile_modes::balanced or result == migraphx::compile_modes::max); +} + +int main(int argc, const char* argv[]) { test::run(argc, argv); } diff --git a/test/py/CMakeLists.txt b/test/py/CMakeLists.txt index 3cb86030ce0..cca16bd4520 100644 --- a/test/py/CMakeLists.txt +++ b/test/py/CMakeLists.txt @@ -106,6 +106,7 @@ add_py_test(module_construct test_module_construct.py common ${VENV} WORKING_DIR add_py_test(macro test_macro.py common ${VENV} WORKING_DIRECTORY ${TEST_ONNX_DIR}) add_py_test(literal test_literal.py common ${VENV} WORKING_DIRECTORY ${TEST_ONNX_DIR}) add_py_test(autocast_fp8 test_autocast_fp8.py common ${VENV} WORKING_DIRECTORY ${TEST_ONNX_DIR}) +add_py_test(compile_modes test_compile_modes.py common ${VENV} WORKING_DIRECTORY ${TEST_ONNX_DIR}) add_py_test(debug_symbols test_debug_symbols.py common ${VENV} WORKING_DIRECTORY ${TEST_ONNX_DIR}) if(MIGRAPHX_ENABLE_GPU) add_py_test(gpu_offload test_gpu_offload.py common ${VENV} WORKING_DIRECTORY ${TEST_ONNX_DIR}) diff --git a/test/py/test_compile_modes.py b/test/py/test_compile_modes.py new file mode 100644 index 00000000000..fcb4302cb32 --- /dev/null +++ b/test/py/test_compile_modes.py @@ -0,0 +1,93 @@ +##################################################################################### +# The MIT License (MIT) +# +# Copyright (c) 2015-2026 Advanced Micro Devices, Inc. All rights reserved. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +##################################################################################### +import migraphx + + +def test_compile_modes_enum_exists(): + assert hasattr(migraphx, 'compile_modes') + assert hasattr(migraphx.compile_modes, 'eager') + assert hasattr(migraphx.compile_modes, 'balanced') + assert hasattr(migraphx.compile_modes, 'max') + + +def test_compile_modes_enum_values(): + assert migraphx.compile_modes.eager.value == 0 + assert migraphx.compile_modes.balanced.value == 50 + assert migraphx.compile_modes.max.value == 100 + + +def test_compile_with_eager_mode(): + p = migraphx.parse_onnx("conv_relu_maxpool_test.onnx") + s1 = p.get_output_shapes()[-1] + p.compile(migraphx.get_target("ref"), + compile_mode=migraphx.compile_modes.eager) + s2 = p.get_output_shapes()[-1] + assert s1 == s2 + + +def test_compile_with_balanced_mode(): + p = migraphx.parse_onnx("conv_relu_maxpool_test.onnx") + s1 = p.get_output_shapes()[-1] + p.compile(migraphx.get_target("ref"), + compile_mode=migraphx.compile_modes.balanced) + s2 = p.get_output_shapes()[-1] + assert s1 == s2 + + +def test_compile_with_max_mode(): + p = migraphx.parse_onnx("conv_relu_maxpool_test.onnx") + s1 = p.get_output_shapes()[-1] + p.compile(migraphx.get_target("ref"), + compile_mode=migraphx.compile_modes.max) + s2 = p.get_output_shapes()[-1] + assert s1 == s2 + + +def test_compile_default_mode(): + p = migraphx.parse_onnx("conv_relu_maxpool_test.onnx") + s1 = p.get_output_shapes()[-1] + # Default should be balanced + p.compile(migraphx.get_target("ref")) + s2 = p.get_output_shapes()[-1] + assert s1 == s2 + + +def test_compile_eager_produces_valid_output(): + p = migraphx.parse_onnx("conv_relu_maxpool_test.onnx") + p.compile(migraphx.get_target("ref"), + compile_mode=migraphx.compile_modes.eager) + params = {} + for key, value in p.get_parameter_shapes().items(): + params[key] = migraphx.generate_argument(value) + result = p.run(params) + assert len(result) > 0 + + +test_compile_modes_enum_exists() +test_compile_modes_enum_values() +test_compile_with_eager_mode() +test_compile_with_balanced_mode() +test_compile_with_max_mode() +test_compile_default_mode() +test_compile_eager_produces_valid_output() diff --git a/test/verify/main.cpp b/test/verify/main.cpp index a93d78e7e10..d22e45bcd55 100644 --- a/test/verify/main.cpp +++ b/test/verify/main.cpp @@ -173,5 +173,6 @@ int main(int argc, const char* argv[]) "test_quant_dot_3args_4", "test_quant_dot_3args_5", }); + rv.run(argc, argv); } diff --git a/test/verify/run_verify.cpp b/test/verify/run_verify.cpp index 6197af4c6c8..a26330db038 100644 --- a/test/verify/run_verify.cpp +++ b/test/verify/run_verify.cpp @@ -173,7 +173,7 @@ static auto get_hash(const T& x) return std::hash{}(x); } -void run_verify::verify(const program_info& pi) const +void run_verify::verify(const program_info& pi, migraphx::compile_modes mode) const { const std::string name = pi.name; const migraphx::program p = pi.get_program(); @@ -215,8 +215,9 @@ void run_verify::verify(const program_info& pi) const m[x.first] = migraphx::generate_argument(x.second, get_hash(x.first)); } } - const migraphx::compile_options c_opts = pi.compile_options; - auto ref_f = detach_async([=] { return run_ref(p, m, c_opts); }); + migraphx::compile_options c_opts = pi.compile_options; + c_opts.compile_mode = mode; + auto ref_f = detach_async([=] { return run_ref(p, m, c_opts); }); for(const auto& tname : target_names) { target_info ti = get_target_info(tname); @@ -264,7 +265,11 @@ void run_verify::run(int argc, const char* argv[]) const for(auto&& p : get_programs()) { labels[p.section].push_back(p.name); - test::add_test_case(p.name, [=] { verify(p); }); + test::add_test_case(p.name, [=] { verify(p, migraphx::compile_modes::balanced); }); + + const std::string eager_name = p.name + "_eager"; + labels[p.section].push_back(eager_name); + test::add_test_case(eager_name, [=] { verify(p, migraphx::compile_modes::eager); }); } test::driver d{}; d.get_case_names = [&](const std::string& name) -> std::vector { diff --git a/test/verify/run_verify.hpp b/test/verify/run_verify.hpp index 51bf764f1db..86cb48babbd 100644 --- a/test/verify/run_verify.hpp +++ b/test/verify/run_verify.hpp @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright (c) 2015-2025 Advanced Micro Devices, Inc. All rights reserved. + * Copyright (c) 2015-2026 Advanced Micro Devices, Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,6 +25,7 @@ #define MIGRAPHX_GUARD_TEST_RUN_VERIFY_HPP #include +#include #include #include @@ -53,7 +54,7 @@ struct run_verify void validate(const migraphx::target& t, const migraphx::program& p, const migraphx::parameter_map& m) const; - void verify(const program_info& pi) const; + void verify(const program_info& pi, migraphx::compile_modes mode) const; void run(int argc, const char* argv[]) const; target_info get_target_info(const std::string& name) const; diff --git a/tools/api/api.cpp b/tools/api/api.cpp index 599f9e843b5..3a7dc97e4cb 100644 --- a/tools/api/api.cpp +++ b/tools/api/api.cpp @@ -190,6 +190,11 @@ static void set_exhaustive_tune_flag(compile_options& options, bool value) options.exhaustive_tune = value; } +static void set_compile_mode(compile_options& options, int8_t value) +{ + options.compile_mode = convert_to_compile_mode(value); +} + // Parse the backend options from `options_json` and merge them into the // compile options. See migraphx::set_backend_options for the merge semantics. static void set_backend_options(compile_options& options, const char* options_json, va_list vlist) diff --git a/tools/api/migraphx.h b/tools/api/migraphx.h index 263dacd0160..e93c7360141 100644 --- a/tools/api/migraphx.h +++ b/tools/api/migraphx.h @@ -76,6 +76,14 @@ typedef enum } migraphx_shape_datatype_t; #undef MIGRAPHX_SHAPE_GENERATE_ENUM_TYPES +typedef enum +{ + migraphx_compile_mode_eager = 0, + migraphx_compile_mode_balanced = 50, + migraphx_compile_mode_max = 100, + +} migraphx_compile_mode; + <% generate_c_header() %>