Esempio n. 1
0
def tune_kernel(kernel_name,
                kernel_string,
                problem_size,
                arguments,
                tune_params,
                grid_div_x=None,
                grid_div_y=None,
                grid_div_z=None,
                restrictions=None,
                answer=None,
                atol=1e-6,
                verify=None,
                verbose=False,
                lang=None,
                device=0,
                platform=0,
                cmem_args=None,
                num_threads=1,
                use_noodles=False,
                sample_fraction=False,
                compiler=None,
                compiler_options=None,
                log=None,
                iterations=7,
                times=False,
                block_size_names=None,
                quiet=False,
                strategy=None,
                method=None):

    if log:
        logging.basicConfig(filename=kernel_name +
                            datetime.now().strftime('%Y%m%d-%H:%M:%S') +
                            '.log',
                            level=log)

    _check_user_input(kernel_name, kernel_string, arguments, block_size_names)

    # check for forbidden names in tune parameters
    util.check_tune_params_list(tune_params)

    # check whether block_size_names are used as expected
    util.check_block_size_params_names_list(block_size_names, tune_params)

    if iterations < 1:
        raise ValueError("Iterations should be at least one!")

    #sort all the options into separate dicts
    opts = locals()
    kernel_options = Options([(k, opts[k]) for k in _kernel_options.keys()])
    tuning_options = Options([(k, opts[k]) for k in _tuning_options.keys()])
    device_options = Options([(k, opts[k]) for k in _device_options.keys()])

    logging.debug('tune_kernel called')
    logging.debug('kernel_options: %s', util.get_config_string(kernel_options))
    logging.debug('tuning_options: %s', util.get_config_string(tuning_options))
    logging.debug('device_options: %s', util.get_config_string(device_options))

    #select strategy based on user options
    if sample_fraction and not strategy in [None, 'sample_fraction']:
        raise ValueError("It's not possible to use both sample_fraction in combination with other strategies. " \
                         'Please set strategy=None or strategy="random_sample", when using sample_fraction')

    if strategy in [None, 'sample_fraction', 'brute_force']:
        if sample_fraction:
            use_strategy = random_sample
        else:
            use_strategy = brute_force
    elif strategy in ["minimize", "basinhopping"]:
        if method:
            if not (method in [
                    "Nelder-Mead", "Powell", "CG", "BFGS", "L-BFGS-B", "TNC",
                    "COBYLA", "SLSQP"
            ] or callable(method)):
                raise ValueError("method option not recognized")
        else:
            method = "L-BFGS-B"
        if strategy == "minimize":
            use_strategy = minimize
        else:
            use_strategy = basinhopping
    elif strategy == "diff_evo":
        use_strategy = diff_evo
        if method:
            if not method in [
                    "best1bin", "best1exp", "rand1exp", "randtobest1exp",
                    "best2exp", "rand2exp", "randtobest1bin", "best2bin",
                    "rand2bin", "rand1bin"
            ]:
                raise ValueError("method option not recognized")
    else:
        raise ValueError("strategy option not recognized")
    strategy = use_strategy

    #select runner based on user options
    if num_threads == 1 and not use_noodles:
        from kernel_tuner.runners.sequential import SequentialRunner
        runner = SequentialRunner(kernel_options, device_options, iterations)
    elif num_threads > 1 and not use_noodles:
        raise ValueError(
            "Using multiple threads requires the Noodles runner, use use_noodles=True"
        )
    elif use_noodles:
        #check if Python version matches required by Noodles
        if sys.version_info[0] < 3 or (sys.version_info[0] == 3
                                       and sys.version_info[1] < 5):
            raise ValueError(
                "Using multiple threads requires Noodles, Noodles requires Python 3.5 or higher"
            )
        #check if noodles is installed in a way that works with Python 3.4 or newer
        noodles_installed = importlib.util.find_spec("noodles") is not None
        if not noodles_installed:
            raise ValueError(
                "Using multiple threads requires Noodles, please use 'pip install noodles'"
            )
        #import the NoodlesRunner
        from kernel_tuner.runners.noodles import NoodlesRunner
        runner = NoodlesRunner(device_options, num_threads)
    else:
        raise ValueError(
            "Somehow no runner was selected, this should not happen, please file a bug report"
        )

    #call the strategy to execute the tuning process
    results, env = strategy.tune(runner, kernel_options, device_options,
                                 tuning_options)

    #finished iterating over search space
    if not device_options.quiet:
        if results:  #checks if results is not empty
            best_config = min(results, key=lambda x: x['time'])
            units = getattr(runner, "units", None)
            print("best performing configuration:",
                  util.get_config_string(best_config, units=units))
        else:
            print("no results to report")

    del runner.dev

    return results, env
Esempio n. 2
0
def tune_kernel(kernel_name, kernel_string, problem_size, arguments,
                tune_params, grid_div_x=None, grid_div_y=None, grid_div_z=None,
                restrictions=None, answer=None, atol=1e-6, verify=None, verbose=False,
                lang=None, device=0, platform=0, cmem_args=None, texmem_args=None,
                compiler=None, compiler_options=None, log=None,
                iterations=7, block_size_names=None, quiet=False, strategy=None, strategy_options=None,
                cache=None):

    if log:
        logging.basicConfig(filename=kernel_name + datetime.now().strftime('%Y%m%d-%H:%M:%S') + '.log', level=log)

    kernel_source = core.KernelSource(kernel_string, lang)

    _check_user_input(kernel_name, kernel_source, arguments, block_size_names)

    # check for forbidden names in tune parameters
    util.check_tune_params_list(tune_params)

    # check whether block_size_names are used as expected
    util.check_block_size_params_names_list(block_size_names, tune_params)

    if iterations < 1:
        raise ValueError("Iterations should be at least one!")

    #sort all the options into separate dicts
    opts = locals()
    kernel_options = Options([(k, opts[k]) for k in _kernel_options.keys()])
    tuning_options = Options([(k, opts[k]) for k in _tuning_options.keys()])
    device_options = Options([(k, opts[k]) for k in _device_options.keys()])

    logging.debug('tune_kernel called')
    logging.debug('kernel_options: %s', util.get_config_string(kernel_options))
    logging.debug('tuning_options: %s', util.get_config_string(tuning_options))
    logging.debug('device_options: %s', util.get_config_string(device_options))

    if strategy:
        if strategy in strategy_map:
            strategy = strategy_map[strategy]
        else:
            raise ValueError("Strategy %s not recognized" % strategy)

        #make strategy_options into an Options object
        if tuning_options.strategy_options:
            if not isinstance(strategy_options, Options):
                tuning_options.strategy_options = Options(strategy_options)

            #select strategy based on user options
            if "fraction" in tuning_options.strategy_options and not tuning_options.strategy == 'random_sample':
                raise ValueError('It is not possible to use fraction in combination with strategies other than "random_sample". ' \
                                 'Please set strategy="random_sample", when using "fraction" in strategy_options')

            #check if method is supported by the selected strategy
            if "method" in tuning_options.strategy_options:
                method = tuning_options.strategy_options.method
                if not method in strategy.supported_methods:
                    raise ValueError('Method %s is not supported for strategy %s' % (method, tuning_options.strategy))

        #if no strategy_options dict has been passed, create empty dictionary
        else:
            tuning_options.strategy_options = Options({})

    #if no strategy selected
    else:
        strategy = brute_force


    runner = SequentialRunner(kernel_source, kernel_options, device_options, iterations)

    #the user-specified function may or may not have an optional atol argument;
    #we normalize it so that it always accepts atol.
    tuning_options.verify = util.normalize_verify_function(tuning_options.verify)

    #process cache
    if cache:
        if cache[-5:] != ".json":
            cache += ".json"

        util.process_cache(cache, kernel_options, tuning_options, runner)
    else:
        tuning_options.cache = {}
        tuning_options.cachefile = None

    #call the strategy to execute the tuning process
    results, env = strategy.tune(runner, kernel_options, device_options, tuning_options)

    #finished iterating over search space
    if not device_options.quiet:
        if results:     #checks if results is not empty
            best_config = min(results, key=lambda x: x['time'])
            units = getattr(runner, "units", None)
            print("best performing configuration:", util.get_config_string(best_config, list(tune_params.keys()) + ['time'], units=units))
        else:
            print("no results to report")

    if cache:
        util.close_cache(cache)

    del runner.dev

    return results, env