From 0c841c8b14fd50721ea8aeadac36d04f009fce26 Mon Sep 17 00:00:00 2001 From: Daniel Roy Greenfeld Date: Tue, 14 Jan 2025 09:54:40 +0000 Subject: [PATCH 1/2] Add load test notebook Co-authored-by: Audrey Roy Greenfeld --- nbs/load_tests.ipynb | 239 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 239 insertions(+) create mode 100644 nbs/load_tests.ipynb diff --git a/nbs/load_tests.ipynb b/nbs/load_tests.ipynb new file mode 100644 index 0000000..842556f --- /dev/null +++ b/nbs/load_tests.ipynb @@ -0,0 +1,239 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "0446d834", + "metadata": {}, + "source": [ + "# Load tests\n", + "\n", + "> Performance testing for apswutils using different configuration" + ] + }, + { + "cell_type": "markdown", + "id": "03c8fc1f", + "metadata": {}, + "source": [ + "Plan: \n", + "\n", + "1. Create a single db load test that uses threading to perform a high volume of writes and some reads to replicate behavior under load by many users. Lock errors will be append to a simple text file called 'lock-errors.txt'\n", + "2. Extract that from the cell and feed that into timeit and/or cProfile in another cell" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c28db89e", + "metadata": {}, + "outputs": [], + "source": [ + "import threading\n", + "import random\n", + "from pathlib import Path\n", + "from string import ascii_letters\n", + "from apswutils.db import *\n", + "import inspect" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2723579a", + "metadata": {}, + "outputs": [], + "source": [ + "db = Database(\"load.db\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b6f315ac", + "metadata": {}, + "outputs": [], + "source": [ + "for t in db.tables: t.drop()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d0646b18", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "users = Table(db, 'Users')\n", + "users" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7423ae31", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "
" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "users.create(columns=dict(id=int, name=str), transform=True, pk='id')\n", + "users" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f1476bfb", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'lrGZVyXEEU'" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def get_random_name(length=10):\n", + " return ''.join(random.choice(ascii_letters) for _ in range(length))\n", + "get_random_name()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "117629a1", + "metadata": {}, + "outputs": [], + "source": [ + "def get_user(id): return users.get(id)\n", + "def set_user(id,name): return users.insert({'name':name},pk='id')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1976b770", + "metadata": {}, + "outputs": [], + "source": [ + "def db_worker():\n", + " record = set_user(random.randint(1,1000), get_random_name()).result[0]\n", + " record['type'] = 'write'\n", + " return record" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a8bb4095", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'id': 11612, 'name': 'nqfVLiFKwl', 'type': 'write'}" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "db_worker()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4ff89700", + "metadata": {}, + "outputs": [], + "source": [ + "def db_worker_batch(size=20):\n", + " for i in range(size): db_worker()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d36eb83a", + "metadata": {}, + "outputs": [], + "source": [ + "def run_concurrent_workers(n_threads=10):\n", + " print(users.count)\n", + " threads = []\n", + " for _ in range(n_threads):\n", + " t = threading.Thread(target=db_worker_batch)\n", + " threads.append(t)\n", + " t.start()\n", + " \n", + " for t in threads:\n", + " t.join()\n", + " print(users.count)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "86ab4bd7", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "101612\n", + "151612\n" + ] + } + ], + "source": [ + "run_concurrent_workers(5000)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c07520e3", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "python3", + "language": "python", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From e735f37d2825cc627b79a0a1ee41d1294a08db86 Mon Sep 17 00:00:00 2001 From: Daniel Roy Greenfeld Date: Tue, 14 Jan 2025 14:32:27 +0000 Subject: [PATCH 2/2] Add timeit Co-authored-by: Audrey Roy Greenfeld --- nbs/load_tests.ipynb | 153 ++++++++++++++++++++++++++----------------- 1 file changed, 94 insertions(+), 59 deletions(-) diff --git a/nbs/load_tests.ipynb b/nbs/load_tests.ipynb index 842556f..8fe264f 100644 --- a/nbs/load_tests.ipynb +++ b/nbs/load_tests.ipynb @@ -30,58 +30,32 @@ "source": [ "import threading\n", "import random\n", - "from pathlib import Path\n", "from string import ascii_letters\n", - "from apswutils.db import *\n", + "from apswutils.db import Database, Table\n", + "import timeit\n", "import inspect" ] }, { "cell_type": "code", "execution_count": null, - "id": "2723579a", + "id": "686289a0", "metadata": {}, "outputs": [], "source": [ - "db = Database(\"load.db\")" + "def get_table(reset=False):\n", + " db = Database(\"load.db\")\n", + " if reset:\n", + " for t in db.tables: t.drop()\n", + " users = Table(db, 'Users')\n", + " users.create(columns=dict(id=int, name=str), transform=True, pk='id')\n", + " return users" ] }, { "cell_type": "code", "execution_count": null, - "id": "b6f315ac", - "metadata": {}, - "outputs": [], - "source": [ - "for t in db.tables: t.drop()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d0646b18", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "
" - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "users = Table(db, 'Users')\n", - "users" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7423ae31", + "id": "a6eaa87e", "metadata": {}, "outputs": [ { @@ -96,7 +70,7 @@ } ], "source": [ - "users.create(columns=dict(id=int, name=str), transform=True, pk='id')\n", + "users = get_table(reset=False)\n", "users" ] }, @@ -109,7 +83,7 @@ { "data": { "text/plain": [ - "'lrGZVyXEEU'" + "'SCyFLvRxqC'" ] }, "execution_count": null, @@ -139,24 +113,11 @@ "execution_count": null, "id": "1976b770", "metadata": {}, - "outputs": [], - "source": [ - "def db_worker():\n", - " record = set_user(random.randint(1,1000), get_random_name()).result[0]\n", - " record['type'] = 'write'\n", - " return record" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a8bb4095", - "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "{'id': 11612, 'name': 'nqfVLiFKwl', 'type': 'write'}" + "{'id': 1, 'name': 'BqjlFTjvLU', 'type': 'write'}" ] }, "execution_count": null, @@ -165,6 +126,10 @@ } ], "source": [ + "def db_worker():\n", + " record = set_user(random.randint(1,1000), get_random_name()).result[0]\n", + " record['type'] = 'write'\n", + " return record\n", "db_worker()" ] }, @@ -175,7 +140,7 @@ "metadata": {}, "outputs": [], "source": [ - "def db_worker_batch(size=20):\n", + "def db_worker_batch(size=100):\n", " for i in range(size): db_worker()" ] }, @@ -196,7 +161,8 @@ " \n", " for t in threads:\n", " t.join()\n", - " print(users.count)" + " print(users.count)\n", + " print('-------')" ] }, { @@ -209,19 +175,88 @@ "name": "stdout", "output_type": "stream", "text": [ - "101612\n", - "151612\n" + "555201\n", + "555301\n", + "-------\n" + ] + } + ], + "source": [ + "run_concurrent_workers(1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8d418750", + "metadata": {}, + "outputs": [], + "source": [ + "setup = \"\"\"\n", + "import threading\n", + "import random\n", + "from string import ascii_letters\n", + "from apswutils.db import Database, Table\n", + "\"\"\"\n", + "setup += f'\\n{inspect.getsource(get_table)}'\n", + "setup += f'\\nusers = get_table()'\n", + "setup += f'\\n{inspect.getsource(get_random_name)}'\n", + "setup += f'\\n{inspect.getsource(get_user)}'\n", + "setup += f'\\n{inspect.getsource(set_user)}'\n", + "setup += f'\\n{inspect.getsource(db_worker)}'\n", + "setup += f'\\n{inspect.getsource(db_worker_batch)}'\n", + "setup += f'\\n{inspect.getsource(run_concurrent_workers)}'\n", + "\n", + "# print(setup)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "60d38c66", + "metadata": {}, + "outputs": [], + "source": [ + "test_code = \"\"\"run_concurrent_workers(1000)\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5b656178", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "555301\n", + "655301\n", + "-------\n", + "655301\n", + "755301\n", + "-------\n", + "755301\n", + "855301\n", + "-------\n", + "855301\n", + "955301\n", + "-------\n", + "955301\n", + "1055301\n", + "-------\n", + "[291.8241256250185, 300.83988204202615, 285.32696783400024, 269.2562499170017, 268.16414191701915]\n" ] } ], "source": [ - "run_concurrent_workers(5000)" + "print(timeit.repeat(stmt=test_code, setup=setup, number=1))" ] }, { "cell_type": "code", "execution_count": null, - "id": "c07520e3", + "id": "ccd6594e", "metadata": {}, "outputs": [], "source": []