mu.py 5.57 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/env python3
# Copyright 2017 The Australian National University
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

John Zhang's avatar
John Zhang committed
16
17
18
19
import subprocess as subproc
import os
from pathlib import Path

John Zhang's avatar
John Zhang committed
20
21
22
from mubench.lang import Language
from mubench import CALLBACKS_DIR
from mubench.exceptions import ExecutionFailure
23
from mubench.util import expandenv
John Zhang's avatar
John Zhang committed
24
25
26
27


class Mu(Language):
    name = 'mu'
Zixian Cai's avatar
PEP 8    
Zixian Cai committed
28
    src_ext = 'c'  # one or a folder of C files calling API to build the bundle
John Zhang's avatar
John Zhang committed
29
    compiled = True
Zixian Cai's avatar
PEP 8    
Zixian Cai committed
30
    default_exec = 'clang'  # assume presence of clang
31
    known_impls = ('holstein', 'zebu')
John Zhang's avatar
John Zhang committed
32
33

    @classmethod
John Zhang's avatar
John Zhang committed
34
    def check_lang(cls, lc):
35
36
37
        assert 'impl' in lc, "Mu impl not specified"
        assert lc['impl'] in cls.known_impls, 'invalid impl: %(impl)s' % lc
        return lc
John Zhang's avatar
John Zhang committed
38

39
    @classmethod
John Zhang's avatar
John Zhang committed
40
    def check_compiler(cls, cc, lc, task):
41
        impl = lc['impl']
John Zhang's avatar
John Zhang committed
42
        env = task.env
43
44
45
46
47

        # check Mu impl environment variable
        v = 'MU_%s' % (impl.upper())
        assert v in env, '%s needs to be defined in environ.'

John Zhang's avatar
John Zhang committed
48
        mudir = Path(env[v])
John Zhang's avatar
John Zhang committed
49

50
51
        exe = cc.get('exec', cls.default_exec)
        cc['exec'] = expandenv(exe, env)
52

53
54
55
        # include dirs
        include_dirs = cc.get('include_dirs', [])
        include_dirs.append(CALLBACKS_DIR / cls.name)
56
        if impl == 'holstein':
John Zhang's avatar
John Zhang committed
57
            include_dirs.append(mudir / 'cbinding')
58
        elif impl == 'zebu':
John Zhang's avatar
John Zhang committed
59
            include_dirs.append(mudir / 'src' / 'vm' / 'api')
60
        cc['include_dirs'] = include_dirs
61

62
63
        # library dirs
        library_dirs = cc.get('library_dirs', [])
64
65
66
        libmu_dir = ''
        libname = ''
        if impl == 'holstein':
John Zhang's avatar
John Zhang committed
67
            libmu_dir = mudir / 'cbinding'
68
69
            libname = 'murefimpl2start'
        elif impl == 'zebu':
John Zhang's avatar
John Zhang committed
70
            libmu_dir = mudir / 'target' / env.get('ZEBU_BUILD', 'release')
71
            libname = 'mu'
72
73
74
75
        library_dirs.append(libmu_dir)
        cc['library_dirs'] = library_dirs
        cc.setdefault('libmu_link_name', libname)

John Zhang's avatar
John Zhang committed
76
        # vmarg
John Zhang's avatar
John Zhang committed
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
        def set_default_args(defl_d, vmargs):
            # include default args if not specified, otherwise use custom-defined value
            for key, val in defl_d.items():
                if not any([key in arg for arg in vmargs]):
                    vmargs.append('%(key)s=%(val)s' % locals())
            return vmargs

        vmargs = list(map(lambda a: expandenv(a, task.env), cc.get('vmargs', [])))
        if lc['impl'] == 'holstein':
            separators = '\n'
            default_args = {}
        else:   # zebu
            separators = ' '
            emit_dir = task.output_dir / ('%s_%s-emit' % (task.taskset.name, task.name))
            default_args = {
                '--aot-emit-dir': str(emit_dir)
            }
        vmargs = set_default_args(default_args, vmargs)
        vmarg_s = separators.join(vmargs)
96
97
        if lc['impl'] == 'zebu':
            vmarg_s = 'init_mu ' + vmarg_s
John Zhang's avatar
John Zhang committed
98
        cc['vmarg_s'] = vmarg_s
99
100
101
        return cc

    @classmethod
102
103
    def check_runner(cls, rc, lc, task):
        env = task.env
104
        if lc['impl'] == 'holstein':
105
106
107
108
            mu_holstein_dir = Path(env['MU_HOLSTEIN'])
            default_exec = mu_holstein_dir / 'tools' / 'runmu.sh'
            rc.setdefault('exec', default_exec)
            rc['exec'] = Path(expandenv(str(rc['exec']), env))
109
110
111
112
113
114
115
116

            holstein_default_flags = ['--uPtrHack=True']
            rc['flags'] = holstein_default_flags + rc.get('flags', [])
        return rc

    @classmethod
    def compile(cls, task):
        callback_dir = CALLBACKS_DIR / cls.name
117

John Zhang's avatar
John Zhang committed
118
119
        cc = task.compiler
        lc = task.lang
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134

        # First compile the build scripts
        cmd = []
        cmd.append(cc['exec'])

        # flags
        flags = []

        impl = lc['impl']
        flags.append('-DMU_IMPL_%s' % impl.upper())

        flags.extend(['-I%s' % d for d in cc['include_dirs']])
        flags.extend(['-L%s' % d for d in cc['library_dirs']])
        flags.append('-l%(libmu_link_name)s' % cc)

135
136
        target = cls.get_default_target(task)
        build_target = target.with_name('build_' + target.name)
137
        flags.extend(['-o', str(build_target)])
John Zhang's avatar
John Zhang committed
138

139
        cmd.extend(flags)
John Zhang's avatar
John Zhang committed
140

141
        bm_src = task.srcfile
142
143
144
        srcs = [
            callback_dir / 'build_callbacks.c',
            callback_dir / 'main.c',
145
            callback_dir / ('build_cb_%(name)s.c' % task.callback),
146
            bm_src
147
        ]
148
        cmd.extend(srcs)
John Zhang's avatar
John Zhang committed
149

John Zhang's avatar
John Zhang committed
150
        cls.run_in_subproc(cmd, task.env)
John Zhang's avatar
John Zhang committed
151

152
153
154
        assert build_target.exists()

        # Then run the build program to get the boot image
155

156
        cmd = [build_target]
John Zhang's avatar
John Zhang committed
157
        cmd.append(cc['vmarg_s'])
158
        cmd.append(target.absolute())
159

John Zhang's avatar
John Zhang committed
160
        cls.run_in_subproc(cmd, task.env)
161

John Zhang's avatar
John Zhang committed
162
        assert target.exists()
163
        return target
John Zhang's avatar
John Zhang committed
164
165

    @classmethod
166
    def run(cls, target, task):
167
        cmd = []
John Zhang's avatar
John Zhang committed
168
169
        rc = task.runner
        lc = task.lang
170

171
        if lc['impl'] == 'holstein':
172
173
174
175
            cmd.append(rc['exec'])
            cmd.extend(rc.get('flags', []))

        cmd.append(target)
John Zhang's avatar
John Zhang committed
176
177

        # first argument: callback param
John Zhang's avatar
John Zhang committed
178
        cmd.append(task.callback['param'])
John Zhang's avatar
John Zhang committed
179

John Zhang's avatar
John Zhang committed
180
        cmd.extend(task.benchmark['args'])
John Zhang's avatar
John Zhang committed
181

John Zhang's avatar
John Zhang committed
182
        return cls.run_in_subproc(cmd, task.env)