1fa90c9d5SSaurabh Jha"""This file contains benchmarks for sparse tensors. In particular, it 2fa90c9d5SSaurabh Jhacontains benchmarks for both mlir sparse tensor dialect and numpy so that they 3fa90c9d5SSaurabh Jhacan be compared against each other. 4fa90c9d5SSaurabh Jha""" 5fa90c9d5SSaurabh Jhaimport ctypes 6fa90c9d5SSaurabh Jhaimport numpy as np 7fa90c9d5SSaurabh Jhaimport os 8fa90c9d5SSaurabh Jhaimport re 9fa90c9d5SSaurabh Jhaimport time 10fa90c9d5SSaurabh Jha 11fa90c9d5SSaurabh Jhafrom mlir import ir 12fa90c9d5SSaurabh Jhafrom mlir import runtime as rt 135da5483fSIngo Müllerfrom mlir.dialects import func 14fa90c9d5SSaurabh Jhafrom mlir.dialects.linalg.opdsl import lang as dsl 15fa90c9d5SSaurabh Jhafrom mlir.execution_engine import ExecutionEngine 16fa90c9d5SSaurabh Jha 17fa90c9d5SSaurabh Jhafrom common import create_sparse_np_tensor 18fa90c9d5SSaurabh Jhafrom common import emit_timer_func 19fa90c9d5SSaurabh Jhafrom common import emit_benchmark_wrapped_main_func 20fa90c9d5SSaurabh Jhafrom common import get_kernel_func_from_module 21fa90c9d5SSaurabh Jhafrom common import setup_passes 22fa90c9d5SSaurabh Jha 23fa90c9d5SSaurabh Jha 24fa90c9d5SSaurabh Jha@dsl.linalg_structured_op 25fa90c9d5SSaurabh Jhadef matmul_dsl( 26fa90c9d5SSaurabh Jha A=dsl.TensorDef(dsl.T, dsl.S.M, dsl.S.K), 27fa90c9d5SSaurabh Jha B=dsl.TensorDef(dsl.T, dsl.S.K, dsl.S.N), 28*f9008e63STobias Hieta C=dsl.TensorDef(dsl.T, dsl.S.M, dsl.S.N, output=True), 29fa90c9d5SSaurabh Jha): 30fa90c9d5SSaurabh Jha """Helper function for mlir sparse matrix multiplication benchmark.""" 31fa90c9d5SSaurabh Jha C[dsl.D.m, dsl.D.n] += A[dsl.D.m, dsl.D.k] * B[dsl.D.k, dsl.D.n] 32fa90c9d5SSaurabh Jha 33fa90c9d5SSaurabh Jha 34fa90c9d5SSaurabh Jhadef benchmark_sparse_mlir_multiplication(): 35fa90c9d5SSaurabh Jha """Benchmark for mlir sparse matrix multiplication. Because its an 36fa90c9d5SSaurabh Jha MLIR benchmark we need to return both a `compiler` function and a `runner` 37fa90c9d5SSaurabh Jha function. 38fa90c9d5SSaurabh Jha """ 39fa90c9d5SSaurabh Jha with ir.Context(), ir.Location.unknown(): 40fa90c9d5SSaurabh Jha module = ir.Module.create() 41fa90c9d5SSaurabh Jha f64 = ir.F64Type.get() 42fa90c9d5SSaurabh Jha param1_type = ir.RankedTensorType.get([1000, 1500], f64) 43fa90c9d5SSaurabh Jha param2_type = ir.RankedTensorType.get([1500, 2000], f64) 44fa90c9d5SSaurabh Jha result_type = ir.RankedTensorType.get([1000, 2000], f64) 45fa90c9d5SSaurabh Jha with ir.InsertionPoint(module.body): 46*f9008e63STobias Hieta 4736550692SRiver Riddle @func.FuncOp.from_py_func(param1_type, param2_type, result_type) 48fa90c9d5SSaurabh Jha def sparse_kernel(x, y, z): 49fa90c9d5SSaurabh Jha return matmul_dsl(x, y, outs=[z]) 50fa90c9d5SSaurabh Jha 51fa90c9d5SSaurabh Jha def compiler(): 52fa90c9d5SSaurabh Jha with ir.Context(), ir.Location.unknown(): 53fa90c9d5SSaurabh Jha kernel_func = get_kernel_func_from_module(module) 54fa90c9d5SSaurabh Jha timer_func = emit_timer_func() 55*f9008e63STobias Hieta wrapped_func = emit_benchmark_wrapped_main_func(kernel_func, timer_func) 56fa90c9d5SSaurabh Jha main_module_with_benchmark = ir.Module.parse( 57fa90c9d5SSaurabh Jha str(timer_func) + str(wrapped_func) + str(kernel_func) 58fa90c9d5SSaurabh Jha ) 59fa90c9d5SSaurabh Jha setup_passes(main_module_with_benchmark) 60fa90c9d5SSaurabh Jha c_runner_utils = os.getenv("MLIR_C_RUNNER_UTILS", "") 61*f9008e63STobias Hieta assert os.path.exists(c_runner_utils), ( 62*f9008e63STobias Hieta f"{c_runner_utils} does not exist." 63*f9008e63STobias Hieta f" Please pass a valid value for" 64fa90c9d5SSaurabh Jha f" MLIR_C_RUNNER_UTILS environment variable." 65*f9008e63STobias Hieta ) 66fa90c9d5SSaurabh Jha runner_utils = os.getenv("MLIR_RUNNER_UTILS", "") 67*f9008e63STobias Hieta assert os.path.exists(runner_utils), ( 68*f9008e63STobias Hieta f"{runner_utils} does not exist." 69*f9008e63STobias Hieta f" Please pass a valid value for MLIR_RUNNER_UTILS" 70fa90c9d5SSaurabh Jha f" environment variable." 71*f9008e63STobias Hieta ) 72fa90c9d5SSaurabh Jha 73fa90c9d5SSaurabh Jha engine = ExecutionEngine( 74fa90c9d5SSaurabh Jha main_module_with_benchmark, 75fa90c9d5SSaurabh Jha 3, 76*f9008e63STobias Hieta shared_libs=[c_runner_utils, runner_utils], 77fa90c9d5SSaurabh Jha ) 78fa90c9d5SSaurabh Jha return engine.invoke 79fa90c9d5SSaurabh Jha 80fa90c9d5SSaurabh Jha def runner(engine_invoke): 81fa90c9d5SSaurabh Jha compiled_program_args = [] 82*f9008e63STobias Hieta for argument_type in [result_type, param1_type, param2_type, result_type]: 83fa90c9d5SSaurabh Jha argument_type_str = str(argument_type) 84fa90c9d5SSaurabh Jha dimensions_str = re.sub("<|>|tensor", "", argument_type_str) 85fa90c9d5SSaurabh Jha dimensions = [int(dim) for dim in dimensions_str.split("x")[:-1]] 86fa90c9d5SSaurabh Jha if argument_type == result_type: 87fa90c9d5SSaurabh Jha argument = np.zeros(dimensions, np.float64) 88fa90c9d5SSaurabh Jha else: 89fa90c9d5SSaurabh Jha argument = create_sparse_np_tensor(dimensions, 1000) 90fa90c9d5SSaurabh Jha compiled_program_args.append( 91fa90c9d5SSaurabh Jha ctypes.pointer( 92fa90c9d5SSaurabh Jha ctypes.pointer(rt.get_ranked_memref_descriptor(argument)) 93fa90c9d5SSaurabh Jha ) 94fa90c9d5SSaurabh Jha ) 95fa90c9d5SSaurabh Jha np_timers_ns = np.array([0], dtype=np.int64) 96fa90c9d5SSaurabh Jha compiled_program_args.append( 97fa90c9d5SSaurabh Jha ctypes.pointer( 98fa90c9d5SSaurabh Jha ctypes.pointer(rt.get_ranked_memref_descriptor(np_timers_ns)) 99fa90c9d5SSaurabh Jha ) 100fa90c9d5SSaurabh Jha ) 101fa90c9d5SSaurabh Jha engine_invoke("main", *compiled_program_args) 102fa90c9d5SSaurabh Jha return int(np_timers_ns[0]) 103fa90c9d5SSaurabh Jha 104fa90c9d5SSaurabh Jha return compiler, runner 105fa90c9d5SSaurabh Jha 106fa90c9d5SSaurabh Jha 107fa90c9d5SSaurabh Jhadef benchmark_np_matrix_multiplication(): 108fa90c9d5SSaurabh Jha """Benchmark for numpy matrix multiplication. Because its a python 109fa90c9d5SSaurabh Jha benchmark, we don't have any `compiler` function returned. We just return 110fa90c9d5SSaurabh Jha the `runner` function. 111fa90c9d5SSaurabh Jha """ 112*f9008e63STobias Hieta 113fa90c9d5SSaurabh Jha def runner(): 114fa90c9d5SSaurabh Jha argument1 = np.random.uniform(low=0.0, high=100.0, size=(1000, 1500)) 115fa90c9d5SSaurabh Jha argument2 = np.random.uniform(low=0.0, high=100.0, size=(1500, 2000)) 116fa90c9d5SSaurabh Jha start_time = time.time_ns() 117fa90c9d5SSaurabh Jha np.matmul(argument1, argument2) 118fa90c9d5SSaurabh Jha return time.time_ns() - start_time 119fa90c9d5SSaurabh Jha 120fa90c9d5SSaurabh Jha return None, runner 121