#ifndef __INFINIOPTEST_HPP__ #define __INFINIOPTEST_HPP__ #include "gguf.hpp" #include "tensor.hpp" #include #include #include #include #define RESET "\033[0m" #define GREEN "\033[32m" #define RED "\033[31m" #define YELLOW "\033[33m" namespace infiniop_test { enum class TestStatus { PASS, TEST_INIT_FAILED, OP_CREATION_FAILED, OP_EXECUTION_FAILED, RESULT_INCORRECT, }; // Result of a testcase class Result { private: TestStatus _status; double _time = 0.; std::string _description; std::string _error_message; public: Result(TestStatus status_, double time_, const std::string &description_, const std::string &error_message_) : _status(status_), _time(time_), _description(description_), _error_message(error_message_) {} bool isPassed() const { return _status == TestStatus::PASS; } std::string toString() const; }; // Quick macro for creating a test result #define TEST_PASSED(delay) std::make_shared(infiniop_test::TestStatus::PASS, delay, toString(), "") #define TEST_FAILED(reason, msg) std::make_shared(infiniop_test::TestStatus::reason, 0., toString(), msg) #define TEST_INIT_FAILED(op_name) std::make_shared(infiniop_test::TestStatus::TEST_INIT_FAILED, 0., "Invalid " + std::string(op_name), "") // Run all tests read from a GGUF file std::vector> runAllTests( const GGUFFileReader &, infiniDevice_t device, int device_id, size_t warm_ups, size_t iterations, double rtol, double atol); // Run a single test read from a GGUF file std::shared_ptr runTest( const GGUFFileReader &, infiniDevice_t device, int device_id, size_t warm_ups, size_t iterations, double rtol, double atol, size_t test_id); // Check if two tensors are close within given tolerance void allClose(std::shared_ptr actual, std::shared_ptr expected, double rtol = 1e-3, double atol = 1e-3); // Helper function for benchmarking a function double benchmark(std::function func, size_t warmups, size_t iterations); } // namespace infiniop_test namespace infiniop_test::base { // Base class for a testcase, each operator test should inherit from this class class Test { public: virtual std::shared_ptr run( infiniopHandle_t handle, infiniDevice_t device, int device_id, size_t warm_ups, size_t iterations) = 0; virtual std::string toString() const = 0; }; } // namespace infiniop_test::base // Quick macro for declaring a new testcase #define DECLARE_INFINIOP_TEST(name) \ namespace infiniop_test::name { \ class Test : public infiniop_test::base::Test { \ double _rtol, _atol; \ \ public: \ static std::string op_name() { return #name; } \ static std::shared_ptr build( \ std::unordered_map> attributes, \ std::unordered_map> tensors, \ double, double); \ \ static std::vector attribute_names(); \ static std::vector tensor_names(); \ static std::vector output_names(); \ \ std::shared_ptr run( \ infiniopHandle_t handle, infiniDevice_t device, int device_id, \ size_t warm_ups, size_t iterations) override; \ \ std::string toString() const override; \ \ ~Test(); \ \ private: \ struct Attributes; \ Attributes *_attributes; \ Test() = delete; \ Test(double rtol, double atol) : _rtol(rtol), _atol(atol) {} \ }; \ } namespace infiniop_test { using BuilderFunc = std::function( std::unordered_map>, std::unordered_map>, double, double)>; // Testcase Registry // Each testcase should provid a formatted builder, attribute names, and tensor names struct TestBuilder { BuilderFunc build; std::vector attribute_names; std::vector tensor_names; std::vector output_names; }; } // namespace infiniop_test #endif