def __init__old(self, kernel, machine, cores=<NUM_LIT:1>):

CachePredictor.__init__(self, kernel, machine, cores)<EOL>csim = self.machine.get_cachesim(self.cores)<EOL>element_size = self.kernel.datatypes_size[self.kernel.datatype]<EOL>cacheline_size = self.machine['<STR_LIT>']<EOL>elements_per_cacheline = int(cacheline_size // element_size)<EOL>inner_loop = list(self.kernel.get_loop_stack(subs_consts=True))[-<NUM_LIT:1>]<EOL>inner_index = symbol_pos_int(inner_loop['<STR_LIT:index>'])<EOL>inner_increment = inner_loop['<STR_LIT>']  <EOL>max_cache_size = max(map(lambda c: c.size(), csim.levels(with_mem=False)))<EOL>max_array_size = max(self.kernel.array_sizes(in_bytes=True, subs_consts=True).values())<EOL>warmup_indices = {<EOL>symbol_pos_int(l['<STR_LIT:index>']): ((l['<STR_LIT>']-l['<STR_LIT:start>'])//l['<STR_LIT>'])//<NUM_LIT:3><EOL>for l in self.kernel.get_loop_stack(subs_consts=True)}<EOL>warmup_iteration_count = self.kernel.indices_to_global_iterator(warmup_indices)<EOL>while warmup_iteration_count * element_size > max_cache_size*<NUM_LIT>:<EOL><INDENT>for l in self.kernel.get_loop_stack():<EOL><INDENT>index = symbol_pos_int(l['<STR_LIT:index>'])<EOL>if warmup_indices[index] > l['<STR_LIT:start>']:<EOL><INDENT>warmup_indices[index] -= <NUM_LIT:1><EOL>diff_iterations = (warmup_iteration_count -<EOL>self.kernel.indices_to_global_iterator(warmup_indices))<EOL>diff_size = diff_iterations*element_size<EOL>warmup_indices[index] = max(<EOL>l['<STR_LIT:start>'],<EOL>(warmup_iteration_count - (max_cache_size*<NUM_LIT>) // element_size) // diff_size<EOL>)<EOL>break<EOL><DEDENT><DEDENT>warmup_iteration_count = self.kernel.indices_to_global_iterator(warmup_indices)<EOL><DEDENT>o = self.kernel.compile_global_offsets(iteration=warmup_iteration_count)[<NUM_LIT:0>]<EOL>if len(o[<NUM_LIT:1>]):<EOL><INDENT>first_offset = min(o[<NUM_LIT:1>])<EOL><DEDENT>else:<EOL><INDENT>first_offset = min(o[<NUM_LIT:0>])<EOL><DEDENT>diff = first_offset -(int(first_offset) >> csim.first_level.cl_bits << csim.first_level.cl_bits)<EOL>warmup_iteration_count -= (diff//element_size)//inner_increment<EOL>warmup_indices = self.kernel.global_iterator_to_indices(warmup_iteration_count)<EOL>offsets = self.kernel.compile_global_offsets(<EOL>iteration=range(<NUM_LIT:0>, warmup_iteration_count))<EOL>if max_array_size < <NUM_LIT:2>*max_cache_size:<EOL><INDENT>offsets = np.concatenate((self.kernel.compile_global_offsets(<EOL>iteration=range(<NUM_LIT:0>, self.kernel.iteration_length())),<EOL>offsets))<EOL><DEDENT>csim.loadstore(offsets, length=element_size)<EOL>csim.reset_stats()<EOL>bench_iteration_start = warmup_iteration_count<EOL>first_dim_factor = int((inner_loop['<STR_LIT>'] - warmup_indices[inner_index] - <NUM_LIT:1>)<EOL>// (elements_per_cacheline // inner_increment))<EOL>if first_dim_factor == <NUM_LIT:0>:<EOL><INDENT>print('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'.format(<EOL>inner_loop['<STR_LIT:index>'], inner_loop['<STR_LIT:start>'], inner_loop['<STR_LIT>']<EOL>))<EOL>first_dim_factor = <NUM_LIT:100><EOL><DEDENT>bench_iteration_end = (bench_iteration_start +<EOL>elements_per_cacheline * inner_increment * first_dim_factor)<EOL>offsets = self.kernel.compile_global_offsets(<EOL>iteration=range(bench_iteration_start, bench_iteration_end))<EOL>csim.loadstore(offsets, length=element_size)<EOL>self.stats = list(csim.stats())<EOL>self.first_dim_factor = first_dim_factor<EOL>


return [self.stats[cache_level]['<STR_LIT>'] / self.first_dim_factor<EOL>for cache_level in range(len(self.machine['<STR_LIT>']))]<EOL>

Return a list with number of loaded cache lines per memory hierarchy level.


return [self.stats[cache_level]['<STR_LIT>']/self.first_dim_factor<EOL>for cache_level in range(len(self.machine['<STR_LIT>']))]<EOL>

Return a list with number of hit cache lines per memory hierarchy level.


Return a list with number of missed cache lines per memory hierarchy level.


Return a list with number of stored cache lines per memory hierarchy level.


Return a list with number of evicted cache lines per memory hierarchy level.


first_dim_factor = self.first_dim_factor<EOL>infos = {'<STR_LIT>': [], '<STR_LIT>': self.stats,<EOL>'<STR_LIT>': first_dim_factor}<EOL>for cache_level, cache_info in list(enumerate(self.machine['<STR_LIT>'])):<EOL><INDENT>infos['<STR_LIT>'].append({<EOL>'<STR_LIT:index>': len(infos['<STR_LIT>']),<EOL>'<STR_LIT>': '<STR_LIT:{}>'.format(cache_info['<STR_LIT>']),<EOL>'<STR_LIT>': self.stats[cache_level]['<STR_LIT>']/first_dim_factor,<EOL>'<STR_LIT>': self.stats[cache_level]['<STR_LIT>']/first_dim_factor,<EOL>'<STR_LIT>': self.stats[cache_level]['<STR_LIT>']/first_dim_factor,<EOL>'<STR_LIT>': self.stats[cache_level]['<STR_LIT>']/first_dim_factor,<EOL>'<STR_LIT>': self.stats[cache_level]['<STR_LIT>']/first_dim_factor,<EOL>'<STR_LIT>': self.stats[cache_level]['<STR_LIT>']/first_dim_factor,<EOL>'<STR_LIT>': self.stats[cache_level]['<STR_LIT>']/first_dim_factor,<EOL>'<STR_LIT>': self.stats[cache_level]['<STR_LIT>']/first_dim_factor,<EOL>'<STR_LIT>': self.stats[cache_level]['<STR_LIT>']/first_dim_factor,<EOL>'<STR_LIT>': self.stats[cache_level]['<STR_LIT>']/first_dim_factor,<EOL>'<STR_LIT>': None})<EOL><DEDENT>return infos<EOL>

Return verbose information about the predictor.


return self.value*self.PREFIXES[self.prefix]<EOL>


def good_prefix(self, max_error=<NUM_LIT>, round_length=<NUM_LIT:2>, min_prefix='<STR_LIT>', max_prefix=None):

good_prefix = min_prefix<EOL>base_value = self.base_value()<EOL>for k, v in list(self.PREFIXES.items()):<EOL><INDENT>if max_prefix is not None and v > self.PREFIXES[max_prefix]:<EOL><INDENT>continue<EOL><DEDENT>if abs(round(base_value/v, round_length)*v - base_value) > base_value*max_error:<EOL><INDENT>continue<EOL><DEDENT>if abs(round(base_value/v, round_length)) < <NUM_LIT>:<EOL><INDENT>continue<EOL><DEDENT>if v < self.PREFIXES[good_prefix]:<EOL><INDENT>continue<EOL><DEDENT>good_prefix = k<EOL><DEDENT>return good_prefix<EOL>

returns the largest prefix where the relative error is bellow *max_error* although rounded
by *round_length*

if *max_prefix* is found in PrefixedUnit.PREFIXES, returned value will not exceed this
prefix.
if *min_prefix* is given, returned value will atleast be of that prefix (no matter the
error)


kwargs.update({'<STR_LIT>': True,<EOL>'<STR_LIT>': True})<EOL>return sympy.Symbol(*args, **kwargs)<EOL>

Create a sympy.Symbol with positive and integer assumptions.


def prefix_indent(prefix, textblock, later_prefix='<STR_LIT:U+0020>'):

textblock = textblock.split('<STR_LIT:\n>')<EOL>line = prefix + textblock[<NUM_LIT:0>] + '<STR_LIT:\n>'<EOL>if len(later_prefix) == <NUM_LIT:1>:<EOL><INDENT>later_prefix = '<STR_LIT:U+0020>'*len(prefix)<EOL><DEDENT>line = line + '<STR_LIT:\n>'.join([later_prefix + x for x in textblock[<NUM_LIT:1>:]])<EOL>if line[-<NUM_LIT:1>] != '<STR_LIT:\n>':<EOL><INDENT>return line + '<STR_LIT:\n>'<EOL><DEDENT>else:<EOL><INDENT>return line<EOL><DEDENT>

Prefix and indent all lines in *textblock*.

*prefix* is a prefix string
*later_prefix* is used on all but the first line, if it is a single character
               it will be repeated to match length of *prefix*


dims = []<EOL>type_ = decl.type<EOL>while type(type_) is c_ast.ArrayDecl:<EOL><INDENT>dims.append(type_.dim)<EOL>type_ = type_.type<EOL><DEDENT>if dims:<EOL><INDENT>decl.type.dim = reduce(lambda l, r: c_ast.BinaryOp('<STR_LIT:*>', l, r), dims)<EOL>decl.type.type = type_<EOL><DEDENT>return decl.name, dims<EOL>

Transform ast of multidimensional declaration to a single dimension declaration.

In-place operation!

Returns name and dimensions of array (to be used with transform_multidim_to_1d_ref())


dims = []<EOL>name = aref<EOL>while type(name) is c_ast.ArrayRef:<EOL><INDENT>dims.append(name.subscript)<EOL>name = name.name<EOL><DEDENT>subscript_list = []<EOL>for i, d in enumerate(dims):<EOL><INDENT>if i == <NUM_LIT:0>:<EOL><INDENT>subscript_list.append(d)<EOL><DEDENT>else:<EOL><INDENT>subscript_list.append(c_ast.BinaryOp('<STR_LIT:*>', d, reduce(<EOL>lambda l, r: c_ast.BinaryOp('<STR_LIT:*>', l, r),<EOL>dimension_dict[name.name][-<NUM_LIT:1>:-i-<NUM_LIT:1>:-<NUM_LIT:1>])))<EOL><DEDENT><DEDENT>aref.subscript = reduce(<EOL>lambda l, r: c_ast.BinaryOp('<STR_LIT:+>', l, r), subscript_list)<EOL>aref.name = name<EOL>

Transform ast of multidimensional reference to a single dimension reference.

In-place operation!


if type(decl.type) is not c_ast.ArrayDecl:<EOL><INDENT>return<EOL><DEDENT>type_ = c_ast.PtrDecl([], decl.type.type)<EOL>if with_init:<EOL><INDENT>decl.init = c_ast.FuncCall(<EOL>c_ast.ID('<STR_LIT>'),<EOL>c_ast.ExprList([<EOL>c_ast.BinaryOp(<EOL>'<STR_LIT:*>',<EOL>c_ast.UnaryOp(<EOL>'<STR_LIT>',<EOL>c_ast.Typename(None, [], c_ast.TypeDecl(<EOL>None, [], decl.type.type.type))),<EOL>decl.type.dim),<EOL>c_ast.Constant('<STR_LIT:int>', '<STR_LIT>')]))<EOL><DEDENT>decl.type = type_<EOL>

Transform ast of "type var_name[N]" to "type* var_name = aligned_malloc(sizeof(type)*N, 32)"

In-place operation.

:param with_init: if False, ommit malloc


if type(ast) is node_type:<EOL><INDENT>return [ast]<EOL><DEDENT>elif type(ast) is list:<EOL><INDENT>return reduce(operator.add, list(map(lambda a: find_node_type(a, node_type), ast)), [])<EOL><DEDENT>elif ast is None:<EOL><INDENT>return []<EOL><DEDENT>else:<EOL><INDENT>return reduce(operator.add,<EOL>[find_node_type(o[<NUM_LIT:1>], node_type) for o in ast.children()], [])<EOL><DEDENT>


if type(ast) is c_ast.Pragma:<EOL><INDENT>return [ast]<EOL><DEDENT>


def wrapper(*args, **kwargs):<EOL><INDENT>r = f(*args, **kwargs)<EOL>if hasattr(r, '<STR_LIT>'):<EOL><INDENT>return r<EOL><DEDENT>else:<EOL><INDENT>return [r]<EOL><DEDENT><DEDENT>return wrapper<EOL>

Will make any functions return an iterable objects by wrapping its result in a list.


relative_path = os.path.relpath(path)<EOL>if len(relative_path) < len(path):<EOL><INDENT>return relative_path<EOL><DEDENT>else:<EOL><INDENT>return path<EOL><DEDENT>

Reduce absolute path to relative (if shorter) for easier readability.


self._machine = machine<EOL>self._loop_stack = []<EOL>self.variables = {}<EOL>self.sources = {}<EOL>self.destinations = {}<EOL>self._flops = {}<EOL>self.datatype = None<EOL>self.constants = None<EOL>self.clear_state()<EOL>


datatypes = [v[<NUM_LIT:0>] for v in self.variables.values()]<EOL>assert len(set(datatypes)) <= <NUM_LIT:1>, '<STR_LIT>'<EOL>

Check that information about kernel makes sens and is valid.


assert isinstance(name, str) or isinstance(name, sympy.Symbol),"<STR_LIT>"<EOL>assert type(value) is int, "<STR_LIT>"<EOL>if isinstance(name, sympy.Symbol):<EOL><INDENT>self.constants[name] = value<EOL><DEDENT>else:<EOL><INDENT>self.constants[symbol_pos_int(name)] = value<EOL><DEDENT>

Set constant of name to value.

:param name: may be a str or a sympy.Symbol
:param value: must be an int


def set_variable(self, name, type_, size):

assert type_ in self.datatypes_size, '<STR_LIT>'<EOL>if self.datatype is None:<EOL><INDENT>self.datatype = type_<EOL><DEDENT>else:<EOL><INDENT>assert type_ == self.datatype, '<STR_LIT>'<EOL><DEDENT>assert type(size) in [tuple, type(None)], '<STR_LIT>'<EOL>self.variables[name] = (type_, size)<EOL>

Register variable of name and type_, with a (multidimensional) size.

:param name: variable name as it appears in code
:param type_: may be any key from Kernel.datatypes_size (typically float or double)
:param size: either None for scalars or an n-tuple of ints for an n-dimensional array


self.constants = collections.OrderedDict()<EOL>self.subs_consts.cache_clear()<EOL>

Clear mutable internal states (constants, asm_blocks and asm_block_idx).


if isinstance(expr, numbers.Number):<EOL><INDENT>return expr<EOL><DEDENT>else:<EOL><INDENT>return expr.subs(self.constants)<EOL><DEDENT>

Substitute constants in expression unless it is already a number.


def array_sizes(self, in_bytes=False, subs_consts=False):

var_sizes = {}<EOL>for var_name, var_info in self.variables.items():<EOL><INDENT>var_type, var_size = var_info<EOL>if var_size is None:<EOL><INDENT>continue<EOL><DEDENT>var_sizes[var_name] = reduce(operator.mul, var_size, <NUM_LIT:1>)<EOL>if in_bytes:<EOL><INDENT>element_size = self.datatypes_size[var_type]<EOL>var_sizes[var_name] *= element_size<EOL><DEDENT><DEDENT>if subs_consts:<EOL><INDENT>return {k: self.subs_consts(v) for k, v in var_sizes.items()}<EOL><DEDENT>else:<EOL><INDENT>return var_sizes<EOL><DEDENT>

Return a dictionary with all arrays sizes.

:param in_bytes: If True, output will be in bytes, not element counts.
:param subs_consts: If True, output will be numbers and not symbolic.

Scalar variables are ignored.


def _calculate_relative_offset(self, name, access_dimensions):

<EOL>offset = <NUM_LIT:0><EOL>base_dims = self.variables[name][<NUM_LIT:1>]<EOL>for dim, offset_info in enumerate(access_dimensions):<EOL><INDENT>offset_type, idx_name, dim_offset = offset_info<EOL>assert offset_type == '<STR_LIT>', '<STR_LIT>'<EOL>if offset_type == '<STR_LIT>':<EOL><INDENT>offset += self.subs_consts(<EOL>dim_offset*reduce(operator.mul, base_dims[dim+<NUM_LIT:1>:], sympy.Integer(<NUM_LIT:1>)))<EOL><DEDENT>else:<EOL><INDENT>pass<EOL><DEDENT><DEDENT>return offset<EOL>

Return the offset from the iteration center in number of elements.

The order of indices used in access is preserved.


self.destinations = {var_name: set(acs) for var_name, acs in self.destinations.items()}<EOL>self.sources = {var_name: set(acs) for var_name, acs in self.sources.items()}<EOL>

Remove duplicate source and destination accesses


def access_to_sympy(self, var_name, access):

base_sizes = self.variables[var_name][<NUM_LIT:1>]<EOL>expr = sympy.Number(<NUM_LIT:0>)<EOL>for dimension, a in enumerate(access):<EOL><INDENT>base_size = reduce(operator.mul, base_sizes[dimension+<NUM_LIT:1>:], sympy.Integer(<NUM_LIT:1>))<EOL>expr += base_size*a<EOL><DEDENT>return expr<EOL>

Transform a (multidimensional) variable access to a flattend sympy expression.

Also works with flat array accesses.


total_length = <NUM_LIT:1><EOL>if dimension is not None:<EOL><INDENT>loops = [self._loop_stack[dimension]]<EOL><DEDENT>else:<EOL><INDENT>loops = reversed(self._loop_stack)<EOL><DEDENT>for var_name, start, end, incr in loops:<EOL><INDENT>length = end-start<EOL>total_length = total_length*length<EOL><DEDENT>return self.subs_consts(total_length)<EOL>

Return the number of global loop iterations that are performed.

If dimension is not None, it is the loop dimension that is returned
(-1 is the inner most loop and 0 the outermost)


for l in self._loop_stack:<EOL><INDENT>if subs_consts:<EOL><INDENT>yield {'<STR_LIT:index>': l[<NUM_LIT:0>],<EOL>'<STR_LIT:start>': self.subs_consts(l[<NUM_LIT:1>]),<EOL>'<STR_LIT>': self.subs_consts(l[<NUM_LIT:2>]),<EOL>'<STR_LIT>': self.subs_consts(l[<NUM_LIT:3>])}<EOL><DEDENT>else:<EOL><INDENT>yield {'<STR_LIT:index>': l[<NUM_LIT:0>], '<STR_LIT:start>': l[<NUM_LIT:1>], '<STR_LIT>': l[<NUM_LIT:2>], '<STR_LIT>': l[<NUM_LIT:3>]}<EOL><DEDENT><DEDENT>

Yield loop stack dictionaries in order from outer to inner.


def index_order(self, sources=True, destinations=True):

if sources:<EOL><INDENT>arefs = chain(*self.sources.values())<EOL><DEDENT>else:<EOL><INDENT>arefs = []<EOL><DEDENT>if destinations:<EOL><INDENT>arefs = chain(arefs, *self.destinations.values())<EOL><DEDENT>ret = []<EOL>for a in [aref for aref in arefs if aref is not None]:<EOL><INDENT>ref = []<EOL>for expr in a:<EOL><INDENT>ref.append(expr.free_symbols)<EOL><DEDENT>ret.append(ref)<EOL><DEDENT>return ret<EOL>

Return the order of indices as they appear in array references.

Use *source* and *destination* to filter output


def compile_sympy_accesses(self, sources=True, destinations=True):

sympy_accesses = defaultdict(list)<EOL>for var_name in self.variables:<EOL><INDENT>if sources:<EOL><INDENT>for r in self.sources.get(var_name, []):<EOL><INDENT>if r is None:<EOL><INDENT>continue<EOL><DEDENT>sympy_accesses[var_name].append(self.access_to_sympy(var_name, r))<EOL><DEDENT><DEDENT>if destinations:<EOL><INDENT>for w in self.destinations.get(var_name, []):<EOL><INDENT>if w is None:<EOL><INDENT>continue<EOL><DEDENT>sympy_accesses[var_name].append(self.access_to_sympy(var_name, w))<EOL><DEDENT><DEDENT><DEDENT>return sympy_accesses<EOL>

Return a dictionary of lists of sympy accesses, for each variable.

Use *source* and *destination* to filter output


if sympy_accesses is None:<EOL><INDENT>sympy_accesses = self.compile_sympy_accesses()<EOL><DEDENT>sympy_distances = defaultdict(list)<EOL>for var_name, accesses in sympy_accesses.items():<EOL><INDENT>for i in range(<NUM_LIT:1>, len(accesses)):<EOL><INDENT>sympy_distances[var_name].append((accesses[i-<NUM_LIT:1>]-accesses[i]).simplify())<EOL><DEDENT><DEDENT>return sympy_distances<EOL>

Return load and store distances between accesses.

:param sympy_accesses: optionally restrict accesses, default from compile_sympy_accesses()

e.g. if accesses are to [+N, +1, -1, -N], relative distances are [N-1, 2, N-1]

returned is a dict of list of sympy expressions, for each variable


<EOL>base_loop_counters = {}<EOL>global_iterator = symbol_pos_int('<STR_LIT>')<EOL>idiv = implemented_function(sympy.Function(str('<STR_LIT>')), lambda x, y: x//y)<EOL>total_length = <NUM_LIT:1><EOL>last_incr = <NUM_LIT:1><EOL>for var_name, start, end, incr in reversed(self._loop_stack):<EOL><INDENT>loop_var = symbol_pos_int(var_name)<EOL>length = end-start  <EOL>counter = start+(idiv(global_iterator*last_incr, total_length)*incr) % length<EOL>total_length = total_length*length<EOL>last_incr = incr<EOL>base_loop_counters[loop_var] = sympy.lambdify(<EOL>global_iterator,<EOL>self.subs_consts(counter), modules=[numpy, {'<STR_LIT>': numpy.mod}])<EOL>if git is not None:<EOL><INDENT>try:  <EOL><INDENT>base_loop_counters[loop_var] = sympy.Integer(self.subs_consts(counter))<EOL>continue<EOL><DEDENT>except (ValueError, TypeError):<EOL><INDENT>base_loop_counters[loop_var] = base_loop_counters[loop_var](git)<EOL><DEDENT><DEDENT><DEDENT>return base_loop_counters<EOL>

Return sympy expressions translating global_iterator to loop indices.

If global_iterator is given, an integer is returned


global_iterator = sympy.Integer(<NUM_LIT:0>)<EOL>total_length = sympy.Integer(<NUM_LIT:1>)<EOL>for var_name, start, end, incr in reversed(self._loop_stack):<EOL><INDENT>loop_var = symbol_pos_int(var_name)<EOL>length = end - start  <EOL>global_iterator += (loop_var - start) * total_length<EOL>total_length *= length<EOL><DEDENT>return global_iterator<EOL>


global_iterator = self.subs_consts(self.global_iterator().subs(indices))<EOL>return global_iterator<EOL>

Transform a dictionary of indices to a global iterator integer.

Inverse of global_iterator_to_indices().


return self.indices_to_global_iterator({<EOL>symbol_pos_int(var_name): end-<NUM_LIT:1> for var_name, start, end, incr in self._loop_stack<EOL>})<EOL>

Return global iterator with last iteration number


def compile_global_offsets(self, iteration=<NUM_LIT:0>, spacing=<NUM_LIT:0>):

global_load_offsets = []<EOL>global_store_offsets = []<EOL>if isinstance(iteration, range):<EOL><INDENT>iteration = numpy.arange(iteration.start, iteration.stop, iteration.step, dtype='<STR_LIT:O>')<EOL><DEDENT>else:<EOL><INDENT>if not isinstance(iteration, collections.Sequence):<EOL><INDENT>iteration = [iteration]<EOL><DEDENT>iteration = numpy.array(iteration, dtype='<STR_LIT:O>')<EOL><DEDENT>base_loop_counters = self.global_iterator_to_indices()<EOL>total_length = self.iteration_length()<EOL>assert iteration.max() < self.subs_consts(total_length),"<STR_LIT>""<STR_LIT>".format(<EOL>iteration.max(), self.subs_consts(total_length))<EOL>var_sizes = self.array_sizes(in_bytes=True, subs_consts=True)<EOL>base_offsets = {}<EOL>base = <NUM_LIT:0><EOL>for var_name, var_size in sorted(var_sizes.items(), key=lambda v: v[<NUM_LIT:0>]):<EOL><INDENT>base_offsets[var_name] = base<EOL>array_total_size = self.subs_consts(var_size + spacing)<EOL>array_total_size = ((int(array_total_size) + <NUM_LIT>) & ~<NUM_LIT>)<EOL>base += array_total_size<EOL><DEDENT>for var_name, var_size in var_sizes.items():<EOL><INDENT>element_size = self.datatypes_size[self.variables[var_name][<NUM_LIT:0>]]<EOL>for r in self.sources.get(var_name, []):<EOL><INDENT>offset_expr = self.access_to_sympy(var_name, r)<EOL>if not any([s in base_loop_counters.keys() for s in offset_expr.free_symbols]):<EOL><INDENT>continue<EOL><DEDENT>offset = force_iterable(sympy.lambdify(<EOL>base_loop_counters.keys(),<EOL>self.subs_consts(<EOL>offset_expr*element_size<EOL>+ base_offsets[var_name]), numpy))<EOL>global_load_offsets.append(offset)<EOL><DEDENT>for w in self.destinations.get(var_name, []):<EOL><INDENT>offset_expr = self.access_to_sympy(var_name, w)<EOL>if not any([s in base_loop_counters.keys() for s in offset_expr.free_symbols]):<EOL><INDENT>continue<EOL><DEDENT>offset = force_iterable(sympy.lambdify(<EOL>base_loop_counters.keys(),<EOL>self.subs_consts(<EOL>offset_expr*element_size<EOL>+ base_offsets[var_name]), numpy))<EOL>global_store_offsets.append(offset)<EOL><DEDENT><DEDENT>counter_per_it = [v(iteration) for v in base_loop_counters.values()]<EOL>load_offsets = []<EOL>for o in global_load_offsets:<EOL><INDENT>load_offsets.append(o(*counter_per_it))<EOL><DEDENT>load_offsets = numpy.asarray(load_offsets).T<EOL>store_offsets = []<EOL>for o in global_store_offsets:<EOL><INDENT>store_offsets.append(o(*counter_per_it))<EOL><DEDENT>store_offsets = numpy.asarray(store_offsets).T<EOL>store_width = store_offsets.shape[<NUM_LIT:1>] if len(store_offsets.shape) > <NUM_LIT:1> else <NUM_LIT:0><EOL>dtype = [('<STR_LIT>', load_offsets.dtype, (load_offsets.shape[<NUM_LIT:1>],)),<EOL>('<STR_LIT:store>', store_offsets.dtype, (store_width,))]<EOL>offsets = numpy.empty(max(load_offsets.shape[<NUM_LIT:0>], store_offsets.shape[<NUM_LIT:0>]), dtype=dtype)<EOL>offsets['<STR_LIT>'] = load_offsets<EOL>offsets['<STR_LIT:store>'] = store_offsets<EOL>return offsets<EOL>

Return load and store offsets on a virtual address space.

:param iteration: controls the inner index counter
:param spacing: sets a spacing between the arrays, default is 0

All array variables (non scalars) are laid out linearly starting from 0. An optional
spacing can be set. The accesses are based on this layout.

The iteration 0 is the first iteration. All loops are mapped to this linear iteration
space.

Accesses to scalars are ignored.

Returned are load and store byte-offset pairs for each iteration.


<EOL>var_name = list(self.destinations)[<NUM_LIT:0>]<EOL>var_type = self.variables[var_name][<NUM_LIT:0>]<EOL>return self.datatypes_size[var_type] * self._loop_stack[-<NUM_LIT:1>][<NUM_LIT:3>]<EOL>

Consecutive bytes written out per high-level iterations (as counted by loop stack).

Is used to compute number of iterations per cacheline.


table = ('<STR_LIT>' +<EOL>'<STR_LIT>')<EOL>for l in self._loop_stack:<EOL><INDENT>table += '<STR_LIT>'.format(*l)<EOL><DEDENT>print(prefix_indent('<STR_LIT>', table), file=output_file)<EOL>table = ('<STR_LIT>' +<EOL>'<STR_LIT>')<EOL>for name, offsets in list(self.sources.items()):<EOL><INDENT>prefix = '<STR_LIT>'.format(name)<EOL>right_side = '<STR_LIT:\n>'.join(['<STR_LIT>'.format(o) for o in offsets])<EOL>table += prefix_indent(prefix, right_side, later_prefix='<STR_LIT>')<EOL><DEDENT>print(prefix_indent('<STR_LIT>', table), file=output_file)<EOL>table = ('<STR_LIT>' +<EOL>'<STR_LIT>')<EOL>for name, offsets in list(self.destinations.items()):<EOL><INDENT>prefix = '<STR_LIT>'.format(name)<EOL>right_side = '<STR_LIT:\n>'.join(['<STR_LIT>'.format(o) for o in offsets])<EOL>table += prefix_indent(prefix, right_side, later_prefix='<STR_LIT>')<EOL><DEDENT>print(prefix_indent('<STR_LIT>', table), file=output_file)<EOL>table = ('<STR_LIT>' +<EOL>'<STR_LIT>')<EOL>for op, count in list(self._flops.items()):<EOL><INDENT>table += '<STR_LIT>'.format(op, count)<EOL><DEDENT>table += '<STR_LIT>'<EOL>table += '<STR_LIT>'.format(sum(self._flops.values()))<EOL>print(prefix_indent('<STR_LIT>', table), file=output_file)<EOL>

Print kernel information in human readble format.


table = ('<STR_LIT>' +<EOL>'<STR_LIT>')<EOL>for name, var_info in list(self.variables.items()):<EOL><INDENT>table += '<STR_LIT>'.format(name, var_info[<NUM_LIT:0>], var_info[<NUM_LIT:1>])<EOL><DEDENT>print(prefix_indent('<STR_LIT>', table), file=output_file)<EOL>

Print variables information in human readble format.


table = ('<STR_LIT>' +<EOL>'<STR_LIT>')<EOL>for name, value in list(self.constants.items()):<EOL><INDENT>table += '<STR_LIT>'.format(name, value)<EOL><DEDENT>print(prefix_indent('<STR_LIT>', table), file=output_file)<EOL>

Print constants information in human readble format.


def iaca_analysis(self, *args, **kwargs):

raise NotImplementedError("<STR_LIT>"<EOL>"<STR_LIT>")<EOL>


def build_executable(self, *args, **kwargs):


def __init__(self, kernel_code, machine, filename=None, keep_intermediates=True):

super(KernelCode, self).__init__(machine=machine)<EOL>self.asm_block = None<EOL>self.kernel_code = kernel_code<EOL>self._filename = filename<EOL>self._keep_intermediates = keep_intermediates<EOL>parser = CParser()<EOL>try:<EOL><INDENT>self.kernel_ast = parser.parse(self._strip_comments(self._as_function()),<EOL>filename=filename).ext[<NUM_LIT:0>].body<EOL><DEDENT>except plyparser.ParseError as e:<EOL><INDENT>print('<STR_LIT>', e)<EOL>sys.exit(<NUM_LIT:1>)<EOL><DEDENT>self._process_code()<EOL>self.check()<EOL>

Create kernel representation from source code str and machine object.

:param kernel_code: string with kernel code file content
:param machine: MachineModel object
:param filename: used for prettier error messages and as storage location prefix
:param keep_intermediates: if set to True, intermediate files (for and by compilation) will
                           be preserved. If set to False, they will be deleted after use.


def _get_intermediate_file(self, name, machine_and_compiler_dependent=True, binary=False,<EOL>fp=True):

if self._filename:<EOL><INDENT>base_name = os.path.join(os.path.dirname(self._filename),<EOL>'<STR_LIT:.>' + os.path.basename(self._filename) + '<STR_LIT>')<EOL><DEDENT>else:<EOL><INDENT>base_name = tempfile.mkdtemp()<EOL><DEDENT>if not self._keep_intermediates:<EOL><INDENT>atexit.register(shutil.rmtree, base_name)<EOL><DEDENT>if machine_and_compiler_dependent:<EOL><INDENT>compiler, compiler_args = self._machine.get_compiler()<EOL>compiler_args = '<STR_LIT:_>'.join(compiler_args).replace('<STR_LIT:/>', '<STR_LIT>')<EOL>base_name += '<STR_LIT>'.format(<EOL>self._machine.get_identifier(), compiler, compiler_args)<EOL><DEDENT>os.makedirs(base_name, exist_ok=True)<EOL>file_path = os.path.join(base_name, name)<EOL>already_exists = False<EOL>if os.path.exists(file_path):<EOL><INDENT>file_modified = datetime.utcfromtimestamp(os.stat(file_path).st_mtime)<EOL>if (file_modified < self._machine.get_last_modified_datetime() or<EOL>file_modified < kerncraft.get_last_modified_datetime() or<EOL>(self._filename and<EOL>file_modified < datetime.utcfromtimestamp(os.stat(self._filename).st_mtime))):<EOL><INDENT>os.remove(file_path)<EOL><DEDENT>else:<EOL><INDENT>already_exists = True<EOL><DEDENT><DEDENT>if fp:<EOL><INDENT>if already_exists:<EOL><INDENT>mode = '<STR_LIT>'<EOL><DEDENT>else:<EOL><INDENT>mode = '<STR_LIT:w>'<EOL><DEDENT>if binary:<EOL><INDENT>mode += '<STR_LIT:b>'<EOL><DEDENT>f = open(file_path, mode)<EOL>return f, already_exists<EOL><DEDENT>else:<EOL><INDENT>return reduce_path(file_path), already_exists<EOL><DEDENT>

Create or open intermediate file (may be used for caching).

Will replace files older than kernel file, machine file or kerncraft version.

:param machine_and_compiler_dependent: set to False if file content does not depend on
                                       machine file or compiler settings
:param fp: if False, will only return file name, not file object
:paarm binary: if True, use binary mode for file access

:return: (file object or file name, boolean if already existent and up-to-date)


print(self.kernel_code, file=output_file)<EOL>


super(KernelCode, self).clear_state()<EOL>self.asm_block = None<EOL>


if type(math_ast) is c_ast.ID:<EOL><INDENT>return symbol_pos_int(math_ast.name)<EOL><DEDENT>elif type(math_ast) is c_ast.Constant:<EOL><INDENT>return sympy.Integer(math_ast.value)<EOL><DEDENT>else:  <EOL><INDENT>op = {<EOL>'<STR_LIT:*>': operator.mul,<EOL>'<STR_LIT:+>': operator.add,<EOL>'<STR_LIT:->': operator.sub<EOL>}<EOL>return op[math_ast.op](<EOL>self.conv_ast_to_sym(math_ast.left),<EOL>self.conv_ast_to_sym(math_ast.right))<EOL><DEDENT>

Convert mathematical expressions to a sympy representation.

May only contain paranthesis, addition, subtraction and multiplication from AST.


def _get_offsets(self, aref, dim=<NUM_LIT:0>):

if isinstance(aref, c_ast.ID):<EOL><INDENT>return None<EOL><DEDENT>assert type(aref.name) in [c_ast.ArrayRef, c_ast.ID],"<STR_LIT>"<EOL>assert type(aref.subscript) in [c_ast.ID, c_ast.Constant, c_ast.BinaryOp],'<STR_LIT>'<EOL>idxs = [self.conv_ast_to_sym(aref.subscript)]<EOL>if type(aref.name) is c_ast.ArrayRef:<EOL><INDENT>idxs += self._get_offsets(aref.name, dim=dim+<NUM_LIT:1>)<EOL><DEDENT>if dim == <NUM_LIT:0>:<EOL><INDENT>idxs.reverse()<EOL><DEDENT>return tuple(idxs)<EOL>

Return a tuple of offsets of an ArrayRef object in all dimensions.

The index order is right to left (c-code order).
e.g. c[i+1][j-2] -> (-2, +1)

If aref is actually a c_ast.ID, None will be returned.


if isinstance(aref.name, c_ast.ArrayRef):<EOL><INDENT>return cls._get_basename(aref.name)<EOL><DEDENT>elif isinstance(aref.name, str):<EOL><INDENT>return aref.name<EOL><DEDENT>else:<EOL><INDENT>return aref.name.name<EOL><DEDENT>

Return base name of ArrayRef object.

e.g. c[i+1][j-2] -> 'c'


if loop_nest is None:<EOL><INDENT>loop_nest = self.get_kernel_loop_nest()<EOL><DEDENT>if type(loop_nest) is c_ast.For:<EOL><INDENT>loop_nest = [loop_nest]<EOL><DEDENT>index_types = (None, None)<EOL>for s in loop_nest:<EOL><INDENT>if type(s) is c_ast.For:<EOL><INDENT>if type(s.stmt) in [c_ast.For, c_ast.Compound]:<EOL><INDENT>other = self.get_index_type(loop_nest=s.stmt)<EOL><DEDENT>else:<EOL><INDENT>other = None<EOL><DEDENT>index_types = (s.init.decls[<NUM_LIT:0>].type.type.names, other)<EOL>break<EOL><DEDENT><DEDENT>if index_types[<NUM_LIT:0>] == index_types[<NUM_LIT:1>] or index_types[<NUM_LIT:1>] is None:<EOL><INDENT>return index_types[<NUM_LIT:0>]<EOL><DEDENT>else:<EOL><INDENT>raise ValueError("<STR_LIT>".format(index_types))<EOL><DEDENT>

Return index type used in loop nest.

If index type between loops differ, an exception is raised.


decls = []<EOL>index_type = self.get_index_type()<EOL>i = <NUM_LIT:2>  <EOL>for k in self.constants:<EOL><INDENT>type_decl = c_ast.TypeDecl(k.name, ['<STR_LIT>'], c_ast.IdentifierType(index_type))<EOL>init = None<EOL>if with_init:<EOL><INDENT>init = c_ast.FuncCall(<EOL>c_ast.ID('<STR_LIT>'),<EOL>c_ast.ExprList([c_ast.ArrayRef(c_ast.ID('<STR_LIT>'),<EOL>c_ast.Constant('<STR_LIT:int>', str(i)))]))<EOL><DEDENT>i += <NUM_LIT:1><EOL>decls.append(c_ast.Decl(<EOL>k.name, ['<STR_LIT>'], [], [],<EOL>type_decl, init, None))<EOL><DEDENT>return decls<EOL>

Generate constants declarations

:return: list of declarations


return [d for d in self.kernel_ast.block_items<EOL>if type(d) is c_ast.Decl and type(d.type) is c_ast.ArrayDecl]<EOL>


loop_nest = [s for s in self.kernel_ast.block_items<EOL>if type(s) in [c_ast.For, c_ast.Pragma, c_ast.FuncCall]]<EOL>assert len(loop_nest) >= <NUM_LIT:1>, "<STR_LIT>"<EOL>return loop_nest<EOL>

Return kernel loop nest including any preceding pragmas and following swaps.


<EOL>array_declarations = deepcopy(self.get_array_declarations())<EOL>array_dict = []<EOL>for d in array_declarations:<EOL><INDENT>array_dict.append(transform_multidim_to_1d_decl(d))<EOL>transform_array_decl_to_malloc(d, with_init=with_init)<EOL><DEDENT>return array_declarations, dict(array_dict)<EOL>

Generate declaration statements for arrays.

Also transforming multi-dim to 1d arrays and initializing with malloc.

:param with_init: ommit malloc initialization

:return: list of declarations nodes, dictionary of array names and original dimensions


r = None<EOL>for s in loop_nest:<EOL><INDENT>if type(s) is c_ast.For:<EOL><INDENT>return self._find_inner_most_loop(s) or s<EOL><DEDENT>else:<EOL><INDENT>r = r or self._find_inner_most_loop(s)<EOL><DEDENT><DEDENT>return r<EOL>


kernel = deepcopy(deepcopy(self.get_kernel_loop_nest()))<EOL>inner_most = self._find_inner_most_loop(kernel)<EOL>orig_inner_stmt = inner_most.stmt<EOL>inner_most.stmt = c_ast.Compound([])<EOL>rand_float_str = str(random.uniform(<NUM_LIT:1.0>, <NUM_LIT:0.1>))<EOL>for aref in find_node_type(orig_inner_stmt, c_ast.ArrayRef):<EOL><INDENT>transform_multidim_to_1d_ref(aref, array_dimensions)<EOL>inner_most.stmt.block_items.append(c_ast.Assignment(<EOL>'<STR_LIT:=>', aref, c_ast.Constant('<STR_LIT:float>', rand_float_str)))<EOL><DEDENT>return kernel<EOL>

Generate initialization statements for arrays.

:param array_dimensions: dictionary of array dimensions

:return: list of nodes


<EOL>dummy_calls = []<EOL>for d in self.kernel_ast.block_items:<EOL><INDENT>if type(d) is not c_ast.Decl: continue<EOL>if type(d.type) is c_ast.ArrayDecl:<EOL><INDENT>dummy_calls.append(c_ast.FuncCall(<EOL>c_ast.ID('<STR_LIT>'),<EOL>c_ast.ExprList([c_ast.ID(d.name)])))<EOL><DEDENT>else:<EOL><INDENT>dummy_calls.append(c_ast.FuncCall(<EOL>c_ast.ID('<STR_LIT>'),<EOL>c_ast.ExprList([c_ast.UnaryOp('<STR_LIT:&>', c_ast.ID(d.name))])))<EOL><DEDENT><DEDENT>dummy_stmt = c_ast.If(<EOL>cond=c_ast.ID('<STR_LIT>'),<EOL>iftrue=c_ast.Compound(dummy_calls),<EOL>iffalse=None)<EOL>return dummy_stmt<EOL>

Generate false if branch with dummy calls

Requires kerncraft.h to be included, which defines dummy(...) and var_false.

:return: dummy statement


array_declarations, array_dimensions = self._build_array_declarations(with_init=False)<EOL>scalar_declarations = self._build_scalar_declarations(with_init=False)<EOL>const_declarations = self._build_const_declartions(with_init=False)<EOL>return c_ast.FuncDecl(args=c_ast.ParamList(params=array_declarations + scalar_declarations +<EOL>const_declarations),<EOL>type=c_ast.TypeDecl(declname=name,<EOL>quals=[],<EOL>type=c_ast.IdentifierType(names=['<STR_LIT>'])))<EOL>

Build and return kernel function declaration


<EOL>scalar_declarations = [deepcopy(d) for d in self.kernel_ast.block_items<EOL>if type(d) is c_ast.Decl and type(d.type) is c_ast.TypeDecl]<EOL>if with_init:<EOL><INDENT>random.seed(<NUM_LIT>)  <EOL>for d in scalar_declarations:<EOL><INDENT>if d.type.type.names[<NUM_LIT:0>] in ['<STR_LIT>', '<STR_LIT:float>']:<EOL><INDENT>d.init = c_ast.Constant('<STR_LIT:float>', str(random.uniform(<NUM_LIT:1.0>, <NUM_LIT:0.1>)))<EOL><DEDENT>elif d.type.type.names[<NUM_LIT:0>] in ['<STR_LIT:int>', '<STR_LIT>', '<STR_LIT>',<EOL>'<STR_LIT>', '<STR_LIT>', '<STR_LIT>']:<EOL><INDENT>d.init = c_ast.Constant('<STR_LIT:int>', <NUM_LIT:2>)<EOL><DEDENT><DEDENT><DEDENT>return scalar_declarations<EOL>

Build and return scalar variable declarations


def get_kernel_code(self, openmp=False, as_filename=False, name='<STR_LIT>'):

assert self.kernel_ast is not None, "<STR_LIT>""<STR_LIT>"<EOL>file_name = '<STR_LIT>'<EOL>if openmp:<EOL><INDENT>file_name += '<STR_LIT>'<EOL><DEDENT>file_name += '<STR_LIT>'<EOL>fp, already_available = self._get_intermediate_file(<EOL>file_name, machine_and_compiler_dependent=False)<EOL>if already_available:<EOL><INDENT>code = fp.read()<EOL><DEDENT>else:<EOL><INDENT>array_declarations, array_dimensions = self._build_array_declarations()<EOL>if openmp:<EOL><INDENT>kernel = deepcopy(self.get_kernel_loop_nest())<EOL>for aref in find_node_type(kernel, c_ast.ArrayRef):<EOL><INDENT>transform_multidim_to_1d_ref(aref, array_dimensions)<EOL><DEDENT>omp_pragmas = [p for p in find_node_type(kernel, c_ast.Pragma)<EOL>if '<STR_LIT>' in p.string]<EOL>if not omp_pragmas:<EOL><INDENT>kernel.insert(<NUM_LIT:0>, c_ast.Pragma("<STR_LIT>"))<EOL><DEDENT><DEDENT>else:<EOL><INDENT>kernel = deepcopy(self.get_kernel_loop_nest())<EOL>for aref in find_node_type(kernel, c_ast.ArrayRef):<EOL><INDENT>transform_multidim_to_1d_ref(aref, array_dimensions)<EOL><DEDENT><DEDENT>function_ast = c_ast.FuncDef(decl=c_ast.Decl(<EOL>name=name, type=self._build_kernel_function_declaration(name=name), quals=[],<EOL>storage=[], funcspec=[], init=None, bitsize=None),<EOL>body=c_ast.Compound(block_items=kernel),<EOL>param_decls=None)<EOL>code = CGenerator().visit(function_ast)<EOL>code = '<STR_LIT>' + code<EOL>fp.write(code)<EOL><DEDENT>fp.close()<EOL>if as_filename:<EOL><INDENT>return fp.name<EOL><DEDENT>else:<EOL><INDENT>return code<EOL><DEDENT>

Generate and return compilable source code with kernel function from AST.

:param openmp: if true, OpenMP code will be generated
:param as_filename: if true, will save to file and return filename
:param name: name of kernel function


return c_ast.FuncCall(name=c_ast.ID(name=name), args=c_ast.ExprList(exprs=[<EOL>c_ast.ID(name=d.name) for d in (<EOL>self._build_array_declarations()[<NUM_LIT:0>] +<EOL>self._build_scalar_declarations() +<EOL>self._build_const_declartions())]))<EOL>


def get_main_code(self, as_filename=False, kernel_function_name='<STR_LIT>'):

<EOL>assert self.kernel_ast is not None, "<STR_LIT>""<STR_LIT>"<EOL>fp, already_available = self._get_intermediate_file('<STR_LIT>',<EOL>machine_and_compiler_dependent=False)<EOL>if already_available:<EOL><INDENT>code = fp.read()<EOL><DEDENT>else:<EOL><INDENT>parser = CParser()<EOL>template_code = self.CODE_TEMPLATE<EOL>template_ast = parser.parse(clean_code(template_code,<EOL>macros=True, comments=True, pragmas=False))<EOL>ast = deepcopy(template_ast)<EOL>replace_id(ast, "<STR_LIT>", self._build_const_declartions(with_init=True))<EOL>array_declarations, array_dimensions = self._build_array_declarations()<EOL>replace_id(ast, "<STR_LIT>", array_declarations)<EOL>replace_id(ast, "<STR_LIT>", self._build_scalar_declarations())<EOL>replace_id(ast, "<STR_LIT>", self._build_dummy_calls())<EOL>ast.ext.insert(<NUM_LIT:0>, self._build_kernel_function_declaration(<EOL>name=kernel_function_name))<EOL>replace_id(ast, "<STR_LIT>", self._build_kernel_call())<EOL>replace_id(ast, "<STR_LIT>", self._build_array_initializations(array_dimensions))<EOL>code = CGenerator().visit(ast)<EOL>code = '<STR_LIT:\n>'.join([l for l in template_code.split('<STR_LIT:\n>') if l.startswith("<STR_LIT>")]) +'<STR_LIT>' + code<EOL>fp.write(code)<EOL><DEDENT>fp.close()<EOL>if as_filename:<EOL><INDENT>return fp.name<EOL><DEDENT>else:<EOL><INDENT>return code<EOL><DEDENT>

Generate and return compilable source code from AST.


def assemble_to_object(self, in_filename, verbose=False):

<EOL>file_base_name = os.path.splitext(os.path.basename(in_filename))[<NUM_LIT:0>]<EOL>out_filename, already_exists = self._get_intermediate_file(file_base_name + '<STR_LIT>',<EOL>binary=True,<EOL>fp=False)<EOL>if already_exists:<EOL><INDENT>pass<EOL><DEDENT>compiler, compiler_args = self._machine.get_compiler()<EOL>compiler_args.append('<STR_LIT:-c>')<EOL>cmd = [compiler] + [<EOL>in_filename] +compiler_args + ['<STR_LIT>', out_filename]<EOL>if verbose:<EOL><INDENT>print('<STR_LIT>', '<STR_LIT:U+0020>'.join(cmd))<EOL><DEDENT>try:<EOL><INDENT>subprocess.check_output(cmd)<EOL><DEDENT>except subprocess.CalledProcessError as e:<EOL><INDENT>print("<STR_LIT>", e, file=sys.stderr)<EOL>sys.exit(<NUM_LIT:1>)<EOL><DEDENT>return out_filename<EOL>

Assemble *in_filename* assembly into *out_filename* object.

If *iaca_marked* is set to true, markers are inserted around the block with most packed
instructions or (if no packed instr. were found) the largest block and modified file is
saved to *in_file*.

*asm_block* controls how the to-be-marked block is chosen. "auto" (default) results in
the largest block, "manual" results in interactive and a number in the according block.

*pointer_increment* is the number of bytes the pointer is incremented after the loop or
   - 'auto': automatic detection, RuntimeError is raised in case of failure
   - 'auto_with_manual_fallback': automatic detection, fallback to manual input
   - 'manual': prompt user

Returns two-tuple (filepointer, filename) to temp binary file.


def compile_kernel(self, openmp=False, assembly=False, verbose=False):

compiler, compiler_args = self._machine.get_compiler()<EOL>in_filename = self.get_kernel_code(openmp=openmp, as_filename=True)<EOL>if assembly:<EOL><INDENT>compiler_args += ['<STR_LIT>']<EOL>suffix = '<STR_LIT>'<EOL><DEDENT>else:<EOL><INDENT>suffix = '<STR_LIT>'<EOL><DEDENT>out_filename, already_exists = self._get_intermediate_file(<EOL>os.path.splitext(os.path.basename(in_filename))[<NUM_LIT:0>]+suffix, binary=not assembly, fp=False)<EOL>if already_exists:<EOL><INDENT>if verbose:<EOL><INDENT>print('<STR_LIT>', '<STR_LIT>', out_filename)<EOL><DEDENT>return out_filename<EOL><DEDENT>compiler_args += ['<STR_LIT>']<EOL>cmd = ([compiler] +<EOL>[in_filename,<EOL>'<STR_LIT:-c>',<EOL>'<STR_LIT>'+reduce_path(os.path.abspath(os.path.dirname(<EOL>os.path.realpath(__file__)))+'<STR_LIT>'),<EOL>'<STR_LIT>', out_filename] +<EOL>compiler_args)<EOL>if verbose:<EOL><INDENT>print('<STR_LIT>', '<STR_LIT:U+0020>'.join(cmd))<EOL><DEDENT>try:<EOL><INDENT>subprocess.check_output(cmd)<EOL><DEDENT>except subprocess.CalledProcessError as e:<EOL><INDENT>print("<STR_LIT>", e, file=sys.stderr)<EOL>sys.exit(<NUM_LIT:1>)<EOL><DEDENT>if compiler == '<STR_LIT>' and assembly:<EOL><INDENT>with open(out_filename, '<STR_LIT>') as f:<EOL><INDENT>assembly = f.read()<EOL>f.seek(<NUM_LIT:0>)<EOL>f.write(assembly.replace('<STR_LIT>', '<STR_LIT>'))<EOL>f.truncate()<EOL><DEDENT><DEDENT>return out_filename<EOL>

Compile source (from as_code(type_)) to assembly or object and return (fileptr, filename).

Output can be used with Kernel.assemble()


def iaca_analysis(self, micro_architecture, asm_block='<STR_LIT>',<EOL>pointer_increment='<STR_LIT>', verbose=False):

asm_filename = self.compile_kernel(assembly=True, verbose=verbose)<EOL>asm_marked_filename = os.path.splitext(asm_filename)[<NUM_LIT:0>]+'<STR_LIT>'<EOL>with open(asm_filename, '<STR_LIT:r>') as in_file, open(asm_marked_filename, '<STR_LIT:w>') as out_file:<EOL><INDENT>self.asm_block = iaca.iaca_instrumentation(<EOL>in_file, out_file,<EOL>block_selection=asm_block,<EOL>pointer_increment=pointer_increment)<EOL><DEDENT>obj_name = self.assemble_to_object(asm_marked_filename, verbose=verbose)<EOL>return iaca.iaca_analyse_instrumented_binary(obj_name, micro_architecture), self.asm_block<EOL>

Run an IACA analysis and return its outcome.

*asm_block* controls how the to-be-marked block is chosen. "auto" (default) results in
the largest block, "manual" results in interactive and a number in the according block.

*pointer_increment* is the number of bytes the pointer is incremented after the loop or
   - 'auto': automatic detection, RuntimeError is raised in case of failure
   - 'auto_with_manual_fallback': automatic detection, fallback to manual input
   - 'manual': prompt user


def build_executable(self, lflags=None, verbose=False, openmp=False):

compiler, compiler_args = self._machine.get_compiler()<EOL>kernel_obj_filename = self.compile_kernel(openmp=openmp, verbose=verbose)<EOL>out_filename, already_exists = self._get_intermediate_file(<EOL>os.path.splitext(os.path.basename(kernel_obj_filename))[<NUM_LIT:0>], binary=True, fp=False)<EOL>if not already_exists:<EOL><INDENT>main_source_filename = self.get_main_code(as_filename=True)<EOL>if not (('<STR_LIT>' in os.environ or '<STR_LIT>' in os.environ) and<EOL>'<STR_LIT>' in os.environ):<EOL><INDENT>print('<STR_LIT>'<EOL>'<STR_LIT>',<EOL>file=sys.stderr)<EOL>sys.exit(<NUM_LIT:1>)<EOL><DEDENT>compiler_args += [<EOL>'<STR_LIT>',<EOL>'<STR_LIT>'+reduce_path(os.path.abspath(os.path.dirname(<EOL>os.path.realpath(__file__)))+'<STR_LIT>'),<EOL>os.environ.get('<STR_LIT>', '<STR_LIT>'),<EOL>os.environ.get('<STR_LIT>', '<STR_LIT>'),<EOL>'<STR_LIT>']<EOL>if os.environ.get('<STR_LIT>') == '<STR_LIT>':<EOL><INDENT>compiler_args = compiler_args[:-<NUM_LIT:1>]<EOL><DEDENT>if lflags is None:<EOL><INDENT>lflags = []<EOL><DEDENT>lflags += os.environ['<STR_LIT>'].split('<STR_LIT:U+0020>') + ['<STR_LIT>']<EOL>compiler_args += os.environ['<STR_LIT>'].split('<STR_LIT:U+0020>') + ['<STR_LIT>']<EOL>infiles = [reduce_path(os.path.abspath(os.path.dirname(<EOL>os.path.realpath(__file__)))+'<STR_LIT>'),<EOL>kernel_obj_filename, main_source_filename]<EOL>cmd = [compiler] + infiles + compiler_args + ['<STR_LIT>', out_filename]<EOL>cmd = list(filter(bool, cmd))<EOL>if verbose:<EOL><INDENT>print('<STR_LIT>', '<STR_LIT:U+0020>'.join(cmd))<EOL><DEDENT>try:<EOL><INDENT>subprocess.check_output(cmd)<EOL><DEDENT>except subprocess.CalledProcessError as e:<EOL><INDENT>print("<STR_LIT>", e, file=sys.stderr)<EOL>sys.exit(<NUM_LIT:1>)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>if verbose:<EOL><INDENT>print('<STR_LIT>', '<STR_LIT>', out_filename)<EOL><DEDENT><DEDENT>return out_filename<EOL>

Compile source to executable with likwid capabilities and return the executable name.


def __init__(self, description, machine=None):

super(KernelDescription, self).__init__(machine=machine)<EOL>self._loop_stack = list([<EOL>(l['<STR_LIT:index>'], self.string_to_sympy(l['<STR_LIT:start>']),<EOL>self.string_to_sympy(l['<STR_LIT>']), self.string_to_sympy(l['<STR_LIT>']))<EOL>for l in description['<STR_LIT>']<EOL>])<EOL>for var_name, v in description['<STR_LIT>'].items():<EOL><INDENT>self.set_variable(var_name, v['<STR_LIT:type>'], self.string_to_sympy(v['<STR_LIT>']))<EOL><DEDENT>self.datatype = list(self.variables.values())[<NUM_LIT:0>][<NUM_LIT:0>]<EOL>self.sources = {<EOL>var_name: set([self.string_to_sympy(idx) for idx in v])<EOL>for var_name, v in description['<STR_LIT>'].items()<EOL>}<EOL>self.destinations = {<EOL>var_name: set([self.string_to_sympy(idx) for idx in v])<EOL>for var_name, v in description['<STR_LIT>'].items()<EOL>}<EOL>self._flops = description['<STR_LIT>']<EOL>self.check()<EOL>

Create kernel representation from a description dictionary.

:param description: must have a dictionary like interface (e.g., a YAML object).


if isinstance(s, int):<EOL><INDENT>return sympy.Integer(s)<EOL><DEDENT>elif isinstance(s, list):<EOL><INDENT>return tuple([cls.string_to_sympy(e) for e in s])<EOL><DEDENT>elif s is None:<EOL><INDENT>return None<EOL><DEDENT>else:<EOL><INDENT>local_dict = {c: symbol_pos_int(c) for c in s if c in string.ascii_letters}<EOL>preliminary_expr = parse_expr(s, local_dict=local_dict)<EOL>local_dict.update(<EOL>{s.name: symbol_pos_int(s.name) for s in preliminary_expr.free_symbols})<EOL>return parse_expr(s, local_dict=local_dict)<EOL><DEDENT>

Convert any string to a sympy object or None.


for k, v in u.items():<EOL><INDENT>if isinstance(v, collections.Mapping):<EOL><INDENT>r = update(d.get(k, {}), v)<EOL>d[k] = r<EOL><DEDENT>else:<EOL><INDENT>d[k] = u[k]<EOL><DEDENT><DEDENT>return d<EOL>

Update dictionary recursivly.

Origin: http://stackoverflow.com/a/3233356/2754040


parser = argparse.ArgumentParser(<EOL>description='<STR_LIT>'<EOL>'<STR_LIT>')<EOL>parser.add_argument('<STR_LIT>', type=argparse.FileType('<STR_LIT>'),<EOL>help='<STR_LIT>')<EOL>parser.add_argument('<STR_LIT:source>', type=argparse.FileType('<STR_LIT:rb>'), nargs='<STR_LIT:+>',<EOL>help='<STR_LIT>')<EOL>args = parser.parse_args()<EOL>result = pickle.load(args.destination)<EOL>assert isinstance(result, collections.Mapping), "<STR_LIT>"<EOL>for s in args.source:<EOL><INDENT>data = pickle.load(s)<EOL>assert isinstance(data, collections.Mapping), "<STR_LIT>"<EOL>update(result, data)<EOL><DEDENT>args.destination.seek(<NUM_LIT:0>)<EOL>args.destination.truncate()<EOL>pickle.dump(result, args.destination)<EOL>


def simulate(kernel, model, define_dict, blocking_constant, blocking_length):

kernel.clear_state()<EOL>for k, v in define_dict.items():<EOL><INDENT>kernel.set_constant(k, v)<EOL><DEDENT>kernel.set_constant(blocking_constant, blocking_length)<EOL>model.analyze()<EOL>return sum([cy for dscr, cy in model.results['<STR_LIT>']])<EOL>

Setup and execute model with given blocking length


operating_system = get_os()<EOL>return [os.path.expanduser("<STR_LIT>".format(operating_system)),<EOL>os.path.abspath(os.path.dirname(os.path.realpath(__file__))) + '<STR_LIT>'.format(<EOL>operating_system)]<EOL>

Return potential locations of IACA installation.


requires = ['<STR_LIT>', '<STR_LIT>', '<STR_LIT>']<EOL>for path in serach_path():<EOL><INDENT>path += '<STR_LIT>'<EOL>valid = True<EOL>for r in requires:<EOL><INDENT>if not os.path.exists(path + r):<EOL><INDENT>valid = False<EOL>break<EOL><DEDENT><DEDENT>if valid:<EOL><INDENT>return path<EOL><DEDENT><DEDENT>raise RuntimeError("<STR_LIT>"<EOL>"<STR_LIT>".format(serach_path()))<EOL>

Return (hopefully) valid installation of IACA.


def measure_bw(type_, total_size, threads_per_core, max_threads_per_core, cores_per_socket,<EOL>sockets):

groups = []<EOL>for s in range(sockets):<EOL><INDENT>groups += [<EOL>'<STR_LIT>',<EOL>'<STR_LIT:S>' + str(s) + '<STR_LIT::>' + str(total_size) + '<STR_LIT>' +<EOL>str(threads_per_core * cores_per_socket) +<EOL>'<STR_LIT>' + str(int(max_threads_per_core / threads_per_core))]<EOL><DEDENT>cmd = ['<STR_LIT>', '<STR_LIT>', type_] + groups<EOL>sys.stderr.write('<STR_LIT:U+0020>'.join(cmd))<EOL>output = subprocess.Popen(cmd, stdout=subprocess.PIPE).communicate()[<NUM_LIT:0>].decode('<STR_LIT:utf-8>')<EOL>if not output:<EOL><INDENT>print('<STR_LIT:U+0020>'.join(cmd) + '<STR_LIT>'<EOL>'<STR_LIT>', file=sys.stderr)<EOL>sys.exit(<NUM_LIT:1>)<EOL><DEDENT>bw = float(get_match_or_break(r'<STR_LIT>', output)[<NUM_LIT:0>])<EOL>print('<STR_LIT:U+0020>', PrefixedUnit(bw, '<STR_LIT>'), file=sys.stderr)<EOL>return PrefixedUnit(bw, '<STR_LIT>')<EOL>


import os<EOL>return os.path.abspath(os.path.dirname(os.path.realpath(__file__))) + '<STR_LIT>'<EOL>

Return local folder path of header files.


asm_stripped = []<EOL>for line in asm_lines:<EOL><INDENT>asm_stripped.append(line.split('<STR_LIT:#>')[<NUM_LIT:0>].strip())<EOL><DEDENT>return asm_stripped<EOL>

Strip whitespaces and comments from asm lines.


asm_stripped = []<EOL>for line in asm_lines:<EOL><INDENT>if re.match(r'<STR_LIT>', line):<EOL><INDENT>label = line[<NUM_LIT:0>:line.find('<STR_LIT::>')]<EOL>if not any([re.match(r'<STR_LIT>' + re.escape(label) + '<STR_LIT>', l) for l in asm_lines]):<EOL><INDENT>line = '<STR_LIT>'<EOL><DEDENT><DEDENT>asm_stripped.append(line)<EOL><DEDENT>return asm_stripped<EOL>

Strip all labels, which are never referenced.


blocks = []<EOL>last_labels = OrderedDict()<EOL>packed_ctr = <NUM_LIT:0><EOL>avx_ctr = <NUM_LIT:0><EOL>xmm_references = []<EOL>ymm_references = []<EOL>zmm_references = []<EOL>gp_references = []<EOL>mem_references = []<EOL>increments = {}<EOL>for i, line in enumerate(asm_lines):<EOL><INDENT>zmm_references += re.findall('<STR_LIT>', line)<EOL>ymm_references += re.findall('<STR_LIT>', line)<EOL>xmm_references += re.findall('<STR_LIT>', line)<EOL>gp_references += re.findall('<STR_LIT>', line)<EOL>if re.search(r'<STR_LIT>', line):<EOL><INDENT>m = re.search(r'<STR_LIT>'<EOL>r'<STR_LIT>',<EOL>line)<EOL>mem_references.append((<EOL>int(m.group('<STR_LIT>')) if m.group('<STR_LIT>') else <NUM_LIT:0>,<EOL>m.group('<STR_LIT>'),<EOL>m.group('<STR_LIT>'),<EOL>int(m.group('<STR_LIT>')) if m.group('<STR_LIT>') else <NUM_LIT:1>,<EOL>'<STR_LIT>' if m.group('<STR_LIT>') is None else '<STR_LIT:store>'))<EOL><DEDENT>if re.match(r"<STR_LIT>", line):<EOL><INDENT>if line.startswith('<STR_LIT:v>'):<EOL><INDENT>avx_ctr += <NUM_LIT:1><EOL><DEDENT>packed_ctr += <NUM_LIT:1><EOL><DEDENT>elif re.match(r'<STR_LIT>', line):<EOL><INDENT>last_labels[line[<NUM_LIT:0>:line.find('<STR_LIT::>')]] =i<EOL>packed_ctr = <NUM_LIT:0><EOL>avx_ctr = <NUM_LIT:0><EOL>xmm_references = []<EOL>ymm_references = []<EOL>zmm_references = []<EOL>gp_references = []<EOL>mem_references = []<EOL>increments = {}<EOL><DEDENT>elif re.match(r'<STR_LIT>', line):<EOL><INDENT>reg_start = line.find('<STR_LIT:%>') + <NUM_LIT:1><EOL>increments[line[reg_start:]] = <NUM_LIT:1><EOL><DEDENT>elif re.match(r'<STR_LIT>', line):<EOL><INDENT>const_start = line.find('<STR_LIT:$>') + <NUM_LIT:1><EOL>const_end = line[const_start + <NUM_LIT:1>:].find('<STR_LIT:U+002C>') + const_start + <NUM_LIT:1><EOL>reg_start = line.find('<STR_LIT:%>') + <NUM_LIT:1><EOL>increments[line[reg_start:]] = int(line[const_start:const_end])<EOL><DEDENT>elif re.match(r'<STR_LIT>', line):<EOL><INDENT>reg_start = line.find('<STR_LIT:%>') + <NUM_LIT:1><EOL>increments[line[reg_start:]] = -<NUM_LIT:1><EOL><DEDENT>elif re.match(r'<STR_LIT>', line):<EOL><INDENT>const_start = line.find('<STR_LIT:$>') + <NUM_LIT:1><EOL>const_end = line[const_start + <NUM_LIT:1>:].find('<STR_LIT:U+002C>') + const_start + <NUM_LIT:1><EOL>reg_start = line.find('<STR_LIT:%>') + <NUM_LIT:1><EOL>increments[line[reg_start:]] = -int(line[const_start:const_end])<EOL><DEDENT>elif last_labels and re.match(r'<STR_LIT>', line):<EOL><INDENT>last_label = None<EOL>last_label_line = -<NUM_LIT:1><EOL>for label_name, label_line in last_labels.items():<EOL><INDENT>if re.match(r'<STR_LIT>' + re.escape(label_name) + r'<STR_LIT>', line):<EOL><INDENT>last_label = label_name<EOL>last_label_line = label_line<EOL><DEDENT><DEDENT>labels = list(last_labels.keys())<EOL>if last_label:<EOL><INDENT>pointer_increment = None  <EOL>possible_idx_regs = None<EOL>if mem_references:<EOL><INDENT>store_references = [mref for mref in mem_references<EOL>if mref[<NUM_LIT:4>] == '<STR_LIT:store>']<EOL>refs = store_references or mem_references<EOL>possible_idx_regs = list(set(increments.keys()).intersection(<EOL>set([r[<NUM_LIT:1>] for r in refs if r[<NUM_LIT:1>] is not None] +<EOL>[r[<NUM_LIT:2>] for r in refs if r[<NUM_LIT:2>] is not None])))<EOL>for mref in refs:<EOL><INDENT>for reg in list(possible_idx_regs):<EOL><INDENT>if None not in mref[<NUM_LIT:1>:<NUM_LIT:3>]:<EOL><INDENT>if not (reg == mref[<NUM_LIT:1>] or reg == mref[<NUM_LIT:2>]):<EOL><INDENT>possible_idx_regs.remove(reg)<EOL><DEDENT><DEDENT><DEDENT><DEDENT>idx_reg = None<EOL>if len(possible_idx_regs) == <NUM_LIT:1>:<EOL><INDENT>idx_reg = possible_idx_regs[<NUM_LIT:0>]<EOL><DEDENT>elif possible_idx_regs and itemsEqual([increments[pidxreg]<EOL>for pidxreg in possible_idx_regs]):<EOL><INDENT>idx_reg = possible_idx_regs[<NUM_LIT:0>]<EOL><DEDENT>if idx_reg:<EOL><INDENT>mem_scales = [mref[<NUM_LIT:3>] for mref in refs<EOL>if idx_reg == mref[<NUM_LIT:2>] or idx_reg == mref[<NUM_LIT:1>]]<EOL>if itemsEqual(mem_scales):<EOL><INDENT>try:<EOL><INDENT>pointer_increment = mem_scales[<NUM_LIT:0>] * increments[idx_reg]<EOL><DEDENT>except:<EOL><INDENT>print("<STR_LIT>", pformat(labels[labels.index(last_label):]))<EOL>print("<STR_LIT>", pformat(asm_lines[last_label_line:i + <NUM_LIT:1>]))<EOL>print("<STR_LIT>", increments)<EOL>print("<STR_LIT>", pformat(mem_references))<EOL>print("<STR_LIT>", idx_reg)<EOL>print("<STR_LIT>", mem_scales)<EOL>raise<EOL><DEDENT><DEDENT><DEDENT><DEDENT>blocks.append({'<STR_LIT>': last_label_line,<EOL>'<STR_LIT>': i,<EOL>'<STR_LIT>': i - last_label_line,<EOL>'<STR_LIT>': labels[labels.index(last_label):],<EOL>'<STR_LIT>': packed_ctr,<EOL>'<STR_LIT>': avx_ctr,<EOL>'<STR_LIT>': (len(xmm_references), len(set(xmm_references))),<EOL>'<STR_LIT>': (len(ymm_references), len(set(ymm_references))),<EOL>'<STR_LIT>': (len(zmm_references), len(set(zmm_references))),<EOL>'<STR_LIT>': (len(gp_references), len(set(gp_references))),<EOL>'<STR_LIT>': (len(xmm_references) + len(ymm_references) +<EOL>len(zmm_references) + len(gp_references),<EOL>len(set(xmm_references)) + len(set(ymm_references)) +<EOL>len(set(zmm_references)) +<EOL>len(set(gp_references))),<EOL>'<STR_LIT>': pointer_increment,<EOL>'<STR_LIT>': asm_lines[last_label_line:i + <NUM_LIT:1>],<EOL>'<STR_LIT>': possible_idx_regs,<EOL>'<STR_LIT>': mem_references,<EOL>'<STR_LIT>': increments, })<EOL><DEDENT>packed_ctr = <NUM_LIT:0><EOL>avx_ctr = <NUM_LIT:0><EOL>xmm_references = []<EOL>ymm_references = []<EOL>zmm_references = []<EOL>gp_references = []<EOL>mem_references = []<EOL>increments = {}<EOL>last_labels = OrderedDict()<EOL><DEDENT><DEDENT>return list(enumerate(blocks))<EOL>

Find blocks probably corresponding to loops in assembly.


<EOL>if not blocks:<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>best_block = max(blocks, key=lambda b: b[<NUM_LIT:1>]['<STR_LIT>'])<EOL>if best_block[<NUM_LIT:1>]['<STR_LIT>'] == <NUM_LIT:0>:<EOL><INDENT>best_block = max(blocks,<EOL>key=lambda b: (b[<NUM_LIT:1>]['<STR_LIT>'] + b[<NUM_LIT:1>]['<STR_LIT>'] + b[<NUM_LIT:1>]['<STR_LIT>'],<EOL>b[<NUM_LIT:1>]['<STR_LIT>'], b[<NUM_LIT:1>]['<STR_LIT>'], b[<NUM_LIT:1>]['<STR_LIT>']))<EOL><DEDENT>return best_block[<NUM_LIT:0>]<EOL>

Return best block selected based on simple heuristic.


print("<STR_LIT>")<EOL>print('<STR_LIT>' + ('<STR_LIT>'.join(block['<STR_LIT>'])))<EOL>print()<EOL>increment = None<EOL>while increment is None:<EOL><INDENT>increment = input("<STR_LIT>")<EOL>try:<EOL><INDENT>increment = int(increment)<EOL><DEDENT>except ValueError:<EOL><INDENT>increment = None<EOL><DEDENT><DEDENT>block['<STR_LIT>'] = increment<EOL>return increment<EOL>

Let user interactively select byte increment.


def userselect_block(blocks, default=None, debug=False):

print("<STR_LIT>")<EOL>print("<STR_LIT>"<EOL>"<STR_LIT>")<EOL>for idx, b in blocks:<EOL><INDENT>print('<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'.format(idx, b=b))<EOL>if debug:<EOL><INDENT>ln = b['<STR_LIT>']<EOL>print('<STR_LIT:U+0020>'*<NUM_LIT:4> + '<STR_LIT>')<EOL>for l in b['<STR_LIT>']:<EOL><INDENT>print('<STR_LIT:U+0020>'*<NUM_LIT:8> + '<STR_LIT>'.format(ln, l))<EOL>ln += <NUM_LIT:1><EOL><DEDENT>print('<STR_LIT:U+0020>'*<NUM_LIT:4> + '<STR_LIT>')<EOL>print(textwrap.indent(<EOL>pformat({k: v for k,v in b.items() if k not in ['<STR_LIT>']}),<EOL>'<STR_LIT:U+0020>'*<NUM_LIT:8>))<EOL><DEDENT><DEDENT>block_idx = -<NUM_LIT:1><EOL>while not (<NUM_LIT:0> <= block_idx < len(blocks)):<EOL><INDENT>block_idx = input("<STR_LIT>" + str(default) + "<STR_LIT>") or default<EOL>try:<EOL><INDENT>block_idx = int(block_idx)<EOL><DEDENT>except ValueError:<EOL><INDENT>block_idx = -<NUM_LIT:1><EOL><DEDENT><DEDENT>return block_idx<EOL>


def insert_markers(asm_lines, start_line, end_line):

asm_lines = (asm_lines[:start_line] + START_MARKER +<EOL>asm_lines[start_line:end_line + <NUM_LIT:1>] + END_MARKER +<EOL>asm_lines[end_line + <NUM_LIT:1>:])<EOL>return asm_lines<EOL>

Insert IACA marker into list of ASM instructions at given indices.


assembly_orig = input_file.readlines()<EOL>if input_file is output_file:<EOL><INDENT>output_file.seek(<NUM_LIT:0>)<EOL>output_file.truncate()<EOL><DEDENT>if debug:<EOL><INDENT>block_selection = '<STR_LIT>'<EOL><DEDENT>assembly = strip_and_uncomment(copy(assembly_orig))<EOL>assembly = strip_unreferenced_labels(assembly)<EOL>blocks = find_asm_blocks(assembly)<EOL>if block_selection == '<STR_LIT>':<EOL><INDENT>block_idx = select_best_block(blocks)<EOL><DEDENT>elif block_selection == '<STR_LIT>':<EOL><INDENT>block_idx = userselect_block(blocks, default=select_best_block(blocks), debug=debug)<EOL><DEDENT>elif isinstance(block_selection, int):<EOL><INDENT>block_idx = block_selection<EOL><DEDENT>else:<EOL><INDENT>raise ValueError("<STR_LIT>")<EOL><DEDENT>block = blocks[block_idx][<NUM_LIT:1>]<EOL>if pointer_increment == '<STR_LIT>':<EOL><INDENT>if block['<STR_LIT>'] is None:<EOL><INDENT>raise RuntimeError("<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>")<EOL><DEDENT><DEDENT>elif pointer_increment == '<STR_LIT>':<EOL><INDENT>if block['<STR_LIT>'] is None:<EOL><INDENT>block['<STR_LIT>'] = userselect_increment(block)<EOL><DEDENT><DEDENT>elif pointer_increment == '<STR_LIT>':<EOL><INDENT>block['<STR_LIT>'] = userselect_increment(block)<EOL><DEDENT>elif isinstance(pointer_increment, int):<EOL><INDENT>block['<STR_LIT>'] = pointer_increment<EOL><DEDENT>else:<EOL><INDENT>raise ValueError("<STR_LIT>"<EOL>"<STR_LIT>")<EOL><DEDENT>instrumented_asm = insert_markers(assembly_orig, block['<STR_LIT>'], block['<STR_LIT>'])<EOL>output_file.writelines(instrumented_asm)<EOL>return block<EOL>

Add IACA markers to an assembly file.

If instrumentation fails because loop increment could not determined automatically, a ValueError
is raised.

:param input_file: file-like object to read from
:param output_file: file-like object to write to
:param block_selection: index of the assembly block to instrument, or 'auto' for automatically
                        using block with the
                        most vector instructions, or 'manual' to read index to prompt user
:param pointer_increment: number of bytes the pointer is incremented after the loop or
                          - 'auto': automatic detection, otherwise RuntimeError is raised
                          - 'auto_with_manual_fallback': like auto with fallback to manual input
                          - 'manual': prompt user
:param debug: output additional internal analysis information. Only works with manual selection.
:return: the instrumented assembly block


<EOL>arch_map = {<EOL>'<STR_LIT>': ('<STR_LIT>', '<STR_LIT>', ['<STR_LIT>']),<EOL>'<STR_LIT>': ('<STR_LIT>', '<STR_LIT>', ['<STR_LIT>']),<EOL>'<STR_LIT>': ('<STR_LIT>', '<STR_LIT>', ['<STR_LIT>']),<EOL>'<STR_LIT>': ('<STR_LIT>', '<STR_LIT>', ['<STR_LIT>']),<EOL>'<STR_LIT>': ('<STR_LIT>', '<STR_LIT>', []),<EOL>'<STR_LIT>': ('<STR_LIT>', '<STR_LIT>', []),<EOL>'<STR_LIT>': ('<STR_LIT>', '<STR_LIT>', []),<EOL>'<STR_LIT>': ('<STR_LIT>', '<STR_LIT>', []),<EOL>}<EOL>if micro_architecture not in arch_map:<EOL><INDENT>raise ValueError('<STR_LIT>'.format(<EOL>micro_architecture, '<STR_LIT:U+002CU+0020>'.join(arch_map.keys())))<EOL><DEDENT>iaca_path = iaca_get.find_iaca()  <EOL>os.environ['<STR_LIT>'] += '<STR_LIT::>' + iaca_path<EOL>iaca_exec, iaca_version, base_args = arch_map[micro_architecture]<EOL>if find_executable(iaca_exec) is None:<EOL><INDENT>raise RuntimeError("<STR_LIT>"<EOL>"<STR_LIT>".format(iaca_exec, iaca_path))<EOL><DEDENT>result = {}<EOL>cmd = [iaca_exec] + base_args + ['<STR_LIT>', micro_architecture, instrumented_binary_file]<EOL>try:<EOL><INDENT>iaca_output = subprocess.check_output(cmd).decode('<STR_LIT:utf-8>')<EOL>result['<STR_LIT>'] = iaca_output<EOL><DEDENT>except OSError as e:<EOL><INDENT>raise RuntimeError("<STR_LIT>" + '<STR_LIT:U+0020>'.join(cmd) + '<STR_LIT:\n>' + str(e))<EOL><DEDENT>except subprocess.CalledProcessError as e:<EOL><INDENT>raise RuntimeError("<STR_LIT>" + str(e))<EOL><DEDENT>match = re.search(r'<STR_LIT>', iaca_output, re.MULTILINE)<EOL>assert match, "<STR_LIT>"<EOL>throughput = float(match.groups()[<NUM_LIT:0>])<EOL>result['<STR_LIT>'] = throughput<EOL>ports = [l for l in iaca_output.split('<STR_LIT:\n>') if l.startswith('<STR_LIT>')]<EOL>cycles = [l for l in iaca_output.split('<STR_LIT:\n>') if l.startswith('<STR_LIT>')]<EOL>assert ports and cycles, "<STR_LIT>"<EOL>ports = [p.strip() for p in ports[<NUM_LIT:0>].split('<STR_LIT:|>')][<NUM_LIT:2>:]<EOL>cycles = [c.strip() for c in cycles[<NUM_LIT:0>].split('<STR_LIT:|>')][<NUM_LIT:2>:]<EOL>port_cycles = []<EOL>for i in range(len(ports)):<EOL><INDENT>if '<STR_LIT:->' in ports[i] and '<STR_LIT:U+0020>' in cycles[i]:<EOL><INDENT>subports = [p.strip() for p in ports[i].split('<STR_LIT:->')]<EOL>subcycles = [c for c in cycles[i].split('<STR_LIT:U+0020>') if bool(c)]<EOL>port_cycles.append((subports[<NUM_LIT:0>], float(subcycles[<NUM_LIT:0>])))<EOL>port_cycles.append((subports[<NUM_LIT:0>] + subports[<NUM_LIT:1>], float(subcycles[<NUM_LIT:1>])))<EOL><DEDENT>elif ports[i] and cycles[i]:<EOL><INDENT>port_cycles.append((ports[i], float(cycles[i])))<EOL><DEDENT><DEDENT>result['<STR_LIT>'] = dict(port_cycles)<EOL>match = re.search(r'<STR_LIT>', iaca_output, re.MULTILINE)<EOL>assert match, "<STR_LIT>"<EOL>result['<STR_LIT>'] = float(match.groups()[<NUM_LIT:0>])<EOL>return result<EOL>

Run IACA analysis on an instrumented binary.

:param instrumented_binary_file: path of binary that was built with IACA markers
:param micro_architecture: micro architecture string as taken by IACA.
                           one of: NHM, WSM, SNB, IVB, HSW, BDW
:return: a dictionary with the following keys:
    - 'output': the output of the iaca executable
    - 'throughput': the block throughput in cycles for one possibly vectorized loop iteration
    - 'port cycles': dict, mapping port name to number of active cycles
    - 'uops': total number of Uops


parser = argparse.ArgumentParser(<EOL>description='<STR_LIT>',<EOL>epilog='<STR_LIT>'<EOL>'<STR_LIT>')<EOL>parser.add_argument('<STR_LIT>', action='<STR_LIT:version>', version='<STR_LIT>'.format(__version__))<EOL>parser.add_argument('<STR_LIT:source>', type=argparse.FileType(), nargs='<STR_LIT:?>', default=sys.stdin,<EOL>help='<STR_LIT>')<EOL>parser.add_argument('<STR_LIT>', '<STR_LIT>', type=argparse.FileType('<STR_LIT:w>'), nargs='<STR_LIT:?>',<EOL>default=sys.stdout, help='<STR_LIT>')<EOL>parser.add_argument('<STR_LIT>', action='<STR_LIT:store_true>',<EOL>help='<STR_LIT>')<EOL>args = parser.parse_args()<EOL>iaca_instrumentation(input_file=args.source, output_file=args.outfile,<EOL>block_selection='<STR_LIT>', pointer_increment=<NUM_LIT:1>, debug=args.debug)<EOL>


return re.subn('<STR_LIT>', '<STR_LIT:_>', name)[<NUM_LIT:0>]<EOL>

Sanitize all characters not matched to a symbol by sympy's parse_expr.

Based on same rules as used for python variables.


def __init__(self, path_to_yaml=None, machine_yaml=None, args=None):

if not path_to_yaml and not machine_yaml:<EOL><INDENT>raise ValueError('<STR_LIT>')<EOL><DEDENT>if path_to_yaml and machine_yaml:<EOL><INDENT>raise ValueError('<STR_LIT>')<EOL><DEDENT>self._path = path_to_yaml<EOL>self._data = machine_yaml<EOL>self._args = args<EOL>if path_to_yaml:<EOL><INDENT>with open(path_to_yaml, '<STR_LIT:r>') as f:<EOL><INDENT>self._data = ruamel.yaml.load(f, Loader=ruamel.yaml.Loader)<EOL><DEDENT><DEDENT>assert '<STR_LIT>' in self._data,"<STR_LIT>""<STR_LIT>"<EOL>file_version = LooseVersion(self._data['<STR_LIT>'])<EOL>if not (MIN_SUPPORTED_VERSION <= file_version<EOL><= LooseVersion(__version__)):<EOL><INDENT>print("<STR_LIT>")<EOL>print('<STR_LIT:\n>'.join(['<STR_LIT>'.format(version, help_text)<EOL>for version, help_text in CHANGES_SINCE.items()<EOL>if LooseVersion(version) > file_version]))<EOL>raise ValueError("<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>".format(<EOL>MIN_SUPPORTED_VERSION, __version__))<EOL><DEDENT>

Create machine representation from yaml file.


return self._data[key]<EOL>


return '<STR_LIT>'.format(<EOL>self.__class__.__name__,<EOL>repr(self._path or self._data['<STR_LIT>']),<EOL>)<EOL>


if self._path:<EOL><INDENT>return os.path.basename(self._path)<EOL><DEDENT>else:<EOL><INDENT>return hashlib.sha256(hashlib.sha256(repr(self._data).encode())).hexdigest()<EOL><DEDENT>

Return identifier which is either the machine file name or sha256 checksum of data.


if self._path:<EOL><INDENT>statbuf = os.stat(self._path)<EOL>return datetime.utcfromtimestamp(statbuf.st_mtime)<EOL><DEDENT>else:<EOL><INDENT>return datetime.now()<EOL><DEDENT>

Return datetime object of modified time of machine file. Return now if not a file.


cache_dict = {}<EOL>for c in self['<STR_LIT>']:<EOL><INDENT>if '<STR_LIT>' not in c:<EOL><INDENT>continue<EOL><DEDENT>cache_dict[c['<STR_LIT>']] = deepcopy(c['<STR_LIT>'])<EOL>if c['<STR_LIT>'] > <NUM_LIT:1>:<EOL><INDENT>cache_dict[c['<STR_LIT>']]['<STR_LIT>'] //= cores<EOL><DEDENT><DEDENT>cs, caches, mem = cachesim.CacheSimulator.from_dict(cache_dict)<EOL>return cs<EOL>

Return a cachesim.CacheSimulator object based on the machine description.

:param cores: core count (default: 1)


def get_bandwidth(self, cache_level, read_streams, write_streams, threads_per_core, cores=None):

<EOL>try:<EOL><INDENT>target_ratio = read_streams/write_streams<EOL><DEDENT>except ZeroDivisionError:<EOL><INDENT>target_ratio = float('<STR_LIT>')<EOL><DEDENT>measurement_kernel = '<STR_LIT>'<EOL>measurement_kernel_info = self['<STR_LIT>']['<STR_LIT>'][measurement_kernel]<EOL>measurement_kernel_ratio = float('<STR_LIT>')<EOL>for kernel_name, kernel_info in sorted(self['<STR_LIT>']['<STR_LIT>'].items()):<EOL><INDENT>try:<EOL><INDENT>kernel_ratio = ((kernel_info['<STR_LIT>']['<STR_LIT>'] +<EOL>kernel_info['<STR_LIT>']['<STR_LIT>'] -<EOL>kernel_info['<STR_LIT>']['<STR_LIT>']) /<EOL>kernel_info['<STR_LIT>']['<STR_LIT>'])<EOL><DEDENT>except ZeroDivisionError:<EOL><INDENT>kernel_ratio = float('<STR_LIT>')<EOL><DEDENT>if abs(kernel_ratio - target_ratio) < abs(measurement_kernel_ratio - target_ratio):<EOL><INDENT>measurement_kernel = kernel_name<EOL>measurement_kernel_info = kernel_info<EOL>measurement_kernel_ratio = kernel_ratio<EOL><DEDENT><DEDENT>bw_level = self['<STR_LIT>'][cache_level]['<STR_LIT>']<EOL>bw_measurements =self['<STR_LIT>']['<STR_LIT>'][bw_level][threads_per_core]<EOL>assert threads_per_core == bw_measurements['<STR_LIT>'],'<STR_LIT>'<EOL>if cores is not None:<EOL><INDENT>run_index = bw_measurements['<STR_LIT>'].index(cores)<EOL>bw = bw_measurements['<STR_LIT>'][measurement_kernel][run_index]<EOL><DEDENT>else:<EOL><INDENT>max_cores = min(self['<STR_LIT>'][cache_level]['<STR_LIT>'],<EOL>self['<STR_LIT>'])<EOL>bw = max(bw_measurements['<STR_LIT>'][measurement_kernel][:max_cores])<EOL><DEDENT>if cache_level == <NUM_LIT:0>:<EOL><INDENT>factor = <NUM_LIT:1.0><EOL><DEDENT>else:<EOL><INDENT>factor = (float(measurement_kernel_info['<STR_LIT>']['<STR_LIT>']) +<EOL><NUM_LIT>*float(measurement_kernel_info['<STR_LIT>']['<STR_LIT>']) -<EOL>float(measurement_kernel_info['<STR_LIT>']['<STR_LIT>'])) /(float(measurement_kernel_info['<STR_LIT>']['<STR_LIT>']) +<EOL>float(measurement_kernel_info['<STR_LIT>']['<STR_LIT>']))<EOL><DEDENT>bw = bw * factor<EOL>return bw, measurement_kernel<EOL>

Return best fitting bandwidth according to number of threads, read and write streams.

:param cache_level: integer of cache (0 is L1, 1 is L2 ...)
:param read_streams: number of read streams expected
:param write_streams: number of write streams expected
:param threads_per_core: number of threads that are run on each core
:param cores: if not given, will choose maximum bandwidth for single NUMA domain


def get_compiler(self, compiler=None, flags=None):

if self._args:<EOL><INDENT>compiler = compiler or self._args.compiler<EOL>flags = flags or self._args.compiler_flags<EOL><DEDENT>if compiler is None:<EOL><INDENT>for c in self['<STR_LIT>'].keys():<EOL><INDENT>if find_executable(c) is not None:<EOL><INDENT>compiler = c<EOL>break<EOL><DEDENT><DEDENT>else:<EOL><INDENT>raise RuntimeError("<STR_LIT>"<EOL>"<STR_LIT>"<EOL>"<STR_LIT>".format(list(self['<STR_LIT>'].keys())))<EOL><DEDENT><DEDENT>if flags is None:<EOL><INDENT>flags = self['<STR_LIT>'].get(compiler, '<STR_LIT>')<EOL><DEDENT>return compiler, flags.split('<STR_LIT:U+0020>')<EOL>

Return tuple of compiler and compiler flags.

Selects compiler and flags from machine description file, commandline arguments or call
arguements.


split_perfctr = perfctr.split('<STR_LIT::>')<EOL>assert len(split_perfctr) >= <NUM_LIT:2>, "<STR_LIT>"<EOL>event_tuple = split_perfctr[:<NUM_LIT:2>]<EOL>parameters = {}<EOL>for p in split_perfctr[<NUM_LIT:2>:]:<EOL><INDENT>if '<STR_LIT:=>' in p:<EOL><INDENT>k, v = p.split('<STR_LIT:=>')<EOL>if v.startswith('<STR_LIT>'):<EOL><INDENT>parameters[k] = int(v, <NUM_LIT:16>)<EOL><DEDENT>else:<EOL><INDENT>parameters[k] = int(v)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>parameters[p] = None<EOL><DEDENT><DEDENT>event_tuple.append(parameters)<EOL>return tuple(event_tuple)<EOL>

Parse events in machine description to tuple representation used in Benchmark module.

Examples:
>>> parse_perfctr_event('PERF_EVENT:REG[0-3]')
('PERF_EVENT', 'REG[0-3]')
>>> parse_perfctr_event('PERF_EVENT:REG[0-3]:STAY:FOO=23:BAR=0x23')
('PERF_EVENT', 'REG[0-3]', {'STAY': None, 'FOO': 23, 'BAR': 35})


<EOL>perfcounters = re.findall(r'<STR_LIT>', metric)<EOL>temp_metric = metric<EOL>temp_pc_names = {"<STR_LIT>".format(re.sub("<STR_LIT>", "<STR_LIT:_>", pc)): pc<EOL>for i, pc in enumerate(perfcounters)}<EOL>for var_name, pc in temp_pc_names.items():<EOL><INDENT>temp_metric = temp_metric.replace(pc, var_name)<EOL><DEDENT>expr = parse_expr(temp_metric)<EOL>for s in expr.free_symbols:<EOL><INDENT>if s.name in temp_pc_names:<EOL><INDENT>s.name = temp_pc_names[str(s)]<EOL><DEDENT><DEDENT>events = {s: MachineModel.parse_perfctr_event(s.name) for s in expr.free_symbols<EOL>if s.name in perfcounters}<EOL>return expr, events<EOL>

Return (sympy expressions, event names and symbols dict) from performance metric str.


self.data = list(args)<EOL>if not kwargs.get('<STR_LIT>', False):<EOL><INDENT>self.data = [d for d in self.data if d[<NUM_LIT:1>] > d[<NUM_LIT:0>]]<EOL>self._enforce_order()<EOL>self._enforce_no_overlap()<EOL><DEDENT>

If keywords *sane* is True (default: False), checks will not be done on given data.


self.data.sort(key=lambda d: d[<NUM_LIT:0>])<EOL>

Enforce the order of all entries in internal storage.


i = start_at<EOL>while i+<NUM_LIT:1> < len(self.data):<EOL><INDENT>if self.data[i][<NUM_LIT:1>] >= self.data[i+<NUM_LIT:1>][<NUM_LIT:0>]:<EOL><INDENT>if self.data[i][<NUM_LIT:1>] < self.data[i+<NUM_LIT:1>][<NUM_LIT:1>]:<EOL><INDENT>self.data[i][<NUM_LIT:1>] = self.data[i+<NUM_LIT:1>][<NUM_LIT:1>]<EOL><DEDENT>del self.data[i+<NUM_LIT:1>]<EOL><DEDENT>i += <NUM_LIT:1><EOL><DEDENT>

Enforce that no ranges overlap in internal storage.


return Intervals(*(self.data+other.data))<EOL>

Combine two intervals, under the assumption that they are sane.


return int(sum(upper-lower for (lower, upper) in self.data))<EOL>


return any(lower <= needle < upper for (lower, upper) in self.data)<EOL>

Return True if needle is contained in intervals.


return str(self.__class__) + '<STR_LIT:(>' + '<STR_LIT:U+002CU+0020>'.join([list.__repr__(d) for d in self.data]) + '<STR_LIT:)>'<EOL>


return self.data == other.data<EOL>

Return True if other contains exactly the same interval regions.


ordered_chars = string.ascii_letters + string.digits<EOL>tokenizer = ('<STR_LIT>'<EOL>'<STR_LIT>')<EOL>for m in re.finditer(tokenizer, group):<EOL><INDENT>if m.group('<STR_LIT>'):<EOL><INDENT>start, sep, end = m.group('<STR_LIT>')<EOL>for i in range(ordered_chars.index(start), ordered_chars.index(end)+<NUM_LIT:1>):<EOL><INDENT>yield ordered_chars[i]<EOL><DEDENT><DEDENT>else:<EOL><INDENT>yield m.group('<STR_LIT>')<EOL><DEDENT><DEDENT>

Yild all groups of simple regex-like expression.

The only special character is a dash (-), which take the preceding and the following chars to
compute a range. If the range is non-sensical (e.g., b-a) it will be empty

Example:
>>> list(group_iterator('a-f'))
['a', 'b', 'c', 'd', 'e', 'f']
>>> list(group_iterator('148'))
['1', '4', '8']
>>> list(group_iterator('7-9ab'))
['7', '8', '9', 'a', 'b']
>>> list(group_iterator('0B-A1'))
['0', '1']


if not regdescr:<EOL><INDENT>yield None<EOL><DEDENT>tokenizer = ('<STR_LIT>'<EOL>'<STR_LIT>')<EOL>for u in regdescr.split('<STR_LIT:|>'):<EOL><INDENT>m = re.match(tokenizer, u)<EOL>if m.group('<STR_LIT>'):<EOL><INDENT>current = group_iterator(m.group('<STR_LIT>'))<EOL><DEDENT>else:<EOL><INDENT>current = [m.group('<STR_LIT>')]<EOL><DEDENT>for c in current:<EOL><INDENT>if u[m.end():]:<EOL><INDENT>for r in register_options(u[m.end():]):<EOL><INDENT>yield c + r<EOL><DEDENT><DEDENT>else:<EOL><INDENT>yield c<EOL><DEDENT><DEDENT><DEDENT>

Very reduced regular expressions for describing a group of registers.

Only groups in square bracktes and unions with pipes (|) are supported.

Examples:
>>> list(register_options('PMC[0-3]'))
['PMC0', 'PMC1', 'PMC2', 'PMC3']
>>> list(register_options('MBOX0C[01]'))
['MBOX0C0', 'MBOX0C1']
>>> list(register_options('CBOX2C1'))
['CBOX2C1']
>>> list(register_options('CBOX[0-3]C[01]'))
['CBOX0C0', 'CBOX0C1', 'CBOX1C0', 'CBOX1C1', 'CBOX2C0', 'CBOX2C1', 'CBOX3C0', 'CBOX3C1']
>>> list(register_options('PMC[0-1]|PMC[23]'))
['PMC0', 'PMC1', 'PMC2', 'PMC3']


def eventstr(event_tuple=None, event=None, register=None, parameters=None):

if len(event_tuple) == <NUM_LIT:3>:<EOL><INDENT>event, register, parameters = event_tuple<EOL><DEDENT>elif len(event_tuple) == <NUM_LIT:2>:<EOL><INDENT>event, register = event_tuple<EOL><DEDENT>event_dscr = [event, register]<EOL>if parameters:<EOL><INDENT>for k, v in sorted(event_tuple[<NUM_LIT:2>].items()):  <EOL><INDENT>if type(v) is int:<EOL><INDENT>k += "<STR_LIT>".format(hex(v))<EOL><DEDENT>event_dscr.append(k)<EOL><DEDENT><DEDENT>return "<STR_LIT::>".join(event_dscr)<EOL>

Return a LIKWID event string from an event tuple or keyword arguments.

*event_tuple* may have two or three arguments: (event, register) or
(event, register, parameters)

Keyword arguments will be overwritten by *event_tuple*.

>>> eventstr(('L1D_REPLACEMENT', 'PMC0', None))
'L1D_REPLACEMENT:PMC0'
>>> eventstr(('L1D_REPLACEMENT', 'PMC0'))
'L1D_REPLACEMENT:PMC0'
>>> eventstr(('MEM_UOPS_RETIRED_LOADS', 'PMC3', {'EDGEDETECT': None, 'THRESHOLD': 2342}))
'MEM_UOPS_RETIRED_LOADS:PMC3:EDGEDETECT:THRESHOLD=0x926'
>>> eventstr(event='DTLB_LOAD_MISSES_WALK_DURATION', register='PMC3')
'DTLB_LOAD_MISSES_WALK_DURATION:PMC3'


<EOL>events = [e for i, e in enumerate(events) if events.index(e) == i]<EOL>scheduled_runs = {}<EOL>scheduled_events = []<EOL>cur_run = <NUM_LIT:0><EOL>while len(scheduled_events) != len(events):<EOL><INDENT>for event_tpl in events:<EOL><INDENT>event, registers, parameters = event_tpl<EOL>if event_tpl in scheduled_events:<EOL><INDENT>continue<EOL><DEDENT>for possible_reg in register_options(registers):<EOL><INDENT>s = scheduled_runs.setdefault(cur_run, {})<EOL>if possible_reg not in s:<EOL><INDENT>s[possible_reg] = (event, possible_reg, parameters)<EOL>scheduled_events.append(event_tpl)<EOL>break<EOL><DEDENT><DEDENT><DEDENT>cur_run += <NUM_LIT:1><EOL><DEDENT>runs = [list(v.values()) for v in scheduled_runs.values()]<EOL>return runs<EOL>

Compile list of minimal runs for given events.


<EOL>app = Flask(__name__)<EOL>app.debug = True<EOL>app.testing = True<EOL>gw.receiver_blueprints_register(app, prefix='<STR_LIT>')<EOL>@app.route('<STR_LIT>', methods=['<STR_LIT:GET>','<STR_LIT:POST>'])<EOL>def kill():<EOL><INDENT>func = request.environ.get('<STR_LIT>')<EOL>if func is None:<EOL><INDENT>raise RuntimeError('<STR_LIT>')<EOL><DEDENT>func()<EOL>return '<STR_LIT>'<EOL><DEDENT>app.run('<STR_LIT>', port, threaded=False, use_reloader=False, passthrough_errors=True)<EOL>

:param gw: Gateway
:type gw: smsframework.Gateway.Gateway
:return:
:rtype:


def add_provider(self, name, Provider, **config):

assert issubclass(Provider, IProvider), '<STR_LIT>'<EOL>assert isinstance(name, str), '<STR_LIT>'<EOL>provider = Provider(self, name, **config)<EOL>assert name not in self._providers, '<STR_LIT>'<EOL>self._providers[name] = provider<EOL>if self.default_provider is None:<EOL><INDENT>self.default_provider = name<EOL><DEDENT>return provider<EOL>

Register a provider on the gateway

            The first provider defined becomes the default one: used in case the routing function has no better idea.

            :type name: str
            :param name: Provider name that will be used to uniquely identify it
            :type Provider: type
            :param Provider: Provider class that inherits from `smsframework.IProvider`
            :param config: Provider configuration. Please refer to the Provider documentation.
            :rtype: IProvider
            :returns: The created provider


return self._default_provider<EOL>

Default provider name

            :rtype: str | None


return self._providers[name]<EOL>

Get a provider by name

            You don't normally need this, unless the provider has some public API:
            refer to the provider documentation for the details.

            :type name: str
            :param name: Provider name
            :rtype: IProvider
            :raises KeyError: provider not found


<EOL>return None<EOL>

Router function that decides which provider to use for the given message for sending.

            Replace it with a function of your choice for custom routing.

            :type message: data.OutgoingMessage
            :param message: The message being sent
            :type args: Message routing values, as specified with the OutgoingMessage.route
            :rtype: str | None
            :returns: Provider name to use, or None to use the default one


<EOL>provider_name = self._default_provider  <EOL>if message.provider is not None:<EOL><INDENT>assert message.provider in self._providers,'<STR_LIT>'.format(provider_name)<EOL>provider = self.get_provider(message.provider)<EOL><DEDENT>else:<EOL><INDENT>if message.routing_values is not None: <EOL><INDENT>provider_name = self.router(message, *message.routing_values) or self._default_provider<EOL>assert provider_name in self._providers,'<STR_LIT>'.format(provider_name)<EOL><DEDENT>provider = self.get_provider(provider_name)<EOL><DEDENT>message.provider = provider.name<EOL>message = provider.send(message)<EOL>self.onSend(message)<EOL>return message<EOL>

Send a message object

            :type message: data.OutgoingMessage
            :param message: The message to send
            :rtype: data.OutgoingMessage
            :returns: The sent message with populated fields
            :raises AssertionError: wrong provider name encountered (returned by the router, or provided to OutgoingMessage)
            :raises MessageSendError: generic errors
            :raises AuthError: provider authentication failed
            :raises LimitsError: sending limits exceeded
            :raises CreditError: not enough money on the account


<EOL>provider = self.get_provider(name)<EOL>bp = provider.make_receiver_blueprint()<EOL>from flask.globals import g  <EOL>@bp.before_request<EOL>def init_g():<EOL><INDENT>g.provider = provider<EOL><DEDENT>return bp<EOL>

Get a Flask blueprint for the named provider that handles incoming messages & status reports

            Note: this requires Flask microframework.

            :rtype: flask.blueprints.Blueprint
            :returns: Flask Blueprint, fully functional
            :raises KeyError: provider not found
            :raises NotImplementedError: Provider does not implement a receiver


blueprints = {}<EOL>for name in self._providers:<EOL><INDENT>try:<EOL><INDENT>blueprints[name] = self.receiver_blueprint_for(name)<EOL><DEDENT>except NotImplementedError:<EOL><INDENT>pass  <EOL><DEDENT><DEDENT>return blueprints<EOL>

Get Flask blueprints for every provider that supports it

            Note: this requires Flask microframework.

            :rtype: dict
            :returns: A dict { provider-name: Blueprint }


def receiver_blueprints_register(self, app, prefix='<STR_LIT:/>'):

<EOL>for name, bp in self.receiver_blueprints().items():<EOL><INDENT>app.register_blueprint(<EOL>bp,<EOL>url_prefix='<STR_LIT>'.format(<EOL>prefix='<STR_LIT:/>'+prefix.strip('<STR_LIT:/>')+'<STR_LIT:/>' if prefix else '<STR_LIT:/>',<EOL>name=name<EOL>)<EOL>)<EOL><DEDENT>return app<EOL>

Register all provider receivers on the provided Flask application under '/{prefix}/provider-name'

            Note: this requires Flask microframework.

            :type app: flask.Flask
            :param app: Flask app to register the blueprints on
            :type prefix: str
            :param prefix: URL prefix to hide the receivers under.
                You likely want some random stuff here so no stranger can simulate incoming messages.
            :rtype: flask.Flask


return re.sub(r'<STR_LIT>', '<STR_LIT>', num)<EOL>

Remove all non-digit characters from the phone number

        :type num: str
        :param num: Phone number
        :rtype: str


def __init__(self, gateway, name, **config):

self.gateway = gateway<EOL>self.name = name<EOL>

Initialize the provider

            :type gateway: Gateway
            :param gateway: Parent Gateway
            :type name: str
            :param name: Provider name. Used to uniquely identify the provider
            :param config: Provider-dependent configuration


raise NotImplementedError('<STR_LIT>')<EOL>

Send a message

            Providers are required to:
            * Populate `message.msgid` and `message.meta` on completion
            * Expect that `message.src` can be empty
            * Support both ASCII and Unicode messages
            * Use `message.params` for provider-dependent configuration
            * Raise exceptions from `exc.py` for errors

            :type message: data.OutgoingMessage
            :param message: The message to send
            :rtype: OutgoingMessage
            :returns: The sent message with populated fields
            :raises MessageSendError: sending errors


Get a Blueprint for the HTTP receiver

            :rtype: flask.Blueprint
            :returns: configured Flask Blueprint receiver
            :raises NotImplementedError: Provider does not support message reception


<EOL>message.provider = self.name<EOL>self.gateway.onReceive(message)<EOL>return message<EOL>

Incoming message callback

            Calls Gateway.onReceive event hook

            Providers are required to:
            * Cast phone numbers to digits-only
            * Support both ASCII and Unicode messages
            * Populate `message.msgid` and `message.meta` fields
            * If this method fails with an exception, the provider is required to respond with an error to the service

            :type message: IncomingMessage
            :param message: The received message
            :rtype: IncomingMessage


<EOL>status.provider = self.name<EOL>self.gateway.onStatus(status)<EOL>return status<EOL>

Incoming status callback

            Calls Gateway.onStatus event hook

            Providers are required to:
            * Cast phone numbers to digits-only
            * Use proper MessageStatus subclasses
            * Populate `status.msgid` and `status.meta` fields
            * If this method fails with an exception, the provider is required to respond with an error to the service

            :type status: MessageStatus
            :param status: The received status
            :rtype: MessageStatus


req = jsonex_loads(request.get_data())<EOL>message = g.provider._receive_message(req['<STR_LIT:message>'])<EOL>return {'<STR_LIT:message>': message}<EOL>

Incoming message handler: forwarded by ForwardServerProvider


req = jsonex_loads(request.get_data())<EOL>status = g.provider._receive_status(req['<STR_LIT:status>'])<EOL>return {'<STR_LIT:status>': status}<EOL>

Incoming status handler: forwarded by ForwardServerProvider


return json.dumps(data, cls=JsonExEncoder).encode()<EOL>

Serialize with JsonEx
    :rtype: basestring


return json.loads(s.decode('<STR_LIT:utf-8>'), cls=JsonExDecoder, classes=classes, exceptions=exceptions)<EOL>

Unserialize with JsonEx
    :rtype: dict


@wraps(f)<EOL>def wrapper(*args, **kwargs):<EOL><INDENT>try:<EOL><INDENT>code, res = <NUM_LIT:200>, f(*args, **kwargs)<EOL><DEDENT>except HTTPException as e:<EOL><INDENT>code, res = e.code, {'<STR_LIT:error>': e}<EOL><DEDENT>except Exception as e:<EOL><INDENT>code, res = <NUM_LIT>, {'<STR_LIT:error>': e}<EOL>logger.exception('<STR_LIT>')<EOL><DEDENT>response = make_response(jsonex_dumps(res), code)<EOL>response.headers['<STR_LIT:Content-Type>'] = '<STR_LIT:application/json>'<EOL>return response<EOL><DEDENT>return wrapper<EOL>

View wrapper for JsonEx responses. Catches exceptions as well


u = url<EOL>h = {}  <EOL>if url in _parse_authentication._memoize:<EOL><INDENT>u, h = _parse_authentication._memoize[url]<EOL><DEDENT>else:<EOL><INDENT>p = urlsplit(url, '<STR_LIT:http>')<EOL>if p.username and p.password:<EOL><INDENT>h['<STR_LIT>'] = b'<STR_LIT>' + base64.b64encode(p.username.encode() + b'<STR_LIT::>' + p.password.encode())<EOL>u = urlunsplit((p.scheme, p.netloc.split('<STR_LIT:@>', <NUM_LIT:1>)[<NUM_LIT:1>], p.path, p.query, p.fragment))<EOL><DEDENT>_parse_authentication._memoize[url] = (u, h)<EOL><DEDENT>return u, h<EOL>

Parse authentication data from the URL and put it in the `headers` dict. With caching behavior
    :param url: URL
    :type url: str
    :return: (URL without authentication info, headers dict)
    :rtype: str, dict


def jsonex_request(url, data, headers=None):

<EOL>url, headers = _parse_authentication(url)<EOL>headers['<STR_LIT:Content-Type>'] = '<STR_LIT:application/json>'<EOL>try:<EOL><INDENT>req = Request(url, headers=headers)<EOL>response = urlopen(req, jsonex_dumps(data))<EOL>res_str = response.read()<EOL>res = jsonex_loads(res_str)<EOL><DEDENT>except HTTPError as e:<EOL><INDENT>if '<STR_LIT:Content-Type>' in e.headers and e.headers['<STR_LIT:Content-Type>'] == '<STR_LIT:application/json>':<EOL><INDENT>res = jsonex_loads(e.read())<EOL><DEDENT>else:<EOL><INDENT>raise exc.ServerError('<STR_LIT>'.format(url, e))<EOL><DEDENT><DEDENT>except URLError as e:<EOL><INDENT>raise exc.ConnectionError('<STR_LIT>'.format(url, e))<EOL><DEDENT>if '<STR_LIT:error>' in res:  <EOL><INDENT>raise res['<STR_LIT:error>']  <EOL><DEDENT>return res<EOL>

Make a request with JsonEx
    :param url: URL
    :type url: str
    :param data: Data to POST
    :type data: dict
    :return: Response
    :rtype: dict
    :raises exc.ConnectionError: Connection error
    :raises exc.ServerError: Remote server error (unknown)
    :raises exc.ProviderError: any errors reported by the remote


def __init__(self, gateway, name, server_url):

self.server_url = server_url.rstrip('<STR_LIT:/>') + '<STR_LIT:/>'  <EOL>super(ForwardClientProvider, self).__init__(gateway, name)<EOL>

Init the forwarding client
        :param server_url: Server URL.
            The URL should point to ForwardServerProvider registered on the server
        :type server_url: str


res = jsonex_request(self.server_url + '<STR_LIT>'.lstrip('<STR_LIT:/>'), {'<STR_LIT:message>': message})<EOL>msg = res['<STR_LIT:message>']  <EOL>for k, v in msg.__dict__.items():<EOL><INDENT>setattr(message, k, v)<EOL><DEDENT>return message<EOL>

Send a message by forwarding it to the server
        :param message: Message
        :type message: smsframework.data.OutgoingMessage
        :rtype: smsframework.data.OutgoingMessage
        :raise Exception: any exception reported by the other side
        :raise urllib2.URLError: Connection error


from .receiver_client import bp<EOL>return bp<EOL>

Create the receiver so server can send messages to us
        :rtype: flask.Blueprint


def __init__(self, gateway, name, clients):

self.clients = clients<EOL>super(ForwardServerProvider, self).__init__(gateway, name)<EOL>self.gateway.onReceive += self.forward<EOL>self.gateway.onStatus += self.forward<EOL>

Init server
        :param clients: List of client URLs to forward the messages to.
            The URL should point to ForwardClientProvider registered on the client
        :type clients: list[str]


return self.clients<EOL>

Given a message, decides which clients will receive it.

        Override to have custom routing. Default: send to all clients

        :param obj: The object to be forwarded
        :type obj: smsframework.data.IncomingMessage|smsframework.data.MessageStatus
        :return: List of client URLs to forward the message to
        :rtype: list[str]


def _forward_object_to_client(self, client, obj):

url, name = ('<STR_LIT>', '<STR_LIT:message>') if isinstance(obj, IncomingMessage) else ('<STR_LIT>', '<STR_LIT:status>')<EOL>res = jsonex_request(client.rstrip('<STR_LIT:/>') + '<STR_LIT:/>' + url.lstrip('<STR_LIT:/>'), {name: obj})<EOL>return res[name]<EOL>

Forward an object to client
        :type client: str
        :type obj: smsframework.data.IncomingMessage|smsframework.data.MessageStatus
        :rtype: smsframework.data.IncomingMessage|smsframework.data.MessageStatus
        :raise Exception: any exception reported by the other side


assert isinstance(obj, (IncomingMessage, MessageStatus)), '<STR_LIT>'.format(obj)<EOL>clients = self.choose_clients(obj)<EOL>if Parallel:<EOL><INDENT>pll = Parallel(self._forward_object_to_client)<EOL>for client in clients:<EOL><INDENT>pll(client, obj)<EOL><DEDENT>results, errors = pll.join()<EOL>if errors:<EOL><INDENT>raise errors[<NUM_LIT:0>]<EOL><DEDENT><DEDENT>else:<EOL><INDENT>for client in clients:<EOL><INDENT>self._forward_object_to_client(client, obj)<EOL><DEDENT><DEDENT>

Forward an object to clients.

        :param obj: The object to be forwarded
        :type obj: smsframework.data.IncomingMessage|smsframework.data.MessageStatus
        :raises Exception: if any of the clients failed


message.provider = None  <EOL>return self.gateway.send(message)<EOL>

Send a message by looping back to gateway so it sends with some other provider
        :param message: Message
        :type message: data.OutgoingMessage
        :rtype: data.OutgoingMessage


from .receiver_server import bp<EOL>return bp<EOL>

Create the receiver: it gets messages from clients and actually sends them by looping to the own gateway
        :rtype: flask.Blueprint


req = jsonex_loads(request.get_data())<EOL>message = g.provider.send(req['<STR_LIT:message>'])<EOL>return {'<STR_LIT:message>': message}<EOL>

Incoming message handler: sent by ForwardClientProvider


def __init__(self, classes, exceptions, *args, **kwargs):

self.classes = classes<EOL>self.exceptions = exceptions<EOL>kwargs['<STR_LIT>'] = self.dict_to_object<EOL>super(JsonExDecoder, self).__init__(*args, object_hook=self.dict_to_object)<EOL>

:param classes:
        Dict of class names,
        mapped to:
            - Class
            - Callable function: lambda **props
        With class, property names MUST match constructor argument names!
        Extra properties are stupidly copied to the object
:type classes: dict
:param exceptions:
        Dict of exception class names,
        mapped to:
            - Class
            - Callable function: lambda *args
        If exception is not registered -- defaults to RuntimeError
:type exceptions: dict


def __init__(self, gateway, name, logger=None):

super(LogProvider, self).__init__(gateway, name)<EOL>self.logger = logger or logging.getLogger(__name__)<EOL>

Configure provider

            :type logger: logging.Logger | None
            :param logger: The logger to use. Default logger is used if nothing provided


try:<EOL><INDENT>return self._traffic<EOL><DEDENT>finally:<EOL><INDENT>self._traffic = []<EOL><DEDENT>

Fetch the accumulated messages and reset

            :rtype: list
            :returns: List of both IncomingMessage & OutgoingMessage objects


<EOL>self._msgid += <NUM_LIT:1><EOL>message = IncomingMessage(src, body, self._msgid)<EOL>self._traffic.append(message)<EOL>self._receive_message(message)<EOL>return message<EOL>

Simulate an incoming message

            :type src: str
            :param src: Message source
            :type boby: str | unicode
            :param body: Message body
            :rtype: IncomingMessage


self._subscribers[digits_only(number)] = callback<EOL>return self<EOL>

Register a virtual subscriber which receives messages to the matching number.

            :type number: str
            :param number: Subscriber phone number
            :type callback: callable
            :param callback: A callback(OutgoingMessage) which handles the messages directed to the subscriber.
                The message object is augmented with the .reply(str) method which allows to send a reply easily!
            :rtype: LoopbackProvider


def __init__(self, dst, body, src=None, provider=None):

self.src = src<EOL>self.dst = digits_only(dst)<EOL>self.body = body<EOL>self.provider = provider<EOL>self.provider_options = OutgoingMessageOptions()<EOL>self.provider_params = {}<EOL>

Create a message for sending

            :type dst: str | None
            :param dst: Destination phone number. Non-digit chars are cut off
            :type body: str | unicode
            :param body: Message

            :type src: str | None
            :param src: Source phone number. Non-digit chars are cut off
            :type provider: str | None
            :param provider: Provider name to use for sending.
                If not specified explicitly, the message will be routed using the routing values:
                see :meth:`OutgoingMessage.route`


self.provider_options.__dict__.update(kwargs)<EOL>return self<EOL>

Specify sending options for the Gateway.

            See: :class:`OutgoingMessageOptions`

            :param allow_reply: Replies allowed?
            :param status_report: Request a status report from the network?
            :param expires: Message validity period, minutes
            :param senderId: Sender ID to replace the number
            :param escalate: Is a high-pri message? These are delivered faster and costier.

            :rtype: OutgoingMessage


self.provider_params = params<EOL>return self<EOL>

Specify provider-specific sending parameters

            :rtype: OutgoingMessage


self.routing_values = args<EOL>return self<EOL>

Specify arbitrary routing values.

            These are used by the Gateway's routing function to decide on which provider to use for the message
            (if no provider was explicitly specified),

            If no routing values are provided at all - the default route is used.

            :rtype: OutgoingMessage


def __init__(self, src, body, msgid=None, dst=None, rtime=None, meta=None):

self.msgid = msgid<EOL>self.src = digits_only(src)<EOL>self.body = body<EOL>self.dst = digits_only(dst) if dst else None<EOL>self.rtime = rtime or datetime.utcnow()<EOL>self.meta = meta or {}<EOL>

Create the received message struct

            :type src: str
            :param src: Source number (sender)
            :type body: str | unicode
            :param body: Message contents
            :type msgid: str | None
            :param msgid: Message ID from the provider
            :type dst: str | None
            :param dst: Destination number (receiver)
            :type rtime: datetime
            :param rtime: Received time, naive, UTC
            :type meta: dict | None
            :param meta: Provider-dependent message info


def __init__(self, msgid, rtime=None, meta=None):

self.msgid = msgid<EOL>self.rtime = rtime or datetime.utcnow()<EOL>self.meta = meta or {}<EOL>

Create the message status struct.

            Most fields are defined with direct property access, or by using subclasses

            :type msgid: str
            :param msgid: Unique message id
            :type rtime: datetime | None
            :param rtime: Status timestamp, naive, UTC
            :type meta: dict | None
            :param meta: Provider-dependent info


ret = set()<EOL>if self.accepted:<EOL><INDENT>ret.add('<STR_LIT>')<EOL><DEDENT>if self.delivered:<EOL><INDENT>ret.add('<STR_LIT>')<EOL><DEDENT>if self.expired:<EOL><INDENT>ret.add('<STR_LIT>')<EOL><DEDENT>if self.error:<EOL><INDENT>ret.add('<STR_LIT:error>')<EOL><DEDENT>return ret<EOL>

Get the set of states. Mostly used for pretty printing

            :rtype: set
            :returns: Set of 'accepted', 'delivered', 'expired', 'error'


z = traj.x * traj.y<EOL>traj.f_add_result('<STR_LIT:z>', z, comment='<STR_LIT>')<EOL>

Example of a sophisticated numerical experiment
    that involves multiplying two integer values.

    :param traj:
        Trajectory containing the parameters in a particular
        combination, it also serves as a container for results.


def wrapper(decorator):<EOL><INDENT>return func<EOL><DEDENT>return wrapper<EOL>

Replaces functools.wraps in order to undo wrapping.

    Can be used to preserve the decorated function's signature
    in the documentation generated by Sphinx.


if self._vars is None:<EOL><INDENT>self._vars = NNTreeNodeVars(self)<EOL><DEDENT>return self._vars<EOL>

Alternative naming, you can use `node.vars.name` instead of `node.v_name`