~linaro-toolchain-dev/cortex-strings/trunk

29 by Michael Hope
Added some scripts to run the benchmarks and to plot the results.
1
#!/usr/bin/env python
2
58 by Michael Hope
Bumped the version as we're almost at 1.0. Tidied up the README. Added an overview comment to one of the scripts.
3
"""Simple harness that benchmarks different variants of the routines,
4
caches the results, and emits all of the records at the end.
5
6
Results are generated for different values of:
7
 * Source
8
 * Routine
9
 * Length
10
 * Alignment
11
"""
12
29 by Michael Hope
Added some scripts to run the benchmarks and to plot the results.
13
import subprocess
14
import math
15
import sys
16
32 by Michael Hope
Added support for different alignments. Flattened out the loops.
17
# Prefix to the executables
29 by Michael Hope
Added some scripts to run the benchmarks and to plot the results.
18
build = '../build/try-'
19
79 by Michael Hope
Update the list of variants and routines in each. Rework how the
20
ALL = 'memchr memcmp memcpy memset strchr strcmp strcpy strlen'
32 by Michael Hope
Added support for different alignments. Flattened out the loops.
21
22
HAS = {
79 by Michael Hope
Update the list of variants and routines in each. Rework how the
23
    'this': 'bounce memchr memcpy memset strchr strcpy strlen',
104 by Will Newton
Add support for bionic-a9 and bionic-a15.
24
    'bionic-a9': 'memcmp memcpy memset strcmp strcpy strlen',
25
    'bionic-a15': 'memcmp memcpy memset strcmp strcpy strlen',
79 by Michael Hope
Update the list of variants and routines in each. Rework how the
26
    'bionic-c': ALL,
27
    'csl': 'memcpy memset',
28
    'glibc': 'memcpy memset strlen',
29
    'glibc-c': ALL,
30
    'newlib': 'memcpy strcmp strcpy strlen',
31
    'newlib-c': ALL,
32
    'newlib-xscale': 'memchr memcpy memset strchr strcmp strcpy strlen',
32 by Michael Hope
Added support for different alignments. Flattened out the loops.
33
    'plain': 'memset memcpy strcmp strcpy',
34
}
35
49 by Michael Hope
Benchmark more sizes and alignments. Make the figures bigger to make the text smaller. Put the 'this' results first.
36
def run(cache, variant, function, bytes, loops, alignment=8, quiet=False):
32 by Michael Hope
Added support for different alignments. Flattened out the loops.
37
    """Perform a single run, exercising the cache as appropriate."""
38
    key = ':'.join('%s' % x for x in (variant, function, bytes, loops, alignment))
29 by Michael Hope
Added some scripts to run the benchmarks and to plot the results.
39
40
    if key in cache:
49 by Michael Hope
Benchmark more sizes and alignments. Make the figures bigger to make the text smaller. Put the 'this' results first.
41
        got = cache[key]
29 by Michael Hope
Added some scripts to run the benchmarks and to plot the results.
42
    else:
43
        xbuild = build
32 by Michael Hope
Added support for different alignments. Flattened out the loops.
44
        cmd = '%(xbuild)s%(variant)s -t %(function)s -c %(bytes)s -l %(loops)s -a %(alignment)s' % locals()
29 by Michael Hope
Added some scripts to run the benchmarks and to plot the results.
45
30 by Michael Hope
Added more ranges. changed everything to MB/s. Account for the loop overhead.
46
        try:
47
            got = subprocess.check_output(cmd.split()).strip()
48
        except OSError, ex:
49
            assert False, 'Error %s while running %s' % (ex, cmd)
29 by Michael Hope
Added some scripts to run the benchmarks and to plot the results.
50
49 by Michael Hope
Benchmark more sizes and alignments. Make the figures bigger to make the text smaller. Put the 'this' results first.
51
    parts = got.split(':')
52
    took = float(parts[5])
53
54
    cache[key] = got
55
56
    if not quiet:
57
        print got
58
        sys.stdout.flush()
59
60
    return took
29 by Michael Hope
Added some scripts to run the benchmarks and to plot the results.
61
105 by Will Newton
Allow running a subset of benchmarks.
62
def run_many(cache, variants, bytes, alignments, all_functions):
49 by Michael Hope
Benchmark more sizes and alignments. Make the figures bigger to make the text smaller. Put the 'this' results first.
63
    # We want the data to come out in a useful order.  So fix an
64
    # alignment and function, and do all sizes for a variant first
65
    bytes = sorted(bytes)
66
    mid = bytes[len(bytes)/2]
67
105 by Will Newton
Allow running a subset of benchmarks.
68
    if not all_functions:
69
        # Use the ordering in 'this' as the default
70
        all_functions = HAS['this'].split()
49 by Michael Hope
Benchmark more sizes and alignments. Make the figures bigger to make the text smaller. Put the 'this' results first.
71
105 by Will Newton
Allow running a subset of benchmarks.
72
        # Find all other functions
73
        for functions in HAS.values():
74
            for function in functions.split():
75
                if function not in all_functions:
76
                    all_functions.append(function)
49 by Michael Hope
Benchmark more sizes and alignments. Make the figures bigger to make the text smaller. Put the 'this' results first.
77
78
    for alignment in alignments:
79
        for function in all_functions:
80
            for variant in variants:
81
                if function not in HAS[variant].split():
82
                    continue
83
84
                # Run a tracer through and see how long it takes and
85
                # adjust the number of loops based on that.  Not great
86
                # for memchr() and similar which are O(n), but it will
87
                # do
88
                f = 50000000
89
                want = 5.0
90
91
                loops = int(f / math.sqrt(max(1, mid)))
92
                took = run(cache, variant, function, mid, loops, alignment, quiet=True)
93
                # Keep it reasonable for silly routines like bounce
94
                factor = min(20, max(0.05, want/took))
95
                f = f * factor
96
                
97
                # Round f to a few significant figures
98
                scale = 10**int(math.log10(f) - 1)
99
                f = scale*int(f/scale)
100
32 by Michael Hope
Added support for different alignments. Flattened out the loops.
101
                for b in sorted(bytes):
102
                    # Figure out the number of loops to give a roughly consistent run
49 by Michael Hope
Benchmark more sizes and alignments. Make the figures bigger to make the text smaller. Put the 'this' results first.
103
                    loops = int(f / math.sqrt(max(1, b)))
32 by Michael Hope
Added support for different alignments. Flattened out the loops.
104
                    run(cache, variant, function, b, loops, alignment)
29 by Michael Hope
Added some scripts to run the benchmarks and to plot the results.
105
106
def run_top(cache):
32 by Michael Hope
Added support for different alignments. Flattened out the loops.
107
    variants = sorted(HAS.keys())
105 by Will Newton
Allow running a subset of benchmarks.
108
    functions = sys.argv[1:]
32 by Michael Hope
Added support for different alignments. Flattened out the loops.
109
49 by Michael Hope
Benchmark more sizes and alignments. Make the figures bigger to make the text smaller. Put the 'this' results first.
110
    # Upper limit in bytes to test to
111
    top = 512*1024
112
    # Test all powers of 2
113
    step1 = 2.0
114
    # Test intermediate powers of 1.4
115
    step2 = 1.4
116
    
117
    bytes = []
79 by Michael Hope
Update the list of variants and routines in each. Rework how the
118
    
119
    for step in [step1, step2]:
120
        if step:
121
            # Figure out how many steps get us up to the top
122
            steps = int(round(math.log(top) / math.log(step)))
123
            bytes.extend([int(step**x) for x in range(0, steps+1)])
49 by Michael Hope
Benchmark more sizes and alignments. Make the figures bigger to make the text smaller. Put the 'this' results first.
124
125
    alignments = [8, 16, 4, 1, 2, 32]
32 by Michael Hope
Added support for different alignments. Flattened out the loops.
126
105 by Will Newton
Allow running a subset of benchmarks.
127
    run_many(cache, variants, bytes, alignments, functions)
29 by Michael Hope
Added some scripts to run the benchmarks and to plot the results.
128
129
def main():
130
    cachename = 'cache.txt'
131
132
    cache = {}
133
134
    try:
135
        with open(cachename) as f:
136
            for line in f:
137
                line = line.strip()
138
                parts = line.split(':')
32 by Michael Hope
Added support for different alignments. Flattened out the loops.
139
                cache[':'.join(parts[:5])] = line
29 by Michael Hope
Added some scripts to run the benchmarks and to plot the results.
140
    except:
141
        pass
142
143
    try:
144
        run_top(cache)
145
    finally:
146
        with open(cachename, 'w') as f:
79 by Michael Hope
Update the list of variants and routines in each. Rework how the
147
            for line in sorted(cache.values()):
29 by Michael Hope
Added some scripts to run the benchmarks and to plot the results.
148
                print >> f, line
149
30 by Michael Hope
Added more ranges. changed everything to MB/s. Account for the loop overhead.
150
if __name__ == '__main__':
151
    main()