diff options
| author | Bjoern Brandenburg <bbb@mpi-sws.org> | 2016-03-28 12:10:58 -0400 |
|---|---|---|
| committer | Bjoern Brandenburg <bbb@mpi-sws.org> | 2016-03-28 12:13:28 -0400 |
| commit | 1f39b952832779cf7626afb35f720f485f4787b4 (patch) | |
| tree | 0c065f7563ed04a17b07e08d0e4938c5f802ed11 | |
| parent | 2f0330ee24d4fa827cfd56e16bd3ae34b703a9ed (diff) | |
Add tools for overhead-processing workflow
| -rwxr-xr-x | ft-combine-samples | 89 | ||||
| -rwxr-xr-x | ft-compute-stats | 135 | ||||
| -rwxr-xr-x | ft-count-samples | 50 | ||||
| -rwxr-xr-x | ft-extract-samples | 75 | ||||
| -rwxr-xr-x | ft-select-samples | 62 | ||||
| -rwxr-xr-x | ft-shuffle-truncate | 136 | ||||
| -rwxr-xr-x | ft-sort-traces | 48 |
7 files changed, 595 insertions, 0 deletions
diff --git a/ft-combine-samples b/ft-combine-samples new file mode 100755 index 0000000..a1f19ed --- /dev/null +++ b/ft-combine-samples | |||
| @@ -0,0 +1,89 @@ | |||
| 1 | #!/bin/bash | ||
| 2 | |||
| 3 | STRIP_CMD="" | ||
| 4 | |||
| 5 | function add_strip() | ||
| 6 | { | ||
| 7 | TAG=$1 | ||
| 8 | STRIP_CMD="$STRIP_CMD -e s/_${TAG}=[^_]*//" | ||
| 9 | } | ||
| 10 | |||
| 11 | while true | ||
| 12 | do | ||
| 13 | case "$1" in | ||
| 14 | -n | --task-count) | ||
| 15 | shift | ||
| 16 | add_strip n | ||
| 17 | ;; | ||
| 18 | |||
| 19 | -c | --cpu) | ||
| 20 | shift | ||
| 21 | add_strip cpu | ||
| 22 | ;; | ||
| 23 | |||
| 24 | -m | --msg) | ||
| 25 | shift | ||
| 26 | add_strip msg | ||
| 27 | ;; | ||
| 28 | |||
| 29 | -s | --seq) | ||
| 30 | shift | ||
| 31 | add_strip seq | ||
| 32 | ;; | ||
| 33 | |||
| 34 | -u | --util) | ||
| 35 | shift | ||
| 36 | add_strip u | ||
| 37 | ;; | ||
| 38 | |||
| 39 | -l | --locks) | ||
| 40 | shift | ||
| 41 | add_strip locks | ||
| 42 | ;; | ||
| 43 | |||
| 44 | -x | --custom) | ||
| 45 | shift | ||
| 46 | add_strip $1 | ||
| 47 | shift | ||
| 48 | ;; | ||
| 49 | |||
| 50 | --std) | ||
| 51 | shift | ||
| 52 | add_strip n | ||
| 53 | add_strip cpu | ||
| 54 | add_strip msg | ||
| 55 | add_strip seq | ||
| 56 | add_strip u | ||
| 57 | ;; | ||
| 58 | |||
| 59 | *) | ||
| 60 | break | ||
| 61 | ;; | ||
| 62 | esac | ||
| 63 | done | ||
| 64 | |||
| 65 | if [ -z "$STRIP_CMD" ] | ||
| 66 | then | ||
| 67 | echo "Error: no fields to strip specified." | ||
| 68 | exit 1 | ||
| 69 | fi | ||
| 70 | |||
| 71 | function do_append() { | ||
| 72 | TARGET=`basename $1 | sed $STRIP_CMD` | ||
| 73 | TARGET="combined-$TARGET" | ||
| 74 | printf "\n[$NUM/$TOTAL] Combining $1 -> $TARGET\n" | ||
| 75 | cat $1 >> $TARGET | ||
| 76 | } | ||
| 77 | |||
| 78 | TOTAL=$# | ||
| 79 | NUM=0 | ||
| 80 | |||
| 81 | echo "File names will be mangled with: sed $STRIP_CMD" | ||
| 82 | |||
| 83 | |||
| 84 | while [ "" != "$*" ] | ||
| 85 | do | ||
| 86 | NUM=$((NUM + 1)) | ||
| 87 | do_append "$1" | ||
| 88 | shift | ||
| 89 | done | ||
diff --git a/ft-compute-stats b/ft-compute-stats new file mode 100755 index 0000000..e07fd16 --- /dev/null +++ b/ft-compute-stats | |||
| @@ -0,0 +1,135 @@ | |||
| 1 | #!/usr/bin/env python | ||
| 2 | |||
| 3 | from __future__ import division | ||
| 4 | |||
| 5 | import numpy | ||
| 6 | |||
| 7 | import optparse | ||
| 8 | import sys | ||
| 9 | import os | ||
| 10 | |||
| 11 | from os.path import splitext | ||
| 12 | |||
| 13 | |||
| 14 | def decode_key_value_filename(name): | ||
| 15 | "Map key=value_otherkey=other-value names to proper dictionary." | ||
| 16 | params = {} | ||
| 17 | parts = name.split('_') | ||
| 18 | for p in parts: | ||
| 19 | kv = p.split('=') | ||
| 20 | k = kv[0] | ||
| 21 | v = kv[1] if len(kv) > 1 else None | ||
| 22 | params[k] = v | ||
| 23 | return params | ||
| 24 | |||
| 25 | |||
| 26 | def stats_for_file(fname, scale): | ||
| 27 | n = 0 | ||
| 28 | max = 0 | ||
| 29 | p95 = 0 | ||
| 30 | p99 = 0 | ||
| 31 | p999 = 0 | ||
| 32 | min = 0 | ||
| 33 | med = 0 | ||
| 34 | avg = 0 | ||
| 35 | std = 0 | ||
| 36 | var = 0 | ||
| 37 | |||
| 38 | size = os.stat(fname).st_size | ||
| 39 | if size: | ||
| 40 | samples = numpy.memmap(fname, dtype='float32', mode='c') | ||
| 41 | |||
| 42 | n = len(samples) | ||
| 43 | if n > 0: | ||
| 44 | samples *= scale | ||
| 45 | max = numpy.amax(samples) | ||
| 46 | p95 = numpy.percentile(samples, 95.0) | ||
| 47 | p99 = numpy.percentile(samples, 99.0) | ||
| 48 | p999 = numpy.percentile(samples, 99.9) | ||
| 49 | med = numpy.median(samples) | ||
| 50 | avg = numpy.mean(samples) | ||
| 51 | min = numpy.amin(samples) | ||
| 52 | |||
| 53 | std = numpy.std(samples, ddof=1) | ||
| 54 | var = numpy.var(samples) | ||
| 55 | |||
| 56 | return [n, max, p999, p99, p95, avg, med, min, std, var] | ||
| 57 | |||
| 58 | o = optparse.make_option | ||
| 59 | |||
| 60 | opts = [ | ||
| 61 | o('-p', '--cycles-per-usec', action='store', dest='cycles', type='float', | ||
| 62 | help='how many cycles per usec'), | ||
| 63 | ] | ||
| 64 | |||
| 65 | defaults = { | ||
| 66 | 'cycles' : None, | ||
| 67 | } | ||
| 68 | |||
| 69 | options = None | ||
| 70 | |||
| 71 | def fmt_cell(x): | ||
| 72 | if type(x) == str: | ||
| 73 | return "%25s" % x | ||
| 74 | if type(x) == int: | ||
| 75 | return "%25d" % x | ||
| 76 | else: | ||
| 77 | return "%25.5f" % x | ||
| 78 | |||
| 79 | def write_header(): | ||
| 80 | labels = ["Plugin", "#cores", "Overhead", 'Unit', "#tasks", | ||
| 81 | "#samples", | ||
| 82 | "max", "99.9th perc.", "99th perc.", "95th perc.", | ||
| 83 | "avg", "med", "min", "std", "var", "file"] | ||
| 84 | header = ", ".join(fmt_cell(x) for x in labels) | ||
| 85 | print '#%s' % header[1:] | ||
| 86 | |||
| 87 | |||
| 88 | def stats_file(fname): | ||
| 89 | name, ext = splitext(fname) | ||
| 90 | conf = decode_key_value_filename(name) | ||
| 91 | |||
| 92 | if 'overhead' in conf and conf['overhead'].rfind('-LATENCY') != -1: | ||
| 93 | # latency is stored in nanoseconds, not cycles | ||
| 94 | scale = 1 / 1000 # convert from nanoseconds | ||
| 95 | unit = 'microseconds (scale = 1/1000)' | ||
| 96 | elif options.cycles is None: | ||
| 97 | scale = 1 | ||
| 98 | unit = 'cycles' | ||
| 99 | else: | ||
| 100 | # convert from cycles to usec | ||
| 101 | scale = 1 / options.cycles | ||
| 102 | unit = 'microseconds (scale = 1/%f)' % options.cycles | ||
| 103 | |||
| 104 | stats = stats_for_file(fname, scale) | ||
| 105 | if 'locks' in conf: | ||
| 106 | sched = '%s_locks=%s' % (conf['scheduler'], conf['locks']) | ||
| 107 | elif 'scheduler' in conf: | ||
| 108 | sched = conf['scheduler'] | ||
| 109 | else: | ||
| 110 | sched = 'UNKNOWN' | ||
| 111 | |||
| 112 | ohead = conf['overhead'] if 'overhead' in conf else 'UNKNOWN' | ||
| 113 | n = conf['n'] if 'n' in conf else '*' | ||
| 114 | m = conf['m'] if 'm' in conf else '*' | ||
| 115 | |||
| 116 | info = [sched, m, ohead, unit, n] | ||
| 117 | finfo = [fname] | ||
| 118 | print ", ".join([fmt_cell(x) for x in info + stats + finfo]) | ||
| 119 | sys.stdout.flush() | ||
| 120 | |||
| 121 | if __name__ == '__main__': | ||
| 122 | # FIXME: would be nicer with argparse | ||
| 123 | parser = optparse.OptionParser(option_list=opts) | ||
| 124 | parser.set_defaults(**defaults) | ||
| 125 | (options, files) = parser.parse_args() | ||
| 126 | |||
| 127 | try: | ||
| 128 | write_header() | ||
| 129 | for f in files: | ||
