benchmark.py 7.02 KB
Newer Older
1
import math
Martin Bauer's avatar
Martin Bauer committed
2
import os
3
import time
Martin Bauer's avatar
Martin Bauer committed
4

5
6
7
import numpy as np
import sympy as sp
from git import Repo
Martin Bauer's avatar
Martin Bauer committed
8
from influxdb import InfluxDBClient
9
from kerncraft.machinemodel import MachineModel
Martin Bauer's avatar
Martin Bauer committed
10
from kerncraft.models import ECM, Benchmark, Roofline, RooflineIACA
11
from kerncraft.prefixedunit import PrefixedUnit
Martin Bauer's avatar
Martin Bauer committed
12
13

from pystencils import Assignment, Field, create_kernel
14
15
16
from pystencils.kerncraft_coupling import KerncraftParameters, PyStencilsKerncraftKernel


Martin Bauer's avatar
Martin Bauer committed
17
def output_benchmark(analysis):
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
    output = {}
    keys = ['Runtime (per repetition) [s]', 'Iterations per repetition',
            'Runtime (per cacheline update) [cy/CL]', 'MEM volume (per repetition) [B]',
            'Performance [MFLOP/s]', 'Performance [MLUP/s]', 'Performance [MIt/s]', 'MEM BW [MByte/s]']
    copies = {key: analysis[key] for key in keys}
    output.update(copies)

    for cache, metrics in analysis['data transfers'].items():
        for metric_name, metric_value in metrics.items():
            fixed = metric_value.with_prefix('')
            output[cache + ' ' + metric_name + ' ' + fixed.prefix + fixed.unit] = fixed.value

    for level, value in analysis['ECM'].items():
        output['Phenomenological ECM ' + level + ' cy/CL'] = value
    return output


Martin Bauer's avatar
Martin Bauer committed
35
def output_ecm(analysis):
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
    output = {}
    keys = ['T_nOL', 'T_OL', 'cl throughput', 'uops']
    copies = {key: analysis[key] for key in keys}
    output.update(copies)

    if 'memory bandwidth kernel' in analysis:
        output['memory bandwidth kernel' + analysis['memory bandwidth kernel'] + analysis['memory bandwidth'].prefix +
               analysis['memory bandwidth'].unit] = analysis['memory bandwidth'].value

    output['scaling cores'] = int(analysis['scaling cores']) if not math.isinf(analysis['scaling cores']) else -1

    for key, value in analysis['cycles']:
        output[key] = value
    return output


Martin Bauer's avatar
Martin Bauer committed
52
def output_roofline(analysis):
53
    output = {}
Martin Bauer's avatar
Martin Bauer committed
54
    keys = ['min performance']  # 'bottleneck level'
55
56
57
58
    copies = {key: analysis[key] for key in keys}
    output.update(copies)
    # TODO save bottleneck information (compute it here)

Martin Bauer's avatar
Martin Bauer committed
59
60
    # fixed = analysis['max_flops'].with_prefix('G')
    # output['max GFlop/s'] = fixed.value
61

Martin Bauer's avatar
Martin Bauer committed
62
    # if analysis['min performance'] > max_flops:
63
64
65
    #    # CPU bound
    #    print('CPU bound with {} cores(s)'.format(self._args.cores), file=output_file)
    #    print('{!s} due to CPU max. FLOP/s'.format(max_flops), file=output_file)
Martin Bauer's avatar
Martin Bauer committed
66
    # else:
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
    # Memory bound
    bottleneck = analysis['mem bottlenecks'][analysis['bottleneck level']]
    output['bottleneck GFlop/s'] = bottleneck['performance'].with_prefix('G').value
    output['bottleneck level'] = bottleneck['level']
    output['bottleneck bw kernel'] = bottleneck['bw kernel']
    output['bottleneck arithmetic intensity'] = bottleneck['arithmetic intensity']

    for i, level in enumerate(analysis['mem bottlenecks']):
        if level is None:
            continue
        for key, value in level.items():
            if isinstance(value, PrefixedUnit):
                fixed = value.with_prefix('G')
                output['level ' + str(i) + ' ' + key + ' [' + fixed.prefix + fixed.unit + ']'] = 'inf' if isinstance(
                    fixed.value, float) and math.isinf(fixed.value) else fixed.value
            else:
                output['level ' + str(i) + ' ' + key] = 'inf' if isinstance(value, float) and math.isinf(
                    value) else value
    return output


Martin Bauer's avatar
Martin Bauer committed
88
def output_roofline_iaca(analysis):
89
    output = {}
Martin Bauer's avatar
Martin Bauer committed
90
    keys = ['min performance']  # 'bottleneck level'
91
    copies = {key: analysis[key] for key in keys}
Martin Bauer's avatar
Martin Bauer committed
92
    # output.update(copies)
93
94
    # TODO save bottleneck information (compute it here)

Martin Bauer's avatar
Martin Bauer committed
95
96
    # fixed = analysis['max_flops'].with_prefix('G')
    # output['max GFlop/s'] = fixed.value
97

Martin Bauer's avatar
Martin Bauer committed
98
    # if analysis['min performance'] > max_flops:
99
100
101
    #    # CPU bound
    #    print('CPU bound with {} cores(s)'.format(self._args.cores), file=output_file)
    #    print('{!s} due to CPU max. FLOP/s'.format(max_flops), file=output_file)
Martin Bauer's avatar
Martin Bauer committed
102
    # else:
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
    # Memory bound
    bottleneck = analysis['mem bottlenecks'][analysis['bottleneck level']]
    output['bottleneck GFlop/s'] = bottleneck['performance'].with_prefix('G').value
    output['bottleneck level'] = bottleneck['level']
    output['bottleneck bw kernel'] = bottleneck['bw kernel']
    output['bottleneck arithmetic intensity'] = bottleneck['arithmetic intensity']

    for i, level in enumerate(analysis['mem bottlenecks']):
        if level is None:
            continue
        for key, value in level.items():
            if isinstance(value, PrefixedUnit):
                fixed = value.with_prefix('G')
                output['level ' + str(i) + ' ' + key + ' [' + fixed.prefix + fixed.unit + ']'] = 'inf' if isinstance(
                    fixed.value, float) and math.isinf(fixed.value) else fixed.value
            else:
                output['level ' + str(i) + ' ' + key] = 'inf' if isinstance(value, float) and math.isinf(
                    value) else value
    return output


Martin Bauer's avatar
Martin Bauer committed
124
def report_analysis(ast, models, machine, tags, fields=None):
125
126
127
128
129
130
131
132
133
134
135
136
    kernel = PyStencilsKerncraftKernel(ast, machine)
    client = InfluxDBClient('i10grafana.informatik.uni-erlangen.de', 8086, 'pystencils',
                            'roggan', 'pystencils')
    repo = Repo(search_parent_directories=True)
    commit = repo.head.commit
    point_time = int(time.time())

    for model in models:
        benchmark = model(kernel, machine, KerncraftParameters())
        benchmark.analyze()
        analysis = benchmark.results
        if model is Benchmark:
Martin Bauer's avatar
Martin Bauer committed
137
            output = output_benchmark(analysis)
138
        elif model is ECM:
Martin Bauer's avatar
Martin Bauer committed
139
            output = output_ecm(analysis)
140
        elif model is Roofline:
Martin Bauer's avatar
Martin Bauer committed
141
            output = output_roofline(analysis)
142
        elif model is RooflineIACA:
Martin Bauer's avatar
Martin Bauer committed
143
            output = output_roofline_iaca(analysis)
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
        else:
            raise ValueError('No valid model for analysis given!')

        if fields is not None:
            output.update(fields)

        output['commit'] = commit.hexsha

        json_body = [
            {
                'measurement': model.__name__,
                'tags': tags,
                'time': point_time,
                'fields': output
            }
        ]
        client.write_points(json_body, time_precision='s')


def main():
    size = [20, 200, 200]
    arr = np.zeros(size)
    a = Field.create_from_numpy_array('a', arr, index_dimensions=0)
    b = Field.create_from_numpy_array('b', arr, index_dimensions=0)
    s = sp.Symbol("s")
    rhs = a[0, -1, 0] + a[0, 1, 0] + \
          a[-1, 0, 0] + a[1, 0, 0] + \
          a[0, 0, -1] + a[0, 0, 1]

Martin Bauer's avatar
Martin Bauer committed
173
174
175
176
177
    update_rule = Assignment(b[0, 0, 0], s * rhs)
    ast = create_kernel([update_rule])
    input_folder = "./"
    machine_file_path = os.path.join(input_folder, "SkylakeSP_Gold-5122_allinclusive.yaml")
    machine = MachineModel(path_to_yaml=machine_file_path)
178
    tags = {
Martin Bauer's avatar
Martin Bauer committed
179
180
181
182
        'host': os.uname()[1],
        'project': 'pystencils',
        'kernel': 'jacobi_3D ' + str(size)
    }
183

Martin Bauer's avatar
Martin Bauer committed
184
    report_analysis(ast, [ECM, Roofline, RooflineIACA, Benchmark], machine, tags)
185
186
187
188


if __name__ == '__main__':
    main()