From d722dd01d27face7c30202f5082c43957b19ecdb Mon Sep 17 00:00:00 2001 From: "Xinyi Wu (i26343)" Date: Fri, 5 Jun 2026 18:16:05 +0800 Subject: [PATCH] add flash attention baseline package --- .../baselines/fused_moe/.vscode/settings.json | 3 + .../api/v1/query/client-vscode/query.json | 1 + .../reply/cache-v2-ea2ef11d05674d96d761.json | 471 ++ .../cmakeFiles-v1-7899829d23c1c1ae3e98.json | 73 + .../codemodel-v2-7cd0b1b00876e71f364f.json | 69 + ...irectory-.-Debug-f5ebdc15457944623624.json | 14 + .../reply/index-2026-05-29T05-34-43-0302.json | 132 + ...tn_example-Debug-a97a299baa6c6c6d83d0.json | 73 + ...target-run-Debug-0d66e135afa1376e0f20.json | 73 + .../toolchains-v1-8ae3cf416ede58af34e6.json | 18 + .../baselines/fused_moe/build/CMakeCache.txt | 127 + .../build/CMakeFiles/3.28.3/CMakeSystem.cmake | 15 + .../build/CMakeFiles/CMakeConfigureLog.yaml | 11 + .../build/CMakeFiles/TargetDirectories.txt | 4 + .../build/CMakeFiles/cmake.check_cache | 1 + .../fused_moe/build/CMakeFiles/rules.ninja | 45 + .../baselines/fused_moe/build/build.ninja | 146 + .../fused_moe/build/cmake_install.cmake | 49 + .../scripts/build_fused_moe_i8_tn_pybind.sh | 52 + .../scripts/run_fused_moe_i8_tn_benchmark.sh | 12 + .../run_fused_moe_i8_tn_pybind_test.sh | 12 + .../fused_moe_bf16_tn/CMakeLists.txt | 45 + .../standalone/fused_moe_bf16_tn/Makefile | 28 + .../src/fused_moe_bf16_tn_example.cpp | 246 + .../standalone/fused_moe_i8_tn/CMakeLists.txt | 44 + .../standalone/fused_moe_i8_tn/Makefile | 27 + .../fused_moe_i8_tn/benchmark_results.md | 30 + .../build/fused_moe_i8_tn_pybind.o | Bin 0 -> 579800 bytes .../build/fused_moe_i8_tn_pybind.so | Bin 0 -> 370600 bytes .../fused-moe-i8-tn-pybind-triton-guide.md | 214 + .../benchmark_fused_moe_i8_tn.cpython-312.pyc | Bin 0 -> 3283 bytes .../fused_moe_i8_tn_triton.cpython-310.pyc | Bin 0 -> 8010 bytes .../fused_moe_i8_tn_triton.cpython-312.pyc | Bin 0 -> 14958 bytes ...est_fused_moe_i8_tn_pybind.cpython-310.pyc | Bin 0 -> 4911 bytes ...est_fused_moe_i8_tn_pybind.cpython-312.pyc | Bin 0 -> 8503 bytes .../python/benchmark_fused_moe_i8_tn.py | 63 + .../python/fused_moe_i8_tn_triton.py | 368 ++ .../python/test_fused_moe_i8_tn_pybind.py | 154 + .../src/fused_moe_i8_tn_example.cpp | 324 ++ .../src/fused_moe_i8_tn_kernel.h | 629 +++ .../src/fused_moe_i8_tn_macros.h | 21 + .../src/fused_moe_i8_tn_pybind.cpp | 101 + .../src/fused_moe_i8_tn_runner.h | 331 ++ .../src/fused_moe_i8_tn_types.h | 167 + .../CMakeLists.txt | 46 + .../gemm_i8_tn_256x256x128_raw_arrays.hpp | 368 ++ .../include/standalone_maca_kernel_utils.hpp | 18 + .../i8_tn_256x256x128_raw_arrays/src/test.cpp | 229 + .../pybind11/include/pybind11/attr.h | 730 +++ .../pybind11/include/pybind11/buffer_info.h | 209 + .../pybind11/include/pybind11/cast.h | 2447 ++++++++++ .../pybind11/include/pybind11/chrono.h | 227 + .../pybind11/include/pybind11/common.h | 2 + .../pybind11/include/pybind11/complex.h | 95 + .../include/pybind11/conduit/README.txt | 15 + .../pybind11/conduit/pybind11_conduit_v1.h | 116 + .../conduit/pybind11_platform_abi_id.h | 87 + .../pybind11/conduit/wrap_include_python_h.h | 72 + .../include/pybind11/critical_section.h | 56 + .../include/pybind11/detail/argument_vector.h | 417 ++ .../pybind11/include/pybind11/detail/class.h | 850 ++++ .../pybind11/include/pybind11/detail/common.h | 1427 ++++++ .../include/pybind11/detail/cpp_conduit.h | 75 + .../pybind11/include/pybind11/detail/descr.h | 231 + .../detail/dynamic_raw_ptr_cast_if_possible.h | 39 + .../pybind11/detail/exception_translation.h | 71 + .../detail/function_record_pyobject.h | 192 + .../include/pybind11/detail/function_ref.h | 101 + .../detail/holder_caster_foreign_helpers.h | 104 + .../pybind11/include/pybind11/detail/init.h | 548 +++ .../include/pybind11/detail/internals.h | 1082 +++++ .../pybind11/detail/native_enum_data.h | 227 + .../detail/pybind11_namespace_macros.h | 82 + .../pybind11/detail/struct_smart_holder.h | 398 ++ .../pybind11/detail/type_caster_base.h | 1723 +++++++ .../pybind11/include/pybind11/detail/typeid.h | 65 + .../pybind11/detail/using_smart_holder.h | 22 + .../pybind11/detail/value_and_holder.h | 92 + .../pybind11/include/pybind11/eigen.h | 12 + .../pybind11/include/pybind11/eigen/common.h | 9 + .../pybind11/include/pybind11/eigen/matrix.h | 723 +++ .../pybind11/include/pybind11/eigen/tensor.h | 520 +++ .../pybind11/include/pybind11/embed.h | 320 ++ .../pybind11/include/pybind11/eval.h | 161 + .../pybind11/include/pybind11/functional.h | 146 + .../pybind11/include/pybind11/gil.h | 203 + .../include/pybind11/gil_safe_call_once.h | 273 ++ .../pybind11/include/pybind11/gil_simple.h | 37 + .../pybind11/include/pybind11/iostream.h | 301 ++ .../pybind11/include/pybind11/native_enum.h | 76 + .../pybind11/include/pybind11/numpy.h | 2412 ++++++++++ .../pybind11/include/pybind11/operators.h | 202 + .../pybind11/include/pybind11/options.h | 92 + .../pybind11/include/pybind11/pybind11.h | 4048 +++++++++++++++++ .../pybind11/include/pybind11/pytypes.h | 2736 +++++++++++ .../pybind11/include/pybind11/stl.h | 666 +++ .../include/pybind11/stl/filesystem.h | 114 + .../pybind11/include/pybind11/stl_bind.h | 858 ++++ .../include/pybind11/subinterpreter.h | 462 ++ .../pybind11/trampoline_self_life_support.h | 65 + .../pybind11/type_caster_pyobject_ptr.h | 61 + .../pybind11/include/pybind11/typing.h | 293 ++ .../pybind11/include/pybind11/warnings.h | 75 + 103 files changed, 31521 insertions(+) create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/.vscode/settings.json create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/.cmake/api/v1/query/client-vscode/query.json create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/.cmake/api/v1/reply/cache-v2-ea2ef11d05674d96d761.json create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/.cmake/api/v1/reply/cmakeFiles-v1-7899829d23c1c1ae3e98.json create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/.cmake/api/v1/reply/codemodel-v2-7cd0b1b00876e71f364f.json create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/.cmake/api/v1/reply/directory-.-Debug-f5ebdc15457944623624.json create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/.cmake/api/v1/reply/index-2026-05-29T05-34-43-0302.json create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/.cmake/api/v1/reply/target-build_fused_moe_i8_tn_example-Debug-a97a299baa6c6c6d83d0.json create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/.cmake/api/v1/reply/target-run-Debug-0d66e135afa1376e0f20.json create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/.cmake/api/v1/reply/toolchains-v1-8ae3cf416ede58af34e6.json create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/CMakeCache.txt create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/CMakeFiles/3.28.3/CMakeSystem.cmake create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/CMakeFiles/CMakeConfigureLog.yaml create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/CMakeFiles/TargetDirectories.txt create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/CMakeFiles/cmake.check_cache create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/CMakeFiles/rules.ninja create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/build.ninja create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/cmake_install.cmake create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/scripts/build_fused_moe_i8_tn_pybind.sh create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/scripts/run_fused_moe_i8_tn_benchmark.sh create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/scripts/run_fused_moe_i8_tn_pybind_test.sh create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_bf16_tn/CMakeLists.txt create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_bf16_tn/Makefile create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_bf16_tn/src/fused_moe_bf16_tn_example.cpp create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/CMakeLists.txt create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/Makefile create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/benchmark_results.md create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/build/fused_moe_i8_tn_pybind.o create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/build/fused_moe_i8_tn_pybind.so create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/fused-moe-i8-tn-pybind-triton-guide.md create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/python/__pycache__/benchmark_fused_moe_i8_tn.cpython-312.pyc create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/python/__pycache__/fused_moe_i8_tn_triton.cpython-310.pyc create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/python/__pycache__/fused_moe_i8_tn_triton.cpython-312.pyc create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/python/__pycache__/test_fused_moe_i8_tn_pybind.cpython-310.pyc create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/python/__pycache__/test_fused_moe_i8_tn_pybind.cpython-312.pyc create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/python/benchmark_fused_moe_i8_tn.py create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/python/fused_moe_i8_tn_triton.py create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/python/test_fused_moe_i8_tn_pybind.py create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/src/fused_moe_i8_tn_example.cpp create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/src/fused_moe_i8_tn_kernel.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/src/fused_moe_i8_tn_macros.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/src/fused_moe_i8_tn_pybind.cpp create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/src/fused_moe_i8_tn_runner.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/src/fused_moe_i8_tn_types.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/i8_tn_256x256x128_raw_arrays/CMakeLists.txt create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/i8_tn_256x256x128_raw_arrays/include/gemm_i8_tn_256x256x128_raw_arrays.hpp create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/i8_tn_256x256x128_raw_arrays/include/standalone_maca_kernel_utils.hpp create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/i8_tn_256x256x128_raw_arrays/src/test.cpp create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/attr.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/buffer_info.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/cast.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/chrono.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/common.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/complex.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/conduit/README.txt create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/conduit/pybind11_conduit_v1.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/conduit/pybind11_platform_abi_id.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/conduit/wrap_include_python_h.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/critical_section.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/detail/argument_vector.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/detail/class.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/detail/common.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/detail/cpp_conduit.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/detail/descr.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/detail/dynamic_raw_ptr_cast_if_possible.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/detail/exception_translation.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/detail/function_record_pyobject.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/detail/function_ref.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/detail/holder_caster_foreign_helpers.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/detail/init.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/detail/internals.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/detail/native_enum_data.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/detail/pybind11_namespace_macros.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/detail/struct_smart_holder.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/detail/type_caster_base.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/detail/typeid.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/detail/using_smart_holder.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/detail/value_and_holder.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/eigen.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/eigen/common.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/eigen/matrix.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/eigen/tensor.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/embed.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/eval.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/functional.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/gil.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/gil_safe_call_once.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/gil_simple.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/iostream.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/native_enum.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/numpy.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/operators.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/options.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/pybind11.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/pytypes.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/stl.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/stl/filesystem.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/stl_bind.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/subinterpreter.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/trampoline_self_life_support.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/type_caster_pyobject_ptr.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/typing.h create mode 100644 基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/warnings.h diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/.vscode/settings.json b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/.vscode/settings.json new file mode 100644 index 0000000..c497274 --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "cmake.sourceDirectory": "/root/Project/fusedmoe_v2/standalone/fused_moe_i8_tn" +} \ No newline at end of file diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/.cmake/api/v1/query/client-vscode/query.json b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/.cmake/api/v1/query/client-vscode/query.json new file mode 100644 index 0000000..82bb964 --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/.cmake/api/v1/query/client-vscode/query.json @@ -0,0 +1 @@ +{"requests":[{"kind":"cache","version":2},{"kind":"codemodel","version":2},{"kind":"toolchains","version":1},{"kind":"cmakeFiles","version":1}]} \ No newline at end of file diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/.cmake/api/v1/reply/cache-v2-ea2ef11d05674d96d761.json b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/.cmake/api/v1/reply/cache-v2-ea2ef11d05674d96d761.json new file mode 100644 index 0000000..3a5515b --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/.cmake/api/v1/reply/cache-v2-ea2ef11d05674d96d761.json @@ -0,0 +1,471 @@ +{ + "entries" : + [ + { + "name" : "CMAKE_BUILD_TYPE", + "properties" : + [ + { + "name" : "HELPSTRING", + "value" : "No help, variable specified on the command line." + } + ], + "type" : "STRING", + "value" : "Debug" + }, + { + "name" : "CMAKE_CACHEFILE_DIR", + "properties" : + [ + { + "name" : "HELPSTRING", + "value" : "This is the directory where this CMakeCache.txt was created" + } + ], + "type" : "INTERNAL", + "value" : "/root/Project/fusedmoe/build" + }, + { + "name" : "CMAKE_CACHE_MAJOR_VERSION", + "properties" : + [ + { + "name" : "HELPSTRING", + "value" : "Major version of cmake used to create the current loaded cache" + } + ], + "type" : "INTERNAL", + "value" : "3" + }, + { + "name" : "CMAKE_CACHE_MINOR_VERSION", + "properties" : + [ + { + "name" : "HELPSTRING", + "value" : "Minor version of cmake used to create the current loaded cache" + } + ], + "type" : "INTERNAL", + "value" : "28" + }, + { + "name" : "CMAKE_CACHE_PATCH_VERSION", + "properties" : + [ + { + "name" : "HELPSTRING", + "value" : "Patch version of cmake used to create the current loaded cache" + } + ], + "type" : "INTERNAL", + "value" : "3" + }, + { + "name" : "CMAKE_COMMAND", + "properties" : + [ + { + "name" : "HELPSTRING", + "value" : "Path to CMake executable." + } + ], + "type" : "INTERNAL", + "value" : "/usr/bin/cmake" + }, + { + "name" : "CMAKE_CPACK_COMMAND", + "properties" : + [ + { + "name" : "HELPSTRING", + "value" : "Path to cpack program executable." + } + ], + "type" : "INTERNAL", + "value" : "/usr/bin/cpack" + }, + { + "name" : "CMAKE_CTEST_COMMAND", + "properties" : + [ + { + "name" : "HELPSTRING", + "value" : "Path to ctest program executable." + } + ], + "type" : "INTERNAL", + "value" : "/usr/bin/ctest" + }, + { + "name" : "CMAKE_CXX_COMPILER", + "properties" : + [ + { + "name" : "HELPSTRING", + "value" : "No help, variable specified on the command line." + } + ], + "type" : "FILEPATH", + "value" : "/usr/bin/g++" + }, + { + "name" : "CMAKE_C_COMPILER", + "properties" : + [ + { + "name" : "HELPSTRING", + "value" : "No help, variable specified on the command line." + } + ], + "type" : "FILEPATH", + "value" : "/usr/bin/gcc" + }, + { + "name" : "CMAKE_EXPORT_COMPILE_COMMANDS", + "properties" : + [ + { + "name" : "HELPSTRING", + "value" : "No help, variable specified on the command line." + } + ], + "type" : "BOOL", + "value" : "TRUE" + }, + { + "name" : "CMAKE_EXTRA_GENERATOR", + "properties" : + [ + { + "name" : "HELPSTRING", + "value" : "Name of external makefile project generator." + } + ], + "type" : "INTERNAL", + "value" : "" + }, + { + "name" : "CMAKE_FIND_PACKAGE_REDIRECTS_DIR", + "properties" : + [ + { + "name" : "HELPSTRING", + "value" : "Value Computed by CMake." + } + ], + "type" : "STATIC", + "value" : "/root/Project/fusedmoe/build/CMakeFiles/pkgRedirects" + }, + { + "name" : "CMAKE_GENERATOR", + "properties" : + [ + { + "name" : "HELPSTRING", + "value" : "Name of generator." + } + ], + "type" : "INTERNAL", + "value" : "Ninja" + }, + { + "name" : "CMAKE_GENERATOR_INSTANCE", + "properties" : + [ + { + "name" : "HELPSTRING", + "value" : "Generator instance identifier." + } + ], + "type" : "INTERNAL", + "value" : "" + }, + { + "name" : "CMAKE_GENERATOR_PLATFORM", + "properties" : + [ + { + "name" : "HELPSTRING", + "value" : "Name of generator platform." + } + ], + "type" : "INTERNAL", + "value" : "" + }, + { + "name" : "CMAKE_GENERATOR_TOOLSET", + "properties" : + [ + { + "name" : "HELPSTRING", + "value" : "Name of generator toolset." + } + ], + "type" : "INTERNAL", + "value" : "" + }, + { + "name" : "CMAKE_HOME_DIRECTORY", + "properties" : + [ + { + "name" : "HELPSTRING", + "value" : "Source directory with the top level CMakeLists.txt file for this project" + } + ], + "type" : "INTERNAL", + "value" : "/root/Project/fusedmoe/standalone/fused_moe_i8_tn" + }, + { + "name" : "CMAKE_INSTALL_PREFIX", + "properties" : + [ + { + "name" : "HELPSTRING", + "value" : "Install path prefix, prepended onto install directories." + } + ], + "type" : "PATH", + "value" : "/usr/local" + }, + { + "name" : "CMAKE_INSTALL_SO_NO_EXE", + "properties" : + [ + { + "name" : "HELPSTRING", + "value" : "Install .so files without execute permission." + } + ], + "type" : "INTERNAL", + "value" : "1" + }, + { + "name" : "CMAKE_MAKE_PROGRAM", + "properties" : + [ + { + "name" : "ADVANCED", + "value" : "1" + }, + { + "name" : "HELPSTRING", + "value" : "Program used to build from build.ninja files." + } + ], + "type" : "FILEPATH", + "value" : "/opt/conda/bin/ninja" + }, + { + "name" : "CMAKE_NUMBER_OF_MAKEFILES", + "properties" : + [ + { + "name" : "HELPSTRING", + "value" : "number of local generators" + } + ], + "type" : "INTERNAL", + "value" : "1" + }, + { + "name" : "CMAKE_PLATFORM_INFO_INITIALIZED", + "properties" : + [ + { + "name" : "HELPSTRING", + "value" : "Platform information initialized" + } + ], + "type" : "INTERNAL", + "value" : "1" + }, + { + "name" : "CMAKE_PROJECT_DESCRIPTION", + "properties" : + [ + { + "name" : "HELPSTRING", + "value" : "Value Computed by CMake" + } + ], + "type" : "STATIC", + "value" : "" + }, + { + "name" : "CMAKE_PROJECT_HOMEPAGE_URL", + "properties" : + [ + { + "name" : "HELPSTRING", + "value" : "Value Computed by CMake" + } + ], + "type" : "STATIC", + "value" : "" + }, + { + "name" : "CMAKE_PROJECT_NAME", + "properties" : + [ + { + "name" : "HELPSTRING", + "value" : "Value Computed by CMake" + } + ], + "type" : "STATIC", + "value" : "fused_moe_i8_tn" + }, + { + "name" : "CMAKE_ROOT", + "properties" : + [ + { + "name" : "HELPSTRING", + "value" : "Path to CMake installation." + } + ], + "type" : "INTERNAL", + "value" : "/usr/share/cmake-3.28" + }, + { + "name" : "CMAKE_SKIP_INSTALL_RPATH", + "properties" : + [ + { + "name" : "ADVANCED", + "value" : "1" + }, + { + "name" : "HELPSTRING", + "value" : "If set, runtime paths are not added when installing shared libraries, but are added when building." + } + ], + "type" : "BOOL", + "value" : "NO" + }, + { + "name" : "CMAKE_SKIP_RPATH", + "properties" : + [ + { + "name" : "ADVANCED", + "value" : "1" + }, + { + "name" : "HELPSTRING", + "value" : "If set, runtime paths are not added when using shared libraries." + } + ], + "type" : "BOOL", + "value" : "NO" + }, + { + "name" : "CMAKE_UNAME", + "properties" : + [ + { + "name" : "HELPSTRING", + "value" : "uname command" + } + ], + "type" : "INTERNAL", + "value" : "/usr/bin/uname" + }, + { + "name" : "CMAKE_VERBOSE_MAKEFILE", + "properties" : + [ + { + "name" : "ADVANCED", + "value" : "1" + }, + { + "name" : "HELPSTRING", + "value" : "If this value is on, makefiles will be generated without the .SILENT directive, and all commands will be echoed to the console during the make. This is useful for debugging only. With Visual Studio IDE projects all commands are done without /nologo." + } + ], + "type" : "BOOL", + "value" : "FALSE" + }, + { + "name" : "MACA_PATH", + "properties" : + [ + { + "name" : "HELPSTRING", + "value" : "Path to MACA SDK" + } + ], + "type" : "PATH", + "value" : "/opt/maca" + }, + { + "name" : "MXCC", + "properties" : + [ + { + "name" : "HELPSTRING", + "value" : "Path to a program." + } + ], + "type" : "FILEPATH", + "value" : "/opt/maca/mxgpu_llvm/bin/mxcc" + }, + { + "name" : "_CMAKE_LINKER_PUSHPOP_STATE_SUPPORTED", + "properties" : + [ + { + "name" : "HELPSTRING", + "value" : "linker supports push/pop state" + } + ], + "type" : "INTERNAL", + "value" : "FALSE" + }, + { + "name" : "fused_moe_i8_tn_BINARY_DIR", + "properties" : + [ + { + "name" : "HELPSTRING", + "value" : "Value Computed by CMake" + } + ], + "type" : "STATIC", + "value" : "/root/Project/fusedmoe/build" + }, + { + "name" : "fused_moe_i8_tn_IS_TOP_LEVEL", + "properties" : + [ + { + "name" : "HELPSTRING", + "value" : "Value Computed by CMake" + } + ], + "type" : "STATIC", + "value" : "ON" + }, + { + "name" : "fused_moe_i8_tn_SOURCE_DIR", + "properties" : + [ + { + "name" : "HELPSTRING", + "value" : "Value Computed by CMake" + } + ], + "type" : "STATIC", + "value" : "/root/Project/fusedmoe/standalone/fused_moe_i8_tn" + } + ], + "kind" : "cache", + "version" : + { + "major" : 2, + "minor" : 0 + } +} diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/.cmake/api/v1/reply/cmakeFiles-v1-7899829d23c1c1ae3e98.json b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/.cmake/api/v1/reply/cmakeFiles-v1-7899829d23c1c1ae3e98.json new file mode 100644 index 0000000..99000ff --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/.cmake/api/v1/reply/cmakeFiles-v1-7899829d23c1c1ae3e98.json @@ -0,0 +1,73 @@ +{ + "inputs" : + [ + { + "path" : "CMakeLists.txt" + }, + { + "isCMake" : true, + "isExternal" : true, + "path" : "/usr/share/cmake-3.28/Modules/CMakeDetermineSystem.cmake" + }, + { + "isCMake" : true, + "isExternal" : true, + "path" : "/usr/share/cmake-3.28/Modules/CMakeSystem.cmake.in" + }, + { + "isGenerated" : true, + "path" : "/root/Project/fusedmoe/build/CMakeFiles/3.28.3/CMakeSystem.cmake" + }, + { + "isCMake" : true, + "isExternal" : true, + "path" : "/usr/share/cmake-3.28/Modules/CMakeNinjaFindMake.cmake" + }, + { + "isCMake" : true, + "isExternal" : true, + "path" : "/usr/share/cmake-3.28/Modules/CMakeSystemSpecificInitialize.cmake" + }, + { + "isCMake" : true, + "isExternal" : true, + "path" : "/usr/share/cmake-3.28/Modules/Platform/Linux-Initialize.cmake" + }, + { + "isCMake" : true, + "isExternal" : true, + "path" : "/usr/share/cmake-3.28/Modules/CMakeSystemSpecificInformation.cmake" + }, + { + "isCMake" : true, + "isExternal" : true, + "path" : "/usr/share/cmake-3.28/Modules/CMakeGenericSystem.cmake" + }, + { + "isCMake" : true, + "isExternal" : true, + "path" : "/usr/share/cmake-3.28/Modules/CMakeInitializeConfigs.cmake" + }, + { + "isCMake" : true, + "isExternal" : true, + "path" : "/usr/share/cmake-3.28/Modules/Platform/Linux.cmake" + }, + { + "isCMake" : true, + "isExternal" : true, + "path" : "/usr/share/cmake-3.28/Modules/Platform/UnixPaths.cmake" + } + ], + "kind" : "cmakeFiles", + "paths" : + { + "build" : "/root/Project/fusedmoe/build", + "source" : "/root/Project/fusedmoe/standalone/fused_moe_i8_tn" + }, + "version" : + { + "major" : 1, + "minor" : 0 + } +} diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/.cmake/api/v1/reply/codemodel-v2-7cd0b1b00876e71f364f.json b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/.cmake/api/v1/reply/codemodel-v2-7cd0b1b00876e71f364f.json new file mode 100644 index 0000000..507753c --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/.cmake/api/v1/reply/codemodel-v2-7cd0b1b00876e71f364f.json @@ -0,0 +1,69 @@ +{ + "configurations" : + [ + { + "directories" : + [ + { + "build" : ".", + "jsonFile" : "directory-.-Debug-f5ebdc15457944623624.json", + "minimumCMakeVersion" : + { + "string" : "3.20" + }, + "projectIndex" : 0, + "source" : ".", + "targetIndexes" : + [ + 0, + 1 + ] + } + ], + "name" : "Debug", + "projects" : + [ + { + "directoryIndexes" : + [ + 0 + ], + "name" : "fused_moe_i8_tn", + "targetIndexes" : + [ + 0, + 1 + ] + } + ], + "targets" : + [ + { + "directoryIndex" : 0, + "id" : "build_fused_moe_i8_tn_example::@6890427a1f51a3e7e1df", + "jsonFile" : "target-build_fused_moe_i8_tn_example-Debug-a97a299baa6c6c6d83d0.json", + "name" : "build_fused_moe_i8_tn_example", + "projectIndex" : 0 + }, + { + "directoryIndex" : 0, + "id" : "run::@6890427a1f51a3e7e1df", + "jsonFile" : "target-run-Debug-0d66e135afa1376e0f20.json", + "name" : "run", + "projectIndex" : 0 + } + ] + } + ], + "kind" : "codemodel", + "paths" : + { + "build" : "/root/Project/fusedmoe/build", + "source" : "/root/Project/fusedmoe/standalone/fused_moe_i8_tn" + }, + "version" : + { + "major" : 2, + "minor" : 6 + } +} diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/.cmake/api/v1/reply/directory-.-Debug-f5ebdc15457944623624.json b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/.cmake/api/v1/reply/directory-.-Debug-f5ebdc15457944623624.json new file mode 100644 index 0000000..3a67af9 --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/.cmake/api/v1/reply/directory-.-Debug-f5ebdc15457944623624.json @@ -0,0 +1,14 @@ +{ + "backtraceGraph" : + { + "commands" : [], + "files" : [], + "nodes" : [] + }, + "installers" : [], + "paths" : + { + "build" : ".", + "source" : "." + } +} diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/.cmake/api/v1/reply/index-2026-05-29T05-34-43-0302.json b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/.cmake/api/v1/reply/index-2026-05-29T05-34-43-0302.json new file mode 100644 index 0000000..109ba15 --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/.cmake/api/v1/reply/index-2026-05-29T05-34-43-0302.json @@ -0,0 +1,132 @@ +{ + "cmake" : + { + "generator" : + { + "multiConfig" : false, + "name" : "Ninja" + }, + "paths" : + { + "cmake" : "/usr/bin/cmake", + "cpack" : "/usr/bin/cpack", + "ctest" : "/usr/bin/ctest", + "root" : "/usr/share/cmake-3.28" + }, + "version" : + { + "isDirty" : false, + "major" : 3, + "minor" : 28, + "patch" : 3, + "string" : "3.28.3", + "suffix" : "" + } + }, + "objects" : + [ + { + "jsonFile" : "codemodel-v2-7cd0b1b00876e71f364f.json", + "kind" : "codemodel", + "version" : + { + "major" : 2, + "minor" : 6 + } + }, + { + "jsonFile" : "cache-v2-ea2ef11d05674d96d761.json", + "kind" : "cache", + "version" : + { + "major" : 2, + "minor" : 0 + } + }, + { + "jsonFile" : "cmakeFiles-v1-7899829d23c1c1ae3e98.json", + "kind" : "cmakeFiles", + "version" : + { + "major" : 1, + "minor" : 0 + } + }, + { + "jsonFile" : "toolchains-v1-8ae3cf416ede58af34e6.json", + "kind" : "toolchains", + "version" : + { + "major" : 1, + "minor" : 0 + } + } + ], + "reply" : + { + "client-vscode" : + { + "query.json" : + { + "requests" : + [ + { + "kind" : "cache", + "version" : 2 + }, + { + "kind" : "codemodel", + "version" : 2 + }, + { + "kind" : "toolchains", + "version" : 1 + }, + { + "kind" : "cmakeFiles", + "version" : 1 + } + ], + "responses" : + [ + { + "jsonFile" : "cache-v2-ea2ef11d05674d96d761.json", + "kind" : "cache", + "version" : + { + "major" : 2, + "minor" : 0 + } + }, + { + "jsonFile" : "codemodel-v2-7cd0b1b00876e71f364f.json", + "kind" : "codemodel", + "version" : + { + "major" : 2, + "minor" : 6 + } + }, + { + "jsonFile" : "toolchains-v1-8ae3cf416ede58af34e6.json", + "kind" : "toolchains", + "version" : + { + "major" : 1, + "minor" : 0 + } + }, + { + "jsonFile" : "cmakeFiles-v1-7899829d23c1c1ae3e98.json", + "kind" : "cmakeFiles", + "version" : + { + "major" : 1, + "minor" : 0 + } + } + ] + } + } + } +} diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/.cmake/api/v1/reply/target-build_fused_moe_i8_tn_example-Debug-a97a299baa6c6c6d83d0.json b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/.cmake/api/v1/reply/target-build_fused_moe_i8_tn_example-Debug-a97a299baa6c6c6d83d0.json new file mode 100644 index 0000000..b2bb402 --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/.cmake/api/v1/reply/target-build_fused_moe_i8_tn_example-Debug-a97a299baa6c6c6d83d0.json @@ -0,0 +1,73 @@ +{ + "backtrace" : 1, + "backtraceGraph" : + { + "commands" : + [ + "add_custom_target" + ], + "files" : + [ + "CMakeLists.txt" + ], + "nodes" : + [ + { + "file" : 0 + }, + { + "command" : 0, + "file" : 0, + "line" : 38, + "parent" : 0 + } + ] + }, + "id" : "build_fused_moe_i8_tn_example::@6890427a1f51a3e7e1df", + "name" : "build_fused_moe_i8_tn_example", + "paths" : + { + "build" : ".", + "source" : "." + }, + "sourceGroups" : + [ + { + "name" : "", + "sourceIndexes" : + [ + 0 + ] + }, + { + "name" : "CMake Rules", + "sourceIndexes" : + [ + 1, + 2 + ] + } + ], + "sources" : + [ + { + "backtrace" : 1, + "isGenerated" : true, + "path" : "/root/Project/fusedmoe/build/CMakeFiles/build_fused_moe_i8_tn_example", + "sourceGroupIndex" : 0 + }, + { + "backtrace" : 0, + "isGenerated" : true, + "path" : "/root/Project/fusedmoe/build/CMakeFiles/build_fused_moe_i8_tn_example.rule", + "sourceGroupIndex" : 1 + }, + { + "backtrace" : 0, + "isGenerated" : true, + "path" : "/root/Project/fusedmoe/build/fused_moe_i8_tn_example.rule", + "sourceGroupIndex" : 1 + } + ], + "type" : "UTILITY" +} diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/.cmake/api/v1/reply/target-run-Debug-0d66e135afa1376e0f20.json b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/.cmake/api/v1/reply/target-run-Debug-0d66e135afa1376e0f20.json new file mode 100644 index 0000000..3a3883e --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/.cmake/api/v1/reply/target-run-Debug-0d66e135afa1376e0f20.json @@ -0,0 +1,73 @@ +{ + "backtrace" : 1, + "backtraceGraph" : + { + "commands" : + [ + "add_custom_target" + ], + "files" : + [ + "CMakeLists.txt" + ], + "nodes" : + [ + { + "file" : 0 + }, + { + "command" : 0, + "file" : 0, + "line" : 40, + "parent" : 0 + } + ] + }, + "id" : "run::@6890427a1f51a3e7e1df", + "name" : "run", + "paths" : + { + "build" : ".", + "source" : "." + }, + "sourceGroups" : + [ + { + "name" : "", + "sourceIndexes" : + [ + 0 + ] + }, + { + "name" : "CMake Rules", + "sourceIndexes" : + [ + 1, + 2 + ] + } + ], + "sources" : + [ + { + "backtrace" : 1, + "isGenerated" : true, + "path" : "/root/Project/fusedmoe/build/CMakeFiles/run", + "sourceGroupIndex" : 0 + }, + { + "backtrace" : 0, + "isGenerated" : true, + "path" : "/root/Project/fusedmoe/build/CMakeFiles/run.rule", + "sourceGroupIndex" : 1 + }, + { + "backtrace" : 0, + "isGenerated" : true, + "path" : "/root/Project/fusedmoe/build/fused_moe_i8_tn_example.rule", + "sourceGroupIndex" : 1 + } + ], + "type" : "UTILITY" +} diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/.cmake/api/v1/reply/toolchains-v1-8ae3cf416ede58af34e6.json b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/.cmake/api/v1/reply/toolchains-v1-8ae3cf416ede58af34e6.json new file mode 100644 index 0000000..2fdb147 --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/.cmake/api/v1/reply/toolchains-v1-8ae3cf416ede58af34e6.json @@ -0,0 +1,18 @@ +{ + "kind" : "toolchains", + "toolchains" : + [ + { + "compiler" : + { + "implicit" : {} + }, + "language" : "NONE" + } + ], + "version" : + { + "major" : 1, + "minor" : 0 + } +} diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/CMakeCache.txt b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/CMakeCache.txt new file mode 100644 index 0000000..d8b74ab --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/CMakeCache.txt @@ -0,0 +1,127 @@ +# This is the CMakeCache file. +# For build in directory: /root/Project/fusedmoe/build +# It was generated by CMake: /usr/bin/cmake +# You can edit this file to change values found and used by cmake. +# If you do not want to change any of the values, simply exit the editor. +# If you do want to change a value, simply edit, save, and exit the editor. +# The syntax for the file is as follows: +# KEY:TYPE=VALUE +# KEY is the name of a variable in the cache. +# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT TYPE!. +# VALUE is the current value for the KEY. + +######################## +# EXTERNAL cache entries +######################## + +//No help, variable specified on the command line. +CMAKE_BUILD_TYPE:STRING=Debug + +//No help, variable specified on the command line. +CMAKE_CXX_COMPILER:FILEPATH=/usr/bin/g++ + +//No help, variable specified on the command line. +CMAKE_C_COMPILER:FILEPATH=/usr/bin/gcc + +//No help, variable specified on the command line. +CMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE + +//Value Computed by CMake. +CMAKE_FIND_PACKAGE_REDIRECTS_DIR:STATIC=/root/Project/fusedmoe/build/CMakeFiles/pkgRedirects + +//Install path prefix, prepended onto install directories. +CMAKE_INSTALL_PREFIX:PATH=/usr/local + +//Program used to build from build.ninja files. +CMAKE_MAKE_PROGRAM:FILEPATH=/opt/conda/bin/ninja + +//Value Computed by CMake +CMAKE_PROJECT_DESCRIPTION:STATIC= + +//Value Computed by CMake +CMAKE_PROJECT_HOMEPAGE_URL:STATIC= + +//Value Computed by CMake +CMAKE_PROJECT_NAME:STATIC=fused_moe_i8_tn + +//If set, runtime paths are not added when installing shared libraries, +// but are added when building. +CMAKE_SKIP_INSTALL_RPATH:BOOL=NO + +//If set, runtime paths are not added when using shared libraries. +CMAKE_SKIP_RPATH:BOOL=NO + +//If this value is on, makefiles will be generated without the +// .SILENT directive, and all commands will be echoed to the console +// during the make. This is useful for debugging only. With Visual +// Studio IDE projects all commands are done without /nologo. +CMAKE_VERBOSE_MAKEFILE:BOOL=FALSE + +//Path to MACA SDK +MACA_PATH:PATH=/opt/maca + +//Path to a program. +MXCC:FILEPATH=/opt/maca/mxgpu_llvm/bin/mxcc + +//Value Computed by CMake +fused_moe_i8_tn_BINARY_DIR:STATIC=/root/Project/fusedmoe/build + +//Value Computed by CMake +fused_moe_i8_tn_IS_TOP_LEVEL:STATIC=ON + +//Value Computed by CMake +fused_moe_i8_tn_SOURCE_DIR:STATIC=/root/Project/fusedmoe/standalone/fused_moe_i8_tn + + +######################## +# INTERNAL cache entries +######################## + +//This is the directory where this CMakeCache.txt was created +CMAKE_CACHEFILE_DIR:INTERNAL=/root/Project/fusedmoe/build +//Major version of cmake used to create the current loaded cache +CMAKE_CACHE_MAJOR_VERSION:INTERNAL=3 +//Minor version of cmake used to create the current loaded cache +CMAKE_CACHE_MINOR_VERSION:INTERNAL=28 +//Patch version of cmake used to create the current loaded cache +CMAKE_CACHE_PATCH_VERSION:INTERNAL=3 +//Path to CMake executable. +CMAKE_COMMAND:INTERNAL=/usr/bin/cmake +//Path to cpack program executable. +CMAKE_CPACK_COMMAND:INTERNAL=/usr/bin/cpack +//Path to ctest program executable. +CMAKE_CTEST_COMMAND:INTERNAL=/usr/bin/ctest +//Name of external makefile project generator. +CMAKE_EXTRA_GENERATOR:INTERNAL= +//Name of generator. +CMAKE_GENERATOR:INTERNAL=Ninja +//Generator instance identifier. +CMAKE_GENERATOR_INSTANCE:INTERNAL= +//Name of generator platform. +CMAKE_GENERATOR_PLATFORM:INTERNAL= +//Name of generator toolset. +CMAKE_GENERATOR_TOOLSET:INTERNAL= +//Source directory with the top level CMakeLists.txt file for this +// project +CMAKE_HOME_DIRECTORY:INTERNAL=/root/Project/fusedmoe/standalone/fused_moe_i8_tn +//Install .so files without execute permission. +CMAKE_INSTALL_SO_NO_EXE:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MAKE_PROGRAM +CMAKE_MAKE_PROGRAM-ADVANCED:INTERNAL=1 +//number of local generators +CMAKE_NUMBER_OF_MAKEFILES:INTERNAL=1 +//Platform information initialized +CMAKE_PLATFORM_INFO_INITIALIZED:INTERNAL=1 +//Path to CMake installation. +CMAKE_ROOT:INTERNAL=/usr/share/cmake-3.28 +//ADVANCED property for variable: CMAKE_SKIP_INSTALL_RPATH +CMAKE_SKIP_INSTALL_RPATH-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SKIP_RPATH +CMAKE_SKIP_RPATH-ADVANCED:INTERNAL=1 +//uname command +CMAKE_UNAME:INTERNAL=/usr/bin/uname +//ADVANCED property for variable: CMAKE_VERBOSE_MAKEFILE +CMAKE_VERBOSE_MAKEFILE-ADVANCED:INTERNAL=1 +//linker supports push/pop state +_CMAKE_LINKER_PUSHPOP_STATE_SUPPORTED:INTERNAL=FALSE + diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/CMakeFiles/3.28.3/CMakeSystem.cmake b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/CMakeFiles/3.28.3/CMakeSystem.cmake new file mode 100644 index 0000000..2e26099 --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/CMakeFiles/3.28.3/CMakeSystem.cmake @@ -0,0 +1,15 @@ +set(CMAKE_HOST_SYSTEM "Linux-5.15.0-58-generic") +set(CMAKE_HOST_SYSTEM_NAME "Linux") +set(CMAKE_HOST_SYSTEM_VERSION "5.15.0-58-generic") +set(CMAKE_HOST_SYSTEM_PROCESSOR "x86_64") + + + +set(CMAKE_SYSTEM "Linux-5.15.0-58-generic") +set(CMAKE_SYSTEM_NAME "Linux") +set(CMAKE_SYSTEM_VERSION "5.15.0-58-generic") +set(CMAKE_SYSTEM_PROCESSOR "x86_64") + +set(CMAKE_CROSSCOMPILING "FALSE") + +set(CMAKE_SYSTEM_LOADED 1) diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/CMakeFiles/CMakeConfigureLog.yaml b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/CMakeFiles/CMakeConfigureLog.yaml new file mode 100644 index 0000000..17b4ac2 --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/CMakeFiles/CMakeConfigureLog.yaml @@ -0,0 +1,11 @@ + +--- +events: + - + kind: "message-v1" + backtrace: + - "/usr/share/cmake-3.28/Modules/CMakeDetermineSystem.cmake:233 (message)" + - "CMakeLists.txt:3 (project)" + message: | + The system is: Linux - 5.15.0-58-generic - x86_64 +... diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/CMakeFiles/TargetDirectories.txt b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/CMakeFiles/TargetDirectories.txt new file mode 100644 index 0000000..8336d29 --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/CMakeFiles/TargetDirectories.txt @@ -0,0 +1,4 @@ +/root/Project/fusedmoe/build/CMakeFiles/build_fused_moe_i8_tn_example.dir +/root/Project/fusedmoe/build/CMakeFiles/run.dir +/root/Project/fusedmoe/build/CMakeFiles/edit_cache.dir +/root/Project/fusedmoe/build/CMakeFiles/rebuild_cache.dir diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/CMakeFiles/cmake.check_cache b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/CMakeFiles/cmake.check_cache new file mode 100644 index 0000000..3dccd73 --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/CMakeFiles/cmake.check_cache @@ -0,0 +1 @@ +# This file is generated by cmake for dependency checking of the CMakeCache.txt file diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/CMakeFiles/rules.ninja b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/CMakeFiles/rules.ninja new file mode 100644 index 0000000..ede407b --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/CMakeFiles/rules.ninja @@ -0,0 +1,45 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Ninja" Generator, CMake Version 3.28 + +# This file contains all the rules used to get the outputs files +# built from the input files. +# It is included in the main 'build.ninja'. + +# ============================================================================= +# Project: fused_moe_i8_tn +# Configurations: Debug +# ============================================================================= +# ============================================================================= + +############################################# +# Rule for running custom commands. + +rule CUSTOM_COMMAND + command = $COMMAND + description = $DESC + + +############################################# +# Rule for re-running cmake. + +rule RERUN_CMAKE + command = /usr/bin/cmake --regenerate-during-build -S/root/Project/fusedmoe/standalone/fused_moe_i8_tn -B/root/Project/fusedmoe/build + description = Re-running CMake... + generator = 1 + + +############################################# +# Rule for cleaning all built files. + +rule CLEAN + command = /opt/conda/bin/ninja $FILE_ARG -t clean $TARGETS + description = Cleaning all built files... + + +############################################# +# Rule for printing all primary targets available. + +rule HELP + command = /opt/conda/bin/ninja -t targets + description = All primary targets available: + diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/build.ninja b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/build.ninja new file mode 100644 index 0000000..76ee09c --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/build.ninja @@ -0,0 +1,146 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Ninja" Generator, CMake Version 3.28 + +# This file contains all the build statements describing the +# compilation DAG. + +# ============================================================================= +# Write statements declared in CMakeLists.txt: +# +# Which is the root file. +# ============================================================================= + +# ============================================================================= +# Project: fused_moe_i8_tn +# Configurations: Debug +# ============================================================================= + +############################################# +# Minimal version of Ninja required by this file + +ninja_required_version = 1.5 + + +############################################# +# Set configuration variable for custom commands. + +CONFIGURATION = Debug +# ============================================================================= +# Include auxiliary files. + + +############################################# +# Include rules file. + +include CMakeFiles/rules.ninja + +# ============================================================================= + +############################################# +# Logical path to working directory; prefix for absolute paths. + +cmake_ninja_workdir = /root/Project/fusedmoe/build/ + +############################################# +# Utility command for build_fused_moe_i8_tn_example + +build build_fused_moe_i8_tn_example: phony CMakeFiles/build_fused_moe_i8_tn_example fused_moe_i8_tn_example + + +############################################# +# Utility command for run + +build run: phony CMakeFiles/run fused_moe_i8_tn_example + + +############################################# +# Utility command for edit_cache + +build CMakeFiles/edit_cache.util: CUSTOM_COMMAND + COMMAND = cd /root/Project/fusedmoe/build && /usr/bin/cmake -E echo No\ interactive\ CMake\ dialog\ available. + DESC = No interactive CMake dialog available... + restat = 1 + +build edit_cache: phony CMakeFiles/edit_cache.util + + +############################################# +# Utility command for rebuild_cache + +build CMakeFiles/rebuild_cache.util: CUSTOM_COMMAND + COMMAND = cd /root/Project/fusedmoe/build && /usr/bin/cmake --regenerate-during-build -S/root/Project/fusedmoe/standalone/fused_moe_i8_tn -B/root/Project/fusedmoe/build + DESC = Running CMake to regenerate build system... + pool = console + restat = 1 + +build rebuild_cache: phony CMakeFiles/rebuild_cache.util + + +############################################# +# Phony custom command for CMakeFiles/build_fused_moe_i8_tn_example + +build CMakeFiles/build_fused_moe_i8_tn_example | ${cmake_ninja_workdir}CMakeFiles/build_fused_moe_i8_tn_example: phony fused_moe_i8_tn_example + + +############################################# +# Custom command for fused_moe_i8_tn_example + +build fused_moe_i8_tn_example | ${cmake_ninja_workdir}fused_moe_i8_tn_example: CUSTOM_COMMAND /root/Project/fusedmoe/standalone/fused_moe_i8_tn/src/fused_moe_i8_tn_example.cpp + COMMAND = cd /root/Project/fusedmoe/standalone/fused_moe_i8_tn && /opt/maca/mxgpu_llvm/bin/mxcc -std=c++17 -xmaca -I\"/root/Project/fusedmoe/standalone/fused_moe_i8_tn/src\" -I\"/opt/maca/include\" /root/Project/fusedmoe/standalone/fused_moe_i8_tn/src/fused_moe_i8_tn_example.cpp -L\"/opt/maca/lib\" -lmcruntime -o /root/Project/fusedmoe/build/fused_moe_i8_tn_example + DESC = Generating fused_moe_i8_tn_example + restat = 1 + + +############################################# +# Custom command for CMakeFiles/run + +build CMakeFiles/run | ${cmake_ninja_workdir}CMakeFiles/run: CUSTOM_COMMAND fused_moe_i8_tn_example + COMMAND = cd /root/Project/fusedmoe/build && /root/Project/fusedmoe/build/fused_moe_i8_tn_example + pool = console + +# ============================================================================= +# Target aliases. + +# ============================================================================= +# Folder targets. + +# ============================================================================= + +############################################# +# Folder: /root/Project/fusedmoe/build + +build all: phony build_fused_moe_i8_tn_example + +# ============================================================================= +# Built-in targets + + +############################################# +# Re-run CMake if any of its inputs changed. + +build build.ninja: RERUN_CMAKE | /root/Project/fusedmoe/standalone/fused_moe_i8_tn/CMakeLists.txt /usr/share/cmake-3.28/Modules/CMakeDetermineSystem.cmake /usr/share/cmake-3.28/Modules/CMakeGenericSystem.cmake /usr/share/cmake-3.28/Modules/CMakeInitializeConfigs.cmake /usr/share/cmake-3.28/Modules/CMakeNinjaFindMake.cmake /usr/share/cmake-3.28/Modules/CMakeSystem.cmake.in /usr/share/cmake-3.28/Modules/CMakeSystemSpecificInformation.cmake /usr/share/cmake-3.28/Modules/CMakeSystemSpecificInitialize.cmake /usr/share/cmake-3.28/Modules/Platform/Linux-Initialize.cmake /usr/share/cmake-3.28/Modules/Platform/Linux.cmake /usr/share/cmake-3.28/Modules/Platform/UnixPaths.cmake CMakeCache.txt CMakeFiles/3.28.3/CMakeSystem.cmake + pool = console + + +############################################# +# A missing CMake input file is not an error. + +build /root/Project/fusedmoe/standalone/fused_moe_i8_tn/CMakeLists.txt /usr/share/cmake-3.28/Modules/CMakeDetermineSystem.cmake /usr/share/cmake-3.28/Modules/CMakeGenericSystem.cmake /usr/share/cmake-3.28/Modules/CMakeInitializeConfigs.cmake /usr/share/cmake-3.28/Modules/CMakeNinjaFindMake.cmake /usr/share/cmake-3.28/Modules/CMakeSystem.cmake.in /usr/share/cmake-3.28/Modules/CMakeSystemSpecificInformation.cmake /usr/share/cmake-3.28/Modules/CMakeSystemSpecificInitialize.cmake /usr/share/cmake-3.28/Modules/Platform/Linux-Initialize.cmake /usr/share/cmake-3.28/Modules/Platform/Linux.cmake /usr/share/cmake-3.28/Modules/Platform/UnixPaths.cmake CMakeCache.txt CMakeFiles/3.28.3/CMakeSystem.cmake: phony + + +############################################# +# Clean all the built files. + +build clean: CLEAN + + +############################################# +# Print all primary targets available. + +build help: HELP + + +############################################# +# Make the all target the default. + +default all diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/cmake_install.cmake b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/cmake_install.cmake new file mode 100644 index 0000000..9a85ad9 --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/build/cmake_install.cmake @@ -0,0 +1,49 @@ +# Install script for directory: /root/Project/fusedmoe/standalone/fused_moe_i8_tn + +# Set the install prefix +if(NOT DEFINED CMAKE_INSTALL_PREFIX) + set(CMAKE_INSTALL_PREFIX "/usr/local") +endif() +string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") + +# Set the install configuration name. +if(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME) + if(BUILD_TYPE) + string(REGEX REPLACE "^[^A-Za-z0-9_]+" "" + CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}") + else() + set(CMAKE_INSTALL_CONFIG_NAME "Debug") + endif() + message(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"") +endif() + +# Set the component getting installed. +if(NOT CMAKE_INSTALL_COMPONENT) + if(COMPONENT) + message(STATUS "Install component: \"${COMPONENT}\"") + set(CMAKE_INSTALL_COMPONENT "${COMPONENT}") + else() + set(CMAKE_INSTALL_COMPONENT) + endif() +endif() + +# Install shared libraries without execute permission? +if(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE) + set(CMAKE_INSTALL_SO_NO_EXE "1") +endif() + +# Is this installation the result of a crosscompile? +if(NOT DEFINED CMAKE_CROSSCOMPILING) + set(CMAKE_CROSSCOMPILING "FALSE") +endif() + +if(CMAKE_INSTALL_COMPONENT) + set(CMAKE_INSTALL_MANIFEST "install_manifest_${CMAKE_INSTALL_COMPONENT}.txt") +else() + set(CMAKE_INSTALL_MANIFEST "install_manifest.txt") +endif() + +string(REPLACE ";" "\n" CMAKE_INSTALL_MANIFEST_CONTENT + "${CMAKE_INSTALL_MANIFEST_FILES}") +file(WRITE "/root/Project/fusedmoe/build/${CMAKE_INSTALL_MANIFEST}" + "${CMAKE_INSTALL_MANIFEST_CONTENT}") diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/scripts/build_fused_moe_i8_tn_pybind.sh b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/scripts/build_fused_moe_i8_tn_pybind.sh new file mode 100644 index 0000000..785ed79 --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/scripts/build_fused_moe_i8_tn_pybind.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash + +set -euo pipefail + +MACA_PATH="${MACA_PATH:-/opt/maca}" +PYTHON_BIN="${PYTHON_BIN:-/opt/conda/bin/python}" +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" + +export MACA_PATH +export LD_LIBRARY_PATH="$MACA_PATH/mxgpu_llvm/lib:$MACA_PATH/lib:${LD_LIBRARY_PATH:-}" + +BUILD_DIR="$ROOT_DIR/standalone/fused_moe_i8_tn/build" +SO="$BUILD_DIR/fused_moe_i8_tn_pybind.so" +SRC="$ROOT_DIR/standalone/fused_moe_i8_tn/src/fused_moe_i8_tn_pybind.cpp" + +mkdir -p "$BUILD_DIR" + +PYTHON_INCLUDE="$("${PYTHON_BIN}" -c "import sysconfig; print(sysconfig.get_path('include'))")" +PYTHON_LIB="$("${PYTHON_BIN}" -c "import sysconfig; print(sysconfig.get_config_var('LIBDIR'))")" +PYTHON_LDLIB="$("${PYTHON_BIN}" -c "import sysconfig; print(sysconfig.get_config_var('LDLIBRARY'))")" + +PYBIND11_INCLUDE="$ROOT_DIR/third_party/pybind11/include" + +"$MACA_PATH/mxgpu_llvm/bin/mxcc" \ + -std=c++17 \ + -O2 \ + -c \ + -xmaca \ + -fPIC \ + -I"$ROOT_DIR/include" \ + -I"$MACA_PATH/include" \ + -I"$PYTHON_INCLUDE" \ + -I"$PYBIND11_INCLUDE" \ + "$SRC" \ + -o "$BUILD_DIR/fused_moe_i8_tn_pybind.o" + + +g++ \ + -std=c++17 \ + -O2 \ + -shared \ + -fPIC \ + "$BUILD_DIR/fused_moe_i8_tn_pybind.o" \ + -L"$MACA_PATH/lib" \ + -L"/opt/conda/lib" \ + -Wl,-rpath,"/opt/conda/lib" \ + -l:"libpython3.12.so" \ + -lmcruntime \ + -lmccompiler \ + -o "$SO" + +echo "[SUCCESS] $SO" diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/scripts/run_fused_moe_i8_tn_benchmark.sh b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/scripts/run_fused_moe_i8_tn_benchmark.sh new file mode 100644 index 0000000..8469e64 --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/scripts/run_fused_moe_i8_tn_benchmark.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +PYTHON_BIN="${PYTHON_BIN:-/opt/conda/bin/python}" +MACA_PATH="${MACA_PATH:-/opt/maca-20260318}" + +export MACA_PATH +export LD_LIBRARY_PATH="$MACA_PATH/mxgpu_llvm/lib:$MACA_PATH/lib:${LD_LIBRARY_PATH:-}" + +"$PYTHON_BIN" "$ROOT_DIR/standalone/fused_moe_i8_tn/python/benchmark_fused_moe_i8_tn.py" "$@" diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/scripts/run_fused_moe_i8_tn_pybind_test.sh b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/scripts/run_fused_moe_i8_tn_pybind_test.sh new file mode 100644 index 0000000..72108bb --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/scripts/run_fused_moe_i8_tn_pybind_test.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +PYTHON_BIN="${PYTHON_BIN:-/opt/conda/bin/python}" +MACA_PATH="${MACA_PATH:-/opt/maca-20260318}" + +export MACA_PATH +export LD_LIBRARY_PATH="$MACA_PATH/mxgpu_llvm/lib:$MACA_PATH/lib:${LD_LIBRARY_PATH:-}" + +"$PYTHON_BIN" "$ROOT_DIR/standalone/fused_moe_i8_tn/python/test_fused_moe_i8_tn_pybind.py" "$@" diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_bf16_tn/CMakeLists.txt b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_bf16_tn/CMakeLists.txt new file mode 100644 index 0000000..ba191a2 --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_bf16_tn/CMakeLists.txt @@ -0,0 +1,45 @@ +cmake_minimum_required(VERSION 3.20) + +project(fused_moe_bf16_tn LANGUAGES NONE) + +set(MACA_PATH "$ENV{MACA_PATH}" CACHE PATH "Path to MACA SDK") +if(NOT MACA_PATH) + set(MACA_PATH "/opt/maca") +endif() + +find_program(MXCC + NAMES mxcc + PATHS "${MACA_PATH}/mxgpu_llvm/bin" + NO_DEFAULT_PATH) + +if(NOT MXCC) + message(FATAL_ERROR "mxcc not found under ${MACA_PATH}/mxgpu_llvm/bin") +endif() + +set(EXAMPLE_ROOT "${CMAKE_CURRENT_SOURCE_DIR}") +get_filename_component(ROOT_DIR "${EXAMPLE_ROOT}/../.." ABSOLUTE) +set(SRC "${EXAMPLE_ROOT}/src/fused_moe_bf16_tn_example.cpp") +set(BIN "${CMAKE_CURRENT_BINARY_DIR}/fused_moe_bf16_tn_example") + +add_custom_command( + OUTPUT "${BIN}" + COMMAND "${MXCC}" + -std=c++17 + -xmaca + -I"${ROOT_DIR}/include" + -I"${MACA_PATH}/include" + "${SRC}" + -L"${MACA_PATH}/lib" + -lmcruntime + -o "${BIN}" + DEPENDS "${SRC}" + WORKING_DIRECTORY "${ROOT_DIR}" + VERBATIM) + +add_custom_target(build_fused_moe_bf16_tn_example ALL DEPENDS "${BIN}") + +add_custom_target( + run + COMMAND "${BIN}" + DEPENDS "${BIN}" + USES_TERMINAL) diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_bf16_tn/Makefile b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_bf16_tn/Makefile new file mode 100644 index 0000000..1a343b6 --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_bf16_tn/Makefile @@ -0,0 +1,28 @@ +MACA_PATH ?= /opt/maca +MXCC := $(MACA_PATH)/mxgpu_llvm/bin/mxcc +ROOT_DIR := $(abspath $(CURDIR)/../..) +BUILD_DIR := $(CURDIR)/build +SRC := $(CURDIR)/src/fused_moe_bf16_tn_example.cpp +BIN := $(BUILD_DIR)/fused_moe_bf16_tn_example + +.PHONY: all build run clean + +all: build + +build: $(BIN) + +$(BIN): $(SRC) + mkdir -p $(BUILD_DIR) + $(MXCC) -std=c++17 -xmaca \ + -I$(ROOT_DIR)/include \ + -I$(MACA_PATH)/include \ + $(SRC) \ + -L$(MACA_PATH)/lib \ + -lmcruntime \ + -o $(BIN) + +run: $(BIN) + $(BIN) + +clean: + rm -rf $(BUILD_DIR) diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_bf16_tn/src/fused_moe_bf16_tn_example.cpp b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_bf16_tn/src/fused_moe_bf16_tn_example.cpp new file mode 100644 index 0000000..bdce6ef --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_bf16_tn/src/fused_moe_bf16_tn_example.cpp @@ -0,0 +1,246 @@ +#include + +#include +#include +#include +#include +#include +#include + +#include "mctlass/bfloat16.h" +#include "mctlass/frontend_op/gemm_config.h" +#include "mctlass/frontend_op/mctlass_moe_gemm.h" + +namespace { + +using Bf16 = maca_bfloat16; +using LayoutA = mctlass::layout::RowMajor; +using LayoutB = mctlass::layout::ColumnMajor; +using LayoutC = mctlass::layout::RowMajor; +using GemmOp = mctlassMoeGemm; + +constexpr int kNumExperts = 2; +constexpr int kNumTokens = 256; +constexpr int kTopK = 1; +constexpr int kEM = 256; +constexpr int kN = 128; +constexpr int kK = 64; +constexpr int kTileM = 128; + +void check_mc(mcError_t status, const char *expr) { + if (status != mcSuccess) { + std::cerr << expr << " failed: " << mcGetErrorString(status) << '\n'; + std::exit(EXIT_FAILURE); + } +} + +void check_mctlass(mctlass::Status status, const char *expr) { + if (status != mctlass::Status::kSuccess) { + std::cerr << expr << " failed: " << mctlass::mctlassGetStatusString(status) << '\n'; + std::exit(EXIT_FAILURE); + } +} + +Bf16 float_to_bf16(float value) { + return mctlass::bfloat16_t(value).to_bfloat(); +} + +float bf16_to_float(Bf16 value) { + return static_cast(mctlass::bfloat16_t(value)); +} + +void fill_inputs(std::vector &a, + std::vector &b_col_major, + std::vector &moe_weights, + std::vector &token_ids, + std::vector &expert_ids) { + a.resize(static_cast(kNumTokens) * kK); + b_col_major.resize(static_cast(kNumExperts) * kN * kK); + moe_weights.resize(kEM); + token_ids.resize(kEM); + expert_ids = {0, 1}; + + for (int row = 0; row < kNumTokens; ++row) { + for (int kk = 0; kk < kK; ++kk) { + const float value = ((row * 11 + kk * 5 + 7) % 29 - 14) * 0.125f; + a[static_cast(row) * kK + kk] = float_to_bf16(value); + } + token_ids[row] = row; + moe_weights[row] = 0.5f + 0.03125f * static_cast(row % 7); + } + + for (int expert = 0; expert < kNumExperts; ++expert) { + for (int col = 0; col < kN; ++col) { + for (int kk = 0; kk < kK; ++kk) { + const float value = ((expert * 13 + col * 3 + kk * 7 + 1) % 31 - 15) * 0.0625f; + b_col_major[(static_cast(expert) * kN + col) * kK + kk] = float_to_bf16(value); + } + } + } +} + +std::vector reference_fused_moe(const std::vector &a, + const std::vector &b_col_major, + const std::vector &moe_weights, + const std::vector &token_ids, + const std::vector &expert_ids) { + std::vector out(static_cast(kEM) * kN, float_to_bf16(0.0f)); + + for (int routed_row = 0; routed_row < kEM; ++routed_row) { + const int token = token_ids[routed_row]; + const int tile_idx = routed_row / kTileM; + const int expert = expert_ids[tile_idx]; + const float moe_weight = moe_weights[routed_row]; + + for (int col = 0; col < kN; ++col) { + float acc = 0.0f; + for (int kk = 0; kk < kK; ++kk) { + acc += bf16_to_float(a[static_cast(token) * kK + kk]) * + bf16_to_float(b_col_major[(static_cast(expert) * kN + col) * kK + kk]); + } + out[static_cast(routed_row) * kN + col] = float_to_bf16(acc * moe_weight); + } + } + + return out; +} + +bool validate_result(const std::vector &got, const std::vector &expected) { + constexpr float kTolerance = 2e-2f; + size_t mismatch_count = 0; + size_t first_bad = 0; + float max_abs = 0.0f; + + for (size_t i = 0; i < got.size(); ++i) { + const float got_f = bf16_to_float(got[i]); + const float exp_f = bf16_to_float(expected[i]); + const float abs_err = std::fabs(got_f - exp_f); + max_abs = std::max(max_abs, abs_err); + if (abs_err > kTolerance) { + if (mismatch_count == 0) { + first_bad = i; + } + ++mismatch_count; + } + } + + if (mismatch_count != 0) { + const int row = static_cast(first_bad / kN); + const int col = static_cast(first_bad % kN); + std::cerr << "fused_moe_bf16_tn failed" + << ": mismatches=" << mismatch_count + << ", first mismatch at (" << row << ", " << col << ")" + << ", got=" << bf16_to_float(got[first_bad]) + << ", expected=" << bf16_to_float(expected[first_bad]) + << ", max_abs=" << max_abs << '\n'; + return false; + } + + std::cout << "fused_moe_bf16_tn passed" + << ": rows=" << kEM + << ", topk=" << kTopK + << ", N=" << kN + << ", K=" << kK + << ", sample C[0]=" << bf16_to_float(got.front()) + << ", C[last]=" << bf16_to_float(got.back()) + << ", max_abs=" << max_abs << '\n'; + return true; +} + +} // namespace + +int main() { + int device_count = 0; + check_mc(mcGetDeviceCount(&device_count), "mcGetDeviceCount"); + if (device_count <= 0) { + std::cerr << "No MACA device is visible.\n"; + return EXIT_FAILURE; + } + check_mc(mcSetDevice(0), "mcSetDevice"); + + std::vector host_a; + std::vector host_b; + std::vector host_moe_weights; + std::vector host_token_ids; + std::vector host_expert_ids; + std::vector host_num_tokens_post_padded(1, kEM); + std::vector host_output(static_cast(kEM) * kN, float_to_bf16(0.0f)); + + fill_inputs(host_a, host_b, host_moe_weights, host_token_ids, host_expert_ids); + const std::vector expected = + reference_fused_moe(host_a, host_b, host_moe_weights, host_token_ids, host_expert_ids); + + Bf16 *dev_a = nullptr; + Bf16 *dev_b = nullptr; + float *dev_moe_weights = nullptr; + int *dev_token_ids = nullptr; + int *dev_expert_ids = nullptr; + int32_t *dev_num_tokens_post_padded = nullptr; + Bf16 *dev_c = nullptr; + + check_mc(mcMalloc(reinterpret_cast(&dev_a), host_a.size() * sizeof(Bf16)), "mcMalloc(dev_a)"); + check_mc(mcMalloc(reinterpret_cast(&dev_b), host_b.size() * sizeof(Bf16)), "mcMalloc(dev_b)"); + check_mc(mcMalloc(reinterpret_cast(&dev_moe_weights), host_moe_weights.size() * sizeof(float)), + "mcMalloc(dev_moe_weights)"); + check_mc(mcMalloc(reinterpret_cast(&dev_token_ids), host_token_ids.size() * sizeof(int)), + "mcMalloc(dev_token_ids)"); + check_mc(mcMalloc(reinterpret_cast(&dev_expert_ids), host_expert_ids.size() * sizeof(int)), + "mcMalloc(dev_expert_ids)"); + check_mc(mcMalloc(reinterpret_cast(&dev_num_tokens_post_padded), + host_num_tokens_post_padded.size() * sizeof(int32_t)), + "mcMalloc(dev_num_tokens_post_padded)"); + check_mc(mcMalloc(reinterpret_cast(&dev_c), host_output.size() * sizeof(Bf16)), "mcMalloc(dev_c)"); + + check_mc(mcMemcpy(dev_a, host_a.data(), host_a.size() * sizeof(Bf16), mcMemcpyHostToDevice), "mcMemcpy(dev_a)"); + check_mc(mcMemcpy(dev_b, host_b.data(), host_b.size() * sizeof(Bf16), mcMemcpyHostToDevice), "mcMemcpy(dev_b)"); + check_mc(mcMemcpy(dev_moe_weights, + host_moe_weights.data(), + host_moe_weights.size() * sizeof(float), + mcMemcpyHostToDevice), + "mcMemcpy(dev_moe_weights)"); + check_mc(mcMemcpy(dev_token_ids, host_token_ids.data(), host_token_ids.size() * sizeof(int), mcMemcpyHostToDevice), + "mcMemcpy(dev_token_ids)"); + check_mc(mcMemcpy(dev_expert_ids, + host_expert_ids.data(), + host_expert_ids.size() * sizeof(int), + mcMemcpyHostToDevice), + "mcMemcpy(dev_expert_ids)"); + check_mc(mcMemcpy(dev_num_tokens_post_padded, + host_num_tokens_post_padded.data(), + host_num_tokens_post_padded.size() * sizeof(int32_t), + mcMemcpyHostToDevice), + "mcMemcpy(dev_num_tokens_post_padded)"); + check_mc(mcMemset(dev_c, 0, host_output.size() * sizeof(Bf16)), "mcMemset(dev_c)"); + + GemmOp gemm_op; + typename GemmOp::Arguments args( + mctlass::gemm::GemmUniversalMode::kGemm, + mctlass::gemm::BatchedGemmCoord(kEM, kN, kK, kNumExperts), + typename GemmOp::epilogueParams(dev_moe_weights), + dev_a, + dev_b, + dev_c, + typename GemmOp::moeParams(dev_token_ids, + dev_expert_ids, + dev_num_tokens_post_padded, + kEM, + kTopK, + true)); + + check_mctlass(gemm_op(args, nullptr, nullptr), "gemm_op"); + check_mc(mcDeviceSynchronize(), "mcDeviceSynchronize"); + check_mc(mcGetLastError(), "mcGetLastError"); + + check_mc(mcMemcpy(host_output.data(), dev_c, host_output.size() * sizeof(Bf16), mcMemcpyDeviceToHost), + "mcMemcpy(host_output)"); + + check_mc(mcFree(dev_a), "mcFree(dev_a)"); + check_mc(mcFree(dev_b), "mcFree(dev_b)"); + check_mc(mcFree(dev_moe_weights), "mcFree(dev_moe_weights)"); + check_mc(mcFree(dev_token_ids), "mcFree(dev_token_ids)"); + check_mc(mcFree(dev_expert_ids), "mcFree(dev_expert_ids)"); + check_mc(mcFree(dev_num_tokens_post_padded), "mcFree(dev_num_tokens_post_padded)"); + check_mc(mcFree(dev_c), "mcFree(dev_c)"); + + return validate_result(host_output, expected) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/CMakeLists.txt b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/CMakeLists.txt new file mode 100644 index 0000000..897693f --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/CMakeLists.txt @@ -0,0 +1,44 @@ +cmake_minimum_required(VERSION 3.20) + +project(fused_moe_i8_tn LANGUAGES NONE) + +set(MACA_PATH "$ENV{MACA_PATH}" CACHE PATH "Path to MACA SDK") +if(NOT MACA_PATH) + set(MACA_PATH "/opt/maca") +endif() + +find_program(MXCC + NAMES mxcc + PATHS "${MACA_PATH}/mxgpu_llvm/bin" + NO_DEFAULT_PATH) + +if(NOT MXCC) + message(FATAL_ERROR "mxcc not found under ${MACA_PATH}/mxgpu_llvm/bin") +endif() + +set(EXAMPLE_ROOT "${CMAKE_CURRENT_SOURCE_DIR}") +set(SRC "${EXAMPLE_ROOT}/src/fused_moe_i8_tn_example.cpp") +set(BIN "${CMAKE_CURRENT_BINARY_DIR}/fused_moe_i8_tn_example") + +add_custom_command( + OUTPUT "${BIN}" + COMMAND "${MXCC}" + -std=c++17 + -xmaca + -I"${EXAMPLE_ROOT}/src" + -I"${MACA_PATH}/include" + "${SRC}" + -L"${MACA_PATH}/lib" + -lmcruntime + -o "${BIN}" + DEPENDS "${SRC}" + WORKING_DIRECTORY "${EXAMPLE_ROOT}" + VERBATIM) + +add_custom_target(build_fused_moe_i8_tn_example ALL DEPENDS "${BIN}") + +add_custom_target( + run + COMMAND "${BIN}" + DEPENDS "${BIN}" + USES_TERMINAL) diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/Makefile b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/Makefile new file mode 100644 index 0000000..869704f --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/Makefile @@ -0,0 +1,27 @@ +MACA_PATH ?= /opt/maca +MXCC := $(MACA_PATH)/mxgpu_llvm/bin/mxcc +BUILD_DIR := $(CURDIR)/build +SRC := $(CURDIR)/src/fused_moe_i8_tn_example.cpp +BIN := $(BUILD_DIR)/fused_moe_i8_tn_example + +.PHONY: all build run clean + +all: build + +build: $(BIN) + +$(BIN): $(SRC) + mkdir -p $(BUILD_DIR) + $(MXCC) -std=c++17 -xmaca \ + -I$(CURDIR)/src \ + -I$(MACA_PATH)/include \ + $(SRC) \ + -L$(MACA_PATH)/lib \ + -lmcruntime \ + -o $(BIN) + +run: $(BIN) + $(BIN) + +clean: + rm -rf $(BUILD_DIR) diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/benchmark_results.md b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/benchmark_results.md new file mode 100644 index 0000000..4fe76e0 --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/benchmark_results.md @@ -0,0 +1,30 @@ +# Fused MoE i8 TN Benchmark Results + +Remote run environment: + +- host: `10.2.118.21` +- repo: `/home/acl_dnn/mcTlass` +- binary: `standalone/fused_moe_i8_tn/build/fused_moe_i8_tn_example` + +Benchmark command used: + +```bash +MCTLASS_MOE_WARMUP=2 MCTLASS_MOE_ITERS=5 ./standalone/fused_moe_i8_tn/build/fused_moe_i8_tn_example +``` + +Results: + +```text +Benchmark config: warmup=2, iters=5 +fused_moe_i8_tn_topk1 passed: rows=256, topk=1, N=128, K=128, sample C[0]=0.695312, C[last]=-0.445312, max_abs=0 +fused_moe_i8_tn_topk1 benchmark: avg_ms=0.0137216, TOPS=0.611343, warmup=2, iters=5 +fused_moe_i8_tn_topk2 passed: rows=512, topk=2, N=128, K=128, sample C[0]=-0.578125, C[last]=-0.498047, max_abs=0 +fused_moe_i8_tn_topk2 benchmark: avg_ms=0.0121856, TOPS=1.37681, warmup=2, iters=5 +fused_moe_i8_tn_topk3 passed: rows=384, topk=3, N=128, K=128, sample C[0]=-1.08594, C[last]=-0.335938, max_abs=0 +fused_moe_i8_tn_topk3 benchmark: avg_ms=0.0124416, TOPS=1.01136, warmup=2, iters=5 +``` + +Notes: + +- current numbers are from a short sanity benchmark, not a long stabilized run +- default code path still uses `warmup=20` and `iters=100` if env vars are not set diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/build/fused_moe_i8_tn_pybind.o b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/build/fused_moe_i8_tn_pybind.o new file mode 100644 index 0000000000000000000000000000000000000000..ac296d80f51172cf088272917058d616003a23f0 GIT binary patch literal 579800 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�XIK?gqxp{@K?$I%@ux8rQLsD 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

h9&-=(Caf_ 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 literal 0 HcmV?d00001 diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/build/fused_moe_i8_tn_pybind.so b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/build/fused_moe_i8_tn_pybind.so new file mode 100644 index 0000000000000000000000000000000000000000..e55d11c8527761f145c250d1710606a6c470bbcd GIT binary patch literal 370600 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 T)XY6*F1J5tC_iSWOaK1g(}5?I literal 0 HcmV?d00001 diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/python/__pycache__/fused_moe_i8_tn_triton.cpython-312.pyc b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/python/__pycache__/fused_moe_i8_tn_triton.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3092674829ee700deb5dd82ab92fa04ec61b7ee0 GIT binary patch literal 14958 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 R1o6B15V`%j0F~nA{y(d#7PtTa literal 0 HcmV?d00001 diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/python/__pycache__/test_fused_moe_i8_tn_pybind.cpython-310.pyc b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/python/__pycache__/test_fused_moe_i8_tn_pybind.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..14ca55866af3d51068e50e467cd7e11989915c46 GIT binary patch literal 4911 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 E0qG@RE&u=k literal 0 HcmV?d00001 diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/python/benchmark_fused_moe_i8_tn.py b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/python/benchmark_fused_moe_i8_tn.py new file mode 100644 index 0000000..587c4f2 --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/python/benchmark_fused_moe_i8_tn.py @@ -0,0 +1,63 @@ +import argparse +import time + +from test_fused_moe_i8_tn_pybind import fill_inputs, resolve_backends + + +K_N = 128 +K_K = 128 + + +def compute_tops(rows: int, cols: int, k_dim: int, avg_ms: float) -> float: + if avg_ms <= 0.0: + return 0.0 + operations = 2.0 * float(rows) * float(cols) * float(k_dim) + return operations / (avg_ms * 1.0e9) + + +def benchmark_backend_case(backend: str, backend_fn, tag: str, num_tokens: int, topk: int, em: int, tile_experts: list[int], warmup: int, iters: int): + a, b, scale_a, scale_b, moe_weights, token_ids, expert_ids = fill_inputs(num_tokens, topk, tile_experts) + + for _ in range(warmup): + backend_fn(a, b, scale_a, scale_b, moe_weights, token_ids, expert_ids, topk) + + start = time.perf_counter() + for _ in range(iters): + backend_fn(a, b, scale_a, scale_b, moe_weights, token_ids, expert_ids, topk) + elapsed_s = time.perf_counter() - start + + avg_ms = elapsed_s * 1000.0 / iters + tops = compute_tops(em, K_N, K_K, avg_ms) + print( + f"{backend}:{tag} benchmark: avg_ms={avg_ms:.6f}, " + f"TOPS={tops:.6f}, warmup={warmup}, iters={iters}" + ) + + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument( + "--backend", + choices=("pybind", "triton", "reference", "all"), + default="pybind", + ) + parser.add_argument("--warmup", type=int, default=5) + parser.add_argument("--iters", type=int, default=20) + return parser.parse_args() + + +def main(): + args = parse_args() + cases = [ + ("fused_moe_i8_tn_topk1", 256, 1, 256, [0, 1]), + ("fused_moe_i8_tn_topk2", 256, 2, 512, [0, 1, 1, 0]), + ("fused_moe_i8_tn_topk3", 128, 3, 384, [0, 1, 0]), + ] + backends = resolve_backends(args.backend) + for backend, backend_fn in backends: + for case in cases: + benchmark_backend_case(backend, backend_fn, *case, warmup=args.warmup, iters=args.iters) + + +if __name__ == "__main__": + main() diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/python/fused_moe_i8_tn_triton.py b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/python/fused_moe_i8_tn_triton.py new file mode 100644 index 0000000..de905cd --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/python/fused_moe_i8_tn_triton.py @@ -0,0 +1,368 @@ +from __future__ import annotations + +from typing import Any + +import numpy as np + + +K_TILE_M = 128 +BLOCK_SIZE_M = 128 +BLOCK_SIZE_N = 128 +BLOCK_SIZE_K = 32 +GROUP_SIZE_M = 8 + +_TRITON = None +_TL = None +triton = None +tl = None + + +def _require_triton_runtime() -> tuple[Any, Any, Any]: + global _TRITON, _TL, triton, tl + try: + import torch + import triton as triton_mod + import triton.language as tl_mod + except ImportError as exc: + raise RuntimeError("torch and triton are required for the Triton backend") from exc + + if not torch.cuda.is_available(): + raise RuntimeError("the Triton backend currently requires a CUDA-capable torch runtime") + + _TRITON = triton_mod + _TL = tl_mod + triton = triton_mod + tl = tl_mod + return torch, triton_mod, tl_mod + + +def triton_backend_available() -> tuple[bool, str]: + try: + _require_triton_runtime() + except RuntimeError as exc: + return False, str(exc) + return True, "" + + +def _build_blocked_routing(token_ids: np.ndarray, expert_ids: np.ndarray, num_experts: int, block_size_m: int): + total_rows = int(token_ids.shape[0]) + routed_rows_per_expert = [[] for _ in range(num_experts)] + + for routed_row in range(total_rows): + tile_idx = routed_row // K_TILE_M + expert = int(expert_ids[tile_idx]) + routed_rows_per_expert[expert].append(routed_row) + + sorted_routed_rows: list[int] = [] + block_expert_ids: list[int] = [] + invalid_row = total_rows + + for expert, rows in enumerate(routed_rows_per_expert): + if not rows: + continue + sorted_routed_rows.extend(rows) + padded = (-len(rows)) % block_size_m + if padded: + sorted_routed_rows.extend([invalid_row] * padded) + block_count = (len(rows) + padded) // block_size_m + block_expert_ids.extend([expert] * block_count) + + num_tokens_post_padded = len(sorted_routed_rows) + return ( + np.asarray(sorted_routed_rows, dtype=np.int32), + np.asarray(block_expert_ids, dtype=np.int32), + np.asarray([num_tokens_post_padded], dtype=np.int32), + ) + + +def _ensure_triton_symbols(): + if _TRITON is None or _TL is None: + _require_triton_runtime() + return _TRITON, _TL + + +def _get_fused_moe_kernel(): + triton, tl = _ensure_triton_symbols() + + @triton.jit + def _fused_moe_kernel( + a_ptr, + b_ptr, + c_ptr, + b_bias_ptr, + scale_a_ptr, + scale_b_ptr, + moe_weights_ptr, + sorted_routed_rows_ptr, + block_expert_ids_ptr, + num_tokens_post_padded_ptr, + n_dim, + k_dim, + em, + num_valid_tokens, + stride_am, + stride_ak, + stride_be, + stride_bk, + stride_bn, + stride_cm, + stride_cn, + stride_asm, + stride_ask, + stride_bse, + stride_bsk, + stride_bsn, + stride_bbe, + stride_bbn, + group_n: tl.constexpr, + group_k: tl.constexpr, + naive_block_assignment: tl.constexpr, + BLOCK_SIZE_M: tl.constexpr, + BLOCK_SIZE_N: tl.constexpr, + BLOCK_SIZE_K: tl.constexpr, + GROUP_SIZE_M: tl.constexpr, + SPLIT_K: tl.constexpr, + MUL_ROUTED_WEIGHT: tl.constexpr, + top_k: tl.constexpr, + compute_type: tl.constexpr, + use_fp8_w8a8: tl.constexpr, + use_int8_w8a8: tl.constexpr, + use_int8_w8a16: tl.constexpr, + per_channel_quant: tl.constexpr, + HAS_BIAS: tl.constexpr, + ): + pid = tl.program_id(axis=0) + num_pid_m = tl.cdiv(em, BLOCK_SIZE_M) + num_pid_n = tl.cdiv(n_dim, BLOCK_SIZE_N) + num_pid_in_group = GROUP_SIZE_M * num_pid_n + group_id = pid // num_pid_in_group + first_pid_m = group_id * GROUP_SIZE_M + group_size_m = tl.minimum(num_pid_m - first_pid_m, GROUP_SIZE_M) + pid_m = first_pid_m + ((pid % num_pid_in_group) % group_size_m) + pid_n = (pid % num_pid_in_group) // group_size_m + + offs = tl.arange(0, BLOCK_SIZE_M).to(tl.int64) + num_tokens_post_padded = tl.load(num_tokens_post_padded_ptr) + if pid_m * BLOCK_SIZE_M >= num_tokens_post_padded: + return + + if not naive_block_assignment: + offs_token_id = pid_m * BLOCK_SIZE_M + offs + offs_token = tl.load(sorted_routed_rows_ptr + offs_token_id) + else: + offs_token = tl.where( + offs == 0, + pid_m, + num_valid_tokens, + ) + + offs_token = offs_token.to(tl.int64) + token_mask = offs_token < num_valid_tokens + + off_experts = tl.load(block_expert_ids_ptr + pid_m).to(tl.int64) + if off_experts == -1: + zero_acc = tl.zeros((BLOCK_SIZE_M, BLOCK_SIZE_N), dtype=compute_type) + zero_offs_cn = pid_n * BLOCK_SIZE_N + tl.arange(0, BLOCK_SIZE_N) + zero_c_ptrs = c_ptr + stride_cm * offs_token[:, None] + stride_cn * zero_offs_cn[None, :] + zero_c_mask = token_mask[:, None] & (zero_offs_cn[None, :] < n_dim) + tl.store(zero_c_ptrs, zero_acc, mask=zero_c_mask) + return + + offs_bn = (pid_n * BLOCK_SIZE_N + tl.arange(0, BLOCK_SIZE_N).to(tl.int64)) % n_dim + offs_k = tl.arange(0, BLOCK_SIZE_K) + a_ptrs = a_ptr + (offs_token[:, None] // top_k * stride_am + offs_k[None, :] * stride_ak) + b_ptrs = b_ptr + off_experts * stride_be + (offs_k[:, None] * stride_bk + offs_bn[None, :] * stride_bn) + + if use_int8_w8a16: + b_scale_ptrs = scale_b_ptr + off_experts * stride_bse + offs_bn[None, :] * stride_bsn + b_scale = tl.load(b_scale_ptrs) + + if use_fp8_w8a8 or use_int8_w8a8: + if group_k > 0 and group_n > 0: + a_scale_ptrs = scale_a_ptr + (offs_token // top_k) * stride_asm + offs_bsn = offs_bn // group_n + b_scale_ptrs = scale_b_ptr + off_experts * stride_bse + offs_bsn * stride_bsn + elif per_channel_quant: + b_scale_ptrs = scale_b_ptr + off_experts * stride_bse + offs_bn[None, :] * stride_bsn + b_scale = tl.load(b_scale_ptrs) + a_scale_ptrs = scale_a_ptr + (offs_token // top_k) * stride_asm + a_scale = tl.load(a_scale_ptrs, mask=token_mask, other=0.0)[:, None] + else: + a_scale = tl.load(scale_a_ptr) + b_scale = tl.load(scale_b_ptr + off_experts) + + if HAS_BIAS: + bias_ptrs = b_bias_ptr + off_experts * stride_bbe + offs_bn * stride_bbn + bias = tl.load(bias_ptrs, mask=(offs_bn < n_dim), other=0.0) + + accumulator = tl.zeros((BLOCK_SIZE_M, BLOCK_SIZE_N), dtype=tl.float32) + for k in range(0, tl.cdiv(k_dim, BLOCK_SIZE_K)): + a = tl.load( + a_ptrs, + mask=token_mask[:, None] & (offs_k[None, :] < k_dim - k * BLOCK_SIZE_K), + other=0.0, + ) + b = tl.load(b_ptrs, mask=offs_k[:, None] < k_dim - k * BLOCK_SIZE_K, other=0.0) + if use_int8_w8a16: + accumulator = tl.dot(a, b.to(compute_type), acc=accumulator) + elif use_fp8_w8a8 or use_int8_w8a8: + if group_k > 0 and group_n > 0: + k_start = k * BLOCK_SIZE_K + offs_ks = k_start // group_k + a_scale = tl.load(a_scale_ptrs + offs_ks * stride_ask, mask=token_mask, other=0.0) + b_scale = tl.load(b_scale_ptrs + offs_ks * stride_bsk) + accumulator += tl.dot(a, b) * a_scale[:, None] * b_scale[None, :] + else: + if use_fp8_w8a8: + accumulator = tl.dot(a, b, acc=accumulator) + else: + accumulator += tl.dot(a, b) + else: + accumulator += tl.dot(a, b) + + a_ptrs += BLOCK_SIZE_K * stride_ak + b_ptrs += BLOCK_SIZE_K * stride_bk + + if use_int8_w8a16: + accumulator = accumulator * b_scale + elif (use_fp8_w8a8 or use_int8_w8a8) and not (group_k > 0 and group_n > 0): + accumulator = accumulator * a_scale * b_scale + + if HAS_BIAS: + accumulator += bias[None, :] + + if MUL_ROUTED_WEIGHT: + moe_weight = tl.load( + moe_weights_ptr + offs_token, + mask=token_mask, + other=0, + ) + accumulator *= moe_weight[:, None] + + accumulator = accumulator.to(compute_type) + + offs_cn = pid_n * BLOCK_SIZE_N + tl.arange(0, BLOCK_SIZE_N) + c_ptrs = c_ptr + stride_cm * offs_token[:, None] + stride_cn * offs_cn[None, :] + c_mask = token_mask[:, None] & (offs_cn[None, :] < n_dim) + tl.store(c_ptrs, accumulator, mask=c_mask) + + return _fused_moe_kernel + + +def run_fused_moe_i8_tn_triton( + a: np.ndarray, + b_col_major: np.ndarray, + scale_a: np.ndarray, + scale_b: np.ndarray, + moe_weights: np.ndarray, + token_ids: np.ndarray, + expert_ids: np.ndarray, + topk: int, + device: str = "cuda", +) -> np.ndarray: + # Adapted from vLLM's fused MoE Triton path: + # https://github.com/vllm-project/vllm/blob/main/vllm/model_executor/layers/fused_moe/fused_moe.py + torch, triton, tl = _require_triton_runtime() + + if a.ndim != 2: + raise ValueError("a must be a 2D array") + if b_col_major.ndim != 3: + raise ValueError("b_col_major must be a 3D array") + if scale_a.ndim != 1: + raise ValueError("scale_a must be a 1D array") + if scale_b.ndim != 2: + raise ValueError("scale_b must be a 2D array") + if moe_weights.ndim != 1: + raise ValueError("moe_weights must be a 1D array") + if token_ids.ndim != 1: + raise ValueError("token_ids must be a 1D array") + if expert_ids.ndim != 1: + raise ValueError("expert_ids must be a 1D array") + if topk <= 0: + raise ValueError("topk must be > 0") + + num_tokens, k_dim = a.shape + num_experts, n_dim, b_k = b_col_major.shape + total_rows = moe_weights.shape[0] + + if b_k != k_dim: + raise ValueError("B K dimension must match A K dimension") + if scale_a.shape[0] != num_tokens: + raise ValueError("scale_a size mismatch") + if scale_b.shape != (num_experts, n_dim): + raise ValueError("scale_b shape mismatch") + if token_ids.shape[0] != total_rows: + raise ValueError("token_ids size mismatch") + if total_rows != num_tokens * topk: + raise ValueError("moe_weights size must equal num_tokens * topk") + if total_rows % K_TILE_M != 0: + raise ValueError("num_tokens * topk must be a multiple of 128") + if expert_ids.shape[0] != total_rows // K_TILE_M: + raise ValueError("expert_ids size mismatch") + + sorted_routed_rows, block_expert_ids, num_tokens_post_padded = _build_blocked_routing( + token_ids, expert_ids, num_experts, BLOCK_SIZE_M + ) + + a_t = torch.as_tensor(np.ascontiguousarray(a), device=device, dtype=torch.int8) + b_t = torch.as_tensor(np.ascontiguousarray(b_col_major), device=device, dtype=torch.int8) + scale_a_t = torch.as_tensor(np.ascontiguousarray(scale_a), device=device, dtype=torch.float32) + scale_b_t = torch.as_tensor(np.ascontiguousarray(scale_b), device=device, dtype=torch.float32) + moe_weights_t = torch.as_tensor(np.ascontiguousarray(moe_weights), device=device, dtype=torch.float32) + sorted_routed_rows_t = torch.as_tensor(sorted_routed_rows, device=device, dtype=torch.int32) + block_expert_ids_t = torch.as_tensor(block_expert_ids, device=device, dtype=torch.int32) + num_tokens_post_padded_t = torch.as_tensor(num_tokens_post_padded, device=device, dtype=torch.int32) + dummy_bias_t = torch.zeros((num_experts, n_dim), device=device, dtype=torch.float32) + out_t = torch.empty((total_rows, n_dim), device=device, dtype=torch.float32) + + fused_moe_kernel = _get_fused_moe_kernel() + + grid = (triton.cdiv(int(num_tokens_post_padded[0]), BLOCK_SIZE_M) * triton.cdiv(n_dim, BLOCK_SIZE_N),) + fused_moe_kernel[grid]( + a_t, + b_t, + out_t, + dummy_bias_t, + scale_a_t, + scale_b_t, + moe_weights_t, + sorted_routed_rows_t, + block_expert_ids_t, + num_tokens_post_padded_t, + n_dim, + k_dim, + int(num_tokens_post_padded[0]), + total_rows, + a_t.stride(0), + a_t.stride(1), + b_t.stride(0), + b_t.stride(2), + b_t.stride(1), + out_t.stride(0), + out_t.stride(1), + scale_a_t.stride(0), + 0, + scale_b_t.stride(0), + 0, + scale_b_t.stride(1), + dummy_bias_t.stride(0), + dummy_bias_t.stride(1), + group_n=0, + group_k=0, + naive_block_assignment=False, + BLOCK_SIZE_M=BLOCK_SIZE_M, + BLOCK_SIZE_N=BLOCK_SIZE_N, + BLOCK_SIZE_K=BLOCK_SIZE_K, + GROUP_SIZE_M=GROUP_SIZE_M, + SPLIT_K=1, + MUL_ROUTED_WEIGHT=True, + top_k=topk, + compute_type=tl.float32, + use_fp8_w8a8=False, + use_int8_w8a8=True, + use_int8_w8a16=False, + per_channel_quant=True, + HAS_BIAS=False, + ) + + return out_t.cpu().numpy() diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/python/test_fused_moe_i8_tn_pybind.py b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/python/test_fused_moe_i8_tn_pybind.py new file mode 100644 index 0000000..516cdcd --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/python/test_fused_moe_i8_tn_pybind.py @@ -0,0 +1,154 @@ +import argparse +import importlib.util +import os +from pathlib import Path + +import numpy as np + +from fused_moe_i8_tn_triton import run_fused_moe_i8_tn_triton, triton_backend_available + + +K_NUM_EXPERTS = 2 +K_TILE_M = 128 +K_N = 128 +K_K = 128 + + +def load_extension(): + build_dir = Path(__file__).resolve().parents[1] / "build" + candidates = sorted(build_dir.glob("fused_moe_i8_tn_pybind*.so")) + if not candidates: + raise FileNotFoundError(f"no built extension found under {build_dir}") + module_path = candidates[0] + spec = importlib.util.spec_from_file_location("fused_moe_i8_tn_pybind", module_path) + module = importlib.util.module_from_spec(spec) + assert spec.loader is not None + spec.loader.exec_module(module) + return module + + +def fill_inputs(num_tokens: int, topk: int, tile_experts: list[int]): + total_rows = num_tokens * topk + + a = np.empty((num_tokens, K_K), dtype=np.int8) + scale_a = np.empty((num_tokens,), dtype=np.float32) + moe_weights = np.empty((total_rows,), dtype=np.float32) + token_ids = np.empty((total_rows,), dtype=np.int32) + expert_ids = np.asarray(tile_experts, dtype=np.int32) + + for row in range(num_tokens): + for kk in range(K_K): + a[row, kk] = ((row * 13 + kk * 7 + topk * 5 + 3) % 11) - 5 + scale_a[row] = 0.125 + 0.015625 * ((row + topk) % 7) + + for routed_row in range(total_rows): + token_ids[routed_row] = routed_row + moe_weights[routed_row] = 0.5 + 0.03125 * ((routed_row + topk) % 5) + + b = np.empty((K_NUM_EXPERTS, K_N, K_K), dtype=np.int8) + scale_b = np.empty((K_NUM_EXPERTS, K_N), dtype=np.float32) + for expert in range(K_NUM_EXPERTS): + for col in range(K_N): + scale_b[expert, col] = 0.25 + 0.03125 * ((expert * 3 + col + topk) % 9) + for kk in range(K_K): + b[expert, col, kk] = ((expert * 17 + col * 5 + kk * 3 + topk) % 9) - 4 + + return a, b, scale_a, scale_b, moe_weights, token_ids, expert_ids + + +def reference_fused_moe(a, b, scale_a, scale_b, moe_weights, token_ids, expert_ids, topk): + total_rows = token_ids.shape[0] + out = np.zeros((total_rows, K_N), dtype=np.float32) + for routed_row in range(total_rows): + token = token_ids[routed_row] // topk + tile_idx = routed_row // K_TILE_M + expert = expert_ids[tile_idx] + row_scale = scale_a[token] * moe_weights[routed_row] + for col in range(K_N): + acc = 0 + for kk in range(K_K): + acc += int(a[token, kk]) * int(b[expert, col, kk]) + out[routed_row, col] = np.float32(acc * row_scale * scale_b[expert, col]) + return out + + +def run_pybind_backend(module, a, b, scale_a, scale_b, moe_weights, token_ids, expert_ids, topk): + return module.run_fused_moe_i8_tn( + a, + b, + scale_a, + scale_b.reshape(-1), + moe_weights, + token_ids, + expert_ids, + topk, + K_NUM_EXPERTS, + int(os.environ.get("MCTLASS_PY_DEVICE_ID", "0")), + ) + + +def run_reference_backend(a, b, scale_a, scale_b, moe_weights, token_ids, expert_ids, topk): + return reference_fused_moe(a, b, scale_a, scale_b, moe_weights, token_ids, expert_ids, topk) + + +def run_case(backend: str, backend_fn, tag: str, num_tokens: int, topk: int, em: int, tile_experts: list[int]): + assert em == num_tokens * topk + a, b, scale_a, scale_b, moe_weights, token_ids, expert_ids = fill_inputs(num_tokens, topk, tile_experts) + expected = reference_fused_moe(a, b, scale_a, scale_b, moe_weights, token_ids, expert_ids, topk) + got = backend_fn(a, b, scale_a, scale_b, moe_weights, token_ids, expert_ids, topk) + np.testing.assert_allclose(got, expected, rtol=0.0, atol=1e-2) + print( + f"{backend}:{tag} passed: rows={got.shape[0]}, cols={got.shape[1]}, " + f"sample C[0]={got.reshape(-1)[0]}, C[last]={got.reshape(-1)[-1]}" + ) + + +def resolve_backends(requested_backend: str): + backends = [] + + if requested_backend in {"pybind", "all"}: + module = load_extension() + backends.append(("pybind", lambda a, b, scale_a, scale_b, moe_weights, token_ids, expert_ids, topk: run_pybind_backend( + module, a, b, scale_a, scale_b, moe_weights, token_ids, expert_ids, topk + ))) + + if requested_backend in {"reference", "all"}: + backends.append(("reference", run_reference_backend)) + + if requested_backend in {"triton", "all"}: + available, reason = triton_backend_available() + if available: + backends.append(("triton", run_fused_moe_i8_tn_triton)) + elif requested_backend == "triton": + raise RuntimeError(f"Triton backend is unavailable: {reason}") + else: + print(f"skip triton backend: {reason}") + + return backends + + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument( + "--backend", + choices=("pybind", "triton", "reference", "all"), + default=os.environ.get("MCTLASS_FUSED_MOE_BACKEND", "pybind"), + ) + return parser.parse_args() + + +def main(): + args = parse_args() + cases = [ + ("fused_moe_i8_tn_topk1", 256, 1, 256, [0, 1]), + ("fused_moe_i8_tn_topk2", 256, 2, 512, [0, 1, 1, 0]), + ("fused_moe_i8_tn_topk3", 128, 3, 384, [0, 1, 0]), + ] + backends = resolve_backends(args.backend) + for backend, backend_fn in backends: + for case in cases: + run_case(backend, backend_fn, *case) + + +if __name__ == "__main__": + main() diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/src/fused_moe_i8_tn_example.cpp b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/src/fused_moe_i8_tn_example.cpp new file mode 100644 index 0000000..b58c7b5 --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/src/fused_moe_i8_tn_example.cpp @@ -0,0 +1,324 @@ +#include + +#include +#include +#include +#include +#include +#include + +#include "fused_moe_i8_tn_runner.h" + +namespace { + +constexpr int kNumExperts = fused_moe_i8_tn::kDefaultNumExperts; +constexpr int kTileM = fused_moe_i8_tn::kDefaultTileM; +constexpr int kN = fused_moe_i8_tn::kDefaultN; +constexpr int kK = fused_moe_i8_tn::kDefaultK; +constexpr int kDefaultWarmupIterations = 20; +constexpr int kDefaultMeasuredIterations = 100; + +struct CaseConfig { + const char *tag; + int num_tokens; + int topk; + int em; + std::vector tile_experts; +}; + +struct BenchmarkConfig { + int warmup_iterations = 0; + int measured_iterations = 0; +}; + +struct BenchmarkResult { + float avg_ms = 0.0f; + double tops = 0.0; + int warmup_iterations = 0; + int measured_iterations = 0; +}; + +void check_mc(mcError_t status, const char *expr) { + if (status != mcSuccess) { + std::cerr << expr << " failed: " << mcGetErrorString(status) << '\n'; + std::exit(EXIT_FAILURE); + } +} + +int read_env_int(const char *name, int default_value) { + const char *value = std::getenv(name); + if (!value || !value[0]) { + return default_value; + } + + char *end = nullptr; + long parsed = std::strtol(value, &end, 10); + if (end == value || (end && *end != '\0') || parsed < 0) { + std::cerr << "Ignoring invalid " << name << '=' << value + << ", using default " << default_value << '\n'; + return default_value; + } + return static_cast(parsed); +} + +BenchmarkConfig make_benchmark_config() { + BenchmarkConfig config; + config.warmup_iterations = read_env_int("MCTLASS_MOE_WARMUP", kDefaultWarmupIterations); + config.measured_iterations = read_env_int("MCTLASS_MOE_ITERS", kDefaultMeasuredIterations); + if (config.measured_iterations <= 0) { + std::cerr << "MCTLASS_MOE_ITERS must be > 0\n"; + std::exit(EXIT_FAILURE); + } + return config; +} + +double compute_tops(int m, int n, int k, float avg_ms) { + if (avg_ms <= 0.0f) { + return 0.0; + } + const double operations = 2.0 * static_cast(m) * static_cast(n) * static_cast(k); + return operations / (static_cast(avg_ms) * 1.0e9); +} + +void fill_inputs(const CaseConfig &cfg, + std::vector &a, + std::vector &b_col_major, + std::vector &scale_a, + std::vector &scale_b, + std::vector &moe_weights, + std::vector &token_ids, + std::vector &expert_ids) { + const int total_rows = cfg.num_tokens * cfg.topk; + + a.resize(static_cast(cfg.num_tokens) * kK); + scale_a.resize(cfg.num_tokens); + moe_weights.resize(total_rows); + token_ids.resize(total_rows); + expert_ids = cfg.tile_experts; + + for (int row = 0; row < cfg.num_tokens; ++row) { + for (int kk = 0; kk < kK; ++kk) { + a[static_cast(row) * kK + kk] = + static_cast(((row * 13 + kk * 7 + cfg.topk * 5 + 3) % 11) - 5); + } + scale_a[row] = 0.125f + 0.015625f * static_cast((row + cfg.topk) % 7); + } + + for (int routed_row = 0; routed_row < total_rows; ++routed_row) { + token_ids[routed_row] = routed_row; + moe_weights[routed_row] = 0.5f + 0.03125f * static_cast((routed_row + cfg.topk) % 5); + } + + b_col_major.resize(static_cast(kNumExperts) * kN * kK); + scale_b.resize(static_cast(kNumExperts) * kN); + for (int expert = 0; expert < kNumExperts; ++expert) { + for (int col = 0; col < kN; ++col) { + scale_b[static_cast(expert) * kN + col] = + 0.25f + 0.03125f * static_cast((expert * 3 + col + cfg.topk) % 9); + for (int kk = 0; kk < kK; ++kk) { + const int value = ((expert * 17 + col * 5 + kk * 3 + cfg.topk) % 9) - 4; + b_col_major[(static_cast(expert) * kN + col) * kK + kk] = + static_cast(value); + } + } + } +} + +std::vector reference_fused_moe(const CaseConfig &cfg, + const std::vector &a, + const std::vector &b_col_major, + const std::vector &scale_a, + const std::vector &scale_b, + const std::vector &moe_weights, + const std::vector &token_ids, + const std::vector &expert_ids) { + const int total_rows = cfg.num_tokens * cfg.topk; + std::vector out(static_cast(total_rows) * kN, + fused_moe_i8_tn::float_to_bf16(0.0f)); + + for (int routed_row = 0; routed_row < total_rows; ++routed_row) { + const int token = token_ids[routed_row] / cfg.topk; + const int tile_idx = routed_row / kTileM; + const int expert = expert_ids[tile_idx]; + const float row_scale = scale_a[token] * moe_weights[routed_row]; + + for (int col = 0; col < kN; ++col) { + int32_t acc = 0; + for (int kk = 0; kk < kK; ++kk) { + const int32_t lhs = static_cast(a[static_cast(token) * kK + kk]); + const int32_t rhs = + static_cast(b_col_major[(static_cast(expert) * kN + col) * kK + kk]); + acc += lhs * rhs; + } + const float scaled = static_cast(acc) * row_scale * + scale_b[static_cast(expert) * kN + col]; + out[static_cast(routed_row) * kN + col] = fused_moe_i8_tn::float_to_bf16(scaled); + } + } + + return out; +} + +bool validate_result(const std::vector &got, + const std::vector &expected, + const CaseConfig &cfg) { + size_t mismatch_count = 0; + size_t first_bad = 0; + float max_abs = 0.0f; + const int total_rows = cfg.num_tokens * cfg.topk; + + for (size_t i = 0; i < got.size(); ++i) { + const float got_f = fused_moe_i8_tn::bf16_to_float(got[i]); + const float exp_f = fused_moe_i8_tn::bf16_to_float(expected[i]); + const float abs_err = std::fabs(got_f - exp_f); + max_abs = std::max(max_abs, abs_err); + if (abs_err > 1e-2f) { + if (mismatch_count == 0) { + first_bad = i; + } + ++mismatch_count; + } + } + + if (mismatch_count != 0) { + const int row = static_cast(first_bad / kN); + const int col = static_cast(first_bad % kN); + std::cerr << cfg.tag << " failed" + << ": mismatches=" << mismatch_count + << ", first mismatch at (" << row << ", " << col << ")" + << ", got=" << fused_moe_i8_tn::bf16_to_float(got[first_bad]) + << ", expected=" << fused_moe_i8_tn::bf16_to_float(expected[first_bad]) + << ", max_abs=" << max_abs << '\n'; + return false; + } + + std::cout << cfg.tag + << " passed" + << ": rows=" << total_rows + << ", topk=" << cfg.topk + << ", N=" << kN + << ", K=" << kK + << ", sample C[0]=" << fused_moe_i8_tn::bf16_to_float(got.front()) + << ", C[last]=" << fused_moe_i8_tn::bf16_to_float(got.back()) + << ", max_abs=" << max_abs << '\n'; + return true; +} + +template +BenchmarkResult run_benchmark(LaunchFn &&launch, int m, int n, int k, const BenchmarkConfig &config) { + for (int iter = 0; iter < config.warmup_iterations; ++iter) { + launch(); + } + check_mc(mcDeviceSynchronize(), "mcDeviceSynchronize(warmup)"); + + mcEvent_t start; + mcEvent_t stop; + check_mc(mcEventCreate(&start), "mcEventCreate(start)"); + check_mc(mcEventCreate(&stop), "mcEventCreate(stop)"); + + check_mc(mcEventRecord(start, nullptr), "mcEventRecord(start)"); + for (int iter = 0; iter < config.measured_iterations; ++iter) { + launch(); + } + check_mc(mcEventRecord(stop, nullptr), "mcEventRecord(stop)"); + check_mc(mcEventSynchronize(stop), "mcEventSynchronize(stop)"); + + float elapsed_ms = 0.0f; + check_mc(mcEventElapsedTime(&elapsed_ms, start, stop), "mcEventElapsedTime"); + check_mc(mcEventDestroy(start), "mcEventDestroy(start)"); + check_mc(mcEventDestroy(stop), "mcEventDestroy(stop)"); + + BenchmarkResult result; + result.warmup_iterations = config.warmup_iterations; + result.measured_iterations = config.measured_iterations; + result.avg_ms = elapsed_ms / static_cast(config.measured_iterations); + result.tops = compute_tops(m, n, k, result.avg_ms); + return result; +} + +bool run_case(const CaseConfig &cfg, const BenchmarkConfig &benchmark_config) { + std::vector host_a; + std::vector host_b; + std::vector host_scale_a; + std::vector host_scale_b; + std::vector host_moe_weights; + std::vector host_token_ids; + std::vector host_expert_ids; + + fill_inputs(cfg, + host_a, + host_b, + host_scale_a, + host_scale_b, + host_moe_weights, + host_token_ids, + host_expert_ids); + + const std::vector expected = reference_fused_moe( + cfg, host_a, host_b, host_scale_a, host_scale_b, host_moe_weights, host_token_ids, host_expert_ids); + + fused_moe_i8_tn::HostInputs inputs; + inputs.num_tokens = cfg.num_tokens; + inputs.topk = cfg.topk; + inputs.em = cfg.em; + inputs.num_experts = kNumExperts; + inputs.n = kN; + inputs.k = kK; + inputs.a = host_a; + inputs.b_col_major = host_b; + inputs.scale_a = host_scale_a; + inputs.scale_b = host_scale_b; + inputs.moe_weights = host_moe_weights; + inputs.token_ids = host_token_ids; + inputs.expert_ids = host_expert_ids; + + const fused_moe_i8_tn::RunResult run_result = fused_moe_i8_tn::run_fused_moe_i8_tn(inputs); + const bool valid = validate_result(run_result.output, expected, cfg); + if (!valid) { + return false; + } + + const BenchmarkResult benchmark = run_benchmark([&]() { fused_moe_i8_tn::run_fused_moe_i8_tn(inputs); }, + cfg.em, + kN, + kK, + benchmark_config); + std::cout << cfg.tag + << " benchmark" + << ": avg_ms=" << benchmark.avg_ms + << ", TOPS=" << benchmark.tops + << ", warmup=" << benchmark.warmup_iterations + << ", iters=" << benchmark.measured_iterations + << '\n'; + return true; +} + +} // namespace + +int main() { + int device_count = 0; + check_mc(mcGetDeviceCount(&device_count), "mcGetDeviceCount"); + if (device_count <= 0) { + std::cerr << "No MACA device is visible.\n"; + return EXIT_FAILURE; + } + check_mc(mcSetDevice(0), "mcSetDevice"); + + const BenchmarkConfig benchmark_config = make_benchmark_config(); + std::cout << "Benchmark config" + << ": warmup=" << benchmark_config.warmup_iterations + << ", iters=" << benchmark_config.measured_iterations + << '\n'; + + const std::vector cases = { + {"fused_moe_i8_tn_topk1", 256, 1, 256, {0, 1}}, + {"fused_moe_i8_tn_topk2", 256, 2, 512, {0, 1, 1, 0}}, + {"fused_moe_i8_tn_topk3", 128, 3, 384, {0, 1, 0}}, + }; + + bool ok = true; + for (const CaseConfig &cfg : cases) { + ok &= run_case(cfg, benchmark_config); + } + return ok ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/src/fused_moe_i8_tn_kernel.h b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/src/fused_moe_i8_tn_kernel.h new file mode 100644 index 0000000..8e09e6b --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/src/fused_moe_i8_tn_kernel.h @@ -0,0 +1,629 @@ +#pragma once + +#include +#include + +#include + +#include "fused_moe_i8_tn_macros.h" +#include "fused_moe_i8_tn_types.h" + +namespace fused_moe_i8_tn { + +using ElementA = int8_t; +using ElementB = int8_t; +using ElementC = BFloat16; +using ElementAccumulator = int32_t; +using ElementCompute = float; + +using INT1 = __NATIVE_VECTOR__(1, int32_t); +using INT4 = __NATIVE_VECTOR__(4, int32_t); +using FLOAT2 = __NATIVE_VECTOR__(2, float); +using FLOAT4 = __NATIVE_VECTOR__(4, float); +using LdgType = __NATIVE_VECTOR__(4, int32_t); +using StsType = LdgType; +using LdsType = LdgType; +using StgType = __NATIVE_VECTOR__(2, uint); +using Tc = maca_bfloat16; + +constexpr int kTileM = 128; +constexpr int kTileN = 128; +constexpr int kTileK = 128; +constexpr int kThreadCount = 256; +constexpr int kWaveSize = 64; +constexpr int kWaveNum = kThreadCount / kWaveSize; +constexpr int kWaveM = 4; +constexpr int kWaveN = kWaveNum / kWaveM; +constexpr int kLdgSize = sizeof(LdgType) * kThreadCount; +constexpr int kMNPerLdg = kLdgSize / kTileK; +constexpr int kLdgSizePerWave = kLdgSize / kWaveNum; +constexpr int kSizeA = kTileM * kTileK * sizeof(ElementA); +constexpr int kSizeB = kTileN * kTileK * sizeof(ElementB); +constexpr int kLdgNumA = kSizeA / kLdgSize; +constexpr int kLdgNumB = kSizeB / kLdgSize; +constexpr int kLdsNumA = kSizeA / (kLdgSizePerWave * kWaveM); +constexpr int kLdsNumB = kSizeB / (kLdgSizePerWave * kWaveN); +constexpr int kStsNumA = kLdgNumA; +constexpr int kStsNumB = kLdgNumB; +constexpr int kMmaM = kTileM / 16 / kWaveM; +constexpr int kMmaN = kTileN / 16 / kWaveN; +constexpr int kMmaK = kTileK / 16; +constexpr int kRowCSize = 8; +constexpr int kOutputCount = 16; +constexpr int kSmemSize = kSizeA + kSizeB; + +template +struct DirectMoeKernel { + static constexpr bool kIsTopkLog2 = IsTopkLog2; + using EpilogueOutputOp = fused_moe_i8_tn::EpilogueOutputOp; + + struct Arguments { + BatchedGemmCoord problem_size; + typename EpilogueOutputOp::Params output_op; + void const *ptr_A; + void const *ptr_B; + void *ptr_C; + MoeParams moe_params; + + FUSED_MOE_HOST_DEVICE + Arguments() : ptr_A(nullptr), ptr_B(nullptr), ptr_C(nullptr) {} + + FUSED_MOE_HOST_DEVICE + Arguments(BatchedGemmCoord problem_size_, + typename EpilogueOutputOp::Params output_op_, + void const *ptr_A_, + void const *ptr_B_, + void *ptr_C_, + MoeParams moe_params_) + : problem_size(problem_size_), + output_op(output_op_), + ptr_A(ptr_A_), + ptr_B(ptr_B_), + ptr_C(ptr_C_), + moe_params(moe_params_) {} + }; +}; + +template +__global__ void direct_moe_kernel(typename DirectMoeKernel::Arguments args) { + using namespace cute; + +#define MMA_STAGE_MNKX2(m, n, k) \ + accum[m][n] = FUSED_MOE_BUILTIN_MMA_16X16X16_I8(a[m][k], b[n][k], accum[m][n]); \ + accum[m][n] = FUSED_MOE_BUILTIN_MMA_16X16X16_I8(a[m][k + 1], b[n][k + 1], accum[m][n]) + +#define LDG_A_STAGE_I(ldgi) \ + A[ldgi] = __builtin_mxc_ldg_b128_predicator(Aaddr + ldg_a_offs_m[ldgi] + ldg_k, \ + 0, \ + true, \ + true, \ + false, \ + false, \ + rowA_mask[ldgi], \ + 1, \ + MACA_ICMP_EQ) + +#define LDG_B_STAGE_I(ldgi) \ + B[ldgi] = __builtin_mxc_ldg_b128(&(gB(ldg_n[ldgi], ldg_k, tile_k)), \ + 0, \ + -1, \ + true, \ + true, \ + false, \ + false) + +#define LDS_A_B128(rowi, coli) FUSED_MOE_LDS(a[rowi][coli * 4], sA(lds_row_A[rowi], lds_col[coli]), LdsType) +#define LDS_B_B128(rowi, coli) FUSED_MOE_LDS(b[rowi][coli * 4], sB(lds_row_B[rowi], lds_col[coli]), LdsType) + +#define CVT_F32_TO_BF16(dst, src0, src1) \ + src0 = ((src0 >> 16) & 1) + src0 + 0x7fff; \ + src1 = ((src1 >> 16) & 1) + src1 + 0x7fff; \ + dst = __builtin_mxc_byte_perm(src0, src1, 0x03020706) + + int *token_ids_ptr = args.moe_params.token_ids; + int *expert_ids_ptr = args.moe_params.expert_ids; + int *num_tokens_post_padded_ptr = args.moe_params.num_tokens_post_padded_ptr; + + int num_tokens_post_padded = num_tokens_post_padded_ptr[0]; + int tid = threadIdx.x; + int bidx = blockIdx.x + blockIdx.z * gridDim.x; + int bidy = blockIdx.y; + int wave = tid / kWaveSize; + int lane = tid % kWaveSize; + + if (bidx * kTileM >= num_tokens_post_padded) { + return; + } + + EpilogueOutputOp output_op(args.output_op); + + __shared__ int8_t smem_data[kSmemSize]; + int8_t *smem_A = smem_data; + int8_t *smem_B = smem_A + kSizeA; + + int group_idx = expert_ids_ptr[bidx]; + int prev_m = bidx * kTileM; + ElementB *Baddr = (ElementB *)args.ptr_B + uint64_t(group_idx) * args.problem_size.n() * args.problem_size.k(); + + Tensor mB = make_tensor(make_gmem_ptr((ElementB *)Baddr), + make_shape(args.problem_size.n(), args.problem_size.k()), + make_stride(args.problem_size.k(), Int<1>{})); + Tensor gB = local_tile(mB, make_tile(Int{}, Int{}), make_coord(bidy, _)); + + LdgType A[kLdgNumA], B[kLdgNumB]; + int k_head = (args.problem_size.k() - 1) % kTileK + 1; + int col_limit = min(kTileN, args.problem_size.n() - bidy * kTileN); + int ldg_n[kLdgNumB], ldg_a_offs_m[kLdgNumA]; + bool rowA_mask[kLdgNumA]; + int ldg_m_base = tid / 8; + int ldg_n_base = tid / 8 * kLdgNumB; + int ldg_k = (lane % 8) * 16; + int num_tile_k = size<2>(gB); + + ElementA *Aaddr = (ElementA *)args.ptr_A + (num_tile_k - 1) * kTileK; + +#pragma unroll + for (uint32_t ldgi = 0; ldgi < kLdgNumA; ++ldgi) { + int idx_row_a = ldg_m_base + kMNPerLdg * ldgi; + reinterpret_cast(&ldg_a_offs_m)[ldgi] = + __builtin_mxc_ldg_b32(token_ids_ptr + idx_row_a + prev_m, 0, -1, true, true, false, false); + } +#pragma unroll + for (uint32_t ldgi = 0; ldgi < kLdgNumB; ++ldgi) { + ldg_n[ldgi] = min(ldg_n_base + ldgi, col_limit - 1); + B[ldgi] = __builtin_mxc_ldg_b128_predicator(&(gB(ldg_n[ldgi], ldg_k, num_tile_k - 1)), + 0, + true, + true, + false, + false, + ldg_k, + k_head, + MACA_ICMP_SLT); + } +#pragma unroll + for (uint32_t ldgi = 0; ldgi < kLdgNumA; ++ldgi) { + rowA_mask[ldgi] = ldg_a_offs_m[ldgi] < args.problem_size.m(); + if constexpr (IsTopkLog2) { + ldg_a_offs_m[ldgi] = (ldg_a_offs_m[ldgi] >> args.moe_params.topk_bits) * args.problem_size.k(); + } else { + ldg_a_offs_m[ldgi] = (ldg_a_offs_m[ldgi] / args.moe_params.topk) * args.problem_size.k(); + } + A[ldgi] = __builtin_mxc_ldg_b128_predicator(Aaddr + ldg_a_offs_m[ldgi] + ldg_k, + 0, + true, + true, + false, + false, + (ldg_k < k_head) && rowA_mask[ldgi], + 1, + MACA_ICMP_EQ); + } + + Tensor sA = make_tensor(make_smem_ptr((ElementA *)smem_A), + make_shape(Int{}, Int{}), + make_stride(Int{}, Int<1>{})); + Tensor sB = make_tensor(make_smem_ptr((ElementB *)smem_B), + make_shape(Int{}, Int{}), + make_stride(Int{}, Int<1>{})); + + int sts_rowA[kStsNumA], sts_rowB[kStsNumB]; + int sts_col = (((tid / 8) + (tid % 8)) % 8) * 16; +#pragma unroll + for (uint32_t i = 0; i < kStsNumB; ++i) { + sts_rowB[i] = tid / 8 + kMNPerLdg * i; + FUSED_MOE_STS(sB(sts_rowB[i], sts_col), B[i], StsType); + } +#pragma unroll + for (uint32_t i = 0; i < kStsNumA; ++i) { + sts_rowA[i] = wave * 32 + lane / 8 + i * 8; + } + FUSED_MOE_STS(sA(sts_rowA[0], sts_col), A[0], StsType); + FUSED_MOE_STS(sA(sts_rowA[1], sts_col), A[1], StsType); + + INT4 accum[kMmaM][kMmaN] = {0}; + int32_t a[kMmaM][kMmaK], b[kMmaN][kMmaK]; + int lds_row_A[2], lds_row_B[8], lds_col[2]; + +#pragma unroll + for (int i = 0; i < 2; ++i) { + lds_col[i] = (((tid % 16) + (lane / 16) + 4 * i) % 8) * 16; + lds_row_A[i] = (tid % 16) + wave * 32 + 16 * i; + } +#pragma unroll + for (int i = 0; i < 8; ++i) { + lds_row_B[i] = (tid % 16) + 16 * i; + } + + __syncthreadshared(); + + LDS_A_B128(0, 0); + LDS_B_B128(0, 0); + LDS_B_B128(1, 0); + LDS_B_B128(2, 0); + LDS_B_B128(3, 0); + + int loop_tile_k = size<2>(gB) - 1; + Aaddr = (ElementA *)args.ptr_A; + for (uint32_t tile_k = 0; tile_k < loop_tile_k; ++tile_k) { + LDG_B_STAGE_I(0); + LDG_B_STAGE_I(1); + MMA_STAGE_MNKX2(0, 0, 0); + LDS_B_B128(4, 0); + MMA_STAGE_MNKX2(0, 0, 2); + LDS_B_B128(5, 0); + MMA_STAGE_MNKX2(0, 1, 0); + LDS_B_B128(6, 0); + LDG_B_STAGE_I(2); + MMA_STAGE_MNKX2(0, 1, 2); + LDS_B_B128(7, 0); + MMA_STAGE_MNKX2(0, 2, 0); + LDG_B_STAGE_I(3); + MMA_STAGE_MNKX2(0, 2, 2); + MMA_STAGE_MNKX2(0, 3, 0); + LDG_A_STAGE_I(0); + MMA_STAGE_MNKX2(0, 3, 2); + LDG_A_STAGE_I(1); + + MMA_STAGE_MNKX2(0, 4, 0); + LDS_A_B128(0, 1); + MMA_STAGE_MNKX2(0, 4, 2); + LDS_B_B128(0, 1); + MMA_STAGE_MNKX2(0, 5, 0); + LDS_B_B128(1, 1); + MMA_STAGE_MNKX2(0, 5, 2); + LDS_B_B128(2, 1); + MMA_STAGE_MNKX2(0, 6, 0); + LDS_B_B128(3, 1); + MMA_STAGE_MNKX2(0, 6, 2); + MMA_STAGE_MNKX2(0, 7, 0); + MMA_STAGE_MNKX2(0, 7, 2); + + LDS_B_B128(4, 1); + MMA_STAGE_MNKX2(0, 0, 4); + LDS_B_B128(5, 1); + MMA_STAGE_MNKX2(0, 0, 6); + LDS_B_B128(6, 1); + MMA_STAGE_MNKX2(0, 1, 4); + LDS_B_B128(7, 1); + MMA_STAGE_MNKX2(0, 1, 6); + MMA_STAGE_MNKX2(0, 2, 4); + MMA_STAGE_MNKX2(0, 2, 6); + FUSED_MOE_STS(sA(sts_rowA[2], sts_col), A[2], StsType); + MMA_STAGE_MNKX2(0, 3, 4); + MMA_STAGE_MNKX2(0, 3, 6); + FUSED_MOE_STS(sA(sts_rowA[3], sts_col), A[3], StsType); + + MMA_STAGE_MNKX2(0, 4, 4); + LDG_A_STAGE_I(2); + MMA_STAGE_MNKX2(0, 4, 6); + LDG_A_STAGE_I(3); + MMA_STAGE_MNKX2(0, 5, 4); + MMA_STAGE_MNKX2(0, 5, 6); + MMA_STAGE_MNKX2(0, 6, 4); + LDS_A_B128(1, 0); + MMA_STAGE_MNKX2(0, 6, 6); + MMA_STAGE_MNKX2(0, 7, 4); + Aaddr += kTileK; + MMA_STAGE_MNKX2(0, 7, 6); + + __syncthreadshared(); + MMA_STAGE_MNKX2(1, 0, 0); + LDS_A_B128(1, 1); + MMA_STAGE_MNKX2(1, 0, 2); + MMA_STAGE_MNKX2(1, 1, 0); + MMA_STAGE_MNKX2(1, 1, 2); + MMA_STAGE_MNKX2(1, 2, 0); + MMA_STAGE_MNKX2(1, 2, 2); + MMA_STAGE_MNKX2(1, 3, 0); + MMA_STAGE_MNKX2(1, 3, 2); + + MMA_STAGE_MNKX2(1, 4, 0); + FUSED_MOE_STS(sB(sts_rowB[0], sts_col), B[0], StsType); + MMA_STAGE_MNKX2(1, 4, 2); + MMA_STAGE_MNKX2(1, 5, 0); + MMA_STAGE_MNKX2(1, 5, 2); + FUSED_MOE_STS(sB(sts_rowB[1], sts_col), B[1], StsType); + MMA_STAGE_MNKX2(1, 6, 0); + MMA_STAGE_MNKX2(1, 6, 2); + MMA_STAGE_MNKX2(1, 7, 0); + FUSED_MOE_STS(sB(sts_rowB[2], sts_col), B[2], StsType); + MMA_STAGE_MNKX2(1, 7, 2); + + MMA_STAGE_MNKX2(1, 0, 4); + MMA_STAGE_MNKX2(1, 0, 6); + FUSED_MOE_STS(sB(sts_rowB[3], sts_col), B[3], StsType); + MMA_STAGE_MNKX2(1, 1, 4); + MMA_STAGE_MNKX2(1, 1, 6); + MMA_STAGE_MNKX2(1, 2, 4); + FUSED_MOE_STS(sA(sts_rowA[0], sts_col), A[0], StsType); + MMA_STAGE_MNKX2(1, 2, 6); + MMA_STAGE_MNKX2(1, 3, 4); + MMA_STAGE_MNKX2(1, 3, 6); + FUSED_MOE_STS(sA(sts_rowA[1], sts_col), A[1], StsType); + + MMA_STAGE_MNKX2(1, 4, 4); + MMA_STAGE_MNKX2(1, 4, 6); + MMA_STAGE_MNKX2(1, 5, 4); + __syncthreadshared(); + MMA_STAGE_MNKX2(1, 5, 6); + LDS_A_B128(0, 0); + LDS_B_B128(0, 0); + MMA_STAGE_MNKX2(1, 6, 4); + LDS_B_B128(1, 0); + MMA_STAGE_MNKX2(1, 6, 6); + LDS_B_B128(2, 0); + MMA_STAGE_MNKX2(1, 7, 4); + LDS_B_B128(3, 0); + MMA_STAGE_MNKX2(1, 7, 6); + } + + int rowC[kRowCSize]; + MMA_STAGE_MNKX2(0, 0, 0); + LDS_B_B128(4, 0); + MMA_STAGE_MNKX2(0, 0, 2); + LDS_B_B128(5, 0); + MMA_STAGE_MNKX2(0, 1, 0); + LDS_B_B128(6, 0); + MMA_STAGE_MNKX2(0, 1, 2); + LDS_B_B128(7, 0); + MMA_STAGE_MNKX2(0, 2, 0); + int token_row_m = prev_m + ((lane / 16) % 2) * 4 + wave * 8 + (lane / 32) * 32; + MMA_STAGE_MNKX2(0, 2, 2); + MMA_STAGE_MNKX2(0, 3, 0); + MMA_STAGE_MNKX2(0, 3, 2); + +#pragma unroll + for (int j = 0; j < 4; ++j) { + *(reinterpret_cast(&rowC) + j) = + __builtin_mxc_ldg_b32(token_ids_ptr + token_row_m + j, 0, -1, true, true, false, false); + } + + MMA_STAGE_MNKX2(0, 4, 0); + LDS_A_B128(0, 1); + MMA_STAGE_MNKX2(0, 4, 2); + LDS_B_B128(0, 1); + MMA_STAGE_MNKX2(0, 5, 0); + LDS_B_B128(1, 1); + MMA_STAGE_MNKX2(0, 5, 2); + LDS_B_B128(2, 1); + MMA_STAGE_MNKX2(0, 6, 0); + LDS_B_B128(3, 1); + MMA_STAGE_MNKX2(0, 6, 2); + MMA_STAGE_MNKX2(0, 7, 0); + MMA_STAGE_MNKX2(0, 7, 2); + + LDS_B_B128(4, 1); + MMA_STAGE_MNKX2(0, 0, 4); + LDS_B_B128(5, 1); + MMA_STAGE_MNKX2(0, 0, 6); + LDS_B_B128(6, 1); + MMA_STAGE_MNKX2(0, 1, 4); + LDS_B_B128(7, 1); + MMA_STAGE_MNKX2(0, 1, 6); + MMA_STAGE_MNKX2(0, 2, 4); + FUSED_MOE_STS(sA(sts_rowA[2], sts_col), A[2], StsType); + MMA_STAGE_MNKX2(0, 2, 6); + MMA_STAGE_MNKX2(0, 3, 4); + MMA_STAGE_MNKX2(0, 3, 6); + FUSED_MOE_STS(sA(sts_rowA[3], sts_col), A[3], StsType); + + MMA_STAGE_MNKX2(0, 4, 4); + MMA_STAGE_MNKX2(0, 4, 6); + MMA_STAGE_MNKX2(0, 5, 4); + MMA_STAGE_MNKX2(0, 5, 6); + MMA_STAGE_MNKX2(0, 6, 4); + LDS_A_B128(1, 0); + MMA_STAGE_MNKX2(0, 6, 6); + MMA_STAGE_MNKX2(0, 7, 4); + MMA_STAGE_MNKX2(0, 7, 6); + +#pragma unroll + for (int j = 0; j < 4; ++j) { + *(reinterpret_cast(&rowC) + 4 + j) = + __builtin_mxc_ldg_b32(token_ids_ptr + token_row_m + 64 + j, 0, -1, true, true, false, false); + } + + MMA_STAGE_MNKX2(1, 0, 0); + MMA_STAGE_MNKX2(1, 0, 2); + MMA_STAGE_MNKX2(1, 1, 0); + MMA_STAGE_MNKX2(1, 1, 2); + MMA_STAGE_MNKX2(1, 2, 0); + MMA_STAGE_MNKX2(1, 2, 2); + MMA_STAGE_MNKX2(1, 3, 0); + MMA_STAGE_MNKX2(1, 3, 2); + + MMA_STAGE_MNKX2(1, 4, 0); + MMA_STAGE_MNKX2(1, 4, 2); + LDS_A_B128(1, 1); + MMA_STAGE_MNKX2(1, 5, 0); + MMA_STAGE_MNKX2(1, 5, 2); + MMA_STAGE_MNKX2(1, 6, 0); + MMA_STAGE_MNKX2(1, 6, 2); + MMA_STAGE_MNKX2(1, 7, 0); + MMA_STAGE_MNKX2(1, 7, 2); + + MMA_STAGE_MNKX2(1, 0, 4); + MMA_STAGE_MNKX2(1, 0, 6); + MMA_STAGE_MNKX2(1, 1, 4); + MMA_STAGE_MNKX2(1, 1, 6); + MMA_STAGE_MNKX2(1, 2, 4); + MMA_STAGE_MNKX2(1, 2, 6); + MMA_STAGE_MNKX2(1, 3, 4); + MMA_STAGE_MNKX2(1, 3, 6); + + MMA_STAGE_MNKX2(1, 4, 4); + MMA_STAGE_MNKX2(1, 4, 6); + MMA_STAGE_MNKX2(1, 5, 4); + MMA_STAGE_MNKX2(1, 5, 6); + MMA_STAGE_MNKX2(1, 6, 4); + MMA_STAGE_MNKX2(1, 6, 6); + MMA_STAGE_MNKX2(1, 7, 4); + MMA_STAGE_MNKX2(1, 7, 6); + + INT4 output[kOutputCount]; +#pragma unroll + for (uint32_t i = 0; i < 2; ++i) { +#pragma unroll + for (uint32_t j = 0; j < 4; ++j) { + output[i * 8 + 2 * j][0] = accum[i][0][j]; + output[i * 8 + 2 * j][1] = accum[i][2][j]; + output[i * 8 + 2 * j][2] = accum[i][4][j]; + output[i * 8 + 2 * j][3] = accum[i][6][j]; + output[i * 8 + 2 * j + 1][0] = accum[i][1][j]; + output[i * 8 + 2 * j + 1][1] = accum[i][3][j]; + output[i * 8 + 2 * j + 1][2] = accum[i][5][j]; + output[i * 8 + 2 * j + 1][3] = accum[i][7][j]; + } + } + + int colC[2]; + bool colC_mask[2]; + colC[0] = (tid % 16) * 4; + colC[1] = colC[0] + 64; + colC_mask[0] = colC[0] < col_limit; + colC_mask[1] = colC[1] < col_limit; + + float weights[2][4], a_scale[2][4]; + FLOAT4 b_scale[2]; + +#pragma unroll + for (uint32_t i = 0; i < 2; ++i) { +#pragma unroll + for (uint32_t j = 0; j < 4; ++j) { + if (output_op.MUL_WEIGHTS) { + const void *moe_weights_ptr = output_op.moe_weights_ + rowC[i * 4 + j]; + *(reinterpret_cast(&weights[i]) + j) = + __builtin_mxc_ldg_b32_predicator(const_cast(moe_weights_ptr), + 0, + true, + true, + false, + false, + rowC[i * 4 + j], + args.problem_size.m(), + MACA_ICMP_SLT); + } + + int row_a_scale; + if constexpr (IsTopkLog2) { + row_a_scale = (rowC[i * 4 + j] >> args.moe_params.topk_bits); + } else { + row_a_scale = (rowC[i * 4 + j] / args.moe_params.topk); + } + + const void *scale_a_ptr = output_op.scale_a_ + row_a_scale; + *(reinterpret_cast(&a_scale[i]) + j) = + __builtin_mxc_ldg_b32_predicator(const_cast(scale_a_ptr), + 0, + true, + true, + false, + false, + rowC[i * 4 + j], + args.problem_size.m(), + MACA_ICMP_SLT); + } + } + +#pragma unroll + for (uint32_t i = 0; i < 2; ++i) { + const void *scale_b_ptr = + (const float *)output_op.scale_b_ + group_idx * args.problem_size.n() + bidy * kTileN + colC[i]; + b_scale[i] = __builtin_mxc_ldg_b128_predicator(const_cast(scale_b_ptr), + 0, + true, + true, + false, + false, + colC_mask[i], + 1, + MACA_ICMP_EQ); + } + + Tc *Caddr = (Tc *)args.ptr_C + bidy * kTileN; + FLOAT2 zero2 = {0.f, 0.f}; + StgType tempC; + +#pragma unroll + for (uint32_t i = 0; i < 2; ++i) { +#pragma unroll + for (uint32_t j = 0; j < 4; ++j) { + float out[8]; + out[0] = output[i * 8 + 2 * j][0]; + out[1] = output[i * 8 + 2 * j][1]; + out[2] = output[i * 8 + 2 * j][2]; + out[3] = output[i * 8 + 2 * j][3]; + out[4] = output[i * 8 + 2 * j + 1][0]; + out[5] = output[i * 8 + 2 * j + 1][1]; + out[6] = output[i * 8 + 2 * j + 1][2]; + out[7] = output[i * 8 + 2 * j + 1][3]; + + if (output_op.MUL_WEIGHTS) { + a_scale[i][j] *= weights[i][j]; + } + + FLOAT2 a_scale_f2 = {a_scale[i][j], a_scale[i][j]}; + FLOAT2 scale[4]; + scale[0] = __builtin_mxc_pk_fma_f32(reinterpret_cast(&b_scale[0])[0], a_scale_f2, zero2); + scale[1] = __builtin_mxc_pk_fma_f32(reinterpret_cast(&b_scale[0])[1], a_scale_f2, zero2); + scale[2] = __builtin_mxc_pk_fma_f32(reinterpret_cast(&b_scale[1])[0], a_scale_f2, zero2); + scale[3] = __builtin_mxc_pk_fma_f32(reinterpret_cast(&b_scale[1])[1], a_scale_f2, zero2); + *reinterpret_cast(&out[0]) = + __builtin_mxc_pk_fma_f32(*reinterpret_cast(&out[0]), scale[0], zero2); + *reinterpret_cast(&out[2]) = + __builtin_mxc_pk_fma_f32(*reinterpret_cast(&out[2]), scale[1], zero2); + *reinterpret_cast(&out[4]) = + __builtin_mxc_pk_fma_f32(*reinterpret_cast(&out[4]), scale[2], zero2); + *reinterpret_cast(&out[6]) = + __builtin_mxc_pk_fma_f32(*reinterpret_cast(&out[6]), scale[3], zero2); + + CVT_F32_TO_BF16(tempC[0], reinterpret_cast(&out)[0], reinterpret_cast(&out)[1]); + CVT_F32_TO_BF16(tempC[1], reinterpret_cast(&out)[2], reinterpret_cast(&out)[3]); + __builtin_mxc_stg_b64_predicator(Caddr + rowC[i * 4 + j] * args.problem_size.n() + colC[0], + 0, + *(reinterpret_cast(&tempC)), + true, + false, + false, + (rowC[i * 4 + j] < args.problem_size.m()) && colC_mask[0], + 1, + MACA_ICMP_EQ); + + CVT_F32_TO_BF16(tempC[0], reinterpret_cast(&out)[4], reinterpret_cast(&out)[5]); + CVT_F32_TO_BF16(tempC[1], reinterpret_cast(&out)[6], reinterpret_cast(&out)[7]); + __builtin_mxc_stg_b64_predicator(Caddr + rowC[i * 4 + j] * args.problem_size.n() + colC[1], + 0, + *(reinterpret_cast(&tempC)), + true, + false, + false, + (rowC[i * 4 + j] < args.problem_size.m()) && colC_mask[1], + 1, + MACA_ICMP_EQ); + } + } +} + +template +using DirectMoeGemmKernel = DirectMoeKernel; + +template +inline dim3 get_grid_shape(typename Kernel::Arguments const &args) { + const int grid_m = (args.moe_params.EM + kTileM - 1) / kTileM; + const int group_bidx = std::max(1, std::min(8, (args.problem_size.m() / args.problem_size.batch() + kTileM - 1) / kTileM)); + const int grid_x = std::min(grid_m, group_bidx); + const int grid_z = (grid_m + grid_x - 1) / grid_x; + const int grid_y = (args.problem_size.n() + kTileN - 1) / kTileN; + return dim3(grid_x, grid_y, grid_z); +} + +template +inline Status launch(typename Kernel::Arguments const &args, mcStream_t stream = nullptr) { + dim3 const block(kThreadCount, 1, 1); + dim3 const grid = get_grid_shape(args); + direct_moe_kernel<<>>(args); + return Status::kSuccess; +} + +} // namespace fused_moe_i8_tn diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/src/fused_moe_i8_tn_macros.h b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/src/fused_moe_i8_tn_macros.h new file mode 100644 index 0000000..4977f6a --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/src/fused_moe_i8_tn_macros.h @@ -0,0 +1,21 @@ +#pragma once + +#include "fused_moe_i8_tn_types.h" + +#define FUSED_MOE_CP_ASYNC_FENC() asm(";--------------") + +#define FUSED_MOE_LDS(dst, src, type_) \ + FUSED_MOE_CP_ASYNC_FENC(); \ + *reinterpret_cast(&(dst)) = *reinterpret_cast(&(src)); \ + FUSED_MOE_CP_ASYNC_FENC() + +#define FUSED_MOE_STS(dst, src, type_) \ + FUSED_MOE_CP_ASYNC_FENC(); \ + *reinterpret_cast(&(dst)) = *reinterpret_cast(&(src)); \ + FUSED_MOE_CP_ASYNC_FENC() + +#if defined(__MACA_ARCH__) && (__MACA_ARCH__ == 1000 || __MACA_ARCH__ == 1089) +#define FUSED_MOE_BUILTIN_MMA_16X16X16_I8(a, b, c) __builtin_mxc_mma_16x16x16i8(a, b, c) +#else +#define FUSED_MOE_BUILTIN_MMA_16X16X16_I8(a, b, c) 0 +#endif diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/src/fused_moe_i8_tn_pybind.cpp b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/src/fused_moe_i8_tn_pybind.cpp new file mode 100644 index 0000000..692bb3e --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/src/fused_moe_i8_tn_pybind.cpp @@ -0,0 +1,101 @@ +#include + +#include +#include + +#include +#include +#include +#include + +#include "fused_moe_i8_tn_runner.h" + +namespace py = pybind11; + +namespace { + +template +std::vector copy_1d_array(const py::array &array, const char *name) { + auto view = py::array_t::ensure(array); + if (!view) { + throw std::invalid_argument(std::string("failed to cast ") + name); + } + if (view.ndim() != 1) { + throw std::invalid_argument(std::string(name) + " must be a 1D array"); + } + const T *ptr = static_cast(view.data()); + return std::vector(ptr, ptr + view.size()); +} + +std::vector copy_2d_int8_array(const py::array &array, const char *name) { + auto view = py::array_t::ensure(array); + if (!view) { + throw std::invalid_argument(std::string("failed to cast ") + name); + } + if (view.ndim() != 2) { + throw std::invalid_argument(std::string(name) + " must be a 2D array"); + } + const int8_t *ptr = static_cast(view.data()); + return std::vector(ptr, ptr + view.size()); +} + +py::array_t run_fused_moe_pybind(const py::array &a, + const py::array &b_col_major, + const py::array &scale_a, + const py::array &scale_b, + const py::array &moe_weights, + const py::array &token_ids, + const py::array &expert_ids, + int topk, + int num_experts = fused_moe_i8_tn::kDefaultNumExperts, + int device_id = 0) { + auto a_view = py::array_t::ensure(a); + auto b_view = py::array_t::ensure(b_col_major); + if (!a_view || a_view.ndim() != 2) { + throw std::invalid_argument("a must be a 2D int8 array"); + } + if (!b_view || b_view.ndim() != 3) { + throw std::invalid_argument("b_col_major must be a 3D int8 array"); + } + + fused_moe_i8_tn::HostInputs inputs; + inputs.num_tokens = static_cast(a_view.shape(0)); + inputs.k = static_cast(a_view.shape(1)); + inputs.num_experts = num_experts; + inputs.n = static_cast(b_view.shape(1)); + inputs.topk = topk; + inputs.em = inputs.num_tokens * inputs.topk; + inputs.a = copy_2d_int8_array(a, "a"); + inputs.b_col_major.assign(static_cast(b_view.data()), + static_cast(b_view.data()) + b_view.size()); + inputs.scale_a = copy_1d_array(scale_a, "scale_a"); + inputs.scale_b = copy_1d_array(scale_b, "scale_b"); + inputs.moe_weights = copy_1d_array(moe_weights, "moe_weights"); + inputs.token_ids = copy_1d_array(token_ids, "token_ids"); + inputs.expert_ids = copy_1d_array(expert_ids, "expert_ids"); + + fused_moe_i8_tn::RunResult result = fused_moe_i8_tn::run_fused_moe_i8_tn(inputs, device_id); + std::vector output = fused_moe_i8_tn::bf16_vector_to_float(result.output); + + py::array_t out({result.rows, result.cols}); + std::memcpy(out.mutable_data(), output.data(), output.size() * sizeof(float)); + return out; +} + +} // namespace + +PYBIND11_MODULE(fused_moe_i8_tn_pybind, m) { + m.doc() = "Pybind wrapper for standalone fused_moe_i8_tn"; + m.def("run_fused_moe_i8_tn", + &run_fused_moe_pybind, + py::arg("a"), + py::arg("b_col_major"), + py::arg("scale_a"), + py::arg("scale_b"), + py::arg("moe_weights"), + py::arg("token_ids"), + py::arg("expert_ids"), + py::arg("topk"), + py::arg("num_experts") = fused_moe_i8_tn::kDefaultNumExperts, + py::arg("device_id") = 0); +} diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/src/fused_moe_i8_tn_runner.h b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/src/fused_moe_i8_tn_runner.h new file mode 100644 index 0000000..fb55783 --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/src/fused_moe_i8_tn_runner.h @@ -0,0 +1,331 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include +#include + +#include "fused_moe_i8_tn_kernel.h" +#include "fused_moe_i8_tn_types.h" + +namespace fused_moe_i8_tn { + +constexpr int kDefaultNumExperts = 2; +constexpr int kDefaultTileM = 128; +constexpr int kDefaultN = 128; +constexpr int kDefaultK = 128; + +struct HostInputs { + int num_tokens = 0; + int topk = 0; + int em = 0; + int num_experts = kDefaultNumExperts; + int n = kDefaultN; + int k = kDefaultK; + std::vector a; + std::vector b_col_major; + std::vector scale_a; + std::vector scale_b; + std::vector moe_weights; + std::vector token_ids; + std::vector expert_ids; +}; + +struct RunResult { + int rows = 0; + int cols = 0; + std::vector output; +}; + +inline float bf16_to_float(BFloat16 value) { + return static_cast(value); +} + +inline BFloat16 float_to_bf16(float value) { + return BFloat16(value); +} + +inline std::vector bf16_vector_to_float(const std::vector &input) { + std::vector out(input.size()); + for (size_t i = 0; i < input.size(); ++i) { + out[i] = bf16_to_float(input[i]); + } + return out; +} + +inline void check_mc_or_throw(mcError_t status, const char *expr) { + if (status != mcSuccess) { + throw std::runtime_error(std::string(expr) + " failed: " + mcGetErrorString(status)); + } +} + +inline void check_status_or_throw(Status status, const char *expr) { + if (status != Status::kSuccess) { + throw std::runtime_error(std::string(expr) + " failed: " + get_status_string(status)); + } +} + +inline bool is_log2_value(int value) { + return value > 0 && ((value & (value - 1)) == 0); +} + +inline void validate_host_inputs(const HostInputs &inputs) { + if (inputs.num_tokens <= 0) { + throw std::invalid_argument("num_tokens must be > 0"); + } + if (inputs.topk <= 0) { + throw std::invalid_argument("topk must be > 0"); + } + if (inputs.n != kDefaultN) { + throw std::invalid_argument("only N=128 is supported by fused_moe_i8_tn"); + } + if (inputs.k != kDefaultK) { + throw std::invalid_argument("only K=128 is supported by fused_moe_i8_tn"); + } + if (inputs.em <= 0) { + throw std::invalid_argument("em must be > 0"); + } + if (inputs.em != inputs.num_tokens * inputs.topk) { + throw std::invalid_argument("em must equal num_tokens * topk"); + } + if (inputs.em % kDefaultTileM != 0) { + throw std::invalid_argument("em must be a multiple of 128"); + } + if (inputs.num_experts <= 0) { + throw std::invalid_argument("num_experts must be > 0"); + } + + const size_t total_rows = static_cast(inputs.em); + const size_t expected_a = static_cast(inputs.num_tokens) * inputs.k; + const size_t expected_b = static_cast(inputs.num_experts) * inputs.n * inputs.k; + const size_t expected_scale_a = static_cast(inputs.num_tokens); + const size_t expected_scale_b = static_cast(inputs.num_experts) * inputs.n; + const size_t expected_moe_weights = total_rows; + const size_t expected_token_ids = total_rows; + const size_t expected_expert_ids = static_cast(inputs.em / kDefaultTileM); + + if (inputs.a.size() != expected_a) { + throw std::invalid_argument("A size mismatch"); + } + if (inputs.b_col_major.size() != expected_b) { + throw std::invalid_argument("B size mismatch"); + } + if (inputs.scale_a.size() != expected_scale_a) { + throw std::invalid_argument("scale_a size mismatch"); + } + if (inputs.scale_b.size() != expected_scale_b) { + throw std::invalid_argument("scale_b size mismatch"); + } + if (inputs.moe_weights.size() != expected_moe_weights) { + throw std::invalid_argument("moe_weights size mismatch"); + } + if (inputs.token_ids.size() != expected_token_ids) { + throw std::invalid_argument("token_ids size mismatch"); + } + if (inputs.expert_ids.size() != expected_expert_ids) { + throw std::invalid_argument("expert_ids size mismatch"); + } + + for (int expert : inputs.expert_ids) { + if (expert < 0 || expert >= inputs.num_experts) { + throw std::invalid_argument("expert_ids contains out-of-range expert index"); + } + } +} + +template +inline typename GemmKernel::Arguments make_direct_arguments(const HostInputs &inputs, + int total_rows, + int8_t *dev_a, + int8_t *dev_b, + float *dev_scale_a, + float *dev_scale_b, + float *dev_moe_weights, + int *dev_token_ids, + int *dev_expert_ids, + int32_t *dev_num_tokens_post_padded, + BFloat16 *dev_c) { + return typename GemmKernel::Arguments( + BatchedGemmCoord(total_rows, inputs.n, inputs.k, inputs.num_experts), + typename GemmKernel::EpilogueOutputOp::Params(dev_scale_a, dev_scale_b, dev_moe_weights), + dev_a, + dev_b, + dev_c, + MoeParams(dev_token_ids, dev_expert_ids, dev_num_tokens_post_padded, inputs.em, inputs.topk, true)); +} + +inline RunResult run_fused_moe_i8_tn(const HostInputs &inputs, int device_id = 0) { + validate_host_inputs(inputs); + + int device_count = 0; + check_mc_or_throw(mcGetDeviceCount(&device_count), "mcGetDeviceCount"); + if (device_count <= 0) { + throw std::runtime_error("No MACA device is visible."); + } + if (device_id < 0 || device_id >= device_count) { + throw std::invalid_argument("device_id is out of range"); + } + check_mc_or_throw(mcSetDevice(device_id), "mcSetDevice"); + + const int total_rows = inputs.em; + std::vector host_num_tokens_post_padded(1, inputs.em); + std::vector host_output(static_cast(total_rows) * inputs.n, float_to_bf16(0.0f)); + + int8_t *dev_a = nullptr; + int8_t *dev_b = nullptr; + float *dev_scale_a = nullptr; + float *dev_scale_b = nullptr; + float *dev_moe_weights = nullptr; + int *dev_token_ids = nullptr; + int *dev_expert_ids = nullptr; + int32_t *dev_num_tokens_post_padded = nullptr; + BFloat16 *dev_c = nullptr; + + try { + check_mc_or_throw(mcMalloc(reinterpret_cast(&dev_a), inputs.a.size() * sizeof(int8_t)), "mcMalloc(dev_a)"); + check_mc_or_throw(mcMalloc(reinterpret_cast(&dev_b), inputs.b_col_major.size() * sizeof(int8_t)), "mcMalloc(dev_b)"); + check_mc_or_throw(mcMalloc(reinterpret_cast(&dev_scale_a), inputs.scale_a.size() * sizeof(float)), + "mcMalloc(dev_scale_a)"); + check_mc_or_throw(mcMalloc(reinterpret_cast(&dev_scale_b), inputs.scale_b.size() * sizeof(float)), + "mcMalloc(dev_scale_b)"); + check_mc_or_throw(mcMalloc(reinterpret_cast(&dev_moe_weights), inputs.moe_weights.size() * sizeof(float)), + "mcMalloc(dev_moe_weights)"); + check_mc_or_throw(mcMalloc(reinterpret_cast(&dev_token_ids), inputs.token_ids.size() * sizeof(int)), + "mcMalloc(dev_token_ids)"); + check_mc_or_throw(mcMalloc(reinterpret_cast(&dev_expert_ids), inputs.expert_ids.size() * sizeof(int)), + "mcMalloc(dev_expert_ids)"); + check_mc_or_throw(mcMalloc(reinterpret_cast(&dev_num_tokens_post_padded), + host_num_tokens_post_padded.size() * sizeof(int32_t)), + "mcMalloc(dev_num_tokens_post_padded)"); + check_mc_or_throw(mcMalloc(reinterpret_cast(&dev_c), host_output.size() * sizeof(BFloat16)), "mcMalloc(dev_c)"); + + check_mc_or_throw(mcMemcpy(dev_a, inputs.a.data(), inputs.a.size() * sizeof(int8_t), mcMemcpyHostToDevice), + "mcMemcpy(dev_a)"); + check_mc_or_throw(mcMemcpy(dev_b, + inputs.b_col_major.data(), + inputs.b_col_major.size() * sizeof(int8_t), + mcMemcpyHostToDevice), + "mcMemcpy(dev_b)"); + check_mc_or_throw(mcMemcpy(dev_scale_a, + inputs.scale_a.data(), + inputs.scale_a.size() * sizeof(float), + mcMemcpyHostToDevice), + "mcMemcpy(dev_scale_a)"); + check_mc_or_throw(mcMemcpy(dev_scale_b, + inputs.scale_b.data(), + inputs.scale_b.size() * sizeof(float), + mcMemcpyHostToDevice), + "mcMemcpy(dev_scale_b)"); + check_mc_or_throw(mcMemcpy(dev_moe_weights, + inputs.moe_weights.data(), + inputs.moe_weights.size() * sizeof(float), + mcMemcpyHostToDevice), + "mcMemcpy(dev_moe_weights)"); + check_mc_or_throw(mcMemcpy(dev_token_ids, + inputs.token_ids.data(), + inputs.token_ids.size() * sizeof(int), + mcMemcpyHostToDevice), + "mcMemcpy(dev_token_ids)"); + check_mc_or_throw(mcMemcpy(dev_expert_ids, + inputs.expert_ids.data(), + inputs.expert_ids.size() * sizeof(int), + mcMemcpyHostToDevice), + "mcMemcpy(dev_expert_ids)"); + check_mc_or_throw(mcMemcpy(dev_num_tokens_post_padded, + host_num_tokens_post_padded.data(), + host_num_tokens_post_padded.size() * sizeof(int32_t), + mcMemcpyHostToDevice), + "mcMemcpy(dev_num_tokens_post_padded)"); + check_mc_or_throw(mcMemset(dev_c, 0, host_output.size() * sizeof(BFloat16)), "mcMemset(dev_c)"); + + const bool topk_is_log2 = is_log2_value(inputs.topk); + if (topk_is_log2) { + using GemmKernel = DirectMoeKernel; + auto const args = make_direct_arguments(inputs, + total_rows, + dev_a, + dev_b, + dev_scale_a, + dev_scale_b, + dev_moe_weights, + dev_token_ids, + dev_expert_ids, + dev_num_tokens_post_padded, + dev_c); + check_status_or_throw(launch(args), "direct_moe_kernel"); + } else { + using GemmKernel = DirectMoeKernel; + auto const args = make_direct_arguments(inputs, + total_rows, + dev_a, + dev_b, + dev_scale_a, + dev_scale_b, + dev_moe_weights, + dev_token_ids, + dev_expert_ids, + dev_num_tokens_post_padded, + dev_c); + check_status_or_throw(launch(args), "direct_moe_kernel"); + } + + check_mc_or_throw(mcDeviceSynchronize(), "mcDeviceSynchronize"); + check_mc_or_throw(mcGetLastError(), "mcGetLastError"); + check_mc_or_throw(mcMemcpy(host_output.data(), + dev_c, + host_output.size() * sizeof(BFloat16), + mcMemcpyDeviceToHost), + "mcMemcpy(host_output)"); + } catch (...) { + if (dev_a) { + mcFree(dev_a); + } + if (dev_b) { + mcFree(dev_b); + } + if (dev_scale_a) { + mcFree(dev_scale_a); + } + if (dev_scale_b) { + mcFree(dev_scale_b); + } + if (dev_moe_weights) { + mcFree(dev_moe_weights); + } + if (dev_token_ids) { + mcFree(dev_token_ids); + } + if (dev_expert_ids) { + mcFree(dev_expert_ids); + } + if (dev_num_tokens_post_padded) { + mcFree(dev_num_tokens_post_padded); + } + if (dev_c) { + mcFree(dev_c); + } + throw; + } + + check_mc_or_throw(mcFree(dev_a), "mcFree(dev_a)"); + check_mc_or_throw(mcFree(dev_b), "mcFree(dev_b)"); + check_mc_or_throw(mcFree(dev_scale_a), "mcFree(dev_scale_a)"); + check_mc_or_throw(mcFree(dev_scale_b), "mcFree(dev_scale_b)"); + check_mc_or_throw(mcFree(dev_moe_weights), "mcFree(dev_moe_weights)"); + check_mc_or_throw(mcFree(dev_token_ids), "mcFree(dev_token_ids)"); + check_mc_or_throw(mcFree(dev_expert_ids), "mcFree(dev_expert_ids)"); + check_mc_or_throw(mcFree(dev_num_tokens_post_padded), "mcFree(dev_num_tokens_post_padded)"); + check_mc_or_throw(mcFree(dev_c), "mcFree(dev_c)"); + + RunResult result; + result.rows = total_rows; + result.cols = inputs.n; + result.output = std::move(host_output); + return result; +} + +} // namespace fused_moe_i8_tn diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/src/fused_moe_i8_tn_types.h b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/src/fused_moe_i8_tn_types.h new file mode 100644 index 0000000..b4d0f32 --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/fused_moe_i8_tn/src/fused_moe_i8_tn_types.h @@ -0,0 +1,167 @@ +#pragma once + +#include +#include + +#include +#include +#include + +namespace fused_moe_i8_tn { + +#if defined(__MXCC__) || (defined(__clang__) && defined(__MACA__)) +#define FUSED_MOE_HOST_DEVICE __forceinline__ __device__ __host__ +#define FUSED_MOE_DEVICE __forceinline__ __device__ +#else +#define FUSED_MOE_HOST_DEVICE inline +#define FUSED_MOE_DEVICE inline +#endif + +enum class Status { + kSuccess, + kErrorInternal, +}; + +inline const char *get_status_string(Status status) { + switch (status) { + case Status::kSuccess: + return "Success"; + case Status::kErrorInternal: + return "Error Internal"; + } + return "Invalid status"; +} + +struct alignas(2) BFloat16 { + uint16_t storage; + + FUSED_MOE_HOST_DEVICE + BFloat16() : storage(0) {} + + FUSED_MOE_HOST_DEVICE + explicit BFloat16(float x) { +#if defined(__MACA_ARCH__) + auto tmp = __float2bfloat16(x); + storage = reinterpret_cast(tmp); +#else + uint32_t bits; + std::memcpy(&bits, &x, sizeof(bits)); + bits += ((bits >> 16) & 1) + 0x7fff; + storage = static_cast(bits >> 16); +#endif + } + + FUSED_MOE_HOST_DEVICE + operator float() const { +#if defined(__MACA_ARCH__) + __maca_bfloat16_raw raw; + raw.x = storage; + return __bfloat162float(__maca_bfloat16(raw)); +#else + uint32_t bits = static_cast(storage) << 16; + float out; + std::memcpy(&out, &bits, sizeof(out)); + return out; +#endif + } +}; + +struct BatchedGemmCoord { + int m_; + int n_; + int k_; + int batch_; + + FUSED_MOE_HOST_DEVICE + BatchedGemmCoord() : m_(0), n_(0), k_(0), batch_(0) {} + + FUSED_MOE_HOST_DEVICE + BatchedGemmCoord(int m, int n, int k, int batch) : m_(m), n_(n), k_(k), batch_(batch) {} + + FUSED_MOE_HOST_DEVICE + int m() const { return m_; } + + FUSED_MOE_HOST_DEVICE + int n() const { return n_; } + + FUSED_MOE_HOST_DEVICE + int k() const { return k_; } + + FUSED_MOE_HOST_DEVICE + int batch() const { return batch_; } +}; + +struct MoeParams { + int *token_ids; + int *expert_ids; + int *num_tokens_post_padded_ptr; + int32_t EM; + int32_t topk; + bool mul_weight; + int topk_bits; + + FUSED_MOE_HOST_DEVICE + MoeParams() + : token_ids(nullptr), + expert_ids(nullptr), + num_tokens_post_padded_ptr(nullptr), + EM(0), + topk(0), + mul_weight(false), + topk_bits(0) {} + + FUSED_MOE_HOST_DEVICE + MoeParams(int *token_ids_, + int *expert_ids_, + int *num_tokens_post_padded_ptr_, + int EM_, + int topk_, + bool mul_weight_) + : token_ids(token_ids_), + expert_ids(expert_ids_), + num_tokens_post_padded_ptr(num_tokens_post_padded_ptr_), + EM(EM_), + topk(topk_), + mul_weight(mul_weight_), + topk_bits(0) { + int num = topk_; + while (num >>= 1) { + ++topk_bits; + } + } +}; + +struct EpilogueOutputOp { + using ElementOutput = BFloat16; + using ElementCompute = float; + static constexpr int kCount = 2; + static constexpr bool MUL_WEIGHTS = true; + + struct Params { + ElementCompute const *scale_a; + ElementCompute const *scale_b; + ElementCompute const *moe_weights; + + FUSED_MOE_HOST_DEVICE + Params() : scale_a(nullptr), scale_b(nullptr), moe_weights(nullptr) {} + + FUSED_MOE_HOST_DEVICE + Params(ElementCompute const *scale_a_, + ElementCompute const *scale_b_, + ElementCompute const *moe_weights_) + : scale_a(scale_a_), scale_b(scale_b_), moe_weights(moe_weights_) {} + }; + + ElementCompute const *scale_a_; + ElementCompute const *scale_b_; + ElementCompute const *moe_weights_; + + FUSED_MOE_HOST_DEVICE + EpilogueOutputOp() : scale_a_(nullptr), scale_b_(nullptr), moe_weights_(nullptr) {} + + FUSED_MOE_HOST_DEVICE + explicit EpilogueOutputOp(Params const ¶ms) + : scale_a_(params.scale_a), scale_b_(params.scale_b), moe_weights_(params.moe_weights) {} +}; + +} // namespace fused_moe_i8_tn diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/i8_tn_256x256x128_raw_arrays/CMakeLists.txt b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/i8_tn_256x256x128_raw_arrays/CMakeLists.txt new file mode 100644 index 0000000..ab62ec2 --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/i8_tn_256x256x128_raw_arrays/CMakeLists.txt @@ -0,0 +1,46 @@ +cmake_minimum_required(VERSION 3.20) + +project(i8_tn_256x256x128_raw_arrays LANGUAGES NONE) + +set(MACA_PATH "$ENV{MACA_PATH}" CACHE PATH "Path to MACA SDK") +if(NOT MACA_PATH) + set(MACA_PATH "/opt/maca") +endif() + +find_program(MXCC + NAMES mxcc + PATHS "${MACA_PATH}/mxgpu_llvm/bin" + NO_DEFAULT_PATH) + +if(NOT MXCC) + message(FATAL_ERROR "mxcc not found under ${MACA_PATH}/mxgpu_llvm/bin") +endif() + +set(STANDALONE_ROOT "${CMAKE_CURRENT_SOURCE_DIR}") +set(SRC "${STANDALONE_ROOT}/src/test.cpp") +set(BIN "${CMAKE_CURRENT_BINARY_DIR}/i8_tn_256x256x128_raw_arrays_test") + +add_custom_command( + OUTPUT "${BIN}" + COMMAND "${MXCC}" + -std=c++17 + -xmaca + -I"${STANDALONE_ROOT}/include" + -I"${MACA_PATH}/include" + "${SRC}" + -L"${MACA_PATH}/lib" + -lmcruntime + -o "${BIN}" + DEPENDS + "${SRC}" + "${STANDALONE_ROOT}/include/standalone_maca_kernel_utils.hpp" + "${STANDALONE_ROOT}/include/gemm_i8_tn_256x256x128_raw_arrays.hpp" + VERBATIM) + +add_custom_target(build_i8_tn_256x256x128_raw_arrays_test ALL DEPENDS "${BIN}") + +add_custom_target( + run + COMMAND "${BIN}" + DEPENDS "${BIN}" + USES_TERMINAL) diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/i8_tn_256x256x128_raw_arrays/include/gemm_i8_tn_256x256x128_raw_arrays.hpp b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/i8_tn_256x256x128_raw_arrays/include/gemm_i8_tn_256x256x128_raw_arrays.hpp new file mode 100644 index 0000000..9983e9b --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/i8_tn_256x256x128_raw_arrays/include/gemm_i8_tn_256x256x128_raw_arrays.hpp @@ -0,0 +1,368 @@ +#pragma once + +#include "standalone_maca_kernel_utils.hpp" + +namespace standalone_i8_tn_256x256x128_raw_arrays { + +struct KernelConfig { + static constexpr int kTileM = 256; + static constexpr int kTileN = 256; + static constexpr int kTileK = 128; + static constexpr int kThreadCount = 512; + static constexpr int kWaveSize = 64; + static constexpr int kWaveCount = kThreadCount / kWaveSize; + static constexpr int kRowsPerWaveGroup = 64; + static constexpr int kColsPerWaveGroup = 128; + static constexpr int kRowsPerMicroTile = 16; + static constexpr int kColsPerMicroTile = 32; + static constexpr int kColumnGroupsPerWave = 2; + static constexpr int kColBlocksPerWaveGroup = 2; + static constexpr int kRowBlocksPerWave = 4; + static constexpr int kOutputVectorsPerMicroTile = 4; + static constexpr int kOutputVectorsPerColBlock = kRowBlocksPerWave * kOutputVectorsPerMicroTile; + static constexpr int kElementsPer128b = 16; + static constexpr int kSharedBytesA = kTileM * kTileK; + static constexpr int kSharedBytesB = kTileN * kTileK; + static constexpr int kSmemSize = kSharedBytesA + kSharedBytesB; +}; + +using StoreVector = __NATIVE_VECTOR__(2, int32_t); +using LdsTypeI8Mma = __NATIVE_VECTOR__(4, int32_t); +using AbTypeI8Mma = int32_t; +using AccumTypeI8Mma = __NATIVE_VECTOR__(4, int32_t); + +struct ThreadContext { + int a_store_offset[4]; + int a_row_local[4]; + int a_load_k[4]; + int b_store_offset[4]; + int b_col_local[4]; + int b_load_k[4]; + int a_lds_offset[KernelConfig::kRowBlocksPerWave][2]; + int b_lds_offset[KernelConfig::kColumnGroupsPerWave][KernelConfig::kColBlocksPerWaveGroup][2][2]; +}; + +__forceinline__ __device__ int swizzled_slot8(int row_or_col, int q) { + return q ^ (row_or_col & 7); +} + +__forceinline__ __device__ void clear_accumulators( + AccumTypeI8Mma (&accum)[KernelConfig::kColumnGroupsPerWave] + [KernelConfig::kColBlocksPerWaveGroup] + [KernelConfig::kRowBlocksPerWave][2]) { +#pragma unroll + for (int column_group = 0; column_group < KernelConfig::kColumnGroupsPerWave; ++column_group) { +#pragma unroll + for (int col_block = 0; col_block < KernelConfig::kColBlocksPerWaveGroup; ++col_block) { +#pragma unroll + for (int row_block = 0; row_block < KernelConfig::kRowBlocksPerWave; ++row_block) { +#pragma unroll + for (int half = 0; half < 2; ++half) { +#pragma unroll + for (int i = 0; i < KernelConfig::kOutputVectorsPerMicroTile; ++i) { + accum[column_group][col_block][row_block][half][i] = 0; + } + } + } + } + } +} + +__forceinline__ __device__ void build_thread_context(ThreadContext &ctx, + int tid, + int wave_row_group, + int wave_col_group, + int lane16, + int lane_q_block, + int K) { + const int row_or_col_local = tid >> 3; + const int slot8_phys = tid & 7; + +#pragma unroll + for (int pass = 0; pass < 4; ++pass) { + const int row_or_col = pass * 64 + row_or_col_local; + const int q = slot8_phys ^ (row_or_col & 7); + ctx.a_store_offset[pass] = row_or_col * 128 + slot8_phys * KernelConfig::kElementsPer128b; + ctx.a_row_local[pass] = row_or_col; + ctx.a_load_k[pass] = q * KernelConfig::kElementsPer128b; + ctx.b_store_offset[pass] = row_or_col * 128 + slot8_phys * KernelConfig::kElementsPer128b; + ctx.b_col_local[pass] = row_or_col; + ctx.b_load_k[pass] = q * KernelConfig::kElementsPer128b; + } + + const int q_values[2] = {lane_q_block, lane_q_block + 4}; + +#pragma unroll + for (int row_block = 0; row_block < KernelConfig::kRowBlocksPerWave; ++row_block) { + const int a_row = + wave_row_group * KernelConfig::kRowsPerWaveGroup + row_block * KernelConfig::kRowsPerMicroTile + lane16; +#pragma unroll + for (int half = 0; half < 2; ++half) { + const int slot8_phys_local = swizzled_slot8(a_row, q_values[half]); + ctx.a_lds_offset[row_block][half] = a_row * 128 + slot8_phys_local * KernelConfig::kElementsPer128b; + } + } + + const int lds_k_b = (lane_q_block ^ (lane16 & 3)) * KernelConfig::kElementsPer128b; +#pragma unroll + for (int column_group = 0; column_group < KernelConfig::kColumnGroupsPerWave; ++column_group) { +#pragma unroll + for (int col_block = 0; col_block < KernelConfig::kColBlocksPerWaveGroup; ++col_block) { + const int b_chunk = wave_col_group * 4 + column_group * 2 + col_block; + const int b_col0 = b_chunk * KernelConfig::kColsPerMicroTile + lane16; + const int b_col1 = b_col0 + 16; + const int cols[2] = {b_col0, b_col1}; +#pragma unroll + for (int half = 0; half < 2; ++half) { +#pragma unroll + for (int which = 0; which < 2; ++which) { + const int row_or_col = cols[which]; + const int slot8_phys_local = swizzled_slot8(row_or_col, q_values[half]); + ctx.b_lds_offset[column_group][col_block][half][which] = + row_or_col * 128 + slot8_phys_local * KernelConfig::kElementsPer128b; + } + } + } + } +} + +template +__forceinline__ __device__ void load_a_pass(int8_t *smem_a, + const int8_t *a_ptr, + int K, + int global_row_base, + int k_tile_base, + ThreadContext const &ctx) { + const int row = global_row_base + ctx.a_row_local[Pass]; + __builtin_mxc_ldg_b128_bsm( + smem_a + ctx.a_store_offset[Pass], + const_cast(reinterpret_cast( + a_ptr + static_cast(row) * K + k_tile_base + ctx.a_load_k[Pass])), + 0, + -1, + true, + true, + false, + true); +} + +template +__forceinline__ __device__ void load_b_pass(int8_t *smem_b, + const int8_t *b_ptr, + int K, + int global_col_base, + int k_tile_base, + ThreadContext const &ctx) { + const int col = global_col_base + ctx.b_col_local[Pass]; + __builtin_mxc_ldg_b128_bsm( + smem_b + ctx.b_store_offset[Pass], + const_cast(reinterpret_cast( + b_ptr + static_cast(col) * K + k_tile_base + ctx.b_load_k[Pass])), + 0, + -1, + true, + true, + false, + true); +} + +__forceinline__ __device__ void wait_for_tile_load() { + standalone_arrive_gvmcnt(0); + __builtin_mxc_barrier_inst(); +} + +__forceinline__ __device__ void mma_on_pack16(AccumTypeI8Mma &accum_left, + AccumTypeI8Mma &accum_right, + LdsTypeI8Mma const &a_pack, + LdsTypeI8Mma const &b0_pack, + LdsTypeI8Mma const &b1_pack) { + AbTypeI8Mma const *a_frag = reinterpret_cast(&a_pack); + AbTypeI8Mma const *b0_frag = reinterpret_cast(&b0_pack); + AbTypeI8Mma const *b1_frag = reinterpret_cast(&b1_pack); +#pragma unroll + for (int step = 0; step < 4; ++step) { + accum_left = STANDALONE_BUILTIN_MMA_16X16X16_I8(a_frag[step], b0_frag[step], accum_left); + accum_right = STANDALONE_BUILTIN_MMA_16X16X16_I8(a_frag[step], b1_frag[step], accum_right); + } +} + +__forceinline__ __device__ void consume_full_k128_from_shared( + AccumTypeI8Mma (&accum)[KernelConfig::kColumnGroupsPerWave] + [KernelConfig::kColBlocksPerWaveGroup] + [KernelConfig::kRowBlocksPerWave][2], + int8_t const *smem_a, + int8_t const *smem_b, + ThreadContext const &ctx) { + LdsTypeI8Mma b0_pack_low[KernelConfig::kColumnGroupsPerWave][KernelConfig::kColBlocksPerWaveGroup]; + LdsTypeI8Mma b1_pack_low[KernelConfig::kColumnGroupsPerWave][KernelConfig::kColBlocksPerWaveGroup]; + LdsTypeI8Mma b0_pack_high[KernelConfig::kColumnGroupsPerWave][KernelConfig::kColBlocksPerWaveGroup]; + LdsTypeI8Mma b1_pack_high[KernelConfig::kColumnGroupsPerWave][KernelConfig::kColBlocksPerWaveGroup]; + +#pragma unroll + for (int column_group = 0; column_group < KernelConfig::kColumnGroupsPerWave; ++column_group) { +#pragma unroll + for (int col_block = 0; col_block < KernelConfig::kColBlocksPerWaveGroup; ++col_block) { + STANDALONE_LDS( + b0_pack_low[column_group][col_block], + *const_cast(smem_b + ctx.b_lds_offset[column_group][col_block][0][0]), + LdsTypeI8Mma); + STANDALONE_LDS( + b1_pack_low[column_group][col_block], + *const_cast(smem_b + ctx.b_lds_offset[column_group][col_block][0][1]), + LdsTypeI8Mma); + STANDALONE_LDS( + b0_pack_high[column_group][col_block], + *const_cast(smem_b + ctx.b_lds_offset[column_group][col_block][1][0]), + LdsTypeI8Mma); + STANDALONE_LDS( + b1_pack_high[column_group][col_block], + *const_cast(smem_b + ctx.b_lds_offset[column_group][col_block][1][1]), + LdsTypeI8Mma); + } + } + +#pragma unroll + for (int row_block = 0; row_block < KernelConfig::kRowBlocksPerWave; ++row_block) { + LdsTypeI8Mma a_pack_low; + LdsTypeI8Mma a_pack_high; + STANDALONE_LDS(a_pack_low, *const_cast(smem_a + ctx.a_lds_offset[row_block][0]), LdsTypeI8Mma); + STANDALONE_LDS(a_pack_high, *const_cast(smem_a + ctx.a_lds_offset[row_block][1]), LdsTypeI8Mma); + +#pragma unroll + for (int column_group = 0; column_group < KernelConfig::kColumnGroupsPerWave; ++column_group) { +#pragma unroll + for (int col_block = 0; col_block < KernelConfig::kColBlocksPerWaveGroup; ++col_block) { + mma_on_pack16( + accum[column_group][col_block][row_block][0], + accum[column_group][col_block][row_block][1], + a_pack_low, + b0_pack_low[column_group][col_block], + b1_pack_low[column_group][col_block]); + mma_on_pack16( + accum[column_group][col_block][row_block][0], + accum[column_group][col_block][row_block][1], + a_pack_high, + b0_pack_high[column_group][col_block], + b1_pack_high[column_group][col_block]); + } + } + } +} + +__forceinline__ __device__ void store_accumulators_to_global( + int32_t *D, + int M, + int N, + int bidx, + int bidy, + int bidz, + AccumTypeI8Mma const (&accum)[KernelConfig::kColumnGroupsPerWave] + [KernelConfig::kColBlocksPerWaveGroup] + [KernelConfig::kRowBlocksPerWave][2]) { + const int row_limit = ((M - bidy * KernelConfig::kTileM) < KernelConfig::kTileM) + ? (M - bidy * KernelConfig::kTileM) + : KernelConfig::kTileM; + const int col_limit = ((N - bidx * KernelConfig::kTileN) < KernelConfig::kTileN) + ? (N - bidx * KernelConfig::kTileN) + : KernelConfig::kTileN; + const int tid = threadIdx.x; + const int wave_idx = tid / KernelConfig::kWaveSize; + const int lane_idx = tid % KernelConfig::kWaveSize; + const int lane_col = lane_idx % 16; + const int lane_row_group = lane_idx / 16; + const int wave_row_base = (wave_idx / 2) * KernelConfig::kRowsPerWaveGroup; + const int wave_col_base = (wave_idx % 2) * KernelConfig::kColsPerWaveGroup; + + int32_t *d_ptr = D + static_cast(bidz) * M * N; + +#pragma unroll + for (int column_group = 0; column_group < KernelConfig::kColumnGroupsPerWave; ++column_group) { +#pragma unroll + for (int col_block = 0; col_block < KernelConfig::kColBlocksPerWaveGroup; ++col_block) { + const int microtile_col_base = + wave_col_base + column_group * 64 + col_block * KernelConfig::kColsPerMicroTile; + const int col0 = microtile_col_base + lane_col; + const int col1 = col0 + 16; + +#pragma unroll + for (int row_block = 0; row_block < KernelConfig::kRowBlocksPerWave; ++row_block) { + const int output_base = + column_group * (KernelConfig::kColBlocksPerWaveGroup * KernelConfig::kOutputVectorsPerColBlock) + + col_block * KernelConfig::kOutputVectorsPerColBlock + + row_block * KernelConfig::kOutputVectorsPerMicroTile; +#pragma unroll + for (int i = 0; i < KernelConfig::kOutputVectorsPerMicroTile; ++i) { + const int row = wave_row_base + row_block * KernelConfig::kRowsPerMicroTile + + lane_row_group * 4 + i; + if (row >= row_limit) { + continue; + } + const size_t row_offset = static_cast(bidy * KernelConfig::kTileM + row) * N + + bidx * KernelConfig::kTileN; + if (col0 < col_limit) { + d_ptr[row_offset + col0] = accum[column_group][col_block][row_block][0][i]; + } + if (col1 < col_limit) { + d_ptr[row_offset + col1] = accum[column_group][col_block][row_block][1][i]; + } + } + } + } + } +} + +__global__ void gemm_i8_tn_256x256x128_raw_arrays_kernel(const int8_t *A, + const int8_t *B, + int32_t *D, + int M, + int N, + int K) { + __shared__ int8_t smem_data[KernelConfig::kSmemSize]; + + int8_t *smem_a = smem_data; + int8_t *smem_b = smem_data + KernelConfig::kSharedBytesA; + + const int tid = threadIdx.x; + const int bidx = blockIdx.y; + const int bidy = blockIdx.x; + const int bidz = blockIdx.z; + + const int wave_idx = tid / KernelConfig::kWaveSize; + const int lane_idx = tid % KernelConfig::kWaveSize; + const int wave_row_group = wave_idx / 2; + const int wave_col_group = wave_idx % 2; + const int lane16 = lane_idx % 16; + const int lane_q_block = lane_idx / 16; + const int global_row_base = bidy * KernelConfig::kTileM; + const int global_col_base = bidx * KernelConfig::kTileN; + + const int8_t *a_ptr = A + static_cast(bidz) * M * K; + const int8_t *b_ptr = B + static_cast(bidz) * N * K; + + AccumTypeI8Mma accum[KernelConfig::kColumnGroupsPerWave] + [KernelConfig::kColBlocksPerWaveGroup] + [KernelConfig::kRowBlocksPerWave][2]; + ThreadContext ctx; + clear_accumulators(accum); + build_thread_context(ctx, tid, wave_row_group, wave_col_group, lane16, lane_q_block, K); + + for (int k_tile = 0; k_tile < K; k_tile += KernelConfig::kTileK) { + load_a_pass<0>(smem_a, a_ptr, K, global_row_base, k_tile, ctx); + load_a_pass<1>(smem_a, a_ptr, K, global_row_base, k_tile, ctx); + load_a_pass<2>(smem_a, a_ptr, K, global_row_base, k_tile, ctx); + load_a_pass<3>(smem_a, a_ptr, K, global_row_base, k_tile, ctx); + + load_b_pass<0>(smem_b, b_ptr, K, global_col_base, k_tile, ctx); + load_b_pass<1>(smem_b, b_ptr, K, global_col_base, k_tile, ctx); + load_b_pass<2>(smem_b, b_ptr, K, global_col_base, k_tile, ctx); + load_b_pass<3>(smem_b, b_ptr, K, global_col_base, k_tile, ctx); + + wait_for_tile_load(); + consume_full_k128_from_shared(accum, smem_a, smem_b, ctx); + __syncthreadshared(); + } + + store_accumulators_to_global(D, M, N, bidx, bidy, bidz, accum); +} + +} // namespace standalone_i8_tn_256x256x128_raw_arrays diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/i8_tn_256x256x128_raw_arrays/include/standalone_maca_kernel_utils.hpp b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/i8_tn_256x256x128_raw_arrays/include/standalone_maca_kernel_utils.hpp new file mode 100644 index 0000000..87be72e --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/i8_tn_256x256x128_raw_arrays/include/standalone_maca_kernel_utils.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include + +#define standalone_arrive_gvmcnt(count) __builtin_mxc_arrive(64 + count) + +#if defined(__MACA_ARCH__) && (__MACA_ARCH__ == 1000 || __MACA_ARCH__ == 1089) +#define STANDALONE_BUILTIN_MMA_16X16X16_I8(a, b, c) __builtin_mxc_mma_16x16x16i8(a, b, c) +#else +#define STANDALONE_BUILTIN_MMA_16X16X16_I8(a, b, c) 0 +#endif + +#define standalone_cp_async_fenc() asm(";--------------") + +#define STANDALONE_LDS(dst, src, ldstype) \ + standalone_cp_async_fenc(); \ + *reinterpret_cast(&(dst)) = *reinterpret_cast(&(src)); \ + standalone_cp_async_fenc() diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/i8_tn_256x256x128_raw_arrays/src/test.cpp b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/i8_tn_256x256x128_raw_arrays/src/test.cpp new file mode 100644 index 0000000..fe67aa0 --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/standalone/i8_tn_256x256x128_raw_arrays/src/test.cpp @@ -0,0 +1,229 @@ +#include + +#include +#include +#include +#include +#include + +#include "../include/gemm_i8_tn_256x256x128_raw_arrays.hpp" + +namespace { + +using namespace standalone_i8_tn_256x256x128_raw_arrays; + +struct BenchmarkResult { + float avg_ms = 0.0f; + double tflops = 0.0; + int warmup_iterations = 0; + int measured_iterations = 0; +}; + +void check_mc(mcError_t status, const char *expr) { + if (status != mcSuccess) { + std::cerr << expr << " failed: " << mcGetErrorString(status) << '\n'; + std::exit(EXIT_FAILURE); + } +} + +void fill_row_major_a(std::vector &a, int m, int k) { + a.resize(static_cast(m) * k); + for (int row = 0; row < m; ++row) { + for (int kk = 0; kk < k; ++kk) { + a[static_cast(row) * k + kk] = + static_cast(((row * 13 + kk * 7 + 5) % 9) - 4); + } + } +} + +void fill_col_major_b(std::vector &b, int n, int k) { + b.resize(static_cast(n) * k); + for (int col = 0; col < n; ++col) { + for (int kk = 0; kk < k; ++kk) { + b[static_cast(col) * k + kk] = + static_cast(((kk * 11 + col * 5 + 3) % 7) - 3); + } + } +} + +std::vector reference_gemm_tn(const std::vector &a, + const std::vector &b_col_major, + int m, + int n, + int k) { + std::vector out(static_cast(m) * n, 0); + for (int row = 0; row < m; ++row) { + for (int col = 0; col < n; ++col) { + int32_t acc = 0; + for (int kk = 0; kk < k; ++kk) { + acc += static_cast(a[static_cast(row) * k + kk]) * + static_cast(b_col_major[static_cast(col) * k + kk]); + } + out[static_cast(row) * n + col] = acc; + } + } + return out; +} + +bool run_case(int m, int n, int k, const char *tag) { + std::vector host_a; + std::vector host_b; + std::vector host_d(static_cast(m) * n, -1); + fill_row_major_a(host_a, m, k); + fill_col_major_b(host_b, n, k); + const std::vector reference = reference_gemm_tn(host_a, host_b, m, n, k); + + int8_t *dev_a = nullptr; + int8_t *dev_b = nullptr; + int32_t *dev_d = nullptr; + check_mc(mcMalloc(reinterpret_cast(&dev_a), host_a.size() * sizeof(int8_t)), "mcMalloc(dev_a)"); + check_mc(mcMalloc(reinterpret_cast(&dev_b), host_b.size() * sizeof(int8_t)), "mcMalloc(dev_b)"); + check_mc(mcMalloc(reinterpret_cast(&dev_d), host_d.size() * sizeof(int32_t)), "mcMalloc(dev_d)"); + + check_mc(mcMemcpy(dev_a, host_a.data(), host_a.size() * sizeof(int8_t), mcMemcpyHostToDevice), "mcMemcpy(dev_a)"); + check_mc(mcMemcpy(dev_b, host_b.data(), host_b.size() * sizeof(int8_t), mcMemcpyHostToDevice), "mcMemcpy(dev_b)"); + check_mc(mcMemset(dev_d, 0, host_d.size() * sizeof(int32_t)), "mcMemset(dev_d)"); + + dim3 grid((m + KernelConfig::kTileM - 1) / KernelConfig::kTileM, + (n + KernelConfig::kTileN - 1) / KernelConfig::kTileN, + 1); + gemm_i8_tn_256x256x128_raw_arrays_kernel<<>>(dev_a, dev_b, dev_d, m, n, k); + check_mc(mcDeviceSynchronize(), "mcDeviceSynchronize"); + check_mc(mcGetLastError(), "mcGetLastError"); + + check_mc(mcMemcpy(host_d.data(), dev_d, host_d.size() * sizeof(int32_t), mcMemcpyDeviceToHost), "mcMemcpy(host_d)"); + + check_mc(mcFree(dev_a), "mcFree(dev_a)"); + check_mc(mcFree(dev_b), "mcFree(dev_b)"); + check_mc(mcFree(dev_d), "mcFree(dev_d)"); + + size_t mismatch_count = 0; + size_t first_bad = 0; + for (size_t i = 0; i < host_d.size(); ++i) { + if (host_d[i] != reference[i]) { + if (mismatch_count == 0) { + first_bad = i; + } + ++mismatch_count; + } + } + + if (mismatch_count != 0) { + const int row = static_cast(first_bad / n); + const int col = static_cast(first_bad % n); + std::cerr << tag << " validation failed. mismatches=" << mismatch_count + << ", first mismatch at (" << row << ", " << col << ")" + << ", got=" << host_d[first_bad] + << ", expected=" << reference[first_bad] << '\n'; + return false; + } + + std::cout << tag << " passed: M=" << m + << ", N=" << n + << ", K=" << k + << ", sample D[0]=" << host_d[0] + << ", D[last]=" << host_d.back() << '\n'; + return true; +} + +double compute_tflops(int m, int n, int k, float avg_ms) { + if (avg_ms <= 0.0f) { + return 0.0; + } + const double operations = 2.0 * static_cast(m) * n * k; + return operations / (static_cast(avg_ms) * 1.0e9); +} + +BenchmarkResult run_benchmark(int m, int n, int k, int warmup_iterations, int measured_iterations) { + std::vector host_a; + std::vector host_b; + std::vector host_d(static_cast(m) * n, 0); + fill_row_major_a(host_a, m, k); + fill_col_major_b(host_b, n, k); + + int8_t *dev_a = nullptr; + int8_t *dev_b = nullptr; + int32_t *dev_d = nullptr; + check_mc(mcMalloc(reinterpret_cast(&dev_a), host_a.size() * sizeof(int8_t)), "mcMalloc(dev_a)"); + check_mc(mcMalloc(reinterpret_cast(&dev_b), host_b.size() * sizeof(int8_t)), "mcMalloc(dev_b)"); + check_mc(mcMalloc(reinterpret_cast(&dev_d), host_d.size() * sizeof(int32_t)), "mcMalloc(dev_d)"); + + check_mc(mcMemcpy(dev_a, host_a.data(), host_a.size() * sizeof(int8_t), mcMemcpyHostToDevice), "mcMemcpy(dev_a)"); + check_mc(mcMemcpy(dev_b, host_b.data(), host_b.size() * sizeof(int8_t), mcMemcpyHostToDevice), "mcMemcpy(dev_b)"); + check_mc(mcMemset(dev_d, 0, host_d.size() * sizeof(int32_t)), "mcMemset(dev_d)"); + + dim3 grid((m + KernelConfig::kTileM - 1) / KernelConfig::kTileM, + (n + KernelConfig::kTileN - 1) / KernelConfig::kTileN, + 1); + + for (int iter = 0; iter < warmup_iterations; ++iter) { + gemm_i8_tn_256x256x128_raw_arrays_kernel<<>>(dev_a, dev_b, dev_d, m, n, k); + } + check_mc(mcDeviceSynchronize(), "mcDeviceSynchronize(warmup)"); + + mcEvent_t start; + mcEvent_t stop; + check_mc(mcEventCreate(&start), "mcEventCreate(start)"); + check_mc(mcEventCreate(&stop), "mcEventCreate(stop)"); + check_mc(mcEventRecord(start), "mcEventRecord(start)"); + for (int iter = 0; iter < measured_iterations; ++iter) { + gemm_i8_tn_256x256x128_raw_arrays_kernel<<>>(dev_a, dev_b, dev_d, m, n, k); + } + check_mc(mcEventRecord(stop), "mcEventRecord(stop)"); + check_mc(mcEventSynchronize(stop), "mcEventSynchronize(stop)"); + check_mc(mcGetLastError(), "mcGetLastError"); + + float elapsed_ms = 0.0f; + check_mc(mcEventElapsedTime(&elapsed_ms, start, stop), "mcEventElapsedTime"); + check_mc(mcEventDestroy(start), "mcEventDestroy(start)"); + check_mc(mcEventDestroy(stop), "mcEventDestroy(stop)"); + + check_mc(mcFree(dev_a), "mcFree(dev_a)"); + check_mc(mcFree(dev_b), "mcFree(dev_b)"); + check_mc(mcFree(dev_d), "mcFree(dev_d)"); + + BenchmarkResult result; + result.warmup_iterations = warmup_iterations; + result.measured_iterations = measured_iterations; + result.avg_ms = elapsed_ms / static_cast(measured_iterations); + result.tflops = compute_tflops(m, n, k, result.avg_ms); + return result; +} + +} // namespace + +int main() { + constexpr int kExactM = 2048; + constexpr int kExactN = 2048; + constexpr int kExactK = 2048; + constexpr int kBenchM = 2048; + constexpr int kBenchN = 2048; + constexpr int kBenchK = 2048; + constexpr int kWarmupIterations = 3; + constexpr int kMeasuredIterations = 10; + + int device_count = 0; + check_mc(mcGetDeviceCount(&device_count), "mcGetDeviceCount"); + if (device_count <= 0) { + std::cerr << "No MACA device is visible.\n"; + return EXIT_FAILURE; + } + check_mc(mcSetDevice(0), "mcSetDevice"); + + if (!run_case(kExactM, kExactN, kExactK, "standalone_i8_tn_256x256x128_raw_arrays_exact")) { + return EXIT_FAILURE; + } + + const BenchmarkResult benchmark = + run_benchmark(kBenchM, kBenchN, kBenchK, kWarmupIterations, kMeasuredIterations); + std::cout << std::fixed << std::setprecision(3) + << "standalone_i8_tn_256x256x128_raw_arrays benchmark: M=" << kBenchM + << ", N=" << kBenchN + << ", K=" << kBenchK + << ", avg_ms=" << benchmark.avg_ms + << ", TFLOPS=" << benchmark.tflops + << ", warmup=" << benchmark.warmup_iterations + << ", iters=" << benchmark.measured_iterations << '\n'; + + return EXIT_SUCCESS; +} diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/attr.h b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/attr.h new file mode 100644 index 0000000..d337595 --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/attr.h @@ -0,0 +1,730 @@ +/* + pybind11/attr.h: Infrastructure for processing custom + type and function attributes + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "detail/common.h" +#include "cast.h" +#include "trampoline_self_life_support.h" + +#include + +PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + +/// \addtogroup annotations +/// @{ + +/// Annotation for methods +struct is_method { + handle class_; + explicit is_method(const handle &c) : class_(c) {} +}; + +/// Annotation for setters +struct is_setter {}; + +/// Annotation for operators +struct is_operator {}; + +/// Annotation for classes that cannot be subclassed +struct is_final {}; + +/// Annotation for parent scope +struct scope { + handle value; + explicit scope(const handle &s) : value(s) {} +}; + +/// Annotation for documentation +struct doc { + const char *value; + explicit doc(const char *value) : value(value) {} +}; + +/// Annotation for function names +struct name { + const char *value; + explicit name(const char *value) : value(value) {} +}; + +/// Annotation indicating that a function is an overload associated with a given "sibling" +struct sibling { + handle value; + explicit sibling(const handle &value) : value(value.ptr()) {} +}; + +/// Annotation indicating that a class derives from another given type +template +struct base { + + PYBIND11_DEPRECATED( + "base() was deprecated in favor of specifying 'T' as a template argument to class_") + base() = default; +}; + +/// Keep patient alive while nurse lives +template +struct keep_alive {}; + +/// Annotation indicating that a class is involved in a multiple inheritance relationship +struct multiple_inheritance {}; + +/// Annotation which enables dynamic attributes, i.e. adds `__dict__` to a class +struct dynamic_attr {}; + +/// Annotation which enables the buffer protocol for a type +struct buffer_protocol {}; + +/// Annotation which enables releasing the GIL before calling the C++ destructor of wrapped +/// instances (pybind/pybind11#1446). +struct release_gil_before_calling_cpp_dtor {}; + +/// Annotation which requests that a special metaclass is created for a type +struct metaclass { + handle value; + + PYBIND11_DEPRECATED("py::metaclass() is no longer required. It's turned on by default now.") + metaclass() = default; + + /// Override pybind11's default metaclass + explicit metaclass(handle value) : value(value) {} +}; + +/// Specifies a custom callback with signature `void (PyHeapTypeObject*)` that +/// may be used to customize the Python type. +/// +/// The callback is invoked immediately before `PyType_Ready`. +/// +/// Note: This is an advanced interface, and uses of it may require changes to +/// work with later versions of pybind11. You may wish to consult the +/// implementation of `make_new_python_type` in `detail/classes.h` to understand +/// the context in which the callback will be run. +struct custom_type_setup { + using callback = std::function; + + explicit custom_type_setup(callback value) : value(std::move(value)) {} + + callback value; +}; + +/// Annotation that marks a class as local to the module: +struct module_local { + const bool value; + constexpr explicit module_local(bool v = true) : value(v) {} +}; + +/// Annotation to mark enums as an arithmetic type +struct arithmetic {}; + +/// Mark a function for addition at the beginning of the existing overload chain instead of the end +struct prepend {}; + +/** \rst + A call policy which places one or more guard variables (``Ts...``) around the function call. + + For example, this definition: + + .. code-block:: cpp + + m.def("foo", foo, py::call_guard()); + + is equivalent to the following pseudocode: + + .. code-block:: cpp + + m.def("foo", [](args...) { + T scope_guard; + return foo(args...); // forwarded arguments + }); + \endrst */ +template +struct call_guard; + +template <> +struct call_guard<> { + using type = detail::void_type; +}; + +template +struct call_guard { + static_assert(std::is_default_constructible::value, + "The guard type must be default constructible"); + + using type = T; +}; + +template +struct call_guard { + struct type { + T guard{}; // Compose multiple guard types with left-to-right default-constructor order + typename call_guard::type next{}; + }; +}; + +/// @} annotations + +PYBIND11_NAMESPACE_BEGIN(detail) +/* Forward declarations */ +enum op_id : int; +enum op_type : int; +struct undefined_t; +template +struct op_; +void keep_alive_impl(size_t Nurse, size_t Patient, function_call &call, handle ret); + +/// Internal data structure which holds metadata about a keyword argument +struct argument_record { + const char *name; ///< Argument name + const char *descr; ///< Human-readable version of the argument value + handle value; ///< Associated Python object + bool convert : 1; ///< True if the argument is allowed to convert when loading + bool none : 1; ///< True if None is allowed when loading + + argument_record(const char *name, const char *descr, handle value, bool convert, bool none) + : name(name), descr(descr), value(value), convert(convert), none(none) {} +}; + +/// Internal data structure which holds metadata about a bound function (signature, overloads, +/// etc.) +#define PYBIND11_DETAIL_FUNCTION_RECORD_ABI_ID "v1" // PLEASE UPDATE if the struct is changed. +struct function_record { + function_record() + : is_constructor(false), is_new_style_constructor(false), is_stateless(false), + is_operator(false), is_method(false), is_setter(false), has_args(false), + has_kwargs(false), prepend(false) {} + + /// Function name + char *name = nullptr; /* why no C++ strings? They generate heavier code.. */ + + // User-specified documentation string + char *doc = nullptr; + + /// Human-readable version of the function signature + char *signature = nullptr; + + /// List of registered keyword arguments + std::vector args; + + /// Pointer to lambda function which converts arguments and performs the actual call + handle (*impl)(function_call &) = nullptr; + + /// Storage for the wrapped function pointer and captured data, if any + void *data[3] = {}; + + /// Pointer to custom destructor for 'data' (if needed) + void (*free_data)(function_record *ptr) = nullptr; + + /// Return value policy associated with this function + return_value_policy policy = return_value_policy::automatic; + + /// True if name == '__init__' + bool is_constructor : 1; + + /// True if this is a new-style `__init__` defined in `detail/init.h` + bool is_new_style_constructor : 1; + + /// True if this is a stateless function pointer + bool is_stateless : 1; + + /// True if this is an operator (__add__), etc. + bool is_operator : 1; + + /// True if this is a method + bool is_method : 1; + + /// True if this is a setter + bool is_setter : 1; + + /// True if the function has a '*args' argument + bool has_args : 1; + + /// True if the function has a '**kwargs' argument + bool has_kwargs : 1; + + /// True if this function is to be inserted at the beginning of the overload resolution chain + bool prepend : 1; + + /// Number of arguments (including py::args and/or py::kwargs, if present) + std::uint16_t nargs; + + /// Number of leading positional arguments, which are terminated by a py::args or py::kwargs + /// argument or by a py::kw_only annotation. + std::uint16_t nargs_pos = 0; + + /// Number of leading arguments (counted in `nargs`) that are positional-only + std::uint16_t nargs_pos_only = 0; + + /// Python method object + PyMethodDef *def = nullptr; + + /// Python handle to the parent scope (a class or a module) + handle scope; + + /// Python handle to the sibling function representing an overload chain + handle sibling; + + /// Pointer to next overload + function_record *next = nullptr; +}; +// The main purpose of this macro is to make it easy to pin-point the critically related code +// sections. +#define PYBIND11_ENSURE_PRECONDITION_FOR_FUNCTIONAL_H_PERFORMANCE_OPTIMIZATIONS(...) \ + static_assert( \ + __VA_ARGS__, \ + "Violation of precondition for pybind11/functional.h performance optimizations!") + +/// Special data structure which (temporarily) holds metadata about a bound class +struct type_record { + PYBIND11_NOINLINE type_record() + : multiple_inheritance(false), dynamic_attr(false), buffer_protocol(false), + module_local(false), is_final(false), release_gil_before_calling_cpp_dtor(false) {} + + /// Handle to the parent scope + handle scope; + + /// Name of the class + const char *name = nullptr; + + // Pointer to RTTI type_info data structure + const std::type_info *type = nullptr; + + /// How large is the underlying C++ type? + size_t type_size = 0; + + /// What is the alignment of the underlying C++ type? + size_t type_align = 0; + + /// How large is the type's holder? + size_t holder_size = 0; + + /// The global operator new can be overridden with a class-specific variant + void *(*operator_new)(size_t) = nullptr; + + /// Function pointer to class_<..>::init_instance + void (*init_instance)(instance *, const void *) = nullptr; + + /// Function pointer to class_<..>::dealloc + void (*dealloc)(detail::value_and_holder &) = nullptr; + + /// Function pointer for casting alias class (aka trampoline) pointer to + /// trampoline_self_life_support pointer. Sidesteps cross-DSO RTTI issues + /// on platforms like macOS (see PR #5728 for details). + get_trampoline_self_life_support_fn get_trampoline_self_life_support + = [](void *) -> trampoline_self_life_support * { return nullptr; }; + + /// List of base classes of the newly created type + list bases; + + /// Optional docstring + const char *doc = nullptr; + + /// Custom metaclass (optional) + handle metaclass; + + /// Custom type setup. + custom_type_setup::callback custom_type_setup_callback; + + /// Multiple inheritance marker + bool multiple_inheritance : 1; + + /// Does the class manage a __dict__? + bool dynamic_attr : 1; + + /// Does the class implement the buffer protocol? + bool buffer_protocol : 1; + + /// Is the class definition local to the module shared object? + bool module_local : 1; + + /// Is the class inheritable from python classes? + bool is_final : 1; + + /// Solves pybind/pybind11#1446 + bool release_gil_before_calling_cpp_dtor : 1; + + holder_enum_t holder_enum_v = holder_enum_t::undefined; + + PYBIND11_NOINLINE void add_base(const std::type_info &base, void *(*caster)(void *) ) { + auto *base_info = detail::get_type_info(base, false); + if (!base_info) { + std::string tname(base.name()); + detail::clean_type_id(tname); + pybind11_fail("generic_type: type \"" + std::string(name) + + "\" referenced unknown base type \"" + tname + "\""); + } + + // SMART_HOLDER_BAKEIN_FOLLOW_ON: Refine holder compatibility checks. + bool this_has_unique_ptr_holder = (holder_enum_v == holder_enum_t::std_unique_ptr); + bool base_has_unique_ptr_holder + = (base_info->holder_enum_v == holder_enum_t::std_unique_ptr); + if (this_has_unique_ptr_holder != base_has_unique_ptr_holder) { + std::string tname(base.name()); + detail::clean_type_id(tname); + pybind11_fail("generic_type: type \"" + std::string(name) + "\" " + + (this_has_unique_ptr_holder ? "does not have" : "has") + + " a non-default holder type while its base \"" + tname + "\" " + + (base_has_unique_ptr_holder ? "does not" : "does")); + } + + bases.append(reinterpret_cast(base_info->type)); + +#ifdef PYBIND11_BACKWARD_COMPATIBILITY_TP_DICTOFFSET + dynamic_attr |= base_info->type->tp_dictoffset != 0; +#else + dynamic_attr |= (PyType_GetFlags(base_info->type) & Py_TPFLAGS_MANAGED_DICT) != 0; +#endif + + if (caster) { + base_info->implicit_casts.emplace_back(type, caster); + } + } +}; + +inline function_call::function_call(const function_record &f, handle p) : func(f), parent(p) { + args.reserve(f.nargs); + args_convert.reserve(f.nargs); +} + +/// Tag for a new-style `__init__` defined in `detail/init.h` +struct is_new_style_constructor {}; + +/** + * Partial template specializations to process custom attributes provided to + * cpp_function_ and class_. These are either used to initialize the respective + * fields in the type_record and function_record data structures or executed at + * runtime to deal with custom call policies (e.g. keep_alive). + */ +template +struct process_attribute; + +template +struct process_attribute_default { + /// Default implementation: do nothing + static void init(const T &, function_record *) {} + static void init(const T &, type_record *) {} + static void precall(function_call &) {} + static void postcall(function_call &, handle) {} +}; + +/// Process an attribute specifying the function's name +template <> +struct process_attribute : process_attribute_default { + static void init(const name &n, function_record *r) { r->name = const_cast(n.value); } +}; + +/// Process an attribute specifying the function's docstring +template <> +struct process_attribute : process_attribute_default { + static void init(const doc &n, function_record *r) { r->doc = const_cast(n.value); } +}; + +/// Process an attribute specifying the function's docstring (provided as a C-style string) +template <> +struct process_attribute : process_attribute_default { + static void init(const char *d, function_record *r) { r->doc = const_cast(d); } + static void init(const char *d, type_record *r) { r->doc = d; } +}; +template <> +struct process_attribute : process_attribute {}; + +/// Process an attribute indicating the function's return value policy +template <> +struct process_attribute : process_attribute_default { + static void init(const return_value_policy &p, function_record *r) { r->policy = p; } +}; + +/// Process an attribute which indicates that this is an overloaded function associated with a +/// given sibling +template <> +struct process_attribute : process_attribute_default { + static void init(const sibling &s, function_record *r) { r->sibling = s.value; } +}; + +/// Process an attribute which indicates that this function is a method +template <> +struct process_attribute : process_attribute_default { + static void init(const is_method &s, function_record *r) { + r->is_method = true; + r->scope = s.class_; + } +}; + +/// Process an attribute which indicates that this function is a setter +template <> +struct process_attribute : process_attribute_default { + static void init(const is_setter &, function_record *r) { r->is_setter = true; } +}; + +/// Process an attribute which indicates the parent scope of a method +template <> +struct process_attribute : process_attribute_default { + static void init(const scope &s, function_record *r) { r->scope = s.value; } +}; + +/// Process an attribute which indicates that this function is an operator +template <> +struct process_attribute : process_attribute_default { + static void init(const is_operator &, function_record *r) { r->is_operator = true; } +}; + +template <> +struct process_attribute + : process_attribute_default { + static void init(const is_new_style_constructor &, function_record *r) { + r->is_new_style_constructor = true; + } +}; + +inline void check_kw_only_arg(const arg &a, function_record *r) { + if (r->args.size() > r->nargs_pos && (!a.name || a.name[0] == '\0')) { + pybind11_fail("arg(): cannot specify an unnamed argument after a kw_only() annotation or " + "args() argument"); + } +} + +inline void append_self_arg_if_needed(function_record *r) { + if (r->is_method && r->args.empty()) { + r->args.emplace_back("self", nullptr, handle(), /*convert=*/true, /*none=*/false); + } +} + +/// Process a keyword argument attribute (*without* a default value) +template <> +struct process_attribute : process_attribute_default { + static void init(const arg &a, function_record *r) { + append_self_arg_if_needed(r); + r->args.emplace_back(a.name, nullptr, handle(), !a.flag_noconvert, a.flag_none); + + check_kw_only_arg(a, r); + } +}; + +/// Process a keyword argument attribute (*with* a default value) +template <> +struct process_attribute : process_attribute_default { + static void init(const arg_v &a, function_record *r) { + if (r->is_method && r->args.empty()) { + r->args.emplace_back( + "self", /*descr=*/nullptr, /*parent=*/handle(), /*convert=*/true, /*none=*/false); + } + + if (!a.value) { +#if defined(PYBIND11_DETAILED_ERROR_MESSAGES) + std::string descr("'"); + if (a.name) { + descr += std::string(a.name) + ": "; + } + descr += a.type + "'"; + if (r->is_method) { + if (r->name) { + descr += " in method '" + (std::string) str(r->scope) + "." + + (std::string) r->name + "'"; + } else { + descr += " in method of '" + (std::string) str(r->scope) + "'"; + } + } else if (r->name) { + descr += " in function '" + (std::string) r->name + "'"; + } + pybind11_fail("arg(): could not convert default argument " + descr + + " into a Python object (type not registered yet?)"); +#else + pybind11_fail("arg(): could not convert default argument " + "into a Python object (type not registered yet?). " + "#define PYBIND11_DETAILED_ERROR_MESSAGES or compile in debug mode for " + "more information."); +#endif + } + r->args.emplace_back(a.name, a.descr, a.value.inc_ref(), !a.flag_noconvert, a.flag_none); + + check_kw_only_arg(a, r); + } +}; + +/// Process a keyword-only-arguments-follow pseudo argument +template <> +struct process_attribute : process_attribute_default { + static void init(const kw_only &, function_record *r) { + append_self_arg_if_needed(r); + if (r->has_args && r->nargs_pos != static_cast(r->args.size())) { + pybind11_fail("Mismatched args() and kw_only(): they must occur at the same relative " + "argument location (or omit kw_only() entirely)"); + } + r->nargs_pos = static_cast(r->args.size()); + } +}; + +/// Process a positional-only-argument maker +template <> +struct process_attribute : process_attribute_default { + static void init(const pos_only &, function_record *r) { + append_self_arg_if_needed(r); + r->nargs_pos_only = static_cast(r->args.size()); + if (r->nargs_pos_only > r->nargs_pos) { + pybind11_fail("pos_only(): cannot follow a py::args() argument"); + } + // It also can't follow a kw_only, but a static_assert in pybind11.h checks that + } +}; + +/// Process a parent class attribute. Single inheritance only (class_ itself already guarantees +/// that) +template +struct process_attribute::value>> + : process_attribute_default { + static void init(const handle &h, type_record *r) { r->bases.append(h); } +}; + +/// Process a parent class attribute (deprecated, does not support multiple inheritance) +template +struct process_attribute> : process_attribute_default> { + static void init(const base &, type_record *r) { r->add_base(typeid(T), nullptr); } +}; + +/// Process a multiple inheritance attribute +template <> +struct process_attribute : process_attribute_default { + static void init(const multiple_inheritance &, type_record *r) { + r->multiple_inheritance = true; + } +}; + +template <> +struct process_attribute : process_attribute_default { + static void init(const dynamic_attr &, type_record *r) { r->dynamic_attr = true; } +}; + +template <> +struct process_attribute { + static void init(const custom_type_setup &value, type_record *r) { + r->custom_type_setup_callback = value.value; + } +}; + +template <> +struct process_attribute : process_attribute_default { + static void init(const is_final &, type_record *r) { r->is_final = true; } +}; + +template <> +struct process_attribute : process_attribute_default { + static void init(const buffer_protocol &, type_record *r) { r->buffer_protocol = true; } +}; + +template <> +struct process_attribute : process_attribute_default { + static void init(const metaclass &m, type_record *r) { r->metaclass = m.value; } +}; + +template <> +struct process_attribute : process_attribute_default { + static void init(const module_local &l, type_record *r) { r->module_local = l.value; } +}; + +template <> +struct process_attribute + : process_attribute_default { + static void init(const release_gil_before_calling_cpp_dtor &, type_record *r) { + r->release_gil_before_calling_cpp_dtor = true; + } +}; + +/// Process a 'prepend' attribute, putting this at the beginning of the overload chain +template <> +struct process_attribute : process_attribute_default { + static void init(const prepend &, function_record *r) { r->prepend = true; } +}; + +/// Process an 'arithmetic' attribute for enums (does nothing here) +template <> +struct process_attribute : process_attribute_default {}; + +template +struct process_attribute> : process_attribute_default> {}; + +/** + * Process a keep_alive call policy -- invokes keep_alive_impl during the + * pre-call handler if both Nurse, Patient != 0 and use the post-call handler + * otherwise + */ +template +struct process_attribute> + : public process_attribute_default> { + template = 0> + static void precall(function_call &call) { + keep_alive_impl(Nurse, Patient, call, handle()); + } + template = 0> + static void postcall(function_call &, handle) {} + template = 0> + static void precall(function_call &) {} + template = 0> + static void postcall(function_call &call, handle ret) { + keep_alive_impl(Nurse, Patient, call, ret); + } +}; + +/// Recursively iterate over variadic template arguments +template +struct process_attributes { + static void init(const Args &...args, function_record *r) { + PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(r); + PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(r); + using expander = int[]; + (void) expander{ + 0, ((void) process_attribute::type>::init(args, r), 0)...}; + } + static void init(const Args &...args, type_record *r) { + PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(r); + PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(r); + using expander = int[]; + (void) expander{0, + (process_attribute::type>::init(args, r), 0)...}; + } + static void precall(function_call &call) { + PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(call); + using expander = int[]; + (void) expander{0, + (process_attribute::type>::precall(call), 0)...}; + } + static void postcall(function_call &call, handle fn_ret) { + PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(call, fn_ret); + PYBIND11_WORKAROUND_INCORRECT_GCC_UNUSED_BUT_SET_PARAMETER(fn_ret); + using expander = int[]; + (void) expander{ + 0, (process_attribute::type>::postcall(call, fn_ret), 0)...}; + } +}; + +template +struct is_keep_alive : std::false_type {}; + +template +struct is_keep_alive> : std::true_type {}; + +template +using is_call_guard = is_instantiation; + +/// Extract the ``type`` from the first `call_guard` in `Extras...` (or `void_type` if none found) +template +using extract_guard_t = typename exactly_one_t, Extra...>::type; + +/// Check the number of named arguments at compile time +template ::value...), + size_t self = constexpr_sum(std::is_same::value...)> +constexpr bool expected_num_args(size_t nargs, bool has_args, bool has_kwargs) { + PYBIND11_WORKAROUND_INCORRECT_MSVC_C4100(nargs, has_args, has_kwargs); + return named == 0 + || (self + named + static_cast(has_args) + static_cast(has_kwargs)) + == nargs; +} + +PYBIND11_NAMESPACE_END(detail) +PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/buffer_info.h b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/buffer_info.h new file mode 100644 index 0000000..10fa825 --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/buffer_info.h @@ -0,0 +1,209 @@ +/* + pybind11/buffer_info.h: Python buffer object interface + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "detail/common.h" + +PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + +PYBIND11_NAMESPACE_BEGIN(detail) + +// Default, C-style strides +inline std::vector c_strides(const std::vector &shape, ssize_t itemsize) { + auto ndim = shape.size(); + std::vector strides(ndim, itemsize); + if (ndim > 0) { + for (size_t i = ndim - 1; i > 0; --i) { + strides[i - 1] = strides[i] * shape[i]; + } + } + return strides; +} + +// F-style strides; default when constructing an array_t with `ExtraFlags & f_style` +inline std::vector f_strides(const std::vector &shape, ssize_t itemsize) { + auto ndim = shape.size(); + std::vector strides(ndim, itemsize); + for (size_t i = 1; i < ndim; ++i) { + strides[i] = strides[i - 1] * shape[i - 1]; + } + return strides; +} + +template +struct compare_buffer_info; + +PYBIND11_NAMESPACE_END(detail) + +/// Information record describing a Python buffer object +struct buffer_info { + void *ptr = nullptr; // Pointer to the underlying storage + ssize_t itemsize = 0; // Size of individual items in bytes + ssize_t size = 0; // Total number of entries + std::string format; // For homogeneous buffers, this should be set to + // format_descriptor::format() + ssize_t ndim = 0; // Number of dimensions + std::vector shape; // Shape of the tensor (1 entry per dimension) + std::vector strides; // Number of bytes between adjacent entries + // (for each per dimension) + bool readonly = false; // flag to indicate if the underlying storage may be written to + + buffer_info() = default; + + buffer_info(void *ptr, + ssize_t itemsize, + const std::string &format, + ssize_t ndim, + detail::any_container shape_in, + detail::any_container strides_in, + bool readonly = false) + : ptr(ptr), itemsize(itemsize), size(1), format(format), ndim(ndim), + shape(std::move(shape_in)), strides(std::move(strides_in)), readonly(readonly) { + if (ndim != static_cast(shape.size()) + || ndim != static_cast(strides.size())) { + pybind11_fail("buffer_info: ndim doesn't match shape and/or strides length"); + } + for (size_t i = 0; i < static_cast(ndim); ++i) { + size *= shape[i]; + } + } + + template + buffer_info(T *ptr, + detail::any_container shape_in, + detail::any_container strides_in, + bool readonly = false) + : buffer_info(private_ctr_tag(), + ptr, + sizeof(T), + format_descriptor::format(), + static_cast(shape_in->size()), + std::move(shape_in), + std::move(strides_in), + readonly) {} + + buffer_info(void *ptr, + ssize_t itemsize, + const std::string &format, + ssize_t size, + bool readonly = false) + : buffer_info(ptr, itemsize, format, 1, {size}, {itemsize}, readonly) {} + + template + buffer_info(T *ptr, ssize_t size, bool readonly = false) + : buffer_info(ptr, sizeof(T), format_descriptor::format(), size, readonly) {} + + template + buffer_info(const T *ptr, ssize_t size, bool readonly = true) + : buffer_info( + const_cast(ptr), sizeof(T), format_descriptor::format(), size, readonly) {} + + explicit buffer_info(Py_buffer *view, bool ownview = true) + : buffer_info( + view->buf, + view->itemsize, + view->format, + view->ndim, + {view->shape, view->shape + view->ndim}, + /* Though buffer::request() requests PyBUF_STRIDES, ctypes objects + * ignore this flag and return a view with NULL strides. + * When strides are NULL, build them manually. */ + view->strides + ? std::vector(view->strides, view->strides + view->ndim) + : detail::c_strides({view->shape, view->shape + view->ndim}, view->itemsize), + (view->readonly != 0)) { + // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) + this->m_view = view; + // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) + this->ownview = ownview; + } + + buffer_info(const buffer_info &) = delete; + buffer_info &operator=(const buffer_info &) = delete; + + buffer_info(buffer_info &&other) noexcept { (*this) = std::move(other); } + + buffer_info &operator=(buffer_info &&rhs) noexcept { + ptr = rhs.ptr; + itemsize = rhs.itemsize; + size = rhs.size; + format = std::move(rhs.format); + ndim = rhs.ndim; + shape = std::move(rhs.shape); + strides = std::move(rhs.strides); + std::swap(m_view, rhs.m_view); + std::swap(ownview, rhs.ownview); + readonly = rhs.readonly; + return *this; + } + + ~buffer_info() { + if (m_view && ownview) { + PyBuffer_Release(m_view); + delete m_view; + } + } + + Py_buffer *view() const { return m_view; } + Py_buffer *&view() { return m_view; } + + /* True if the buffer item type is equivalent to `T`. */ + // To define "equivalent" by example: + // `buffer_info::item_type_is_equivalent_to(b)` and + // `buffer_info::item_type_is_equivalent_to(b)` may both be true + // on some platforms, but `int` and `unsigned` will never be equivalent. + // For the ground truth, please inspect `detail::compare_buffer_info<>`. + template + bool item_type_is_equivalent_to() const { + return detail::compare_buffer_info::compare(*this); + } + +private: + struct private_ctr_tag {}; + + buffer_info(private_ctr_tag, + void *ptr, + ssize_t itemsize, + const std::string &format, + ssize_t ndim, + detail::any_container &&shape_in, + detail::any_container &&strides_in, + bool readonly) + : buffer_info( + ptr, itemsize, format, ndim, std::move(shape_in), std::move(strides_in), readonly) {} + + Py_buffer *m_view = nullptr; + bool ownview = false; +}; + +PYBIND11_NAMESPACE_BEGIN(detail) + +template +struct compare_buffer_info { + static bool compare(const buffer_info &b) { + // NOLINTNEXTLINE(bugprone-sizeof-expression) Needed for `PyObject *` + return b.format == format_descriptor::format() && b.itemsize == (ssize_t) sizeof(T); + } +}; + +template +struct compare_buffer_info::value>> { + static bool compare(const buffer_info &b) { + return static_cast(b.itemsize) == sizeof(T) + && (b.format == format_descriptor::value + || ((sizeof(T) == sizeof(long)) + && b.format == (std::is_unsigned::value ? "L" : "l")) + || ((sizeof(T) == sizeof(size_t)) + && b.format == (std::is_unsigned::value ? "N" : "n"))); + } +}; + +PYBIND11_NAMESPACE_END(detail) +PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) diff --git a/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/cast.h b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/cast.h new file mode 100644 index 0000000..b7a4c2b --- /dev/null +++ b/基于AI Agent开发范式的国产GPU大模型推理算子库优化/baselines/fused_moe/third_party/pybind11/include/pybind11/cast.h @@ -0,0 +1,2447 @@ +/* + pybind11/cast.h: Partial template specializations to cast between + C++ and Python types + + Copyright (c) 2016 Wenzel Jakob + + All rights reserved. Use of this source code is governed by a + BSD-style license that can be found in the LICENSE file. +*/ + +#pragma once + +#include "detail/argument_vector.h" +#include "detail/common.h" +#include "detail/descr.h" +#include "detail/holder_caster_foreign_helpers.h" +#include "detail/native_enum_data.h" +#include "detail/type_caster_base.h" +#include "detail/typeid.h" +#include "pytypes.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + +PYBIND11_WARNING_DISABLE_MSVC(4127) + +PYBIND11_NAMESPACE_BEGIN(detail) + +template +class type_caster : public type_caster_base {}; +template +using make_caster = type_caster>; + +// Shortcut for calling a caster's `cast_op_type` cast operator for casting a type_caster to a T +template +typename make_caster::template cast_op_type cast_op(make_caster &caster) { + using result_t = typename make_caster::template cast_op_type; // See PR #4893 + return caster.operator result_t(); +} +template +typename make_caster::template cast_op_type::type> +cast_op(make_caster &&caster) { + using result_t = typename make_caster::template cast_op_type< + typename std::add_rvalue_reference::type>; // See PR #4893 + return std::move(caster).operator result_t(); +} + +template +class type_caster_enum_type { +private: + using Underlying = typename std::underlying_type::type; + +public: + static constexpr auto name = const_name(); + + template + static handle cast(SrcType &&src, return_value_policy, handle parent) { + handle native_enum + = global_internals_native_enum_type_map_get_item(std::type_index(typeid(EnumType))); + if (native_enum) { + return native_enum(static_cast(src)).release(); + } + return type_caster_base::cast( + std::forward(src), + // Fixes https://github.com/pybind/pybind11/pull/3643#issuecomment-1022987818: + return_value_policy::copy, + parent); + } + + template + static handle cast(SrcType *src, return_value_policy policy, handle parent) { + return cast(*src, policy, parent); + } + + bool load(handle src, bool convert) { + handle native_enum + = global_internals_native_enum_type_map_get_item(std::type_index(typeid(EnumType))); + if (native_enum) { + if (!isinstance(src, native_enum)) { + return false; + } + type_caster underlying_caster; + if (!underlying_caster.load(src.attr("value"), convert)) { + pybind11_fail("native_enum internal consistency failure."); + } + native_value = static_cast(static_cast(underlying_caster)); + native_loaded = true; + return true; + } + + type_caster_base legacy_caster; + if (legacy_caster.load(src, convert)) { + legacy_ptr = static_cast(legacy_caster); + return true; + } + return false; + } + + template + using cast_op_type = detail::cast_op_type; + + // NOLINTNEXTLINE(google-explicit-constructor) + operator EnumType *() { return native_loaded ? &native_value : legacy_ptr; } + + // NOLINTNEXTLINE(google-explicit-constructor) + operator EnumType &() { + if (!native_loaded && !legacy_ptr) { + throw reference_cast_error(); + } + return native_loaded ? native_value : *legacy_ptr; + } + +private: + EnumType native_value; // if loading a py::native_enum + bool native_loaded = false; + EnumType *legacy_ptr = nullptr; // if loading a py::enum_ +}; + +template +struct type_caster_enum_type_enabled : std::true_type {}; + +template +struct type_uses_type_caster_enum_type { + static constexpr bool value + = std::is_enum::value && type_caster_enum_type_enabled::value; +}; + +template +class type_caster::value>> + : public type_caster_enum_type {}; + +template ::value, int> = 0> +bool isinstance_native_enum_impl(handle obj, const std::type_info &tp) { + handle native_enum = global_internals_native_enum_type_map_get_item(tp); + if (!native_enum) { + return false; + } + return isinstance(obj, native_enum); +} + +template ::value, int> = 0> +bool isinstance_native_enum_impl(handle, const std::type_info &) { + return false; +} + +template +bool isinstance_native_enum(handle obj, const std::type_info &tp) { + return isinstance_native_enum_impl>(obj, tp); +} + +template +class type_caster> { +private: + using caster_t = make_caster; + caster_t subcaster; + using reference_t = type &; + using subcaster_cast_op_type = typename caster_t::template cast_op_type; + + static_assert( + std::is_same::type &, subcaster_cast_op_type>::value + || std::is_same::value, + "std::reference_wrapper caster requires T to have a caster with an " + "`operator T &()` or `operator const T &()`"); + +public: + bool load(handle src, bool convert) { return subcaster.load(src, convert); } + static constexpr auto name = caster_t::name; + static handle + cast(const std::reference_wrapper &src, return_value_policy policy, handle parent) { + // It is definitely wrong to take ownership of this pointer, so mask that rvp + if (policy == return_value_policy::take_ownership + || policy == return_value_policy::automatic) { + policy = return_value_policy::automatic_reference; + } + return caster_t::cast(&src.get(), policy, parent); + } + template + using cast_op_type = std::reference_wrapper; + explicit operator std::reference_wrapper() { return cast_op(subcaster); } +}; + +#define PYBIND11_TYPE_CASTER(type, py_name) \ +protected: \ + type value; \ + \ +public: \ + static constexpr auto name = py_name; \ + template >::value, \ + int> = 0> \ + static ::pybind11::handle cast( \ + T_ *src, ::pybind11::return_value_policy policy, ::pybind11::handle parent) { \ + if (!src) \ + return ::pybind11::none().release(); \ + if (policy == ::pybind11::return_value_policy::take_ownership) { \ + auto h = cast(std::move(*src), policy, parent); \ + delete src; \ + return h; \ + } \ + return cast(*src, policy, parent); \ + } \ + operator type *() { return &value; } /* NOLINT(bugprone-macro-parentheses) */ \ + operator type &() { return value; } /* NOLINT(bugprone-macro-parentheses) */ \ + operator type &&() && { return std::move(value); } /* NOLINT(bugprone-macro-parentheses) */ \ + template \ + using cast_op_type = ::pybind11::detail::movable_cast_op_type + +template +using is_std_char_type = any_of, /* std::string */ +#if defined(PYBIND11_HAS_U8STRING) + std::is_same, /* std::u8string */ +#endif + std::is_same, /* std::u16string */ + std::is_same, /* std::u32string */ + std::is_same /* std::wstring */ + >; + +template +struct type_caster::value && !is_std_char_type::value>> { + using _py_type_0 = conditional_t; + using _py_type_1 = conditional_t::value, + _py_type_0, + typename std::make_unsigned<_py_type_0>::type>; + using py_type = conditional_t::value, double, _py_type_1>; + +public: + bool load(handle src, bool convert) { + py_type py_value; + + if (!src) { + return false; + } + + if (std::is_floating_point::value) { + if (convert || PyFloat_Check(src.ptr()) || PYBIND11_LONG_CHECK(src.ptr())) { + py_value = (py_type) PyFloat_AsDouble(src.ptr()); + } else { + return false; + } + } else if (PyFloat_Check(src.ptr()) + || !(convert || PYBIND11_LONG_CHECK(src.ptr()) + || PYBIND11_INDEX_CHECK(src.ptr()))) { + // Explicitly reject float → int conversion even in convert mode. + // This prevents silent truncation (e.g., 1.9 → 1). + // Only int → float conversion is allowed (widening, no precision loss). + // Also reject if none of the conversion conditions are met. + return false; + } else { + handle src_or_index = src; + // PyPy: 7.3.7's 3.8 does not implement PyLong_*'s __index__ calls. +#if defined(PYPY_VERSION) + object index; + // If not a PyLong, we need to call PyNumber_Index explicitly on PyPy. + // When convert is false, we only reach here if PYBIND11_INDEX_CHECK passed above. + if (!PYBIND11_LONG_CHECK(src.ptr())) { + index = reinterpret_steal(PyNumber_Index(src.ptr())); + if (!index) { + PyErr_Clear(); + if (!convert) + return false; + } else { + src_or_index = index; + } + } +#endif + if (std::is_unsigned::value) { + py_value = as_unsigned(src_or_index.ptr()); + } else { // signed integer: + py_value = sizeof(T) <= sizeof(long) + ? (py_type) PyLong_AsLong(src_or_index.ptr()) + : (py_type) PYBIND11_LONG_AS_LONGLONG(src_or_index.ptr()); + } + } + + bool py_err = (PyErr_Occurred() != nullptr); + if (py_err) { + assert(py_value == static_cast(-1)); + } + + // Check to see if the conversion is valid (integers should match exactly) + // Signed/unsigned checks happen elsewhere + if (py_err + || (std::is_integral::value && sizeof(py_type) != sizeof(T) + && py_value != (py_type) (T) py_value)) { + PyErr_Clear(); + if (py_err && convert && (PyNumber_Check(src.ptr()) != 0)) { + auto tmp = reinterpret_steal(std::is_floating_point::value + ? PyNumber_Float(src.ptr()) + : PyNumber_Long(src.ptr())); + PyErr_Clear(); + return load(tmp, false); + } + return false; + } + + value = (T) py_value; + return true; + } + + template + static typename std::enable_if::value, handle>::type + cast(U src, return_value_policy /* policy */, handle /* parent */) { + return PyFloat_FromDouble((double) src); + } + + template + static typename std::enable_if::value && std::is_signed::value + && (sizeof(U) <= sizeof(long)), + handle>::type + cast(U src, return_value_policy /* policy */, handle /* parent */) { + return PYBIND11_LONG_FROM_SIGNED((long) src); + } + + template + static typename std::enable_if::value && std::is_unsigned::value + && (sizeof(U) <= sizeof(unsigned long)), + handle>::type + cast(U src, return_value_policy /* policy */, handle /* parent */) { + return PYBIND11_LONG_FROM_UNSIGNED((unsigned long) src); + } + + template + static typename std::enable_if::value && std::is_signed::value + && (sizeof(U) > sizeof(long)), + handle>::type + cast(U src, return_value_policy /* policy */, handle /* parent */) { + return PyLong_FromLongLong((long long) src); + } + + template + static typename std::enable_if::value && std::is_unsigned::value + && (sizeof(U) > sizeof(unsigned long)), + handle>::type + cast(U src, return_value_policy /* policy */, handle /* parent */) { + return PyLong_FromUnsignedLongLong((unsigned long long) src); + } + + PYBIND11_TYPE_CASTER( + T, + io_name::value>("typing.SupportsInt | typing.SupportsIndex", + "int", + "typing.SupportsFloat | typing.SupportsIndex", + "float")); +}; + +template +struct void_caster { +public: + bool load(handle src, bool) { + if (src && src.is_none()) { + return true; + } + return false; + } + static handle cast(T, return_value_policy /* policy */, handle /* parent */) { + return none().release(); + } + PYBIND11_TYPE_CASTER(T, const_name("None")); +}; + +template <> +class type_caster : public void_caster {}; + +template <> +class type_caster : public type_caster { +public: + using type_caster::cast; + + bool load(handle h, bool) { + if (!h) { + return false; + } + if (h.is_none()) { + value = nullptr; + return true; + } + + /* Check if this is a capsule */ + if (isinstance(h)) { + value = reinterpret_borrow(h); + return true; + } + + /* Check if this is a C++ type */ + const auto &bases + = all_type_info(reinterpret_cast(type::handle_of(h).ptr())); + if (bases.size() == 1) { // Only allowing loading from a single-value type + value = values_and_holders(reinterpret_cast(h.ptr())).begin()->value_ptr(); + return true; + } + + /* Fail */ + return false; + } + + static handle cast(const void *ptr, return_value_policy /* policy */, handle /* parent */) { + if (ptr) { + return capsule(ptr).release(); + } + return none().release(); + } + + template + using cast_op_type = void *&; + explicit operator void *&() { return value; } + static constexpr auto name = const_name(PYBIND11_CAPSULE_TYPE_TYPE_HINT); + +private: + void *value = nullptr; +}; + +template <> +class type_caster : public void_caster {}; + +template <> +class type_caster { +public: + bool load(handle src, bool convert) { + if (!src) { + return false; + } + if (src.ptr() == Py_True) { + value = true; + return true; + } + if (src.ptr() == Py_False) { + value = false; + return true; + } + if (convert || is_numpy_bool(src)) { + // (allow non-implicit conversion for numpy booleans), use strncmp + // since NumPy 1.x had an additional trailing underscore. + + Py_ssize_t res = -1; + if (src.is_none()) { + res = 0; // None is implicitly converted to False + } +#if defined(PYPY_VERSION) + // On PyPy, check that "__bool__" attr exists + else if (hasattr(src, PYBIND11_BOOL_ATTR)) { + res = PyObject_IsTrue(src.ptr()); + } +#else + // Alternate approach for CPython: this does the same as the above, but optimized + // using the CPython API so as to avoid an unneeded attribute lookup. + else if (auto *tp_as_number = Py_TYPE(src.ptr())->tp_as_number) { + if (PYBIND11_NB_BOOL(tp_as_number)) { + res = (*PYBIND11_NB_BOOL(tp_as_number))(src.ptr()); + } + } +#endif + if (res == 0 || res == 1) { + value = (res != 0); + return true; + } + PyErr_Clear(); + } + return false; + } + static handle cast(bool src, return_value_policy /* policy */, handle /* parent */) { + return handle(src ? Py_True : Py_False).inc_ref(); + } + PYBIND11_TYPE_CASTER(bool, const_name("bool")); + +private: + // Test if an object is a NumPy boolean (without fetching the type). + static bool is_numpy_bool(handle object) { + const char *type_name = Py_TYPE(object.ptr())->tp_name; + // Name changed to `numpy.bool` in NumPy 2, `numpy.bool_` is needed for 1.x support + return std::strcmp("numpy.bool", type_name) == 0 + || std::strcmp("numpy.bool_", type_name) == 0; + } +}; + +// Helper class for UTF-{8,16,32} C++ stl strings: +template +struct string_caster { + using CharT = typename StringType::value_type; + + // Simplify life by being able to assume standard char sizes (the standard only guarantees + // minimums, but Python requires exact sizes) + static_assert(!std::is_same::value || sizeof(CharT) == 1, + "Unsupported char size != 1"); +#if defined(PYBIND11_HAS_U8STRING) + static_assert(!std::is_same::value || sizeof(CharT) == 1, + "Unsupported char8_t size != 1"); +#endif + static_assert(!std::is_same::value || sizeof(CharT) == 2, + "Unsupported char16_t size != 2"); + static_assert(!std::is_same::value || sizeof(CharT) == 4, + "Unsupported char32_t size != 4"); + // wchar_t can be either 16 bits (Windows) or 32 (everywhere else) + static_assert(!std::is_same::value || sizeof(CharT) == 2 || sizeof(CharT) == 4, + "Unsupported wchar_t size != 2/4"); + static constexpr size_t UTF_N = 8 * sizeof(CharT); + + bool load(handle src, bool) { + handle load_src = src; + if (!src) { + return false; + } + if (!PyUnicode_Check(load_src.ptr())) { + return load_raw(load_src); + } + + // For UTF-8 we avoid the need for a temporary `bytes` object by using + // `PyUnicode_AsUTF8AndSize`. + if (UTF_N == 8) { + Py_ssize_t size = -1; + const auto *buffer + = reinterpret_cast(PyUnicode_AsUTF8AndSize(load_src.ptr(), &size)); + if (!buffer) { + PyErr_Clear(); + return false; + } + value = StringType(buffer, static_cast(size)); + return true; + } + + auto utfNbytes + = reinterpret_steal(PyUnicode_AsEncodedString(load_src.ptr(), + UTF_N == 8 ? "utf-8" + : UTF_N == 16 ? "utf-16" + : "utf-32", + nullptr)); + if (!utfNbytes) { + PyErr_Clear(); + return false; + } + + const auto *buffer + = reinterpret_cast(PYBIND11_BYTES_AS_STRING(utfNbytes.ptr())); + size_t length = static_cast(PYBIND11_BYTES_SIZE(utfNbytes.ptr())) / sizeof(CharT); + // Skip BOM for UTF-16/32 + if (UTF_N > 8) { + buffer++; + length--; + } + value = StringType(buffer, length); + + // If we're loading a string_view we need to keep the encoded Python object alive: + if (IsView) { + loader_life_support::add_patient(utfNbytes); + } + + return true; + } + + static handle + cast(const StringType &src, return_value_policy /* policy */, handle /* parent */) { + const char *buffer = reinterpret_cast(src.data()); + auto nbytes = ssize_t(src.size() * sizeof(CharT)); + handle s = decode_utfN(buffer, nbytes); + if (!s) { + throw error_already_set(); + } + return s; + } + + PYBIND11_TYPE_CASTER(StringType, const_name(PYBIND11_STRING_NAME)); + +private: + static handle decode_utfN(const char *buffer, ssize_t nbytes) { +#if !defined(PYPY_VERSION) + return UTF_N == 8 ? PyUnicode_DecodeUTF8(buffer, nbytes, nullptr) + : UTF_N == 16 ? PyUnicode_DecodeUTF16(buffer, nbytes, nullptr, nullptr) + : PyUnicode_DecodeUTF32(buffer, nbytes, nullptr, nullptr); +#else + // PyPy segfaults when on PyUnicode_DecodeUTF16 (and possibly on PyUnicode_DecodeUTF32 as + // well), so bypass the whole thing by just passing the encoding as a string value, which + // works properly: + return PyUnicode_Decode(buffer, + nbytes, + UTF_N == 8 ? "utf-8" + : UTF_N == 16 ? "utf-16" + : "utf-32", + nullptr); +#endif + } + + // When loading into a std::string or char*, accept a bytes/bytearray object as-is (i.e. + // without any encoding/decoding attempt). For other C++ char sizes this is a no-op. + // which supports loading a unicode from a str, doesn't take this path. + template + bool load_raw(enable_if_t::value, handle> src) { + if (PYBIND11_BYTES_CHECK(src.ptr())) { + // We were passed raw bytes; accept it into a std::string or char* + // without any encoding attempt. + const char *bytes = PYBIND11_BYTES_AS_STRING(src.ptr()); + if (!bytes) { + pybind11_fail("Unexpected PYBIND11_BYTES_AS_STRING() failure."); + } + value = StringType(bytes, (size_t) PYBIND11_BYTES_SIZE(src.ptr())); + return true; + } + if (PyByteArray_Check(src.ptr())) { + // We were passed a bytearray; accept it into a std::string or char* + // without any encoding attempt. + const char *bytearray = PyByteArray_AsString(src.ptr()); + if (!bytearray) { + pybind11_fail("Unexpected PyByteArray_AsString() failure."); + } + value = StringType(bytearray, (size_t) PyByteArray_Size(src.ptr())); + return true; + } + + return false; + } + + template + bool load_raw(enable_if_t::value, handle>) { + return false; + } +}; + +template +struct type_caster, + enable_if_t::value>> + : string_caster> {}; + +#ifdef PYBIND11_HAS_STRING_VIEW +template +struct type_caster, + enable_if_t::value>> + : string_caster, true> {}; +#endif + +// Type caster for C-style strings. We basically use a std::string type caster, but also add the +// ability to use None as a nullptr char* (which the string caster doesn't allow). +template +struct type_caster::value>> { + using StringType = std::basic_string; + using StringCaster = make_caster; + StringCaster str_caster; + bool none = false; + CharT one_char = 0; + +public: + bool load(handle src, bool convert) { + if (!src) { + return false; + } + if (src.is_none()) { + // Defer accepting None to other overloads (if we aren't in convert mode): + if (!convert) { + return false; + } + none = true; + return true; + } + return str_caster.load(src, convert); + } + + static handle cast(const CharT *src, return_value_policy policy, handle parent) { + if (src == nullptr) { + return pybind11::none().release(); + } + return StringCaster::cast(StringType(src), policy, parent); + } + + static handle cast(CharT src, return_value_policy policy, handle parent) { + if (std::is_same::value) { + handle s = PyUnicode_DecodeLatin1((const char *) &src, 1, nullptr); + if (!s) { + throw error_already_set(); + } + return s; + } + return StringCaster::cast(StringType(1, src), policy, parent); + } + + explicit operator CharT *() { + return none ? nullptr : const_cast(static_cast(str_caster).c_str()); + } + explicit operator CharT &() { + if (none) { + throw value_error("Cannot convert None to a character"); + } + + auto &value = static_cast(str_caster); + size_t str_len = value.size(); + if (str_len == 0) { + throw value_error("Cannot convert empty string to a character"); + } + + // If we're in UTF-8 mode, we have two possible failures: one for a unicode character that + // is too high, and one for multiple unicode characters (caught later), so we need to + // figure out how long the first encoded character is in bytes to distinguish between these + // two errors. We also allow want to allow unicode characters U+0080 through U+00FF, as + // those can fit into a single char value. + if (StringCaster::UTF_N == 8 && str_len > 1 && str_len <= 4) { + auto v0 = static_cast(value[0]); + // low bits only: 0-127 + // 0b110xxxxx - start of 2-byte sequence + // 0b1110xxxx - start of 3-byte sequence + // 0b11110xxx - start of 4-byte sequence + size_t char0_bytes = (v0 & 0x80) == 0 ? 1 + : (v0 & 0xE0) == 0xC0 ? 2 + : (v0 & 0xF0) == 0xE0 ? 3 + : 4; + + if (char0_bytes == str_len) { + // If we have a 128-255 value, we can decode it into a single char: + if (char0_bytes == 2 && (v0 & 0xFC) == 0xC0) { // 0x110000xx 0x10xxxxxx + one_char = static_cast(((v0 & 3) << 6) + + (static_cast(value[1]) & 0x3F)); + return one_char; + } + // Otherwise we have a single character, but it's > U+00FF + throw value_error("Character code point not in range(0x100)"); + } + } + + // UTF-16 is much easier: we can only have a surrogate pair for values above U+FFFF, thus a + // surrogate pair with total length 2 instantly indicates a range error (but not a "your + // string was too long" error). + else if (StringCaster::UTF_N == 16 && str_len == 2) { + one_char = static_cast(value[0]); + if (one_char >= 0xD800 && one_char < 0xE000) { + throw value_error("Character code point not in range(0x10000)"); + } + } + + if (str_len != 1) { + throw value_error("Expected a character, but multi-character string found"); + } + + one_char = value[0]; + return one_char; + } + + static constexpr auto name = const_name(PYBIND11_STRING_NAME); + template + using cast_op_type = pybind11::detail::cast_op_type<_T>; +}; + +// Base implementation for std::tuple and std::pair +template