code: def run(self):
      events = []
      st = time.monotonic()
      for prg, args in self.cl_cache:
          events.append(prg.clprg(CL.queue, *args))
      mt = time.monotonic()
      Device["GPU"].synchronize()
      et = time.monotonic() - st
      print(
          f"submit in {(mt-st)*1000.0:.2f} ms, total runtime is {et*1000.0:.2f} ms"
      )
  
      if DEBUGCL >= 2:
          for i, ((prg, args), e) in enumerate(
              zip(self.cl_cache, events)
          ):
              print(
                  f"{i:3d} {prg.name:25s} "
                  + "queued @ %5.2f ms, submit @ %5.2fms, start @ %5.2f ms, end @ %5.2f ms"
                  % tuple(
                      (x * OSX_TIMING_RATIO - st * 1e9) / 1e6
                      for x in [
                          e.profile.queued,
                          e.profile.submit,
                          e.profile.start,
                          e.profile.end,
                      ]
                  )
              )
      if DEBUGCL >= 1:
          total_runtime = 0
          for i, ((prg, args), e) in enumerate(
              zip(self.cl_cache, events)
          ):
              runtime = (
                  e.profile.end - e.profile.start
              ) * OSX_TIMING_RATIO
              print(
                  f"{i:3d} time {total_runtime/1e6:5.2f} ms running {prg.name:25s} with {str(args[0]):15s} {str(args[1]):15s} count {len(args)-2:2d} runtime {runtime/1e3:7.2f} us {(getattr(prg, 'op_estimate', float('nan')))/runtime:9.2f} GFLOPS -> {args[2].shape if hasattr(args[2], 'shape') else args[2].size}"
              )
              if hasattr(prg, "prg") and (
                  (DEBUGCL >= 2 and getenv("PRINT_KERNEL", -1) == i)
                  or DEBUGCL >= 3
              ):
                  print(prg.prg)
              total_runtime += runtime
          print(
              f"total runtime: {total_runtime/1e6:.2f} ms   wall time: {et*1000.0:.2f} ms"
          )
          return total_runtime / 1e9
      return et
  
file_path: tinygrad/extra/thneed.py
imports: import time
  import struct
  import json
  import traceback
  import numpy
  from tinygrad.runtime.ops_gpu import CLProgram, compile_gpu
  from tinygrad.device import Device
  from tinygrad.helpers import DEBUG, getenv
  from collections import defaultdict
  import pyopencl
  from tinygrad.runtime.ops_gpu import OSX_TIMING_RATIO
label_desc: Use image node_id 4 for calling the Thneed obj's underlying member method code with example usage: obj.run() and returns: et, unknown