diff --git a/scripts/tools/scale-v3bw-with-budget.py b/scripts/tools/scale-v3bw-with-budget.py new file mode 100755 index 0000000000000000000000000000000000000000..3229e1ebe13c1523e977a1a40b58bf6e174408d3 --- /dev/null +++ b/scripts/tools/scale-v3bw-with-budget.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python3 +# File: scale-v3bw-with-budget.py +# Written by: Matt Traudt +# Copyright/License: CC0 +from collections import OrderedDict +from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter, FileType +import sys + + +def fail_hard(*s): + print(*s, file=sys.stderr) + exit(1) + + +def line_into_dict(line): + words = line.strip().split() + d = OrderedDict() + for word in words: + key, value = word.split('=') + d.update({key: value}) + return d + + +def main(args): + total_input_weight = 0 + line_dicts = [] + is_first_line = True + for line in args.input: + if is_first_line: + # First line is special and is supposed to be a timestamp + try: + int(line) + except ValueError as e: + fail_hard('First line should be an int.', e) + is_first_line = False + args.output.write(line) + continue + # All lines but the first go through this + d = line_into_dict(line) + # Check that the required parts of the line are here + if 'node_id' not in d: + fail_hard('Line without required node_id:', line) + if 'bw' not in d: + fail_hard('Line without required bw:', line) + # Make sure the bw looks like an int + try: + d['bw'] = int(d['bw']) + except ValueError as e: + fail_hard('Found a non-int bw value', d['bw'], e) + # Accumulate the total "bandwidth" weights on the input side + total_input_weight += d['bw'] + # And keep the line for later + line_dicts.append(d) + # Now calculate a ratio to multiply every line by. It's the total budget we + # should give ourselves based on the number of relays in the v3bw file (AKA + # the total output weight) divided by the total input weight + ratio = (len(line_dicts) * args.budget_per_relay) / total_input_weight + for d in line_dicts: + d['bw'] = round(d['bw'] * ratio) + # Accumulate all the parts of the line back together + s = '' + for key in d: + s += '{}={} '.format(key, d[key]) + # Remove trailing ' ' and replace with '\n' + s = s.rstrip() + '\n' + args.output.write(s) + + +def gen_parser(): + d = 'Read a v3bw file, adjust the bandwidth weights of the relays, and '\ + 'write the new v3bw file out. For each relay in the v3bw file, we '\ + 'give ourselves some amount of weight to work with. We then '\ + 'distribute this weight to the relays in the same proportions their '\ + 'input weights were in. This cases the scale of theie weights to '\ + 'move up or down, but their relative weights stay the same.' + p = ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter, + description=d) + p.add_argument('-i', '--input', type=FileType('rt'), + default='/dev/stdin', + help='Input v3bw file to be scaled') + p.add_argument('-o', '--output', type=FileType('wt'), + default='/dev/stdout', + help='Where to write a new, and scaled, v3bw file') + p.add_argument('--budget-per-relay', type=float, default=7500, + help='Per relay in the v3bw file, add this much to our ' + 'budget') + return p + + +if __name__ == '__main__': + p = gen_parser() + args = p.parse_args() + exit(main(args))