code: def run(self, parameter_space, kernel_options, tuning_options):
          
          logging.debug('sequential runner started for ' + kernel_options.kernel_name)
  
          results = []
  
          #iterate over parameter space
          for element in parameter_space:
              params = OrderedDict(zip(tuning_options.tune_params.keys(), element))
  
              time = self.dev.compile_and_benchmark(self.gpu_args, params, kernel_options, tuning_options)
  
              if time is None:
                  logging.debug('received time is None, kernel configuration was skipped silently due to compile or runtime failure')
                  continue
  
              #print and append to results
              params['time'] = time
              output_string = get_config_string(params, self.units)
              logging.debug(output_string)
              if not self.quiet:
                  print(output_string)
              results.append(params)
  
          return results, self.dev.get_environment()
docs: Iterate through the entire parameter space using a single Python process
  
          :param parameter_space: The parameter space as an iterable.
          :type parameter_space: iterable
  
          :param kernel_options: A dictionary with all options for the kernel.
          :type kernel_options: kernel_tuner.interface.Options
  
          :param tuning_options: A dictionary with all options regarding the tuning
              process.
          :type tuning_options: kernel_tuner.iterface.Options
  
          :returns: A list of dictionaries for executed kernel configurations and their
              execution times. And a dictionary that contains a information
              about the hardware/software environment on which the tuning took place.
          :rtype: list(dict()), dict()