From 8f59f935c5961297d9cffc3a18f2bd8d78b36f44 Mon Sep 17 00:00:00 2001 From: Paul Dix Date: Fri, 5 Apr 2024 11:44:08 -0400 Subject: [PATCH] feat: add basic load generator comparison app (#24889) * feat: add basic load generator comparison app * refactor: PR feedback --- influxdb3_load_generator/analysis/README.md | 21 ++ influxdb3_load_generator/analysis/app.py | 112 +++++++++ .../analysis/templates/index.html | 235 ++++++++++++++++++ 3 files changed, 368 insertions(+) create mode 100644 influxdb3_load_generator/analysis/README.md create mode 100644 influxdb3_load_generator/analysis/app.py create mode 100644 influxdb3_load_generator/analysis/templates/index.html diff --git a/influxdb3_load_generator/analysis/README.md b/influxdb3_load_generator/analysis/README.md new file mode 100644 index 0000000000..17cfd94a2f --- /dev/null +++ b/influxdb3_load_generator/analysis/README.md @@ -0,0 +1,21 @@ +# Load Generator Analysis + +This directory contains a lightweight Flask app to compare two runs of the load generator. The app is designed to be run locally and is not intended for production use. + +## Setup + +Make sure you have python and flask installed. You can install flask by running: + +```bash +pip install flask +``` + +## Running the app + +To run the app, navigate to the `analysis` directory and run: + +```bash +python app.py +``` + +Then open your browser to http://127.0.0.1:5000/ to view the app. \ No newline at end of file diff --git a/influxdb3_load_generator/analysis/app.py b/influxdb3_load_generator/analysis/app.py new file mode 100644 index 0000000000..084162cc6f --- /dev/null +++ b/influxdb3_load_generator/analysis/app.py @@ -0,0 +1,112 @@ +from flask import Flask, jsonify, render_template, request +import os +import csv +import math +import sys +import re + +app = Flask(__name__) + +# Directory path (provided as a command-line argument) +RESULTS_DIRECTORY = 'results/' + +@app.route('/') +def index(): + return render_template('index.html') + +@app.route('/api/test-names') +def get_test_names(): + test_names = [name for name in os.listdir(RESULTS_DIRECTORY) if os.path.isdir(os.path.join(RESULTS_DIRECTORY, name))] + return jsonify(test_names) + +@app.route('/api/config-names') +def get_config_names(): + test_name = request.args.get('test_name') + test_path = os.path.join(RESULTS_DIRECTORY, test_name) + config_names = {} + + for config_name in os.listdir(test_path): + config_path = os.path.join(test_path, config_name) + if os.path.isdir(config_path): + run_times = set() + for file_name in os.listdir(config_path): + match = re.search(r'_(\d{4}-\d{2}-\d{2}-\d{2}-\d{2})', file_name) + if match: + run_time = match.group(1) + run_times.add(run_time) + config_names[config_name] = sorted(run_times) + + return jsonify(config_names) + +@app.route('/api/aggregated-data') +def get_aggregated_data(): + test_name = request.args.get('test_name') + config_name = request.args.get('config_name') + run_time = request.args.get('run_time') + + config_path = os.path.join(RESULTS_DIRECTORY, test_name, config_name) + write_file = os.path.join(config_path, f'write_{run_time}.csv') + query_file = os.path.join(config_path, f'query_{run_time}.csv') + system_file = os.path.join(config_path, f'system_{run_time}.csv') + + if os.path.isfile(write_file) and os.path.isfile(query_file) and os.path.isfile(system_file): + write_data = aggregate_data(write_file, 'lines', 'latency_ms') + query_data = aggregate_data(query_file, 'rows', 'response_ms') + system_data = aggregate_system_data(system_file) + + aggregated_data = { + 'config_name': config_name, + 'run_time': run_time, + 'write_data': write_data, + 'query_data': query_data, + 'system_data': system_data + } + + return jsonify(aggregated_data) + else: + return jsonify({'error': 'Files not found for the specified configuration and run time'}) + +def aggregate_data(file_path, lines_field, latency_field): + aggregated_data = [] + + with open(file_path, 'r') as file: + reader = csv.DictReader(file) + data = list(reader) + + for row in data: + test_time = int(row['test_time_ms']) + lines = int(row[lines_field]) + latency = int(row[latency_field]) + + aggregated_data.append({ + 'test_time': test_time, + 'lines': lines, + 'latency': latency + }) + + return aggregated_data + +def aggregate_system_data(file_path): + aggregated_data = [] + + with open(file_path, 'r') as file: + reader = csv.DictReader(file) + data = list(reader) + + for row in data: + aggregated_data.append({ + 'test_time': int(row['test_time_ms']), + 'cpu_usage': float(row['cpu_usage']), + 'memory_bytes': int(row['memory_bytes']) / 1024 / 1024 + }) + + return aggregated_data + +if __name__ == '__main__': + if len(sys.argv) != 2: + print('Usage: python app.py ') + print('results directory not provided, defaulting to "results/"') + else: + RESULTS_DIRECTORY = sys.argv[1] + + app.run() \ No newline at end of file diff --git a/influxdb3_load_generator/analysis/templates/index.html b/influxdb3_load_generator/analysis/templates/index.html new file mode 100644 index 0000000000..73064f6b1d --- /dev/null +++ b/influxdb3_load_generator/analysis/templates/index.html @@ -0,0 +1,235 @@ + + + + Benchmark Results Comparison + + + + +

Benchmark Results Comparison

+
+ + +
+
+ + +
+
+ + +
+ +
+ + + + + + +
+ + + \ No newline at end of file