class_docstr: Simplified version of Triton autotuner that has no invalidation
  key and caches the best config to disk to improve cold start times.
  Unlike the main triton Autotuner, this version can precompile all
  configs, and does not rely on the Triton JIT.
class_docstr_tok: ["Simplified","version","of","Triton","autotuner","that","has","no","invalidation","key","and","caches","the","best","config","to","disk","to","improve","cold","start","times",".","Unlike","the","main","triton","Autotuner",",","this","version","can","precompile","all","configs",",","and","does","not","rely","on","the","Triton","JIT","."]
code: def save_cuda_kernel(self, grid, stream, launcher):
      if callable(grid):
          grid_x, grid_y, grid_z = grid(launcher.config.kwargs)
      else:
          grid_x, grid_y, grid_z = grid
  
      key = self.inductor_meta.get(
          "kernel_name", None
      )  # unique kernel name
      assert key is not None, "kernel_name can not be None"
      params = {
          "mangled_name": launcher.bin.metadata["name"],
          "grid_x": grid_x,
          "grid_y": grid_y,
          "grid_z": grid_z,
          "x_block": launcher.config.kwargs.get("XBLOCK", 1),
          "y_block": launcher.config.kwargs.get("YBLOCK", None),
          "z_block": launcher.config.kwargs.get("ZBLOCK", None),
          "num_warps": launcher.bin.num_warps,
          "shared_mem": launcher.bin.shared,
          "stream": stream,
          # User defined triton kernels will have arbitrary kwarg names
          "meta": launcher.config.kwargs,
      }
  
      if torch.version.hip is None:
          CudaKernelParamCache.set(
              key, params, launcher.bin.asm["cubin"]
          )
      else:
          # There is some divergence between CUDA and ROCm here.
          # On ROCm's triton we only have the the path to the binary, not the binary itself.
          # For ROCm we will copy the binary to the new location instead of writing to file
          import pathlib
  
          launcher.bin.asm["hsaco"] = pathlib.Path(
              launcher.bin.asm["hsaco_path"]
          ).read_bytes()
          CudaKernelParamCache.set(
              key, params, launcher.bin.asm["hsaco"]
          )
  
imports: import builtins
  import copy
  import functools
  import hashlib
  import inspect
  import json
  import logging
  import math
  import operator
  import os
  import os.path
  import re
  import threading
  from enum import auto, Enum
  from typing import Any, Callable, Dict, List, Optional, Set, Tuple
  import torch
  import torch.autograd.profiler
  from torch._dynamo.device_interface import get_interface_for_device
  from torch._dynamo.utils import dynamo_timed, get_first_attr
  from torch.utils._triton import has_triton_package
  from .None import config
  from .codecache import cache_dir, CudaKernelParamCache
  from .coordinate_descent_tuner import CoordescTuner
  from .ir import ReductionHint, TileHint
  from .utils import ceildiv, conditional_product, create_bandwidth_info_str, do_bench, get_num_bytes, next_power_of_2, triton_config_to_hashable
label_desc: Use image node_id 8 for calling the CachingAutotuner obj's underlying member method code with example usage: obj.save_cuda_kernel(grid, stream, launcher) without return types