1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
|
#!/usr/bin/env python3
"""Another app's latency while one app changes again and again on a running
host (docs/design/017's stage 3, research 115).
A host of apps (two connection threads, two workers, stores in RAM, cores
0-2) holds A, an app of items.aup with ITEMS items, and B, the scoreboard
(benchmarks/http/scores.aup). B takes one connection's scores
(benchmarks/http/load on core 3) for SECONDS, while A is left be (quiet)
or changes every EVERY seconds (changing: SIGHUP, its line naming in turn
items.pmod and NEXT). The two take turns, their order turned each round.
isolation.py PURE_SERVE ITEMS NEXT EVERY SECONDS ROUNDS a JSON line per run,
then one with medians
"""
import json
import select
import shutil
import signal
import statistics
import subprocess
import sys
import tempfile
import threading
import time
from pathlib import Path
from window import AUP, HERE, grow
ROOT = HERE.parents[2]
LOAD = ROOT / 'benchmarks' / 'http' / 'load'
def main():
serve, items, after = Path(sys.argv[1]).resolve(), int(sys.argv[2]), sys.argv[3]
every, seconds, rounds = float(sys.argv[4]), int(sys.argv[5]), int(sys.argv[6])
work = Path(tempfile.mkdtemp(prefix='pure-030-', dir='/dev/shm'))
try:
modules = {}
for name, source in (('items', HERE / 'items.aup'), (after, HERE / f'{after}.aup'),
('scores', ROOT / 'benchmarks' / 'http' / 'scores.aup')):
modules[name] = work / f'{name}.pmod'
subprocess.run([str(AUP), 'build', str(source), '-o', str(modules[name])], check=True)
conf = work / 'apps.conf'
def write(module):
conf.write_text(f"a {modules[module]} {work / 'a'}\nb {modules['scores']} {work / 'b'}\n")
write('items')
host = subprocess.Popen(['taskset', '-c', '0-2', str(serve), '--apps', str(conf), '--port', '0', '--threads', '2',
'--workers', '2'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
port = json.loads(host.stdout.readline())['port']
count = grow(port, items, 'a')
p99 = {'quiet': [], 'changing': []}
changes = 0
for round_ in range(1, rounds + 1):
for way in (['quiet', 'changing'] if round_ % 2 else ['changing', 'quiet']):
load = subprocess.Popen(['taskset', '-c', '3', str(LOAD), str(port), '1', str(seconds), 'score', '1',
'keep-alive', '16', '/b'], stdout=subprocess.PIPE, text=True)
made = 0
while way == 'changing' and load.poll() is None:
write(after if changes % 2 == 0 else 'items')
host.send_signal(signal.SIGHUP)
ready, _, _ = select.select([host.stdout], [], [], 60)
assert ready
said = json.loads(host.stdout.readline())
assert said['apps'][0]['running'], said
changes += 1
made += 1
time.sleep(every)
out, _ = load.communicate()
result = json.loads(out)
assert result['5xx'] == 0 and result['errors'] == 0, result
p99[way].append(result['p99_us'])
print(json.dumps({'round': round_, 'way': way, 'items': count, 'next': after, 'changes': made, **result}),
flush=True)
host.terminate()
host.communicate(timeout=600)
quiet, changing = statistics.median(p99['quiet']), statistics.median(p99['changing'])
print(json.dumps({'items': count, 'next': after, 'every_s': every, 'quiet_p99_us': quiet,
'changing_p99_us': changing, 'ratio': round(changing / quiet, 2)}), flush=True)
finally:
shutil.rmtree(work)
if __name__ == '__main__':
main()
|