diff options
Diffstat (limited to 'tools')
-rwxr-xr-x | tools/benchmark-conf-to-json.py | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/tools/benchmark-conf-to-json.py b/tools/benchmark-conf-to-json.py new file mode 100755 index 00000000..928797a1 --- /dev/null +++ b/tools/benchmark-conf-to-json.py @@ -0,0 +1,252 @@ +#!/usr/bin/python +# Script to convert benchmark.conf to benchmark.json +# Hopefully we won't have to maintain benchmark.conf files any longer after +# we fully switch to JSON. + +from configparser import ConfigParser as config_parser +from collections import defaultdict +import json +import sys +import re + +def guess_old_style_used_threads(bench_name, num_threads): + if bench_name == 'CPU Fibonacci': + return 1 + if bench_name == 'CPU FFT': + if num_threads >= 4: + return 4 + if num_threads >= 2: + return 2 + return 1 + if bench_name == 'CPU N-Queens': + if num_threads >= 10: + return 10 + if num_threads >= 5: + return 5 + if num_threads >= 2: + return 2 + return 1 + return num_threads + +def first_truthy_or_none(*args): + for arg in args: + if arg: + return arg + return None + +def nice_cpu_name(name, + trademark_stuff = re.compile(r'\((r|tm|c)\)', re.I), + vendor_intel = re.compile(r'Intel '), + vendor_amd = re.compile(r'AMD '), + integrated_processor = re.compile(r'(Integrated Processor|Processor)', re.I), + frequency = re.compile(r'(\d+\.?\d+?\+?\s*[GH]z)')): + # Cleaned-up port of nice_name_x86_cpuid_model_string() from + # deps/sysobj_early/src/nice_name.c + + name = name.strip() + + name = name.replace("@", "") + name = trademark_stuff.sub("", name) + + # Move vendor to front + match = first_truthy_or_none(vendor_intel.search(name), vendor_amd.search(name)) + if match: + span = match.span() + name = name[span[0]:span[1]] + name[0:span[0]] + name[span[1]:] + + # Remove vendor-specific crud + if name.startswith("AMD"): + name = name.replace("Mobile Technology", "Mobile") + name = name.replace("with Radeon", "") + name = name.replace("Radeon", "") + if "COMPUTE CORES" in name: + name, _ = name.split(',', 2) + if "X2" in name: + name = name.replace("Dual-Core", "") + name = name.replace("Dual Core", "") + if "X3" in name: + name = name.replace("Triple-Core", "") + if "X4" in name: + name = name.replace("Quad-Core", "") + elif name.startswith("Cyrix"): + name = name.replace("tm ", "") + else: + name = name.replace("Genuine Intel", "Intel") + + name = name.replace(" CPU", "") + name = name.replace(" APU", "") + name = integrated_processor.sub("", name) + name = frequency.sub("", name) + + for core_count in ("Dual", "Triple", "Quad", "Six", + "Eight", "Octal", "Twelve", "Sixteen", + "8", "16", "24", "32", "48", "56", "64"): + name = name.replace("%s-Core" % core_count, "") + name = name.replace("%s Core" % core_count, "") + + while " " in name: + name = name.replace(" ", " ") + + return name.strip() + +def cleanup_old_style_cpu_name(name): + for n in ('Intel', 'AMD', 'VIA', 'Cyrix'): + if n in name: + return nice_cpu_name(name) + return name + +def cpu_config_val(config, + mult_freq_re = re.compile(r'((?P<num_cpu>\d+)x\s+)?(?P<freq>\d+\.?\d*)')): + # "2x 1400.00 MHz + 2x 800.00 MHz" -> 4400.0 + value = 0.0 + for _, num, val in mult_freq_re.findall(config): + value += float(val) * (float(num) if num else 1.0) + return value + +def cpu_config_cmp(config1, config2): + r0 = cpu_config_val(config1) + r1 = cpu_config_val(config2) + if r0 == r1: + return 0 + if r0 < r1: + return -1 + return 1 + +def cpu_config_is_close(config1, config2): + r0 = cpu_config_val(config1) + r1 = cpu_config_val(config2) + r1n = r1 * 0.9 + return r0 > r1n and r0 < r1 + +def guess_old_style_cpu_config(cpu_config, num_logical_cpus, + frequency_re = re.compile(r'(?P<freq>\d+\.?\d+)\s*(?P<mult>[GH])z')): + freq_mult = frequency_re.match(cpu_config) + if not freq_mult: + if num_logical_cpus > 1: + return '%dx %s' % (num_logical_cpus, cpu_config) + return cpu_config + + freq, mult = freq_mult.groups() + freq = atof(freq) + if mult[0] == 'G': + freq *= 1000 + + candidate_config = "%dx %.2f MHz" % (num_logical_cpus, freq) + if cpu_config_cmp(cpu_config, candidate_config) == -1 and \ + not cpu_config_is_close(cpu_config, candidate_config): + return candidate_config + + return cpu_config + +def parse_old_style_cpu_info(cpu_config, cpu_name, bench_name, + old_style_cpu_name_re = re.compile('\s*(?P<numcpu>\d+)?(x?\s+)?(?P<cpuname>.*)')): + num_cpus = old_style_cpu_name_re.match(cpu_name) + assert num_cpus + + groups = num_cpus.groupdict() + num_logical_cpus = int(groups['numcpu']) if groups['numcpu'] else 1 + return { + 'NumThreads': num_logical_cpus, + 'NumCores': -1, + 'NumCpus': -1, + 'CpuName': cleanup_old_style_cpu_name(groups['cpuname']), + 'CpuConfig': guess_old_style_cpu_config(cpu_config, num_logical_cpus), + 'UsedThreads': guess_old_style_used_threads(bench_name, num_logical_cpus), + } + +def generate_machine_id(bench, + invalid_chars_re = re.compile(r'[^A-Za-z0-9\(\);]')): + mid = "%s;%s;%.2f" % ( + bench['Board'] if 'Board' in bench else '(Unknown)', + bench['CpuName'], + cpu_config_val(bench['CpuConfig']), + ) + + return invalid_chars_re.sub("_", mid) + +def parse_new_style_bench_value(value): + values = value.strip().split(';') + + if len(values) >= 3: + result = float(values[0].replace(",", ".")) + elapsed_time = float(values[1].replace(",", ".")) + threads_used = int(values[2]) + else: + result = 0 + elapsed_time = 0 + threads_used = 0 + + benchmark_version = int(values[3]) if len(values) >= 4 else 1 + extra = values[4] if len(values) >= 5 and not '|' in values[4] else '' + user_note = values[5] if len(values) >= 6 and not '|' in values[5] else '' + + return { + 'BenchmarkResult': result, + 'ElapsedTime': elapsed_time, + 'UsedThreads': threads_used, + 'BenchmarkVersion': benchmark_version, + 'ExtraInfo': extra, + 'UserNote': user_note, + } + +if __name__ == '__main__': + if len(sys.argv) < 2: + print("Usage: benchmark-conf-to-json.py benchmark.conf") + sys.exit(1) + + cfg = config_parser(strict=False) + cfg.optionxform = lambda opt: opt + cfg.read(sys.argv[1]) + + out = defaultdict(lambda: []) + + for section in cfg.sections(): + if section == 'param': + continue + + for key in cfg[section]: + values = cfg[section][key].split('|') + + if len(values) >= 10: + bench = { + 'MachineId': key, + 'Board': values[2], + 'CpuName': values[3], + 'CpuDesc': values[4], + 'CpuConfig': values[5].replace(",", "."), + 'MemoryInKiB': int(values[6]), + 'NumCpus': int(values[7]), + 'NumCores': int(values[8]), + 'NumThreads': int(values[9]), + } + bench.update(parse_new_style_bench_value(values[0])) + if len(values) >= 11: + bench['OpenGlRenderer'] = values[10] + if len(values) >= 12: + bench['GpuDesc'] = values[11] + if len(values) >= 13: + bench['MachineDataVersion'] = int(values[12]) + if len(values) >= 14: + bench['PointerBits'] = int(values[13]) + if len(values) >= 15: + bench['DataFromSuperUser'] = int(values[14]) + if len(values) >= 16: + bench['PhysicalMemoryInMiB'] = int(values[15]) + if len(values) >= 17: + bench['MemoryTypes'] = values[16] + elif len(values) >= 2: + bench = { + 'BenchmarkResult': float(values[0]), + } + + bench.update(parse_old_style_cpu_info( + values[1].replace(",", "."), + key, + section)) + bench['MachineId'] = generate_machine_id(bench) + else: + raise SyntaxError("unexpected value length: %d (%s)" % (len(values), values)) + + out[section].append(bench) + + print(json.dumps(out)) |