code: def cuda_args(shape):
      """
      Compute the blocks-per-grid and threads-per-block parameters for use when
      invoking cuda kernels
  
      Parameters
      ----------
      shape: int or tuple of ints
          The shape of the input array that the kernel will parallelize over
  
      Returns
      -------
      tuple
          Tuple of (blocks_per_grid, threads_per_block)
      """
      if isinstance(shape, int):
          shape = (shape,)
  
      max_threads = cuda.get_current_device().MAX_THREADS_PER_BLOCK
      # Note: We divide max_threads by 2.0 to leave room for the registers
      # occupied by the kernel. For some discussion, see
      # https://github.com/numba/numba/issues/3798.
      threads_per_block = int(
          ceil(max_threads / 2.0) ** (1.0 / len(shape))
      )
      tpb = (threads_per_block,) * len(shape)
      bpg = tuple(int(ceil(d / threads_per_block)) for d in shape)
      return bpg, tpb
  
imports: from __future__ import annotations
  from math import ceil, isnan
  from packaging.version import Version
  import numba
  import numpy
  from numba import cuda
label_desc: Use image node_id 1 for calling a global function with example usage: cuda_args(shape) and returns: bpg,  tpb