Skip to content

Commit ce425b4

Browse files
committed
pytest: move test_coinmoves.py::test_generate_coinmoves and test_plugin.py::test_spam_commands to benchmark.py
Signed-off-by: Rusty Russell <[email protected]>
1 parent 5fd95b3 commit ce425b4

File tree

3 files changed

+97
-109
lines changed

3 files changed

+97
-109
lines changed

tests/benchmark.py

Lines changed: 97 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,27 @@
11
from concurrent import futures
22
from fixtures import * # noqa: F401,F403
3-
from time import time
43
from tqdm import tqdm
4+
from utils import (wait_for, TIMEOUT)
55

66

7+
import os
78
import pytest
89
import random
10+
import statistics
11+
import threading
12+
import time
913

1014

1115
num_workers = 480
1216
num_payments = 10000
1317

1418

15-
def get_bench_node(node_factory):
19+
def get_bench_node(node_factory, extra_options={}):
1620
"""Get a node which is optimized for benchmarking"""
21+
options = extra_options.copy()
1722
# The normal log-level trace makes for a lot of IO.
18-
node = node_factory.get_node(start=False, options={'log-level': 'info'})
23+
options['log-level'] = 'info'
24+
node = node_factory.get_node(start=False, options=options)
1925
# Memleak detection here creates significant overhead!
2026
del node.daemon.env["LIGHTNINGD_DEV_MEMLEAK"]
2127
# Don't bother recording all our io.
@@ -125,3 +131,91 @@ def do_pay(l1, l2):
125131

126132
def test_start(node_factory, benchmark):
127133
benchmark(node_factory.get_node)
134+
135+
136+
def test_generate_coinmoves(node_factory, bitcoind, executor, benchmark):
137+
l1, l2, l3 = get_bench_line_graph(node_factory, 3, wait_for_announce=True)
138+
139+
# Route some payments
140+
l1.rpc.xpay(l3.rpc.invoice(1, "test_generate_coinmoves", "test_generate_coinmoves")['bolt11'])
141+
# Make some payments
142+
l2.rpc.xpay(l3.rpc.invoice(1, "test_generate_coinmoves3", "test_generate_coinmoves3")['bolt11'])
143+
# Receive some payments
144+
l1.rpc.xpay(l2.rpc.invoice(1, "test_generate_coinmoves", "test_generate_coinmoves")['bolt11'])
145+
wait_for(lambda: all([c['htlcs'] == [] for c in l1.rpc.listpeerchannels()['channels']]))
146+
147+
l2.stop()
148+
entries = l2.db.query('SELECT * FROM channel_moves ORDER BY id;')
149+
assert len(entries) == 4
150+
next_id = entries[-1]['id'] + 1
151+
next_timestamp = entries[-1]['timestamp'] + 1
152+
153+
batch = []
154+
# Let's make 5 million entries.
155+
for _ in range(5_000_000 // len(entries)):
156+
# Random payment_hash
157+
entries[0]['payment_hash'] = entries[1]['payment_hash'] = random.randbytes(32)
158+
entries[2]['payment_hash'] = random.randbytes(32)
159+
entries[3]['payment_hash'] = random.randbytes(32)
160+
# Incrementing timestamps
161+
for e in entries:
162+
e['timestamp'] = next_timestamp
163+
next_timestamp += 1
164+
165+
for e in entries:
166+
batch.append((
167+
next_id,
168+
e['account_channel_id'],
169+
e['account_nonchannel_id'],
170+
e['tag_bitmap'],
171+
e['credit_or_debit'],
172+
e['timestamp'],
173+
e['payment_hash'],
174+
e['payment_part_id'],
175+
e['payment_group_id'],
176+
e['fees'],
177+
))
178+
next_id += 1
179+
180+
l2.db.executemany("INSERT INTO channel_moves"
181+
" (id, account_channel_id, account_nonchannel_id, tag_bitmap, credit_or_debit,"
182+
" timestamp, payment_hash, payment_part_id, payment_group_id, fees)"
183+
" VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
184+
batch)
185+
l2.start()
186+
187+
def measure_latency(node, stop_event):
188+
latencies = []
189+
190+
while not stop_event.is_set():
191+
time.sleep(0.1)
192+
193+
start = time.time()
194+
node.rpc.help()
195+
end = time.time()
196+
197+
latencies.append(end - start)
198+
199+
return latencies
200+
201+
stopme = threading.Event()
202+
fut = executor.submit(measure_latency, l2, stopme)
203+
204+
# This makes bkpr parse it all.
205+
benchmark(l2.rpc.bkpr_listbalances)
206+
207+
stopme.set()
208+
latencies = fut.result(TIMEOUT)
209+
210+
# FIXME: Print this somewhere!
211+
benchmark.extra_info = {"title": "Latency details:",
212+
"min": min(latencies),
213+
"median": statistics.median(latencies),
214+
"max": max(latencies)}
215+
216+
217+
def test_spam_commands(node_factory, bitcoind, benchmark):
218+
plugin = os.path.join(os.getcwd(), "tests/plugins/test_libplugin")
219+
l1 = get_bench_node(node_factory, extra_options={"plugin": plugin})
220+
221+
benchmark(l1.rpc.spamcommand, 1_000_000)

tests/test_coinmoves.py

Lines changed: 0 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,7 @@
77
import os
88
import unittest
99
import pytest
10-
import random
1110
import re
12-
import threading
13-
import statistics
1411
import time
1512
from pyln.testing.utils import EXPERIMENTAL_DUAL_FUND
1613

@@ -2091,86 +2088,3 @@ def test_migration_no_bkpr(node_factory, bitcoind):
20912088
check_channel_moves(l2, expected_channel2)
20922089
check_chain_moves(l1, expected_chain1)
20932090
check_chain_moves(l2, expected_chain2)
2094-
2095-
2096-
def test_generate_coinmoves(node_factory, bitcoind, executor):
2097-
l1, l2, l3 = node_factory.line_graph(3, wait_for_announce=True, opts={'log-level': 'info'})
2098-
2099-
# Route some payments
2100-
l1.rpc.xpay(l3.rpc.invoice(1, "test_generate_coinmoves", "test_generate_coinmoves")['bolt11'])
2101-
# Make some payments
2102-
l2.rpc.xpay(l3.rpc.invoice(1, "test_generate_coinmoves3", "test_generate_coinmoves3")['bolt11'])
2103-
# Receive some payments
2104-
l1.rpc.xpay(l2.rpc.invoice(1, "test_generate_coinmoves", "test_generate_coinmoves")['bolt11'])
2105-
wait_for(lambda: all([c['htlcs'] == [] for c in l1.rpc.listpeerchannels()['channels']]))
2106-
2107-
l2.stop()
2108-
entries = l2.db.query('SELECT * FROM channel_moves ORDER BY id;')
2109-
assert len(entries) == 4
2110-
next_id = entries[-1]['id'] + 1
2111-
next_timestamp = entries[-1]['timestamp'] + 1
2112-
2113-
batch = []
2114-
# Let's make 5 million entries.
2115-
for _ in range(5_000_000 // len(entries)):
2116-
# Random payment_hash
2117-
entries[0]['payment_hash'] = entries[1]['payment_hash'] = random.randbytes(32)
2118-
entries[2]['payment_hash'] = random.randbytes(32)
2119-
entries[3]['payment_hash'] = random.randbytes(32)
2120-
# Incrementing timestamps
2121-
for e in entries:
2122-
e['timestamp'] = next_timestamp
2123-
next_timestamp += 1
2124-
2125-
for e in entries:
2126-
batch.append((
2127-
next_id,
2128-
e['account_channel_id'],
2129-
e['account_nonchannel_id'],
2130-
e['tag_bitmap'],
2131-
e['credit_or_debit'],
2132-
e['timestamp'],
2133-
e['payment_hash'],
2134-
e['payment_part_id'],
2135-
e['payment_group_id'],
2136-
e['fees'],
2137-
))
2138-
next_id += 1
2139-
2140-
l2.db.executemany("INSERT INTO channel_moves"
2141-
" (id, account_channel_id, account_nonchannel_id, tag_bitmap, credit_or_debit,"
2142-
" timestamp, payment_hash, payment_part_id, payment_group_id, fees)"
2143-
" VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
2144-
batch)
2145-
2146-
# Memleak detection here creates significant overhead!
2147-
del l2.daemon.env["LIGHTNINGD_DEV_MEMLEAK"]
2148-
# Don't bother recording all our io.
2149-
del l2.daemon.opts['dev-save-plugin-io']
2150-
l2.start()
2151-
2152-
def measure_latency(node, stop_event):
2153-
latencies = []
2154-
2155-
while not stop_event.is_set():
2156-
time.sleep(0.1)
2157-
2158-
start = time.time()
2159-
node.rpc.help()
2160-
end = time.time()
2161-
2162-
latencies.append(end - start)
2163-
2164-
return latencies
2165-
2166-
stopme = threading.Event()
2167-
fut = executor.submit(measure_latency, l2, stopme)
2168-
2169-
# This makes bkpr parse it all.
2170-
l2.rpc.bkpr_listbalances()
2171-
2172-
stopme.set()
2173-
# Latency under 1 second
2174-
latencies = fut.result(TIMEOUT)
2175-
print(f"RESULT: min, median, max: {min(latencies)}, {statistics.median(latencies)}, {max(latencies)}")
2176-
assert max(latencies) < 1

tests/test_plugin.py

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4719,23 +4719,3 @@ def test_openchannel_hook_channel_type(node_factory, bitcoind):
47194719
l2.daemon.wait_for_log(r"plugin-openchannel_hook_accepter.py: accept by design: channel_type {'bits': \[12, 22\], 'names': \['static_remotekey/even', 'anchors/even'\]}")
47204720
else:
47214721
l2.daemon.wait_for_log(r"plugin-openchannel_hook_accepter.py: accept by design: channel_type {'bits': \[12\], 'names': \['static_remotekey/even'\]}")
4722-
4723-
4724-
@pytest.mark.slow_test
4725-
def test_spam_commands(node_factory, bitcoind):
4726-
plugin = os.path.join(os.getcwd(), "tests/plugins/test_libplugin")
4727-
l1 = node_factory.get_node(options={"plugin": plugin, 'log-level': 'info'},
4728-
start=False)
4729-
4730-
# Memleak detection here creates significant overhead!
4731-
del l1.daemon.env["LIGHTNINGD_DEV_MEMLEAK"]
4732-
# Don't bother recording all our io.
4733-
del l1.daemon.opts['dev-save-plugin-io']
4734-
l1.start()
4735-
4736-
start_time = time.time()
4737-
l1.rpc.spamcommand(1_000_000)
4738-
duration = time.time() - start_time
4739-
4740-
# Change 100 to 0 to get test to fail so you can see the result!
4741-
assert duration < 100

0 commit comments

Comments
 (0)