code: def __call__(
      self,
      tensor_shape: tuple[int, int],
      tensor_in_1: kp.Tensor,
      tensor_in_2: kp.Tensor,
      tensor_out: kp.Tensor,
  ):
      params = [tensor_in_1, tensor_in_2, tensor_out]
  
      if (
          self.algo is None
          or self.tensor_shape != tensor_shape
          or self.params != params
      ):
          self.tensor_shape = tensor_shape
          self.params = params
          local_size_x = min(self.local_size_x, tensor_shape[0])
          local_size_y = min(self.local_size_y, tensor_shape[1])
          self.compiled_shader = kp.Shader.compile_source(
              self.shader.format(
                  local_size_x=local_size_x, local_size_y=local_size_y
              )
          )
          workgroup = (
              tensor_shape[0] // local_size_x,
              tensor_shape[1] // local_size_y,
              1,
          )
          print(
              f"{workgroup=} {self.local_size_x=} {self.local_size_y=}"
          )
          self.algo = self.mgr.algorithm(
              params,  # params
              self.compiled_shader,  # spirv
              workgroup,  # workgroup
              [float(tensor_shape[0])],  # spec_consts
              [],
          )  # push_consts
  
      (
          self.mgr.sequence()
          .record(kp.OpTensorSyncDevice([tensor_in_1, tensor_in_2]))
          .record(kp.OpAlgoDispatch(self.algo))
          .record(kp.OpTensorSyncLocal([tensor_out]))
          .eval()
      )
  
imports: import time
  import kp
  import numpy
label_desc: Use image node_id 2 for calling the MatMulOp obj's underlying member method code with example usage: obj.__call__(tensor_shape, tensor_in_1, tensor_in_2, tensor_out) without return types