code: def __call__(
      self,
      input_rawbuffers: List[Buffer],
      var_vals: Dict[Variable, int],
      wait=False,
      jit=False,
  ) -> Optional[float]:
      # NOTE: you at least can't update the ints if this is running
      if (
          self.command_buffer is not None
          and self.command_buffer in self.device.mtl_buffers_in_flight
      ):
          self.command_buffer.waitUntilCompleted()
      all_resources = self.all_resources + [
          x._buf for x in input_rawbuffers
      ]
      for (j, i), input_idx in self.input_replace.items():
          self.icb.indirectComputeCommandAtIndex_(
              j
          ).setKernelBuffer_offset_atIndex_(
              input_rawbuffers[input_idx]._buf, 0, i
          )
      for j in self.jc_idx_with_updatable_launch_dims:
          global_size, local_size = cast(
              CompiledASTRunner, self.jit_cache[j].prg
          ).launch_dims(var_vals)
          self.icb.indirectComputeCommandAtIndex_(
              j
          ).concurrentDispatchThreadgroups_threadsPerThreadgroup_(
              Metal.MTLSize(*global_size), Metal.MTLSize(*local_size)
          )  # noqa: E501
      for j, value in enumerate(var_vals.values()):
          self.int_buf_view[j] = value
      command_buffer = self.device.mtl_queue.commandBuffer()
      encoder = command_buffer.computeCommandEncoder()
      encoder.useResources_count_usage_(
          all_resources,
          len(all_resources),
          Metal.MTLResourceUsageRead | Metal.MTLResourceUsageWrite,
      )
      encoder.executeCommandsInBuffer_withRange_(
          self.icb,
          Metal.MTLIndirectCommandBufferExecutionRangeMake(
              0, len(self.jit_cache)
          ),
      )
      encoder.endEncoding()
      command_buffer.commit()
      self.command_buffer = command_buffer
      if wait:
          command_buffer.waitUntilCompleted()
          et = (
              command_buffer.GPUEndTime()
              - command_buffer.GPUStartTime()
          )
      else:
          self.device.mtl_buffers_in_flight.append(command_buffer)
          et = None
      update_stats(
          f"<batched {len(self.jit_cache)}>",
          self.op_estimate,
          self.mem_estimate,
          var_vals,
          et,
          buf_count=len(input_rawbuffers),
          jit=jit,
          num_kernels=len(self.jit_cache),
      )  # noqa: E501
      return et
  
file_path: tinygrad/tinygrad/runtime/graph/metal.py
imports: from typing import List, Any, Dict, cast, Optional
  import Metal
  from tinygrad.dtype import dtypes
  from tinygrad.helpers import dedup, unwrap2
  from tinygrad.device import Buffer, CompiledASTRunner, update_stats
  from tinygrad.jit import JitItem, get_input_replace, get_jit_stats, get_jc_idxs_with_updatable_launch_dims, GraphException
  from tinygrad.shape.symbolic import Variable
  from tinygrad.runtime.ops_metal import MetalDevice
label_desc: Use image node_id 2 for calling the MetalGraph obj's underlying member method code with example usage: obj.__call__(input_rawbuffers, var_vals, wait, jit) and returns: et