code: def __call__(self, *args, **kwargs):
      MAX_BLOCK_COUNT = 1024
      SMALL_SEQ_COUNT = 4
  
      s1_func = self.stage1_func
      s2_func = self.stage2_func
  
      kernel_wrapper = kwargs.get("kernel_wrapper")
      if kernel_wrapper is not None:
          s1_func = kernel_wrapper(s1_func)
          s2_func = kernel_wrapper(s2_func)
  
      stream = kwargs.get("stream")
      out = kwargs.pop("out", None)
  
      from .gpuarray import empty
  
      f = s1_func
      arg_types = self.stage1_arg_types
  
      stage1_args = args
  
      while True:
          invocation_args = []
          vectors = []
  
          for arg, arg_tp in zip(args, arg_types):
              if arg_tp == "P":
                  if not arg.flags.forc:
                      raise RuntimeError(
                          "ReductionKernel cannot "
                          "deal with non-contiguous arrays"
                      )
  
                  vectors.append(arg)
                  invocation_args.append(arg.gpudata)
              else:
                  invocation_args.append(arg)
  
          repr_vec = vectors[0]
          sz = repr_vec.size
  
          allocator = kwargs.get("allocator", None)
          if allocator is None:
              allocator = repr_vec.allocator
  
          if sz <= self.block_size * SMALL_SEQ_COUNT * MAX_BLOCK_COUNT:
              total_block_size = SMALL_SEQ_COUNT * self.block_size
              block_count = (
                  sz + total_block_size - 1
              ) // total_block_size
              seq_count = SMALL_SEQ_COUNT
          else:
              block_count = MAX_BLOCK_COUNT
              macroblock_size = block_count * self.block_size
              seq_count = (sz + macroblock_size - 1) // macroblock_size
  
          if block_count == 1 and out is not None:
              if out.dtype != self.dtype_out:
                  raise ValueError(
                      "out must have the same dtype as dtype_out"
                  )
              if out.size == 0:
                  raise ValueError("out array is empty")
              result = out
          elif block_count == 1:
              result = empty((), self.dtype_out, allocator=allocator)
          else:
              result = empty(
                  (block_count,), self.dtype_out, allocator=allocator
              )
  
          kwargs = {
              "shared_size": self.block_size * self.dtype_out.itemsize
          }
  
          # print block_count, seq_count, self.block_size, sz
          f(
              (block_count, 1),
              (self.block_size, 1, 1),
              stream,
              *([result.gpudata] + invocation_args + [seq_count, sz]),
              **kwargs,
          )
  
          if block_count == 1:
              return result
          else:
              f = s2_func
              arg_types = self.stage2_arg_types
              args = (result,) + stage1_args
  
file_path: pycuda/pycuda/reduction.py
imports: from pycuda.tools import context_dependent_memoize
  from pycuda.tools import dtype_to_ctype
  import numpy
label_desc: Use image node_id 2 for calling the ReductionKernel obj's underlying member method code with example usage: obj.__call__() and returns: result