<commit_before>""" Module for kernel tuner utility functions """
from __future__ import print_function

from collections import OrderedDict
import os
import errno
import tempfile
import logging
import numpy
import warnings

default_block_size_names = ["block_size_x", "block_size_y", "block_size_z"]

def check_argument_list(kernel_string, args):
    """ raise an exception if a kernel arguments do not match host arguments """
    kernel_arguments = kernel_string[kernel_string.find("(") + 1:kernel_string.find(")")].split(",")
    if len(kernel_arguments) != len(args):
        raise TypeError("Kernel and host argument lists do not match in size.")
    for (i, arg) in enumerate(args):
        kernel_argument = kernel_arguments[i]
        if "*" in kernel_argument:
            # Corresponding argument should be a NumPy array
            if not isinstance(arg, numpy.ndarray):
                raise TypeError("Argument at position " + str(i) + " of type: "
                    + str(type(arg)) + " does not match " + kernel_argument + ".")
            # CUDA/OpenCL/C uchar arrays
            if ("uchar" in kernel_argument or "unsigned char" in kernel_argument) and arg.dtype == "ubyte":
                continue
            # CUDA/OpenCL/C char arrays
            elif "char" in kernel_argument and arg.dtype == "byte":
                continue
            # CUDA/OpenCL/C ushort arrays
            elif ("ushort" in kernel_argument or "unsigned short" in kernel_argument) and arg.dtype == "uint16":
                continue
            # CUDA/OpenCL/C short arrays
            elif "short" in kernel_argument and arg.dtype == "int16":
                continue
            # CUDA/OpenCL/C uint arrays
            elif ("uint" in kernel_argument or "unsigned int" in kernel_argument) and arg.dtype == "uint32":
                continue
            # CUDA/OpenCL/C int arrays
            elif "int" in kernel_argument and arg.dtype == "int32":
                continue
            # CUDA/OpenCL/C ulong arrays
            elif ("ulong" in kernel_argument or "unsigned long" in kernel_argument) and arg.dtype == "uint64":
                continue
            # CUDA/OpenCL/C long arrays
            elif "long" in kernel_argument and arg.dtype == "int64":
                continue
            # OpenCL/C half arrays
            elif "half" in kernel_argument and arg.dtype == "float16":
                continue
            # CUDA/OpenCL/C float arrays
            elif "float" in kernel_argument and arg.dtype == "float32":
                continue
            # CUDA/OpenCL/C double array
            elif "double" in kernel_argument and arg.dtype == "float64":
                continue
            raise TypeError("Argument at position " + str(i) + " of type: "
                + str(type(arg)) + " does not match " + kernel_argument + ".")
        else:
            # NumPy scalar
            if not isinstance(arg, numpy.generic):
                raise TypeError("Argument at position " + str(i) + " of type: "
                    + str(type(arg)) + " does not match " + kernel_argument + ".")
            # CUDA/OpenCL/C uchar
            if ("uchar" in kernel_argument or "unsigned char" in kernel_argument) and arg.dtype == "ubyte":
                continue
            # CUDA/OpenCL/C char
            elif "char" in kernel_argument and arg.dtype == "byte":
                continue
            # CUDA/OpenCL/C ushort
            elif ("ushort" in kernel_argument or "unsigned short" in kernel_argument) and arg.dtype == "ushort":
                continue
            # CUDA/OpenCL/C short
            elif "short" in kernel_argument and arg.dtype == "short":
                continue
            # CUDA/OpenCL/C uint
            elif ("uint" in kernel_argument or "unsigned int" in kernel_argument) and arg.dtype == "uint32":
                continue
            # CUDA/OpenCL/C int
            elif "int" in kernel_argument and arg.dtype == "int32":
                continue
            # CUDA/OpenCL/C ulong
            elif ("ulong" in kernel_argument or "unsigned long" in kernel_argument) and arg.dtype == "uint64":
                continue
            # CUDA/OpenCL/C long
            elif "long" in kernel_argument and arg.dtype == "int64":
                continue
            # OpenCL/C half
            elif "half" in kernel_argument and arg.dtype == "float16":
                continue
            # CUDA/OpenCL/C float
            elif "float" in kernel_argument and arg.dtype == "float32":
                continue
            # CUDA/OpenCL/C double
            elif "double" in kernel_argument and arg.dtype == "float64":
                continue
            raise TypeError("Argument at position " + str(i) + " of type: "
                + str(type(arg)) + " does not match " + kernel_argument + ".")


def check_tune_params_list(tune_params):
    """ raise an exception if a tune parameter has a forbidden name """
    forbidden_names = ("grid_size_x", "grid_size_y", "grid_size_z")
    forbidden_name_substr = ("time", "times")
    for i, (name, param) in enumerate(tune_params.items()):
        if name in forbidden_names:
            raise ValueError("Tune parameter " + name + " with value " + str(param) + " has a forbidden name!")
        for forbidden_substr in forbidden_name_substr:
            if forbidden_substr in name:
                raise ValueError("Tune parameter " + name + " with value " + str(param) + " has a forbidden name: not allowed to use " + forbidden_substr + " in tune parameter names!")

def check_block_size_names(block_size_names):
    if block_size_names is not None:
        #do some type checks for the user input
        if not isinstance(block_size_names, list):
            raise ValueError("block_size_names should be a list of strings!")
        if len(block_size_names) > 3:
            raise ValueError("block_size_names should not contain more than 3 names!")
        if not all([isinstance(name, "".__class__) for name in block_size_names]):
            raise ValueError("block_size_names should contain only strings!")
        #ensure there is always at least three names
        for i,name in enumerate(default_block_size_names):
            if len(block_size_names) < i+1:
                block_size_names.append(default_block_size_names[i])

def check_block_size_params_names_list(block_size_names, tune_params):
    if block_size_names is not None:
        for name in block_size_names:
            if name not in tune_params.keys():
                warnings.warn("Block size name " + name + " is not specified in the tunable parameters list!", UserWarning)
    else: #if default block size names are used
        if not any([k in default_block_size_names for k in tune_params.keys()]):
            warnings.warn("None of the tunable parameters specify thread block dimensions!", UserWarning)


def check_restrictions(restrictions, element, keys, verbose):
    """ check whether a specific instance meets the search space restrictions """
    params = OrderedDict(zip(keys, element))
    for restrict in restrictions:
        if not eval(replace_param_occurrences(restrict, params)):
            if verbose:
                print("skipping config", get_instance_string(params), "reason: config fails restriction")
            return False
    return True

def delete_temp_file(filename):
    """ delete a temporary file, don't complain if is no longer exists """
    try:
        os.remove(filename)
    except OSError as e:
        if e.errno != errno.ENOENT:
            raise e

def detect_language(lang, kernel_source):
    """attempt to detect language from the kernel_string if not specified"""
    if lang is None:
        if callable(kernel_source):
            raise TypeError("Please specify language when using a code generator function")
        kernel_string = get_kernel_string(kernel_source)
        if "__global__" in kernel_string:
            lang = "CUDA"
        elif "__kernel" in kernel_string:
            lang = "OpenCL"
        else:
            lang = "C"
    return lang

def get_config_string(params):
    """ return a compact string representation of a dictionary """
    return ", ".join([k + "=" + str(v) for k, v in params.items()])

def get_grid_dimensions(current_problem_size, params, grid_div, block_size_names):
    """compute grid dims based on problem sizes and listed grid divisors"""
    def get_dimension_divisor(divisor_list, default, params):
        if divisor_list is None:
            if default in params:
                divisor_list = [default]
            else:
                return 1
        return numpy.prod([int(eval(replace_param_occurrences(s, params))) for s in divisor_list])
    divisors = [get_dimension_divisor(d, block_size_names[i], params) for i, d in enumerate(grid_div)]<commit_msg>Added millisecond units in get_config_string for time parameters<commit_after>""" Module for kernel tuner utility functions """
from __future__ import print_function

from collections import OrderedDict
import os
import errno
import tempfile
import logging
import numpy
import warnings

default_block_size_names = ["block_size_x", "block_size_y", "block_size_z"]

def check_argument_list(kernel_string, args):
    """ raise an exception if a kernel arguments do not match host arguments """
    kernel_arguments = kernel_string[kernel_string.find("(") + 1:kernel_string.find(")")].split(",")
    if len(kernel_arguments) != len(args):
        raise TypeError("Kernel and host argument lists do not match in size.")
    for (i, arg) in enumerate(args):
        kernel_argument = kernel_arguments[i]
        if "*" in kernel_argument:
            # Corresponding argument should be a NumPy array
            if not isinstance(arg, numpy.ndarray):
                raise TypeError("Argument at position " + str(i) + " of type: "
                    + str(type(arg)) + " does not match " + kernel_argument + ".")
            # CUDA/OpenCL/C uchar arrays
            if ("uchar" in kernel_argument or "unsigned char" in kernel_argument) and arg.dtype == "ubyte":
                continue
            # CUDA/OpenCL/C char arrays
            elif "char" in kernel_argument and arg.dtype == "byte":
                continue
            # CUDA/OpenCL/C ushort arrays
            elif ("ushort" in kernel_argument or "unsigned short" in kernel_argument) and arg.dtype == "uint16":
                continue
            # CUDA/OpenCL/C short arrays
            elif "short" in kernel_argument and arg.dtype == "int16":
                continue
            # CUDA/OpenCL/C uint arrays
            elif ("uint" in kernel_argument or "unsigned int" in kernel_argument) and arg.dtype == "uint32":
                continue
            # CUDA/OpenCL/C int arrays
            elif "int" in kernel_argument and arg.dtype == "int32":
                continue
            # CUDA/OpenCL/C ulong arrays
            elif ("ulong" in kernel_argument or "unsigned long" in kernel_argument) and arg.dtype == "uint64":
                continue
            # CUDA/OpenCL/C long arrays
            elif "long" in kernel_argument and arg.dtype == "int64":
                continue
            # OpenCL/C half arrays
            elif "half" in kernel_argument and arg.dtype == "float16":
                continue
            # CUDA/OpenCL/C float arrays
            elif "float" in kernel_argument and arg.dtype == "float32":
                continue
            # CUDA/OpenCL/C double array
            elif "double" in kernel_argument and arg.dtype == "float64":
                continue
            raise TypeError("Argument at position " + str(i) + " of type: "
                + str(type(arg)) + " does not match " + kernel_argument + ".")
        else:
            # NumPy scalar
            if not isinstance(arg, numpy.generic):
                raise TypeError("Argument at position " + str(i) + " of type: "
                    + str(type(arg)) + " does not match " + kernel_argument + ".")
            # CUDA/OpenCL/C uchar
            if ("uchar" in kernel_argument or "unsigned char" in kernel_argument) and arg.dtype == "ubyte":
                continue
            # CUDA/OpenCL/C char
            elif "char" in kernel_argument and arg.dtype == "byte":
                continue
            # CUDA/OpenCL/C ushort
            elif ("ushort" in kernel_argument or "unsigned short" in kernel_argument) and arg.dtype == "ushort":
                continue
            # CUDA/OpenCL/C short
            elif "short" in kernel_argument and arg.dtype == "short":
                continue
            # CUDA/OpenCL/C uint
            elif ("uint" in kernel_argument or "unsigned int" in kernel_argument) and arg.dtype == "uint32":
                continue
            # CUDA/OpenCL/C int
            elif "int" in kernel_argument and arg.dtype == "int32":
                continue
            # CUDA/OpenCL/C ulong
            elif ("ulong" in kernel_argument or "unsigned long" in kernel_argument) and arg.dtype == "uint64":
                continue
            # CUDA/OpenCL/C long
            elif "long" in kernel_argument and arg.dtype == "int64":
                continue
            # OpenCL/C half
            elif "half" in kernel_argument and arg.dtype == "float16":
                continue
            # CUDA/OpenCL/C float
            elif "float" in kernel_argument and arg.dtype == "float32":
                continue
            # CUDA/OpenCL/C double
            elif "double" in kernel_argument and arg.dtype == "float64":
                continue
            raise TypeError("Argument at position " + str(i) + " of type: "
                + str(type(arg)) + " does not match " + kernel_argument + ".")


def check_tune_params_list(tune_params):
    """ raise an exception if a tune parameter has a forbidden name """
    forbidden_names = ("grid_size_x", "grid_size_y", "grid_size_z")
    forbidden_name_substr = ("time", "times")
    for i, (name, param) in enumerate(tune_params.items()):
        if name in forbidden_names:
            raise ValueError("Tune parameter " + name + " with value " + str(param) + " has a forbidden name!")
        for forbidden_substr in forbidden_name_substr:
            if forbidden_substr in name:
                raise ValueError("Tune parameter " + name + " with value " + str(param) + " has a forbidden name: not allowed to use " + forbidden_substr + " in tune parameter names!")

def check_block_size_names(block_size_names):
    if block_size_names is not None:
        #do some type checks for the user input
        if not isinstance(block_size_names, list):
            raise ValueError("block_size_names should be a list of strings!")
        if len(block_size_names) > 3:
            raise ValueError("block_size_names should not contain more than 3 names!")
        if not all([isinstance(name, "".__class__) for name in block_size_names]):
            raise ValueError("block_size_names should contain only strings!")
        #ensure there is always at least three names
        for i,name in enumerate(default_block_size_names):
            if len(block_size_names) < i+1:
                block_size_names.append(default_block_size_names[i])

def check_block_size_params_names_list(block_size_names, tune_params):
    if block_size_names is not None:
        for name in block_size_names:
            if name not in tune_params.keys():
                warnings.warn("Block size name " + name + " is not specified in the tunable parameters list!", UserWarning)
    else: #if default block size names are used
        if not any([k in default_block_size_names for k in tune_params.keys()]):
            warnings.warn("None of the tunable parameters specify thread block dimensions!", UserWarning)


def check_restrictions(restrictions, element, keys, verbose):
    """ check whether a specific instance meets the search space restrictions """
    params = OrderedDict(zip(keys, element))
    for restrict in restrictions:
        if not eval(replace_param_occurrences(restrict, params)):
            if verbose:
                print("skipping config", get_instance_string(params), "reason: config fails restriction")
            return False
    return True

def delete_temp_file(filename):
    """ delete a temporary file, don't complain if is no longer exists """
    try:
        os.remove(filename)
    except OSError as e:
        if e.errno != errno.ENOENT:
            raise e

def detect_language(lang, kernel_source):
    """attempt to detect language from the kernel_string if not specified"""
    if lang is None:
        if callable(kernel_source):
            raise TypeError("Please specify language when using a code generator function")
        kernel_string = get_kernel_string(kernel_source)
        if "__global__" in kernel_string:
            lang = "CUDA"
        elif "__kernel" in kernel_string:
            lang = "OpenCL"
        else:
            lang = "C"
    return lang


def get_config_string(params):
    """ return a compact string representation of a dictionary """
    compact_str_items = []
    # first make a list of compact strings for each parameter
    for k, v in params.items():
        unit = ""
        if "time" in k:
            unit = "ms"
        compact_str_items.append(k + "=" + str(v) + unit)
    # and finally join them
    compact_str = ", ".join(compact_str_items)
    return compact_str


def get_grid_dimensions(current_problem_size, params, grid_div, block_size_names):
    """compute grid dims based on problem sizes and listed grid divisors"""
    def get_dimension_divisor(divisor_list, default, params):
        if divisor_list is None:
            if default in params:
                divisor_list = [default]
            else:
                return 1
        return numpy.prod([int(eval(replace_param_occurrences(s, params))) for s in divisor_list])
    divisors = [get_dimension_divisor(d, block_size_names[i], params) for i, d in enumerate(grid_div)]
{'fraction_non_alphanumeric': 0.0896053362979433, 'fraction_numerical': 0.004113396331295164, 'mean_word_length': 2.2878289473684212, 'pattern_counts': {'":': 44, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '193650', 'n_tokens_mistral': 4971, 'n_tokens_neox': 4819, 'n_words': 1598}