Configuration API¶
ChampSim uses an initial configuration step, written in Python, to parse the JSON configuration file into C++ files for building. The configuration mechanism can be used programmatically, as a Python module.
Parsing API¶
- config.parse.parse_config(*configs, module_dir=None, branch_dir=None, btb_dir=None, pref_dir=None, repl_dir=None, compile_all_modules=False, verbose=False)¶
This is the main parsing dispatch function. Programmatic use of the configuration system should use this as an entry point.
- Parameters:
configs – The configurations given here will be joined into a single configuration, then parsed. These configurations may be simply the result of parsing a JSON file, although the root should be a JSON object.
module_dir – A directory to search for all modules. The structure is assumed to follow the same as the ChampSim repository: branch direction predictors are under branch/, replacement policies under replacement/, etc.
branch_dir – A directory to search for branch direction predictors
btb_dir – A directory to search for branch target predictors
pref_dir – A directory to search for prefetchers
repl_dir – A directory to search for replacement policies
compile_all_modules – If true, all modules in the given directories will be compiled. If false, only the module in the configuration will be compiled.
verbose – Print extra verbose output
File Generation API¶
The file generation API contains two interfaces: a high-level interface with config.filewrite.FileWriter
, and a low-level interface with config.filewrite.Fragment
.
Users should prefer the high-level interface where possible.
The low-level interface may provide greater flexibility when needed, for example a more parallel application.
- class config.filewrite.FileWriter(bindir_name=None, objdir_name=None, makedir_name=None, verbose=False)¶
This class maintains the state of one or more configurations to be written.
This class provides a context manager interface over a set of Fragments, and is more convenient for general use.
- Parameters:
bindir_name – The default directory for binaries if none is given to write_files().
objdir_name – The default directory for object files if none is given to write_files().
- __enter__()¶
This function forms one half of the context manager interface
- __exit__(exc_type, exc_value, traceback)¶
This function terminates the context manager and calls
finish()
.
- finish()¶
Write all accumulated configurations to their files.
- write_files(parsed_config, bindir_name=None, srcdir_names=None, objdir_name=None, makedir_name=None)¶
Accumulate the results of parsing a configuration into the File Writer. Parameters passed here will override parameters given in the constructor
- Parameters:
parsed_config – the result of parsing a configuration file
bindir_name – the directory in which to place the binaries
srcdir_name – the directory to search for source files
objdir_name – the directory to place object files
- static write_fragments(*fragments)¶
Write out a set of prepared fragments.
- class config.filewrite.Fragment(fileparts=None)¶
Examines the given config and prepares to write the needed files.
Programs may use this class for fine-grained control of when and how files are written.
- static from_config(parsed_config, bindir_name=None, srcdir_names=None, objdir_name=None, makedir_name=None, verbose=False)¶
Produce a sequence of Fragments from the result of parse.parse_config().
- Parameters:
parsed_config – the result of parsing a configuration file
bindir_name – the directory in which to place the binaries
srcdir_name – the directory to search for source files
objdir_name – the directory to place object files
makedir_name – the directory to place makefiles
- static join(*frags)¶
Merge multiple Fragments into one.
- write(verbose=False)¶
Write the internal series of fragments to file.
Utility Functions¶
System operations¶
ChampSim’s configuration makes frequent use of sequences of dictionaries. The following functions operate on a system, a dictionary whose values are dictionaries.
- config.util.iter_system(system, name, key='lower_level')¶
Iterate through a dictionary system.
The system is organized as a dictionary of { c[‘name’]: c } for all c. Starting at the given name, generate a path through the system, traversing by the given key. Loops are not allowed, each element may be visited at most once.
- Parameters:
system – the system to be iterated through
name – the key to start at
key – the key that points to the next element
- config.util.combine_named(*iterables)¶
Collect a sequence of sequences of dictionaries by their ‘name’ parameter. Earlier parameters have priority over later parameters.
- config.util.upper_levels_for(system, name, key='lower_level')¶
List all elements of the system who have the given element name under the given key.
- Parameters:
system – the system to be iterated through
name – the key to start at
key – the key that points to the next element
- config.util.propogate_down(path, key)¶
Propogate the value of a key down a path of dictionaries. Later elements inherit the value from earlier elements, unless they have one themselves.
- Parameters:
path – an iterable of dictionary values
key – they dictionary key to propogate
Itertools extentions¶
The following functions are extentions of the itertools package.
- config.util.collect(iterable, key_func, join_func)¶
Perform the “sort->groupby” idiom on an iterable, grouping according to the join_func.
- config.util.batch(it, n)¶
A backport of itertools.batch().
- config.util.sliding(iterable, n)¶
A backport of itertools.sliding()
- config.util.cut(iterable, n=-1)¶
Split an iterable into a head and a tail. The head should be completely consumed before the tail is accesssed.
- Parameters:
iterable – An iterable
n – The length of the head or, if the value is negative, the length of the tail.
- config.util.do_for_first(func, iterable)¶
Evaluate the function for the first element in the iterable and yield it. Then yield the rest of the iterable.
- config.util.append_except_last(iterable, suffix)¶
Concatenate a suffix to each element of the iterable except the last one.
- config.util.multiline(long_line, length=1, indent=0, line_end=None)¶
Split a long string into lines with n words
- config.util.yield_from_star(gen, args, n=2)¶
Python generators can return values when they are finished. This adaptor yields the values from the generators and collects the returned values into a list.
Dictionary Operations¶
ChampSim frequently operates on dictionaries, so these functions are provided as convenience functions.
- config.util.chain(*dicts)¶
Combine two or more dictionaries. Values that are dictionaries are merged recursively. Values that are lists are joined.
Dictionaries given earlier in the parameter list have priority.
>>> chain({ 'a': 1 }, { 'b': 2 }) { 'a': 1, 'b': 2 } >>> chain({ 'a': 1 }, { 'a': 2 }) { 'a': 1 } >>> chain({ 'd': { 'a': 1 } }, { 'd': { 'b': 2 } }) { 'd': { 'a': 1, 'b': 2 } }
- Parameters:
dicts – the sequence to be chained
- config.util.subdict(whole_dict, keys, invert=False)¶
Extract only the given keys from a dictionary. If they keys are not present, they are not defaulted.
- config.util.extend_each(lhs, rhs)¶
For two dictionaries whose values are lists, join the values that have the same key.
- config.util.explode(value, in_key, out_key=None)¶
Convert a dictionary with a list member to a list with dictionary members. :param value: the dictionary to be extracted :param in_key: the key holding the list :param out_key: the key to distinguish the resulting list elements
- config.parse.duplicate_to_length(elements, count)¶
Duplicate an array of elements, truncating if the sequence is longer than the count
>>> duplicate_to_length([1,2,3], 6) [1,1,2,2,3,3] >>> duplicate_to_length([1,2], 5) [1,1,1,2,2] >>> duplicate_to_length([1,2,3,4], 3) [1,2,3]
- Parameters:
elements – the sequence of elements to be duplicated
count – the final length
- config.parse.extract_element(key, *parents)¶
Extract a certain key from the series of parents, returning the merged keys. Keys whose values are not dictionaries are ignored.
>>> a = { 'key': { 'internal': 1 } } >>> b = { 'key': { 'internal': 2 } } >>> extract_element('key', a, b) { 'internal': 1 } >>> c = { 'key': { 'other': 1 } } >>> extract_element('key', a, c) { 'internal': 1, 'other': 1 } >>> d = { 'key': 'foo' } >>> extract_element('key', a, c, d) { 'internal': 1, 'other': 1 }
If one or more of the parents contains a ‘name’ key, the result will contain a ‘name’ key with value ‘{parent[“name”]}_{key}’.
- Parameters:
key – the key to extract
parents – the dictionaries to extract from