Ton

Форк
0
/
stress_tester.py 
293 строки · 9.4 Кб
1
import os
2
import os.path
3
import random
4
import subprocess
5
import sys
6
import tempfile
7

8
def getenv(name, default=None):
9
    if name in os.environ:
10
        return os.environ[name]
11
    if default is not None:
12
        return default
13
    print("Environemnt variable", name, "is not set", file=sys.stderr)
14
    exit(1)
15

16
VAR_CNT = 10
17
TMP_DIR = tempfile.mkdtemp()
18
FUNC_EXECUTABLE = getenv("FUNC_EXECUTABLE", "func")
19
FIFT_EXECUTABLE = getenv("FIFT_EXECUTABLE", "fift")
20
FIFT_LIBS = getenv("FIFT_LIBS")
21
MAGIC = 123456789
22

23
var_idx = 0
24
def gen_var_name():
25
    global var_idx
26
    var_idx += 1
27
    return "i%d" % var_idx
28

29
class State:
30
    def __init__(self, x):
31
        self.x = x
32
        self.vs = [0] * VAR_CNT
33

34
    def copy(self):
35
        s = State(self.x)
36
        s.vs = self.vs.copy()
37
        return s
38

39
    def copy_from(self, s):
40
        self.x = s.x
41
        self.vs = s.vs.copy()
42

43
class Code:
44
    pass
45

46
class CodeEmpty(Code):
47
    def execute(self, state):
48
        return None
49

50
    def write(self, f, indent=0):
51
        pass
52

53
class CodeReturn(Code):
54
    def __init__(self, value):
55
        self.value = value
56

57
    def execute(self, state):
58
        return [self.value] + state.vs
59

60
    def write(self, f, indent=0):
61
        print("  " * indent + "return (%d, %s);" % (self.value, ", ".join("v%d" % i for i in range(VAR_CNT))), file=f)
62

63
class CodeAdd(Code):
64
    def __init__(self, i, value):
65
        self.i = i
66
        self.value = value
67

68
    def execute(self, state):
69
        state.vs[self.i] += self.value
70
        return None
71

72
    def write(self, f, indent=0):
73
        print("  " * indent + "v%d += %d;" % (self.i, self.value), file=f)
74

75
class CodeBlock(Code):
76
    def __init__(self, code):
77
        self.code = code
78

79
    def execute(self, state):
80
        for c in self.code:
81
            res = c.execute(state)
82
            if res is not None:
83
                return res
84
        return None
85

86
    def write(self, f, indent=0):
87
        for c in self.code:
88
            c.write(f, indent)
89

90
class CodeIfRange(Code):
91
    def __init__(self, l, r, c1, c2):
92
        self.l = l
93
        self.r = r
94
        self.c1 = c1
95
        self.c2 = c2
96

97
    def execute(self, state):
98
        if self.l <= state.x < self.r:
99
            return self.c1.execute(state)
100
        else:
101
            return self.c2.execute(state)
102

103
    def write(self, f, indent=0):
104
        print("  " * indent + "if (in(x, %d, %d)) {" % (self.l, self.r), file=f)
105
        self.c1.write(f, indent + 1)
106
        if isinstance(self.c2, CodeEmpty):
107
            print("  " * indent + "}", file=f)
108
        else:
109
            print("  " * indent + "} else {", file=f)
110
            self.c2.write(f, indent + 1)
111
            print("  " * indent + "}", file=f)
112

113
class CodeRepeat(Code):
114
    def __init__(self, n, c, loop_type):
115
        if loop_type == 2:
116
            n = max(n, 1)
117
        self.n = n
118
        self.c = c
119
        self.loop_type = loop_type
120

121
    def execute(self, state):
122
        for _ in range(self.n):
123
            res = self.c.execute(state)
124
            if res is not None:
125
                return res
126
        return None
127

128
    def write(self, f, indent=0):
129
        if self.loop_type == 0:
130
            print("  " * indent + "repeat (%d) {" % self.n, file=f)
131
            self.c.write(f, indent + 1)
132
            print("  " * indent + "}", file=f)
133
        elif self.loop_type == 1:
134
            var = gen_var_name()
135
            print("  " * indent + "int %s = 0;" % var, file=f)
136
            print("  " * indent + "while (%s < %d) {" % (var, self.n), file=f)
137
            self.c.write(f, indent + 1)
138
            print("  " * (indent + 1) + "%s += 1;" % var, file=f)
139
            print("  " * indent + "}", file=f)
140
        elif self.loop_type == 2:
141
            var = gen_var_name()
142
            print("  " * indent + "int %s = 0;" % var, file=f)
143
            print("  " * indent + "do {", file=f)
144
            self.c.write(f, indent + 1)
145
            print("  " * (indent + 1) + "%s += 1;" % var, file=f)
146
            print("  " * indent + "} until (%s >= %d);" % (var, self.n), file=f)
147
        else:
148
            var = gen_var_name()
149
            print("  " * indent + "int %s = %d;" % (var, self.n - 1), file=f)
150
            print("  " * indent + "while (%s >= 0) {" % var, file=f)
151
            self.c.write(f, indent + 1)
152
            print("  " * (indent + 1) + "%s -= 1;" % var, file=f)
153
            print("  " * indent + "}", file=f)
154

155
class CodeThrow(Code):
156
    def __init__(self):
157
        pass
158

159
    def execute(self, state):
160
        return "EXCEPTION"
161

162
    def write(self, f, indent=0):
163
        print("  " * indent + "throw(42);", file=f)
164

165
class CodeTryCatch(Code):
166
    def __init__(self, c1, c2):
167
        self.c1 = c1
168
        self.c2 = c2
169

170
    def execute(self, state):
171
        state0 = state.copy()
172
        res = self.c1.execute(state)
173
        if res == "EXCEPTION":
174
            state.copy_from(state0)
175
            return self.c2.execute(state)
176
        else:
177
            return res
178

179
    def write(self, f, indent=0):
180
        print("  " * indent + "try {", file=f)
181
        self.c1.write(f, indent + 1)
182
        print("  " * indent + "} catch (_, _) {", file=f)
183
        self.c2.write(f, indent + 1)
184
        print("  " * indent + "}", file=f)
185

186
def write_function(f, name, body, inline=False, inline_ref=False, method_id=None):
187
    print("_ %s(int x)" % name, file=f, end="")
188
    if inline:
189
        print(" inline", file=f, end="")
190
    if inline_ref:
191
        print(" inline_ref", file=f, end="")
192
    if method_id is not None:
193
        print(" method_id(%d)" % method_id, file=f, end="")
194
    print(" {", file=f)
195
    for i in range(VAR_CNT):
196
        print("  int v%d = 0;" % i, file=f)
197
    body.write(f, 1)
198
    print("}", file=f)
199

200
def gen_code(xl, xr, with_return, loop_depth=0, try_catch_depth=0, can_throw=False):
201
    if try_catch_depth < 3 and random.randint(0, 5) == 0:
202
        c1 = gen_code(xl, xr, with_return, loop_depth, try_catch_depth + 1, random.randint(0, 1) == 0)
203
        c2 = gen_code(xl, xr, with_return, loop_depth, try_catch_depth + 1, can_throw)
204
        return CodeTryCatch(c1, c2)
205
    code = []
206
    for _ in range(random.randint(0, 2)):
207
        if random.randint(0, 3) == 0 and loop_depth < 3:
208
            c = gen_code(xl, xr, False, loop_depth + 1, try_catch_depth, can_throw)
209
            code.append(CodeRepeat(random.randint(0, 3), c, random.randint(0, 3)))
210
        elif xr - xl > 1:
211
            xmid = random.randrange(xl + 1, xr)
212
            ret = random.choice((0, 0, 0, 0, 0, 1, 2))
213
            c1 = gen_code(xl, xmid, ret == 1, loop_depth, try_catch_depth, can_throw)
214
            if random.randrange(5) == 0:
215
                c2 = CodeEmpty()
216
            else:
217
                c2 = gen_code(xmid, xr, ret == 2, loop_depth, try_catch_depth, can_throw)
218
            code.append(CodeIfRange(xl, xmid, c1, c2))
219
    if xr - xl == 1 and can_throw and random.randint(0, 5) == 0:
220
        code.append(CodeThrow())
221
    if with_return:
222
        if xr - xl == 1:
223
            code.append(CodeReturn(random.randrange(10**9)))
224
        else:
225
            xmid = random.randrange(xl + 1, xr)
226
            c1 = gen_code(xl, xmid, True, loop_depth, try_catch_depth, can_throw)
227
            c2 = gen_code(xmid, xr, True, loop_depth, try_catch_depth, can_throw)
228
            code.append(CodeIfRange(xl, xmid, c1, c2))
229
    for _ in range(random.randint(0, 3)):
230
        pos = random.randint(0, len(code))
231
        code.insert(pos, CodeAdd(random.randrange(VAR_CNT), random.randint(0, 10**6)))
232
    if len(code) == 0:
233
        return CodeEmpty()
234
    return CodeBlock(code)
235

236
class ExecutionError(Exception):
237
    pass
238

239
def compile_func(fc, fif):
240
    res = subprocess.run([FUNC_EXECUTABLE, "-o", fif, "-SPA", fc], capture_output=True)
241
    if res.returncode != 0:
242
        raise ExecutionError(str(res.stderr, "utf-8"))
243

244
def runvm(compiled_fif, xl, xr):
245
    runner = os.path.join(TMP_DIR, "runner.fif")
246
    with open(runner, "w") as f:
247
        print("\"%s\" include <s constant code" % compiled_fif, file=f)
248
        for x in range(xl, xr):
249
            print("%d 0 code 1 runvmx abort\"exitcode is not 0\" .s cr { drop } depth 1- times" % x, file=f)
250
    res = subprocess.run([FIFT_EXECUTABLE, "-I", FIFT_LIBS, runner], capture_output=True)
251
    if res.returncode != 0:
252
        raise ExecutionError(str(res.stderr, "utf-8"))
253
    output = []
254
    for s in str(res.stdout, "utf-8").split("\n"):
255
        if s.strip() != "":
256
            output.append(list(map(int, s.split())))
257
    return output
258

259

260
cnt_ok = 0
261
cnt_fail = 0
262
for test_id in range(0, 1000000):
263
    random.seed(test_id)
264
    inline = random.randint(0, 2)
265
    xr = random.randint(1, 15)
266
    var_idx = 0
267
    code = gen_code(0, xr, True)
268
    fc = os.path.join(TMP_DIR, "code.fc")
269
    fif = os.path.join(TMP_DIR, "compiled.fif")
270
    with open(fc, "w") as f:
271
        print("int in(int x, int l, int r) impure { return (l <= x) & (x < r); }", file=f)
272
        write_function(f, "foo", code, inline=(inline == 1), inline_ref=(inline == 2))
273
        print("_ main(int x) {", file=f)
274
        print("  (int ret, %s) = foo(x);" % ", ".join("int v%d" % i for i in range(VAR_CNT)), file=f)
275
        print("  return (ret, %s, %d);" % (", ".join("v%d" % i for i in range(VAR_CNT)), MAGIC), file=f)
276
        print("}", file=f)
277
    compile_func(fc, fif)
278
    ok = True
279
    try:
280
        output = runvm(fif, 0, xr)
281
        for x in range(xr):
282
            my_out = code.execute(State(x)) + [MAGIC]
283
            fc_out = output[x]
284
            if my_out != fc_out:
285
                ok = False
286
                break
287
    except ExecutionError:
288
        ok = False
289
    if ok:
290
        cnt_ok += 1
291
    else:
292
        cnt_fail += 1
293
    print("Test %-6d %-6s ok:%-6d fail:%-6d" % (test_id, "OK" if ok else "FAIL", cnt_ok, cnt_fail), file=sys.stderr)
294

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.