diff --git a/.gitignore b/.gitignore index 789ad1fc2..b6b54904e 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,4 @@ memgraph *~ *.pyc *.breakpoint +*.session.yaml diff --git a/demo/simulation/static/demo.css b/demo/simulation/static/demo.css index abc32f8d2..ec0cd3441 100644 --- a/demo/simulation/static/demo.css +++ b/demo/simulation/static/demo.css @@ -1,10 +1,16 @@ body { + font-family: GillSans, Calibri, Trebuchet, sans-serif; background-color: #eee; } .w100 { - width: 100%; + width: 100%; +} + +.title { + width: 90%; + color: #007FFF; } .CodeMirror { @@ -15,3 +21,15 @@ body { svg, text { font-size: 28; } + +.btn { + background-color: #007FFF; +} + +.btn:hover { + background-color: #007FFF; +} + +.btn:focus { + background-color: #007FFF; +} diff --git a/demo/simulation/static/demo.html b/demo/simulation/static/demo.html index 3c83c32e3..3898bed09 100644 --- a/demo/simulation/static/demo.html +++ b/demo/simulation/static/demo.html @@ -6,6 +6,7 @@ + @@ -14,17 +15,28 @@ + +
-

Memgraph Benchmark

+

Memgraph Benchmark

+ + +
+ +
-
+
-

25734

+

0

-
+
-

25734

+

0

-
+
-

25734

+

0

-
+
-

25734

+

0

+
+
+ +
+
+ +
+
+
+
+

0

MATCH (n:Person) RETURN n
+ +
-
+
+ +
-
+
-

25734

+

0

-
+
-

25734

+

0

-
+
-

25734

+

0

-
+
-

25734

+

0

+
+
+ +
+
+ +
+
+
+
+

0

(m) RETURN r", + "MATCH (n{id:#}) SET n.prop=^ RETURN n", + "MATCH (n{id:#}) RETURN n", + "MATCH (n{id:#})-[r]->(m) RETURN count(r)" + ]; + + $("#running-button").click(function() { + running = !running; + if (running) { + $(this).text('STOP'); + run(); + updateGraph(); + } + if (!running) + $(this).text('START'); + }); + // counters init + let running = false; let value = 0; let maxQps = 15000; - let card1 = new QueryCard($('#q1')[0], maxQps); - let card2 = new QueryCard($('#q2')[0], maxQps); - let card3 = new QueryCard($('#q3')[0], maxQps); - let card4 = new QueryCard($('#q4')[0], maxQps); - let card5 = new QueryCard($('#q5')[0], maxQps); - let card6 = new QueryCard($('#q6')[0], maxQps); - let card7 = new QueryCard($('#q7')[0], maxQps); - let card8 = new QueryCard($('#q8')[0], maxQps); + // cards init + let neo4jCards = []; + let memgraphCards = []; + queries.forEach(function(query, i) { + query = put_new_line_mod_2(query.split(" ")).join(''); + neo4jCards.push(new QueryCard($('#q-0-' + i.toString())[0], maxQps)); + neo4jCards[i].set_query(query); + memgraphCards.push(new QueryCard($('#q-1-' + i.toString())[0], maxQps)); + memgraphCards[i].set_query(query); + }); - // counters update + // cards update function run() { + if (!running) + return; setTimeout(() => { value += 10; - if(value >= maxQps) value = 0; - - card1.set(value); - card2.set(value); - card3.set(value); - card4.set(value); - card5.set(value); - card6.set(value); - card7.set(value); - card8.set(value); - + queries.forEach(function(query, i) { + neo4jCards[i].set_value(Math.round(1000 + Math.random() * 3000)); + memgraphCards[i].set_value(Math.round(7000 + Math.random() * 7000)); + }); run(); - }, 20); + }, 1000); } - run(); // graph init var data = []; @@ -148,7 +183,7 @@ chart.yAxis .axisLabel('QPS') - .tickFormat(d3.format(',r')); + .tickFormat(d3.format('f')); chartData = d3.select('#chart svg') .datum(data); @@ -162,6 +197,8 @@ // graph update let x = 0; function updateGraph() { + if (!running) + return; setTimeout(() => { x += 1; if (x > 100) @@ -185,6 +222,5 @@ updateGraph(); }, 1000); } - updateGraph(); })(); diff --git a/demo/web_service.py b/demo/web_service.py new file mode 100644 index 000000000..c67ab2fa9 --- /dev/null +++ b/demo/web_service.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- + +from flask import Flask + + +class WebService(Flask): + + def __init__(self): + ''' + ''' + self.server = Flask(__name__) + + def add_route(self, route, code_method, http_method): + ''' + Registers URL rule + + :param route: str, route string + :param object_method: object method responsible for the + request handling + :param http_method: name of http method + ''' + self.server.add_url_rule(route, '%s_%s' % (route, http_method), + code_method, methods=[http_method]) + + def setup_routes(self): + ''' + ''' + self.add_route('/ping', self.ping, 'GET') + + def ping(self): + ''' + Ping endpoint. Returns 204 HTTP status code. + ''' + return ('', 204) diff --git a/demo/worker/worker_web_service.py b/demo/worker/worker_web_service.py new file mode 100644 index 000000000..61e7c30ec --- /dev/null +++ b/demo/worker/worker_web_service.py @@ -0,0 +1,91 @@ +# -*- coding: utf-8 -*- + +import logging +import threading +from flask import request, jsonify + +from .. import WebService +from . import wrapped_client + +log = logging.getLogger(__name__) + + +class WorkerWebServer(WebService): + ''' + Memgraph worker web server. For now it wraps the flask server. + ''' + + def __init__(self): + ''' + Instantiates the flask web server. + ''' + super().__init__() + self.params_data = None + self.is_simulation_running = False + self.stats_data = None + self.setup_routes() + + def setup_routes(self): + ''' + Setup all routes. + ''' + super().__init__() + self.add_route('/start', self.start, 'POST') + self.add_route('/stop', self.stop, 'POST') + self.add_route('/stats', self.stats, 'GET') + self.add_route('/params', self.params_get, 'GET') + self.add_route('/params', self.params_set, 'POST') + + def run_simulation(self): + ''' + If flag is_simulation_running flag is up (True) the executor + epoch will be executed. Epochs will be executed until somebody + set is_simulation_running flag to Flase. + ''' + log.info('new simulation run') + + while self.is_simulation_running: + self.stats_data = wrapped_client(*self.params_data) + + def start(self): + ''' + ''' + self.is_simulation_running = True + t = threading.Thread(target=self.run_simulation, daemon=True) + t.start() + return ('', 204) + + def stop(self): + ''' + ''' + self.is_simulation_running = False + return ('', 204) + + def stats(self): + ''' + Returns the simulation stats. Queries per second. + ''' + if not self.stats_data: + return ('', 204) + + return jsonify(self.stats_data) + + def params_get(self): + ''' + Returns simulation parameters. + ''' + return jsonify(self.simulation_params.json_data()) + + def params_set(self): + ''' + Sets simulation parameters. + ''' + data = request.get_json() + + param_names = ['host', 'port', 'connections', 'duration', 'queries'] + + for param in param_names: + if param in data: + setattr(self.params_data, param, data[param]) + + return self.params_get()