diff --git a/nbs/load_tests.ipynb b/nbs/load_tests.ipynb new file mode 100644 index 0000000..8fe264f --- /dev/null +++ b/nbs/load_tests.ipynb @@ -0,0 +1,274 @@ +{ + "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 string import ascii_letters\n", + "from apswutils.db import Database, Table\n", + "import timeit\n", + "import inspect" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "686289a0", + "metadata": {}, + "outputs": [], + "source": [ + "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": "a6eaa87e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "users = get_table(reset=False)\n", + "users" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f1476bfb", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'SCyFLvRxqC'" + ] + }, + "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": [ + { + "data": { + "text/plain": [ + "{'id': 1, 'name': 'BqjlFTjvLU', 'type': 'write'}" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "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()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4ff89700", + "metadata": {}, + "outputs": [], + "source": [ + "def db_worker_batch(size=100):\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)\n", + " print('-------')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "86ab4bd7", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "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": [ + "print(timeit.repeat(stmt=test_code, setup=setup, number=1))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ccd6594e", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "python3", + "language": "python", + "name": "python3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}