Stress tests now spawn only one memgraph.

Summary:
Added logging to bipartite and create_match tests.

Renamed thread-count to worker-count.

Changed logging in memgraph.

Reviewers: buda, florijan

Reviewed By: buda

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D667
This commit is contained in:
Matej Ferencevic 2017-08-18 14:48:21 +02:00
parent 0435f5c851
commit 1eec3186c4
7 changed files with 106 additions and 52 deletions

View File

@ -70,7 +70,7 @@ class Worker
} }
void OnClose(Session &session) { void OnClose(Session &session) {
std::cout << fmt::format("Client {}:{} closed the connection.", LOG(INFO) << fmt::format("Client {}:{} closed the connection.",
session.socket_.endpoint().address(), session.socket_.endpoint().address(),
session.socket_.endpoint().port()) session.socket_.endpoint().port())
<< std::endl; << std::endl;

View File

@ -160,7 +160,6 @@ class List : Lockable<SpinLock> {
// garbage collector traverses this list and therefore it will become // garbage collector traverses this list and therefore it will become
// deletable // deletable
if (it.prev == nullptr) { if (it.prev == nullptr) {
std::cout << "prev null" << std::endl;
return false; return false;
} }

View File

@ -22,9 +22,6 @@ class StreamReader : public StreamListener<Derived, Stream> {
Socket s; Socket s;
if (!socket.Accept(&s)) return false; if (!socket.Accept(&s)) return false;
std::cout << fmt::format("Client {}:{} connected.", s.endpoint().address(),
s.endpoint().port())
<< std::endl;
DLOG(INFO) << fmt::format( DLOG(INFO) << fmt::format(
"Accepted a connection: socket {}, address '{}', family {}, port {}", "Accepted a connection: socket {}, address '{}', family {}, port {}",
s.id(), s.endpoint().address(), s.endpoint().family(), s.id(), s.endpoint().address(), s.endpoint().family(),

View File

@ -20,9 +20,12 @@ def parse_args():
:return: parsed arguments :return: parsed arguments
''' '''
parser = connection_argument_parser() parser = connection_argument_parser()
parser.add_argument('--thread-count', type=int, parser.add_argument('--worker-count', type=int,
default=multiprocessing.cpu_count(), default=multiprocessing.cpu_count(),
help='Number of concurrent workers.') help='Number of concurrent workers.')
parser.add_argument("--logging", default="INFO",
choices=["INFO", "DEBUG", "WARNING", "ERROR"],
help="Logging level")
parser.add_argument('--u-count', type=int, default=100, parser.add_argument('--u-count', type=int, default=100,
help='Size of U set in the bipartite graph.') help='Size of U set in the bipartite graph.')
parser.add_argument('--v-count', type=int, default=100, parser.add_argument('--v-count', type=int, default=100,
@ -135,7 +138,7 @@ def execution_handler():
vertices_create_end_time - cleanup_end_time) vertices_create_end_time - cleanup_end_time)
# concurrent create execution & tests # concurrent create execution & tests
with multiprocessing.Pool(args.thread_count) as p: with multiprocessing.Pool(args.worker_count) as p:
create_edges_start_time = time.time() create_edges_start_time = time.time()
for worker_id, create_time, time_unit, no_failures in \ for worker_id, create_time, time_unit, no_failures in \
p.map(create_u_v_edges, [i for i in range(args.u_count)]): p.map(create_u_v_edges, [i for i in range(args.u_count)]):
@ -195,7 +198,9 @@ def execution_handler():
if __name__ == '__main__': if __name__ == '__main__':
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=args.logging)
if args.logging != "DEBUG":
logging.getLogger("neo4j").setLevel(logging.WARNING)
output_data.add_status("stress_test_name", "bipartite") output_data.add_status("stress_test_name", "bipartite")
output_data.add_status("number_of_vertices", args.u_count + args.v_count) output_data.add_status("number_of_vertices", args.u_count + args.v_count)
output_data.add_status("number_of_edges", args.u_count * args.v_count) output_data.add_status("number_of_edges", args.u_count * args.v_count)
@ -203,4 +208,5 @@ if __name__ == '__main__':
output_data.add_status("edge_batching", args.edge_batching) output_data.add_status("edge_batching", args.edge_batching)
output_data.add_status("edge_batch_size", args.edge_batch_size) output_data.add_status("edge_batch_size", args.edge_batch_size)
execution_handler() execution_handler()
if args.logging in ["DEBUG", "INFO"]:
output_data.dump() output_data.dump()

View File

@ -2,43 +2,68 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import argparse import argparse
import atexit
import json import json
import multiprocessing import multiprocessing
import os import os
import subprocess import subprocess
import sys import sys
import time
# dataset calibrated for running on Apollo (approx. 1 min per test) # dataset calibrated for running on Apollo (total 4min)
# bipartite runs for approx. 30s
# create_match runs for approx. 30s
# long_running runs for 1min
# long_running runs for 2min
SMALL_DATASET = [ SMALL_DATASET = [
{ {
"test": "bipartite.py", "test": "bipartite.py",
"options": ["--u-count", "100", "--v-count", "100"], "options": ["--u-count", "100", "--v-count", "100"],
"timeout": 5,
}, },
{ {
"test": "create_match.py", "test": "create_match.py",
"options": ["--vertex-count", "40000", "--create-pack-size", "100"], "options": ["--vertex-count", "40000", "--create-pack-size", "100"],
"timeout": 5,
}, },
{ {
"test": "long_running.py", "test": "long_running.py",
"options": ["--vertex-count", "1000", "--edge-count", "1000", "--max-time", "2"], "options": ["--vertex-count", "1000", "--edge-count", "1000", "--max-time", "1", "--verify", "20"],
"timeout": 5,
},
{
"test": "long_running.py",
"options": ["--vertex-count", "1000", "--edge-count", "1000", "--max-time", "2", "--verify", "30"],
"timeout": 5,
}, },
] ]
# dataset calibrated for running on daily stress instance # dataset calibrated for running on daily stress instance (total 9h)
# bipartite and create_match run for approx. 15min # bipartite and create_match run for approx. 15min
# long_running runs for approx. 8h # long_running runs for 5min x 6 times = 30min
# long_running runs for 8h
LARGE_DATASET = [ LARGE_DATASET = [
{ {
"test": "bipartite.py", "test": "bipartite.py",
"options": ["--u-count", "300", "--v-count", "300"], "options": ["--u-count", "300", "--v-count", "300"],
"timeout": 30,
}, },
{ {
"test": "create_match.py", "test": "create_match.py",
"options": ["--vertex-count", "500000", "--create-pack-size", "500"], "options": ["--vertex-count", "500000", "--create-pack-size", "500"],
"timeout": 30,
}, },
] + [
{ {
"test": "long_running.py", "test": "long_running.py",
"options": ["--vertex-count", "100000", "--edge-count", "100000", "--max-time", "480"], "options": ["--vertex-count", "100000", "--edge-count", "100000", "--max-time", "5", "--verify", "60"],
"timeout": 8,
},
] * 6 + [
{
"test": "long_running.py",
"options": ["--vertex-count", "200000", "--edge-count", "2000000", "--max-time", "480", "--verify", "300"],
"timeout": 500,
}, },
] ]
@ -48,39 +73,31 @@ BASE_DIR = os.path.normpath(os.path.join(SCRIPT_DIR, "..", ".."))
BUILD_DIR = os.path.join(BASE_DIR, "build") BUILD_DIR = os.path.join(BASE_DIR, "build")
CONFIG_DIR = os.path.join(BASE_DIR, "config") CONFIG_DIR = os.path.join(BASE_DIR, "config")
def run_test(args, test, options):
print("Running test '{}'".format(test))
# get number of threads # get number of threads
if "THREADS" in os.environ: if "THREADS" in os.environ:
threads = os.environ["THREADS"] THREADS = os.environ["THREADS"]
else: else:
threads = multiprocessing.cpu_count() THREADS = multiprocessing.cpu_count()
# start memgraph
cwd = os.path.dirname(args.memgraph) # run test helper function
cmd = [args.memgraph, "--num-workers=" + str(threads)] def run_test(args, test, options, timeout):
stdout = open("/dev/null", "w") if not args.verbose else None print("Running test '{}'".format(test))
proc_mg = subprocess.Popen(cmd, cwd = cwd, stdout = stdout,
env = {"MEMGRAPH_CONFIG": args.config})
# start test # start test
cmd = [args.python, os.path.join(SCRIPT_DIR, test), "--thread-count", logging = "DEBUG" if args.verbose else "WARNING"
str(threads)] + options cmd = [args.python, "-u", os.path.join(SCRIPT_DIR, test), "--worker-count",
stderr = open("/dev/null", "w") if not args.verbose else None str(THREADS), "--logging", logging] + options
ret_test = subprocess.run(cmd, cwd = SCRIPT_DIR, stderr = stderr) start = time.time()
ret_test = subprocess.run(cmd, cwd = SCRIPT_DIR, timeout = timeout * 60)
# stop memgraph
proc_mg.terminate()
ret_mg = proc_mg.wait()
if ret_mg != 0:
raise Exception("Memgraph binary returned non-zero ({})!".format(
ret_mg))
if ret_test.returncode != 0: if ret_test.returncode != 0:
raise Exception("Test '{}' binary returned non-zero ({})!".format( raise Exception("Test '{}' binary returned non-zero ({})!".format(
test, ret_test.returncode)) test, ret_test.returncode))
runtime = time.time() - start
print(" Done after {:.3f} seconds".format(runtime))
# parse arguments # parse arguments
parser = argparse.ArgumentParser(description = "Run stress tests on Memgraph.") parser = argparse.ArgumentParser(description = "Run stress tests on Memgraph.")
@ -88,6 +105,8 @@ parser.add_argument("--memgraph", default = os.path.join(BUILD_DIR,
"memgraph")) "memgraph"))
parser.add_argument("--config", default = os.path.join(CONFIG_DIR, parser.add_argument("--config", default = os.path.join(CONFIG_DIR,
"stress.conf")) "stress.conf"))
parser.add_argument("--log-file", default = "")
parser.add_argument("--snapshot-directory", default = "")
parser.add_argument("--python", default = os.path.join(SCRIPT_DIR, parser.add_argument("--python", default = os.path.join(SCRIPT_DIR,
"ve3", "bin", "python3"), type = str) "ve3", "bin", "python3"), type = str)
parser.add_argument("--large-dataset", action = "store_const", parser.add_argument("--large-dataset", action = "store_const",
@ -96,8 +115,36 @@ parser.add_argument("--verbose", action = "store_const",
const = True, default = False) const = True, default = False)
args = parser.parse_args() args = parser.parse_args()
# start memgraph
cwd = os.path.dirname(args.memgraph)
cmd = [args.memgraph, "--num-workers=" + str(THREADS)]
if not args.verbose:
cmd += ["--minloglevel", "1"]
if args.log_file:
cmd += ["--log-file", args.log_file]
if args.snapshot_directory:
cmd += ["--snapshot-directory", args.snapshot_directory]
proc_mg = subprocess.Popen(cmd, cwd = cwd,
env = {"MEMGRAPH_CONFIG": args.config})
time.sleep(1.0)
# at exit cleanup
@atexit.register
def cleanup():
global proc_mg
if proc_mg.poll() != None: return
proc_mg.kill()
proc_mg.wait()
# run tests # run tests
dataset = LARGE_DATASET if args.large_dataset else SMALL_DATASET dataset = LARGE_DATASET if args.large_dataset else SMALL_DATASET
for test in dataset: for test in dataset:
run_test(args, **test) run_test(args, **test)
# stop memgraph
proc_mg.terminate()
ret_mg = proc_mg.wait()
if ret_mg != 0:
raise Exception("Memgraph binary returned non-zero ({})!".format(ret_mg))
print("Done!") print("Done!")

View File

@ -25,9 +25,12 @@ def parse_args():
parser = connection_argument_parser() parser = connection_argument_parser()
# specific # specific
parser.add_argument('--thread-count', type=int, parser.add_argument('--worker-count', type=int,
default=multiprocessing.cpu_count(), default=multiprocessing.cpu_count(),
help='Number of concurrent workers.') help='Number of concurrent workers.')
parser.add_argument("--logging", default="INFO",
choices=["INFO", "DEBUG", "WARNING", "ERROR"],
help="Logging level")
parser.add_argument('--vertex-count', type=int, default=100, parser.add_argument('--vertex-count', type=int, default=100,
help='Number of created vertices.') help='Number of created vertices.')
parser.add_argument('--max-property-value', type=int, default=1000, parser.add_argument('--max-property-value', type=int, default=1000,
@ -94,14 +97,14 @@ def create_handler():
session.run("MATCH (n) DETACH DELETE n").consume() session.run("MATCH (n) DETACH DELETE n").consume()
# concurrent create execution & tests # concurrent create execution & tests
with multiprocessing.Pool(args.thread_count) as p: with multiprocessing.Pool(args.worker_count) as p:
for worker_id, create_time, time_unit in \ for worker_id, create_time, time_unit in \
p.map(create_worker, [i for i in range(args.thread_count)]): p.map(create_worker, [i for i in range(args.worker_count)]):
log.info('Worker ID: %s; Create time: %s%s' % log.info('Worker ID: %s; Create time: %s%s' %
(worker_id, create_time, time_unit)) (worker_id, create_time, time_unit))
# check total count # check total count
expected_total_count = args.thread_count * args.vertex_count expected_total_count = args.worker_count * args.vertex_count
total_count = session.run( total_count = session.run(
'MATCH (n) RETURN count(n) AS cnt').data()[0]['cnt'] 'MATCH (n) RETURN count(n) AS cnt').data()[0]['cnt']
assert total_count == expected_total_count, \ assert total_count == expected_total_count, \
@ -110,5 +113,7 @@ def create_handler():
if __name__ == '__main__': if __name__ == '__main__':
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=args.logging)
if args.logging != "DEBUG":
logging.getLogger("neo4j").setLevel(logging.WARNING)
create_handler() create_handler()

View File

@ -277,11 +277,11 @@ class GraphSession():
def runner(params): def runner(params):
num, args = params num, args = params
driver = common.argument_driver(args) driver = common.argument_driver(args)
graph = Graph(args.vertex_count // args.thread_count, graph = Graph(args.vertex_count // args.worker_count,
args.edge_count // args.thread_count) args.edge_count // args.worker_count)
log.info("Starting query runner process") log.info("Starting query runner process")
session = GraphSession(num, graph, driver.session()) session = GraphSession(num, graph, driver.session())
session.run_loop(args.vertex_batch, args.max_queries // args.thread_count, session.run_loop(args.vertex_batch, args.max_queries // args.worker_count,
args.max_time, args.verify) args.max_time, args.verify)
log.info("Runner %d executed %d queries", num, session.executed_queries) log.info("Runner %d executed %d queries", num, session.executed_queries)
driver.close() driver.close()
@ -307,8 +307,8 @@ def parse_args():
help="Maximum execution time in minutes") help="Maximum execution time in minutes")
argp.add_argument("--verify", type=int, default=0, argp.add_argument("--verify", type=int, default=0,
help="Interval (seconds) between checking local info") help="Interval (seconds) between checking local info")
argp.add_argument("--thread-count", type=int, default=1, argp.add_argument("--worker-count", type=int, default=1,
help="The number of threads that operate on the graph " help="The number of workers that operate on the graph "
"independently") "independently")
return argp.parse_args() return argp.parse_args()
@ -323,13 +323,13 @@ def main():
# cleanup and create indexes # cleanup and create indexes
driver = common.argument_driver(args) driver = common.argument_driver(args)
driver.session().run("MATCH (n) DETACH DELETE n").consume() driver.session().run("MATCH (n) DETACH DELETE n").consume()
for i in range(args.thread_count): for i in range(args.worker_count):
label = INDEX_FORMAT.format(i) label = INDEX_FORMAT.format(i)
driver.session().run("CREATE INDEX ON :%s(id)" % label).consume() driver.session().run("CREATE INDEX ON :%s(id)" % label).consume()
driver.close() driver.close()
params = [(i, args) for i in range(args.thread_count)] params = [(i, args) for i in range(args.worker_count)]
with multiprocessing.Pool(args.thread_count) as p: with multiprocessing.Pool(args.worker_count) as p:
p.map(runner, params, 1) p.map(runner, params, 1)
log.info("All query runners done") log.info("All query runners done")