From bd92bbef7136584fa4574e2e723e8c94d75688e8 Mon Sep 17 00:00:00 2001 From: thepoole Date: Mon, 15 Nov 2021 19:15:03 +0100 Subject: [PATCH 1/2] Added testing data for cache timing. --- technologies/caching/Cache_time_test.ipynb | 662 ++++++++++++++++++ .../caching/Cache_time_test_results.txt | 43 ++ 2 files changed, 705 insertions(+) create mode 100644 technologies/caching/Cache_time_test.ipynb create mode 100644 technologies/caching/Cache_time_test_results.txt diff --git a/technologies/caching/Cache_time_test.ipynb b/technologies/caching/Cache_time_test.ipynb new file mode 100644 index 0000000..103f758 --- /dev/null +++ b/technologies/caching/Cache_time_test.ipynb @@ -0,0 +1,662 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "fecfbabd", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Logging hadn't been started.\n", + "Activating auto-logging. Current session state plus future input saved.\n", + "Filename : C:\\Users\\a-davidpoole\\.qcodes\\logs\\command_history.log\n", + "Mode : append\n", + "Output logging : True\n", + "Raw input log : False\n", + "Timestamping : True\n", + "State : active\n", + "Qcodes Logfile : C:\\Users\\a-davidpoole\\.qcodes\\logs\\211115-1704-qcodes.log\n" + ] + } + ], + "source": [ + "#Imports\n", + "\n", + "import os\n", + "import time\n", + "import tqdm\n", + "import numpy as np\n", + "import qcodes as qc\n", + "from qcodes.utils.dataset.doNd import do1d, do2d, dond, plot, LinSweep, LogSweep\n", + "from qcodes.dataset.descriptions.detect_shapes import detect_shape_of_measurement\n", + "from qcodes.tests.instrument_mocks import DummyInstrument, DummyInstrumentWithMeasurement\n", + "\n", + "\n", + "from qcodes.dataset import (\n", + " load_or_create_experiment,\n", + " load_by_guid,\n", + " load_by_run_spec,\n", + " initialise_or_create_database_at,\n", + " Measurement,\n", + " DataSetType,\n", + ")\n", + "from qcodes.tests.instrument_mocks import (\n", + " DummyInstrument,\n", + " DummyInstrumentWithMeasurement,\n", + ")\n", + "from qcodes.dataset.plotting import plot_dataset\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "5dc4bb12", + "metadata": {}, + "outputs": [], + "source": [ + "#Set up local database\n", + "\n", + "testing_db_path = os.path.join(os.getcwd(), 'local.db')\n", + "initialise_or_create_database_at(testing_db_path)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "64cca5d7", + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "# preparatory mocking of physical setup\n", + "dac = DummyInstrument('dac', gates=['ch1', 'ch2'])\n", + "dmm = DummyInstrumentWithMeasurement('dmm', setter_instr=dac)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "93b9a581", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\n", + "# Setting up Measurement\n", + "testing_exp = load_or_create_experiment('loop_1', sample_name='no sample')\n", + "\n", + "#Setting up measuremetn without shape\n", + "meas = Measurement(name= 'simple meas', exp=testing_exp)\n", + "meas.register_parameter(dac.ch1)\n", + "meas.register_parameter(dac.ch2)\n", + "meas.register_parameter(dmm.v1, setpoints=(dac.ch1,dac.ch2))\n", + "meas.register_parameter(dmm.v2, setpoints=(dac.ch1,dac.ch2))\n", + "\n", + "#Setting Up measurement with shapes\n", + "meas_with_shape = Measurement(exp=testing_exp, name='shape meas')\n", + "meas_with_shape.register_parameter(dac.ch1) # register the first independent parameter\n", + "meas_with_shape.register_parameter(dac.ch2) # register the second independent parameter\n", + "meas_with_shape.register_parameter(dmm.v1, setpoints=(dac.ch1, dac.ch2)) # now register the dependent oone\n", + "meas_with_shape.register_parameter(dmm.v2, setpoints=(dac.ch1, dac.ch2)) # now register the dependent oone\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "72fe8350", + "metadata": {}, + "outputs": [], + "source": [ + "#Setting up dataset sizes.\n", + "size_a = 500\n", + "size_b = 200\n", + "size_n = 1" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "1f1c9f0c", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2021-11-15 18:56:44,721 ¦ py.warnings ¦ WARNING ¦ warnings ¦ _showwarnmsg ¦ 109 ¦ C:\\Users\\A-DAVI~1\\AppData\\Local\\Temp/ipykernel_1704/616408506.py:4: TqdmDeprecationWarning: This function will be removed in tqdm==5.0.0\n", + "Please use `tqdm.notebook.tqdm` instead of `tqdm.tqdm_notebook`\n", + " bar = tqdm.tqdm_notebook(total=size_a*size_b*size_n)\n", + "\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "106b08cb98064c1da6a141296f92d918", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + " 0%| | 0/100000 [00:00" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "#plotting the measurement context results in a single figure.\n", + "import matplotlib.mlab as mlab\n", + "import matplotlib.pyplot as plt\n", + "\n", + "plt.plot(t_a, '.r', label='Regular cache, disk DB') \n", + "plt.plot(t_b, '.b', label='Shaped cache, disk DB')\n", + "plt.plot(t_c, '.k', label='No cache, disk DB')\n", + "plt.plot(t_d, '.m', label='Regular cache, memory only')\n", + "plt.plot(t_e, '.g', label='Shaped cache, memory only')\n", + "#plt.ylim(0,0.01)\n", + "plt.ylabel('Iter time (s)') \n", + "plt.xlabel('Iter #') \n", + "plt.legend()\n", + "plt.show() " + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "5048cbcf", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYUAAAEKCAYAAAD9xUlFAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAbG0lEQVR4nO3df5RXdb3v8ec7JEFUEEQjIbGyVJCZQfTQ5WiW1xamqXXUvJ6b5vFEGablufdqrW7qqdaqdcgfo16Lq5adzB9pHcksMxR//wKBQUGvoLnEZcDBwN8m+L5/fPdsB5hhvgPzne/M8Hys9V2z92f/+L73fGfmNfuzf0VmIkkSwHvqXYAkqfcwFCRJJUNBklQyFCRJJUNBklQyFCRJpZqGQkT8OSIWRcSCiJhbtA2PiDsi4uni6y5Fe0REc0QsjYiWiJhYy9okSZvqiT2FT2RmY2ZOKsbPBWZn5t7A7GIc4Ahg7+I1DbiiB2qTJLVRj+6jY4BriuFrgGPbtP88Kx4ChkXEqDrUJ0nbrO1qvP4E/hgRCfwkM2cCu2fmi8X0vwC7F8N7AM+3WXZ50fZimzYiYhqVPQmGDBlywD777FPD8iWp/5k3b95/ZubI9qbVOhT+PjNfiIjdgDsi4sm2EzMzi8CoWhEsMwEmTZqUc+fO7b5qJWkbEBHPdTStpt1HmflC8XUl8BvgIGBFa7dQ8XVlMfsLwJg2i48u2iRJPaRmoRARQyJip9Zh4FPA48As4JRitlOAW4rhWcDJxVlIk4G1bbqZJEk9oJbdR7sDv4mI1vf5ZWb+ISIeBW6MiNOA54ATivlvAz4NLAVeB06tYW2SpHbULBQy8xmgoZ321cBh7bQnML1W9Ui92dtvv83y5ct58803612K+pFBgwYxevRoBg4cWPUytT7QLKkKy5cvZ6eddmLs2LEUe9fSVslMVq9ezfLly9lrr72qXs7bXEi9wJtvvsmIESMMBHWbiGDEiBFd3vs0FKRewkBQd9uSnylDQZJUMhSk3iiie19VGDBgAI2NjYwfP57PfOYzrFmzpts369BDD6XeF5yef/75zJgxo9vX++c//5nx48cDMHfuXM4888wO550zZw5HHXXUZtc3Z84chg4dSlNTEx/96Ec55JBDuPXWW8vp559/PnvssQeNjY3ss88+nH766bzzzjtbvR2GgiQABg8ezIIFC3j88ccZPnw4l19+eb1LYv369fUuYYtMmjSJ5ubmrV7PwQcfzPz583nqqadobm7mjDPOYPbs2eX0b3zjGyxYsIDFixezaNEi7r777q1+T0NB0iY+9rGP8cILlRsKLFu2jKlTp3LAAQdw8MEH8+STT5btkydPZv/99+fb3/42O+64I7Dpf8FnnHEGP/vZzzZ5j9NPP51JkyYxbtw4zjvvvLJ97NixnHPOOUycOJFf/epXGyyzYsUKPvvZz9LQ0EBDQwMPPPAAAMceeywHHHAA48aNY+bMmeX8f/jDH5g4cSINDQ0cdti7Z8IvXryYQw89lA9+8IMb/PH+xS9+wUEHHURjYyNf/vKXOw2lefPmlbW0DdG234O7776bxsZGGhsbaWpq4pVXXtlgHY8++ihNTU0sW7Zss+/V2NjId77zHS677LJNpv3tb3/jzTffZJdddtnsOqphKEjawPr165k9ezZHH300ANOmTePSSy9l3rx5zJgxg69+9asAnHXWWZx11lksWrSI0aNHd/l9vv/97zN37lxaWlq4++67aWlpKaeNGDGCxx57jBNPPHGDZc4880w+/vGPs3DhQh577DHGjRsHwNVXX828efOYO3cuzc3NrF69mlWrVvGlL32Jm2++mYULF24QME8++SS33347jzzyCBdccAFvv/02S5Ys4YYbbuD+++9nwYIFDBgwgGuvvXaz23Dqqady6aWXsnDhwg7nmTFjBpdffjkLFizg3nvvZfDgweW0Bx54gK985SvccsstfOhDH+r0ezZx4sQylAEuuugiGhsbGTVqFB/5yEdobGzsdB2dMRQkAfDGG2/Q2NjI+973PlasWMHhhx/Oq6++ygMPPMDxxx9f/vf84ouVu888+OCDHH/88QCcdNJJXX6/G2+8kYkTJ9LU1MQTTzzB4sWLy2mf//zn213mzjvv5PTTTwcqx0CGDh0KQHNzMw0NDUyePJnnn3+ep59+moceeohDDjmkPEd/+PDh5XqOPPJItt9+e3bddVd22203VqxYwezZs5k3bx4HHnggjY2NzJ49m2eeeabD+tesWcOaNWs45JBDAPjCF77Q7nxTpkzh7LPPprm5mTVr1rDddpXLw5YsWcK0adP47W9/ywc+8IGqvmeVa3zf1dp9tHLlSl577TWuv/76qtazOYaCJODdYwrPPfccmcnll1/OO++8w7Bhw1iwYEH5WrJkyWbXs912221wwLO98+SfffZZZsyYwezZs2lpaeHII4/cYL4hQ4ZUXfecOXP405/+xIMPPsjChQtpamrq9Nz87bffvhweMGAA69atIzM55ZRTyu186qmnOP/886uuoyPnnnsuV155JW+88QZTpkwp/9MfNWoUgwYNYv78+VWva/78+ey7776btA8cOJCpU6dyzz33bHW9hoKkDeywww40Nzfzox/9iB122IG99tqr7HrJzLKrZPLkydx8880AG/yHuueee7J48WLeeust1qxZs8GB0VYvv/wyQ4YMYejQoaxYsYLf//73VdV22GGHccUVlYcyrl+/nrVr17J27Vp22WUXdthhB5588kkeeuihsr577rmHZ599FoCXXnqp03XfdNNNrFy5spz/uecqd5g++eSTeeSRRzaYf9iwYQwbNoz77rsPoMOupmXLlrH//vtzzjnncOCBB5ahMGzYMH73u9/xzW9+kzlz5nS67S0tLXz3u99l+vRN7waUmdx///1VdUF1xlCQeqPM7n11UVNTExMmTOC6667j2muv5aqrrqKhoYFx48Zxyy2VGxtffPHFXHjhhUyYMIGlS5eWXTljxozhhBNOYPz48Zxwwgk0NTVtsv6GhgaamprYZ599OOmkk5gyZUpVdV1yySXcdddd7L///hxwwAEsXryYqVOnsm7dOvbdd1/OPfdcJk+eDMDIkSOZOXMmn/vc52hoaOiwS6rVfvvtx/e+9z0+9alPMWHCBA4//PCyq6ylpYX3v//9myzz05/+lOnTp9PY2LhJ106riy++mPHjxzNhwgQGDhzIEUccUU7bfffdufXWW5k+fToPP/zwJsvee++95Smp06dPp7m5eYMD5q3HFMaPH8/69evL4z1bIzrakL7Ah+yov1iyZEm73QK92euvv87gwYOJCK6//nquu+66MjD6k5dffpnTTjttkzOh+or2frYiYl5mTmpvfm+IJ2mLzJs3jzPOOIPMZNiwYVx99dX1Lqkmdt555z4bCFvCUJC0RQ4++ODNnoqpvsljClIv0Ze7ctU7bcnPlKEg9QKDBg1i9erVBoO6TevzFAYNGtSl5ew+knqB0aNHs3z5clatWlXvUtSPtD55rSsMBakXGDhwYJeejiXVit1HkqSSoSBJKhkKkqSSoSBJKhkKkqSSoSBJKhkKkqSSoSBJKhkKkqSS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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYUAAAEKCAYAAAD9xUlFAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAbw0lEQVR4nO3deZRV5Znv8e8TQOCCggIqAgIqRgGZrJQMpoPhYpzLhRiVjiJNL2wa0XQ6lxiXuUgvXQuXueaKcJNwYwCnFoKiyNVWnIVEBBRBS4nIEAuJzPNY+tw/zluvh6KGXVBnqOL3Weus2vvdw3nOpk792O+ezN0REREB+E6uCxARkfyhUBARkUihICIikUJBREQihYKIiEQKBRERiTIaCma21sxWmNkyM1sS2k4xs/lm9ln4eXJoNzObZGarzGy5mfXJZG0iInKkbOwpXOLuvdy9IIzfBbzm7l2A18I4wOVAl/AaBfw2C7WJiEiaXHQfFQEzwvAM4Nq09sc85V2gpZm1zUF9IiLHrYYZXr8Dr5iZA79396nAae6+IUz/O3BaGG4HfJG2bElo25DWhpmNIrUnQbNmzS4877zzMli+iEj9s3Tp0s3u3qaiaZkOhYvdfb2ZnQrMN7NP0ye6u4fASCwEy1SAgoICX7JkSe1VKyJyHDCzdZVNy2j3kbuvDz83AnOAQuCrsm6h8HNjmH090CFt8fahTUREsiRjoWBmzczsxLJh4FLgI2AuMDzMNhx4PgzPBW4JZyH1BXakdTOJiEgWZLL76DRgjpmVvc9T7v5fZrYYmGVmI4F1wI/D/C8CVwCrgL3AiAzWJiIiFchYKLj7aqBnBe1bgEEVtDswJlP1iOSzQ4cOUVJSwv79+3NditQjTZo0oX379jRq1CjxMpk+0CwiCZSUlHDiiSfSqVMnwt61yDFxd7Zs2UJJSQmdO3dOvJxucyGSB/bv30+rVq0UCFJrzIxWrVrVeO9ToSCSJxQIUtuO5ndKoSAiIpFCQSQPmdXuK4n777+fbt260aNHD3r16sWiRYsA6NSpE5s3b87gpz3c9OnTuf322+vcups3bw7Al19+ydChQyudb+3atXTv3r3Kda1du5amTZvSu3dvzj//fAoLC5k+fXqcPn36dNq0aUOvXr3o1q0bQ4cOZe/evbXyOXSgWUT4y1/+wrx583j//fdp3Lgxmzdv5uDBg7kuq04644wzmD179jGv5+yzz+aDDz4AYPXq1QwZMgR3Z8SI1Nn6N9xwA5MnTwZg2LBhzJw5M047FtpTEBE2bNhA69atady4MQCtW7fmjDPOiNMfeeQR+vTpwwUXXMCnn6buVvPee+/Rr18/evfuTf/+/Vm5ciWQ+l9sUVERAwcOpEuXLkyYMCGu54knnqCwsJBevXpx22238fXXXwMwbdo0zj33XAoLC1m4cGGFNe7evZsRI0ZwwQUX0KNHD5555hkARo8eTUFBAd26dWP8+PFx/sWLF9O/f3969uxJYWEhu3btAlL/k7/sssvo0qUL48aNi/O/8sor9OvXjz59+nD99deze/fuKrfZmjVr6NevHxdccAH33HNPbE/fE/j444/j5+3RowefffbZYetYvXo1vXv3ZvHixVW+11lnncVDDz3EpEmTjphWWlrKnj17OPnkk6tcR2LuXmdfF154oYvUB8XFxYeNQ+2+qrNr1y7v2bOnd+nSxUePHu1vvvlmnNaxY0efNGmSu7tPmTLFR44c6e7uO3bs8EOHDrm7+/z5833IkCHu7j5t2jQ//fTTffPmzb53717v1q2bL1682IuLi/2qq67ygwcPurv76NGjfcaMGf7ll196hw4dfOPGjX7gwAHv37+/jxkz5ogax40b53feeWcc37p1q7u7b9myxd3dS0tL/Qc/+IF/+OGHfuDAAe/cubO/9957h9U6bdo079y5s2/fvt337dvnZ555pv/tb3/zTZs2+fe//33fvXu3u7tPnDjRJ0yYUOU2u/rqq33GjBnu7j558mRv1qyZu7uvWbPGu3Xr5u7ut99+uz/xxBPu7n7gwAHfu3dvnP7pp596r169fNmyZUesO30dZbZt2+ZNmjSJ27h169bes2dPP/XUU/3iiy/20tLSCuss/7vl7g4s8Ur+rh633UeV9bN6jW7PJ1I/NG/enKVLl/LOO+/wxhtvcMMNNzBx4kRuvfVWAIYMGQLAhRdeyLPPPgvAjh07GD58OJ999hlmxqFDh+L6Bg8eTKtWreKyCxYsoGHDhixdupTvfe97AOzbt49TTz2VRYsWMXDgQNq0Sd2084YbbuCvf/3rETW++uqrPP3003G87H/Gs2bNYurUqZSWlrJhwwaKi4sxM9q2bRvf66STTorLDRo0iBYtWgDQtWtX1q1bx/bt2ykuLmbAgAEAHDx4kH79+lW5zRYuXBj3Vm6++WZ+8YtfHDFPv379uP/++ykpKWHIkCF06dIFgE2bNlFUVMSzzz5L165dq3yfMl7uj1NZ95G7M2bMGB588EHuuuuuSpZOTt1HIgJAgwYNGDhwIBMmTGDy5MnxDx4Qu5UaNGhAaWkpAL/61a+45JJL+Oijj3jhhRcOOx++/KmQZoa7M3z4cJYtW8ayZctYuXIl99577zHVvGbNGn7961/z2muvsXz5cq688spqz8sv+yzpn8fdGTx4cKytuLiYRx99tNr3r+6Uz2HDhjF37lyaNm3KFVdcweuvvw5AixYtOPPMM1mwYEGCT5nywQcfcP7551dYw9VXX83bb7+deF1VUSiICCtXrjysv3vZsmV07NixymV27NhBu3btAA47MwZg/vz5bN26lX379vHcc88xYMAABg0axOzZs9m4MXVj5K1bt7Ju3Touuugi3nrrLbZs2cKhQ4f405/+VOH7DR48mClTpsTxbdu2sXPnTpo1a0aLFi346quveOmllwD47ne/y4YNG2Jf/a5du2KYVaRv374sXLiQVatWAbBnz564t/LLX/6SOXPmHLHMgAED4p7Lk08+WeF6V69ezVlnncUdd9xBUVERy5cvB+CEE05gzpw5PPbYYzz11FOV1lVm7dq1/PznP2fs2LEVTl+wYAFnn312tetJ4rjtPhLJZ9nuxty9ezdjx45l+/btNGzYkHPOOYepU6dWucy4ceMYPnw49913H1deeeVh0woLC7nuuusoKSnhJz/5CQUFqafx3nfffVx66aV88803NGrUiClTptC3b1/uvfde+vXrR8uWLenVq1eF73fPPfcwZswYunfvToMGDRg/fjxDhgyhd+/enHfeeXTo0CF2/5xwwgnMnDmTsWPHsm/fPpo2bcqrr75a6Wdp06YN06dP56abbuLAgQOx1nPPPZcVK1ZwzTXXHLHMww8/zLBhw3jggQcoKiqqcL2zZs3i8ccfp1GjRpx++uncfffd7Ny5E4BmzZoxb948Bg8eTPPmzY94j88//5zevXuzf/9+TjzxRO64447YnQcwc+ZMFixYwDfffEP79u2PCOajZeX7qeqSY3nIjo4pSD755JNPKuwaqIumT5/OkiVL4umSdd2PfvQjXn755VyXcdQq+t0ys6XuXlDR/Oo+EhGpQl0OhKOh7iMRqVW33nrr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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYUAAAEKCAYAAAD9xUlFAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAYrklEQVR4nO3dfZBV9Z3n8fd3QG0WBZ/QGFFBw8YHoMF0GBGdJLIkanSwdtVEZqLluMVMVlEnZt1kypRxayqlpaPRxM2GDQGMOkqprKyTRI2ayWCiAgFRQCMiaBMVgoiA0bGT7/5xTx8a6aYvD/de0v1+VZ265/zOOb/7Pbb0p89zZCaSJAH8WaMLkCTtOQwFSVLJUJAklQwFSVLJUJAklQwFSVKppqEQESsj4rmIWBQR84u2AyPi0Yh4qfg8oGiPiLgtIpZHxOKIOLGWtUmStlWPPYXPZOaozGwppr8GPJaZw4DHimmAM4BhxTAZ+F4dapMkddCIw0cTgZnF+EzgnA7td2TFU8D+EXFYA+qTpF6rb437T+CRiEjg+5k5FTg0M18v5r8BHFqMHw681mHd1qLt9Q5tRMRkKnsS9O/f/xPHHntsDcuXpJ5nwYIFv8vMQZ3Nq3UonJKZqyPiEODRiHih48zMzCIwqlYEy1SAlpaWnD9//u6rVpJ6gYhY1dW8mh4+yszVxecaYDYwBniz/bBQ8bmmWHw1cESH1QcXbZKkOqlZKERE/4jYr30c+CzwPDAHuKhY7CLgwWJ8DnBhcRXSScCGDoeZalFfp4Mk9Wa1PHx0KDC7+EXbF7g7M38aEfOAWRFxCbAKOL9Y/sfAmcBy4F3g4hrWJknqRM1CITNXAM2dtK8DxnfSnsCltapH6s0++OADWltbee+99xpdiuqoqamJwYMHs9dee1W9Tq1PNEvaA7S2trLffvsxZMgQD5P2EpnJunXraG1tZejQoVWv52MupF7gvffe46CDDjIQepGI4KCDDtrhvUNDQeolDITeZ2d+5oaCJKlkKEi9UFeXZO/sUO13XnXVVeX0TTfdxDe/+c0abWHnZsyYwWWXXVaTvvfdd18Afvvb33Luued2udzKlSsZPnz4dvtauXIl/fr1Y/To0Rx33HGMGTOGGTNmlPNnzJjBoEGDGDVqFCeccALnnnsu77777m7ZDkNBUl3ss88+PPDAA/zud79rdCk19dGPfpT77rtvl/s55phjWLhwIcuWLeOee+7h29/+NtOnTy/nf+ELX2DRokUsWbKEvffem3vvvXeXvxMMBUl10rdvXyZPnswtt9yyzbyVK1dy2mmnMXLkSMaPH8+rr766zTKbNm3i4osvZsSIEYwcOZL7778fgC9/+cu0tLRwwgkncO2115bLz5s3j5NPPpnm5mbGjBnDxo0bgcpf8qeffjrDhg3j6quvLpd/5JFHGDt2LCeeeCLnnXcemzZt2u72vPLKK4wdO5YRI0ZwzTXXbLUt7XsCS5YsYcyYMYwaNYqRI0fy0ksvbdXHihUrGD16NPPmzdvudx199NHcfPPN3HbbbdvMa2trY/PmzRxwwAHb7aNqmfknO3ziE5/InUXlYX3bDFJPtHTp0q2mu/r/f2eHavTv3z83bNiQRx11VL799tt544035rXXXpuZmWeddVbOmDEjMzOnTZuWEydO3Gb9q6++Oq+44opy+q233srMzHXr1mVmZltbW37qU5/KZ599Nt9///0cOnRoPvPMM5mZuWHDhvzggw9y+vTpOXTo0Hz77bfz97//fR555JH56quv5tq1a/PUU0/NTZs2ZWbm9ddfn9ddd912t+fss8/OmTNnZmbmd7/73ezfv39mZr7yyit5wgknZGbmZZddlnfeeWdmZr7//vv57rvvlvNfeOGFHDVqVC5atGibvjv20W79+vXZ1NSUmZnTp0/Pgw8+OJubm/OQQw7JU045Jdva2jqt88M/+8xMYH528XvVPQVJdTNgwAAuvPDCbf7i/dWvfsWkSZMA+NKXvsTcuXO3WfdnP/sZl1665f7W9r+MZ82axYknnsjo0aNZsmQJS5cu5cUXX+Swww7jk5/8ZPm9fftWbssaP348AwcOpKmpieOPP55Vq1bx1FNPsXTpUsaNG8eoUaOYOXMmq1Z1+cw4AJ588kkuuOCCsubOjB07lm9961vccMMNrFq1in79+gGwdu1aJk6cyF133UVz8zb3+Haq8rt8i/bDR2+88QYjRozgxhtvrKqf7hgKkurqyiuvZNq0aWzevHmX+3rllVe46aabeOyxx1i8eDGf//znu70uf5999inH+/TpQ1tbG5nJhAkTWLRoEYsWLWLp0qVMmzat2+/v7iT7pEmTmDNnDv369ePMM8/k8ccfB2DgwIEceeSRnYZfVxYuXMhxxx3XaQ1nn302v/jFL6rua3sMBUl1deCBB3L++edv9Uv35JNP5p577gHgrrvu4tRTT91mvQkTJnD77beX0+vXr+edd96hf//+DBw4kDfffJOf/OQnAHz84x/n9ddfL4/Vb9y4kba2ti5rOumkk3jyySdZvnw5AJs3b+Y3v/kNAF//+teZPXv2NuuMGzduq5o7s2LFCo4++mguv/xyJk6cyOLFiwHYe++9mT17NnfccQd33313l3W1W7lyJV/96leZMmVKp/Pnzp3LMccc020/1TAUpF6oq+PJOzvsqKuuumqrq5C+853vMH36dEaOHMmPfvQjbr311m3Wueaaa1i/fj3Dhw+nubmZJ554gubmZkaPHs2xxx7LpEmTGDduHEB5Nc6UKVNobm5mwoQJ292DGDRoEDNmzOCCCy5g5MiRjB07lhdeqLz+5bnnnuMjH/nINuvceuut3H777YwYMYLVqzt/yv+sWbMYPnw4o0aN4vnnn+fCCy8s5/Xv35+HHnqIW265hTlz5myz7ssvv1xeknr++edz+eWXc/HFW54Teu+995YnsBcuXMg3vvGNLrdvR8TO/ED3FLvykp2udvv+lP97SF1ZtmxZp4ce1L3Pfe5zPPzww40uY6d19rOPiAWZ2dLZ8u4pSNJ2/CkHws4wFCRJJUNB6iU8NNr77MzP3FCQeoGmpibWrVtnMPQiWbxPoampaYfW8yU7Ui8wePBgWltbWbt2baNLUR21v3ltRxgKUi+w11577dDbt9R7efhIklQyFCRJJUNBklQyFCRJJUNBklQyFCRJJUNBklQyFCRJJUNBklQyFCRJJUNBklQyFCRJJUNBklQyFCRJJUNBklQyFCRJpZqHQkT0iYiFEfFQMT00Ip6OiOURcW9E7F2071NMLy/mD6l1bZKkrdVjT+EKYFmH6RuAWzLzY8B64JKi/RJgfdF+S7GcJKmOahoKETEY+Dzwg2I6gNOA+4pFZgLnFOMTi2mK+eOL5SVJdVLrPYVvA1cDfyymDwLezsy2YroVOLwYPxx4DaCYv6FYfisRMTki5kfEfF9CLkm7V81CISLOAtZk5oLd2W9mTs3MlsxsGTRo0O7sWpJ6vb417Hsc8JcRcSbQBAwAbgX2j4i+xd7AYGB1sfxq4AigNSL6AgOBdTWsT5L0ITXbU8jMr2fm4MwcAnwReDwz/wp4Aji3WOwi4MFifE4xTTH/8czMWtUnSdpWI+5T+B/AVyJiOZVzBtOK9mnAQUX7V4CvNaA2SerVann4qJSZPwd+XoyvAMZ0ssx7wHn1qEeS1DnvaJYklQwFSVLJUJAklQwFSVLJUJAklQwFSVLJUJAklQwFSVLJUJAklQwFSVLJUJAklQwFSVLJUJAklQwFSVLJUJAklQwFSVLJUJAklQwFSVLJUJAklQwFSVLJUJAklQwFSVLJUJAklQwFSVLJUJAklQwFSVLJUJAklQwFSVLJUJAklQwFSVLJUJAklQwFSVLJUJAklQwFSVKpZqEQEU0R8UxEPBsRSyLiuqJ9aEQ8HRHLI+LeiNi7aN+nmF5ezB9Sq9okSZ2r5Z7C+8BpmdkMjAJOj4iTgBuAWzLzY8B64JJi+UuA9UX7LcVykqQ66lvNQhGxD/BfgCEd18nM/9nVOpmZwKZicq9iSOA0YFLRPhP4JvA9YGIxDnAf8N2IiKIfSVIdVLun8CCVX9ptwOYOw3ZFRJ+IWASsAR4FXgbezsy2YpFW4PBi/HDgNYBi/gbgoE76nBwR8yNi/tq1a6ssX5JUjar2FIDBmXn6jnaemX8ARkXE/sBs4Ngd7aOTPqcCUwFaWlrci5Ck3ajaPYVfRsSInf2SzHwbeAIYC+wfEe1hNBhYXYyvBo4AKOYPBNbt7HdKknZctaFwCrAgIl6MiMUR8VxELN7eChExqNhDICL6AROAZVTC4dxisYuoHJoCmFNMU8x/3PMJklRf1R4+OmMn+j4MmBkRfaiEz6zMfCgilgL3RMQ/AguBacXy04AfRcRy4C3gizvxnZKkXVBVKGTmqohoBk4tmv4tM5/tZp3FwOhO2lcAYzppfw84r5p6JEm1UdXho4i4ArgLOKQY7oyIKbUsTJJUf9UeProE+PPM3AwQETcAvwK+U6vCJEn1V+2J5gD+0GH6D0WbJKkHqXZPYTrwdETMLqbPYcsJYklSD1HtieabI+LnVC5NBbg4MxfWrCpJUkNsNxQiYkBmvhMRBwIri6F93oGZ+VZty5Mk1VN3ewp3A2cBC6g8zK5dFNNH16guSVIDbDcUMvOs4nNofcqRJDVStfcpPFZNmyTpT1t35xSagP8AHBwRB7DlMtQBbHnktSSph+junMLfAlcCH6VyXqE9FN4Bvlu7siRJjdDdOYVbgVsjYkpmeveyJPVw1d6n8J2IGA4cDzR1aL+jVoVJkuqv2nc0Xwt8mkoo/JjKo7TnAoaCJPUg1T776FxgPPBGZl4MNFN5M5okqQepNhR+n5l/BNoiYgCwhuLVmZKknqPaB+LNL16t+X+oXIW0icqjsyVJPUi1J5r/WzH6vyPip8CA4s1qkqQepLub107c3rzM/PXuL0mS1Cjd7Sn803bmJXDabqxFktRg3d289pl6FSJJarxq71O4sLN2b16TpJ6l2quPPtlhvInKPQu/xpvXJKlHqfbqoykdp4vLU++pRUGSpMap9ua1D9sM+OIdSephqj2n8P/Y8jrOPsBxwKxaFSVJaoxqzync1GG8DViVma01qEeS1EBVHT7KzH8FXqTyELwDqQSDJKmHqfYdzf8VeAb4z1SemPpURPxNLQuTJNVftYeP/jswOjPXAUTEQcAvgR/WqjBJUv1Ve/XROmBjh+mNRZskqQepdk9hOfB0RDxI5SqkicDiiPgKQGbeXKP6JEl1VG0ovFwM7R4sPvfbveVIkhqp2juarwOIiH2L6U21LEqS1BjVXn00PCIWAkuAJRGxICJOqG1pkqR6q/ZE81TgK5l5VGYeBVxF5dWcXYqIIyLiiYhYGhFLIuKKov3AiHg0Il4qPg8o2iMibouI5RGxeHsv+JEk1Ua1odA/M59on8jMnwP9u1mnDbgqM48HTgIujYjjga8Bj2XmMOCxYhrgDGBYMUwGvlftRkiSdo9qQ2FFRHwjIoYUwzXAiu2tkJmvt7+uMzM3AsuAw6lcuTSzWGwmcE4xPhG4IyueAvaPiMN2bHMkSbui2lD4G2AQ8ABwP3Bw0VaViBgCjAaeBg7NzNeLWW8AhxbjhwOvdVittWj7cF+TI2J+RMxfu3ZttSVIkqqw3auPIqIJ+DvgY8BzVA4HfbAjX1BcsXQ/cGVmvhMR5bzMzIjILlfuRGZOpXKOg5aWlh1aV5K0fd3tKcwEWqgEwhnAjTvSeUTsRSUQ7srMB4rmN9sPCxWfa4r21cARHVYfXLRJkuqku1A4PjP/OjO/T+VBeH9RbcdR2SWYBiz70B3Pc4CLivGL2HIj3BzgwuIqpJOADR0OM0mS6qC7m9fKQ0WZ2dbx0E8VxgFfAp6LiEVF2z8A1wOzIuISYBVwfjHvx8CZVB6p8S5w8Y58mSRp13UXCs0R8U4xHkC/YjqonBIY0NWKmTm3WK4z4ztZPoFLuy9ZklQr2w2FzOxTr0IkSY1X7SWpkqRewFCQJJUMBUlSyVCQJJUMBUlSyVCQJJUMBUlSyVCQJJUMBUlSyVCQJJUMBUlSyVCQJJUMBUlSyVCQJJUMBUlSyVCQJJUMBUlSyVCQJJUMBUlSyVCQJJUMBUlSyVCQJJUMBUlSyVCQJJUMBUlSyVCQJJUMBUlSyVCQJJUMBUlSyVCQJJUMBUlSyVCQJJUMBUlSqWahEBE/jIg1EfF8h7YDI+LRiHip+DygaI+IuC0ilkfE4og4sVZ1SZK6Vss9hRnA6R9q+xrwWGYOAx4rpgHOAIYVw2TgezWsS5LUhZqFQmb+AnjrQ80TgZnF+EzgnA7td2TFU8D+EXFYrWqTJHWu3ucUDs3M14vxN4BDi/HDgdc6LNdatG0jIiZHxPyImL927draVSpJvVDDTjRnZgK5E+tNzcyWzGwZNGhQDSqTpN6r3qHwZvthoeJzTdG+Gjiiw3KDizZJUh3VOxTmABcV4xcBD3Zov7C4CukkYEOHw0ySpDrpW6uOI+KfgU8DB0dEK3AtcD0wKyIuAVYB5xeL/xg4E1gOvAtcXKu6JEldq1koZOYFXcwa38myCVxaq1okSdXxjmZJUslQkCSVDAVJUslQkCSVDAVJUslQkCSVDAVJUslQkCSVDAVJUslQkCSVDAVJUslQkCSVDAVJUslQkCSVDAVJUslQkCSVDAVJUslQkCSVDAVJUslQkCSVDAVJUslQkCSVDAVJUslQkCSVDAVJUslQkCSVDAVJUslQkCSVDAVJUslQkCSVDAVJUslQkCSVDAVJUslQkCSVDAVJUmmPCoWIOD0iXoyI5RHxtUbXI0m9zR4TChHRB7gdOAM4HrggIo5vbFVbRESXgyT1FH0bXUAHY4DlmbkCICLuASYCS+tZhL/kpZ6vq3/nmVnnSrpX71r3pFA4HHitw3Qr8OcfXigiJgOTi8lNEfFiFX0fDPxulyvswh4cJDXd7j1Yb91u6L3bvlu2ew/+t7yNDrXuzLYf1dWMPSkUqpKZU4GpO7JORMzPzJYalbTHcrt7n9667b11u2H3b/sec04BWA0c0WF6cNEmSaqTPSkU5gHDImJoROwNfBGY0+CaJKlX2WMOH2VmW0RcBjwM9AF+mJlLdlP3O3S4qQdxu3uf3rrtvXW7YTdve+yJZ9slSY2xJx0+kiQ1mKEgSSr16FDorY/NiIgfRsSaiHi+0bXUU0QcERFPRMTSiFgSEVc0uqZ6iYimiHgmIp4ttv26RtdUTxHRJyIWRsRDja6lXiJiZUQ8FxGLImL+buu3p55TKB6b8RtgApUb4eYBF2RmXe+QboSI+AtgE3BHZg5vdD31EhGHAYdl5q8jYj9gAXBOL/mZB9A/MzdFxF7AXOCKzHyqwaXVRUR8BWgBBmTmWY2upx4iYiXQkpm79WbFnrynUD42IzP/HWh/bEaPl5m/AN5qdB31lpmvZ+avi/GNwDIqd8r3eFmxqZjcqxh65l98HxIRg4HPAz9odC09QU8Ohc4em9ErfkEIImIIMBp4usGl1E1xCGURsAZ4NDN7y7Z/G7ga+GOD66i3BB6JiAXF4392i54cCuqlImJf4H7gysx8p9H11Etm/iEzR1F5GsCYiOjxhw4j4ixgTWYuaHQtDXBKZp5I5cnSlxaHjXdZTw4FH5vRCxXH0+8H7srMBxpdTyNk5tvAE8DpDS6lHsYBf1kcX78HOC0i7mxsSfWRmauLzzXAbCqHzHdZTw4FH5vRyxQnW6cByzLz5kbXU08RMSgi9i/G+1G5wOKFhhZVB5n59cwcnJlDqPwbfzwz/7rBZdVcRPQvLqYgIvoDnwV2y9WGPTYUMrMNaH9sxjJg1m58bMYeLSL+GfgV8PGIaI2ISxpdU52MA75E5a/FRcVwZqOLqpPDgCciYjGVP4gezcxec3lmL3QoMDcingWeAf4lM3+6OzrusZekSpJ2XI/dU5Ak7ThDQZJUMhQkSSVDQZJUMhQkSSVDQQIiYlPxOSQiJu2G/v7hQ9O/3NU+pXowFKStDQF2KBQiorPX2m4VCpl58i7UJNWNoSBt7Xrg1OLGt78vHjJ3Y0TMi4jFEfG3ABHx6Yj4t4iYA2z1aO6IuB7oV/RxV9G2qcN6/xoRD0bEioi4PiL+qngXwnMRcUyx3KCIuL/43nkRMa6u/xXUa3nzmkTll3Zm7hsRnwa+2v5M/uLpk4dk5j9GxD7Ak8B5wFHAvwDDM/OVrvrrov//CxxH5fHmK4AfZOa1xUuBhmbmlRFxN/C/MnNuRBwJPJyZx9Vq+6V2ne32Stris8DIiDi3mB4IDAP+HXims0CowrzMfB0gIl4GHinanwM+U4z/J+D4yuOcABgQEft2eGeCVBOGgrR9AUzJzIe3aqz8xb95J/t8v8P4HztM/5Et/yb/DDgpM9/bye+QdornFKStbQT26zD9MPDl4pHcRMR/LJ5K2Z0P2tfZSY8AU9onImLULvQlVc1QkLa2GPhDRDwbEX9P5RWPS4FfR8TzwPepbg97KrC4/UTzTrgcaClObi8F/m4n+5F2iCeaJUkl9xQkSSVDQZJUMhQkSSVDQZJUMhQkSSVDQZJUMhQkSaX/D7BB+P/yYZHLAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYUAAAEKCAYAAAD9xUlFAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/MnkTPAAAACXBIWXMAAAsTAAALEwEAmpwYAAAcbUlEQVR4nO3deXhV9b3v8fdXQBAQGQRKSS7DKUqAEJAU8VpKZLBYuICK1OkyHL1YVFq1tXrP9T72nGtbbbEip5QWq4B1QIvHwvE4VBGOcgQZKqJGi4hYggoRBRVECHzvH3vlxwYzrITsIeHzep79ZK3fWuu3vys7ySdrNndHREQE4IRMFyAiItlDoSAiIoFCQUREAoWCiIgECgUREQkUCiIiEqQ0FMxsi5m9ZmbrzWxt1NbWzJ41s7ejr22idjOzWWa2ycw2mNkZqaxNRES+Kh1bCue4ez93L4zGbwaWunsPYGk0DnAe0CN6TQXmpKE2ERFJkondR2OBBdHwAmBcUvv9nrAKaG1mnTJQn4jIcatxivt34C9m5sDv3X0u0NHdP4imfwh0jIY7A1uTli2J2j5IasPMppLYkqBFixYDevbsmcLyRUQannXr1n3k7u0rmpbqUPiWu28zsw7As2b2VvJEd/coMGKLgmUuQGFhoa9du7buqhUROQ6Y2XuVTUvp7iN33xZ93QE8DgwEtpfvFoq+7ohm3wbkJi2eE7WJiEiapCwUzKyFmZ1cPgycC7wOLAEmRbNNAhZHw0uAidFZSIOA3Um7mUREJA1SufuoI/C4mZW/z0Pu/rSZrQEeNbMrgPeACdH8TwLfBTYBe4EpKaxNREQqkLJQcPfNQEEF7TuBYRW0O3BNquoRqYkDBw5QUlLCvn37Ml2KSK01a9aMnJwcmjRpEnuZVB9oFqmXSkpKOPnkk+natSvR1q5IveLu7Ny5k5KSErp16xZ7Od3mQqQC+/bto127dgoEqbfMjHbt2tV4a1ehIFIJBYLUd7X5GVYoiIhIoGMKIjEst+V12l+RF1U7T6NGjcjPz6esrIxu3brxxz/+kdatW9dtHUVFzJgxg8LCwupnTpGf/vSntGzZkh//+McZq6E+SfVnpi0FkSx10kknsX79el5//XXatm3L7NmzM10SBw8ezHQJ9UJZWVmmS6g1hYJIPXDWWWexbVviAv933nmHkSNHMmDAAAYPHsxbb70V2gcNGkR+fj633HILLVu2BGD58uWMHj069HXttdcyf/78r7zHtGnTKCwspHfv3tx6662hvWvXrtx0002cccYZ/OlPfzpime3bt3P++edTUFBAQUEBL730EgDjxo1jwIAB9O7dm7lz54b5n376ac444wwKCgoYNuzwmenFxcUUFRXRvXt3Zs2aFdofeOABBg4cSL9+/bjqqquqDaWioiKuv/56CgsLycvLY82aNVxwwQX06NGDW265pdp+W7ZsyY033kjv3r0ZPnw4q1evDnUtWbIESJyEMGXKFPLz8+nfvz/Lli0DYP78+YwZM4ahQ4cybNgwJk6cyJ///OfwnpdddhmLFy8mmbtz44030qdPH/Lz83nkkUeAxGdWVFTE+PHj6dmzJ5dddhmJs/YPu++++7juuuvC+D333MP1119f5fcnFnevt68BAwa4SCoUFxcfMb6MZXX6iqNFixbu7l5WVubjx4/3p556yt3dhw4d6hs3bnR391WrVvk555zj7u6jRo3yhx56yN3d58yZE5ZftmyZjxo1KvR7zTXX+Lx589zdfciQIb5mzRp3d9+5c2d4vyFDhvirr77q7u5dunTxO+64o8IaJ0yY4HfddVdYbteuXUf0tXfvXu/du7d/9NFHvmPHDs/JyfHNmzcfMc+tt97qZ511lu/bt89LS0u9bdu2vn//fi8uLvbRo0f7/v373d192rRpvmDBgiq/Z0OGDPGf/OQn7u4+c+ZM79Spk7///vu+b98+79y5s3/00UdV9gv4k08+6e7u48aN8xEjRvj+/ft9/fr1XlBQ4O7uM2bM8ClTpri7+5tvvum5ubn+xRdf+Lx587xz585hvZYvX+5jx451d/ddu3Z5165d/cCBA0fUu2jRIh8+fLiXlZX5hx9+6Lm5uf7+++/7smXLvFWrVr5161Y/ePCgDxo0yF988cUjPrPPPvvMu3fvHtbjrLPO8g0bNnzle3L0z3K0nmu9kr+rOqYgkqW++OIL+vXrx7Zt28jLy2PEiBF8/vnnvPTSS1x00UVhvi+//BKAlStXhv9ML7300hrvo3/00UeZO3cuZWVlfPDBBxQXF9O3b18Avve971W4zPPPP8/9998PJI6BnHLKKQDMmjWLxx9/HICtW7fy9ttvU1payre//e1wznzbtm1DP6NGjaJp06Y0bdqUDh06sH37dpYuXcq6dev45je/Gb4fHTp0qHY9xowZA0B+fj69e/emU6fEHfi7d+/O1q1bWbFiRaX9nnjiiYwcOTIs37RpU5o0aUJ+fj5btmwBYMWKFUyfPh2Anj170qVLFzZu3AjAiBEjwnoNGTKEq6++mtLSUh577DEuvPBCGjc+8k/uihUruOSSS2jUqBEdO3ZkyJAhrFmzhlatWjFw4EBycnIA6NevH1u2bOFb3/pWWLZly5YMHTqUJ554gry8PA4cOEB+fn6135/qKBREslT5MYW9e/fyne98h9mzZzN58mRat27N+vXrY/fTuHFjDh06FMYrOm/93XffZcaMGaxZs4Y2bdowefLkI+Zr0aJF7Pdbvnw5zz33HCtXrqR58+YUFRVVe65806ZNw3CjRo0oKyvD3Zk0aRK/+MUvYr93cl8nnHDCEf2ecMIJ1fbbpEmTcBpn8vLly1bn6O/TxIkTeeCBB1i4cCHz5s2r1XrA4e/J0a688kp+/vOf07NnT6ZMqZs7A+mYgkiWa968ObNmzeLOO++kefPmdOvWLezbd3deffVVAAYNGsRjjz0GwMKFC8PyXbp0obi4mC+//JJdu3axdOnSr7zHp59+SosWLTjllFPYvn07Tz31VKzahg0bxpw5iYckHjx4kN27d7N7927atGlD8+bNeeutt1i1alWo74UXXuDdd98F4OOPP66270WLFrFjx44w/3vvJe74PHHiRFavXh2rxpr0G8fgwYN58MEHAdi4cSN///vfOf300yucd/LkycycOROAXr16VdjXI488wsGDByktLeWFF15g4MCBsWs588wz2bp1Kw899BCXXHJJ7OWqoi0FkRjinEKaSv3796dv3748/PDDPPjgg0ybNo3bbruNAwcOcPHFF1NQUMDMmTO5/PLL+dnPfsbIkSPDrpzc3FwmTJhAnz596NatG/379/9K/wUFBfTv35+ePXuSm5vL2WefHauuu+++m6lTp3LvvffSqFEj5syZw8iRI/nd735HXl4ep59+OoMGDQKgffv2zJ07lwsuuIBDhw7RoUMHnn322Ur77tWrF7fddhvnnnsuhw4dokmTJsyePZsuXbqwYcMGvv71r9fiO1l1v3FcffXVTJs2jfz8fBo3bsz8+fOP+K8+WceOHcnLy2PcuHEVTj///PNZuXIlBQUFmBm//OUv+drXvhZOHohjwoQJrF+/njZt2sRepkqVHWyoDy8daJZUqejgXLbbs2ePHzp0yN3dH374YR8zZkyGK0qN3bt3+/jx4zNdRix79uzx7t27hwPwqTBq1Ch/7rnnKp1e0wPN2n0k0kCsW7eOfv360bdvX377299y5513ZrqklGjVqtVXTo3NRs899xx5eXlMnz49bLXVpV27dnHaaadx0kknHXF677HS7iORBmLw4MHh+IJk3vDhw2t0rKKmWrduHc56qkvaUhCphHuNHh8uknVq8zOsUBCpQLNmzdi5c6eCQeotj56n0KxZsxotp91HIhXIycmhpKSE0tLSTJciUmvlT16rCYWCSAWaNGlSo6dViTQU2n0kIiKBQkFERAKFgoiIBAoFEREJFAoiIhIoFEREJFAoiIhIoFAQEZFAoSAiIoFCQUREAoWCiIgECgUREQkUCiIiEigUREQkUCiIiEigUBARkSDloWBmjczsFTN7IhrvZmYvm9kmM3vEzE6M2ptG45ui6V1TXZuIiBwpHVsKPwTeTBq/A7jL3b8BfAJcEbVfAXwStd8VzSciImmU0lAwsxxgFPCHaNyAocCiaJYFwLhoeGw0TjR9WDS/iIikSaq3FGYCPwEORePtgF3uXhaNlwCdo+HOwFaAaPruaP4jmNlUM1trZmv1UHURkbqVslAws9HADndfV5f9uvtcdy9098L27dvXZdciIse9xins+2xgjJl9F2gGtALuBlqbWeNoayAH2BbNvw3IBUrMrDFwCrAzhfWJiMhRUral4O7/291z3L0rcDHwvLtfBiwDxkezTQIWR8NLonGi6c+7u6eqPhER+apMXKdwE3CDmW0icczg3qj9XqBd1H4DcHMGahMROa6lcvdR4O7LgeXR8GZgYAXz7AMuSkc9IiJSMV3RLCIigUJBREQChYKIiAQKBRERCRQKIiISKBRERCRQKIiISKBQEBGRQKEgIiKBQkFERAKFgoiIBAoFEREJFAoiIhIoFEREJFAoiIhIoFAQEZFAoSAiIoFCQUREAoWCiIgECgUREQkUCiIiEigUREQkUCiIiEigUBARkUChICIigUJBREQChYKIiAQKBRERCRQKIiISKBRERCRQKIiISKBQEBGRQKEgIiKBQkFERIKUhYKZNTOz1Wb2qpm9YWb/HLV3M7OXzWyTmT1iZidG7U2j8U3R9K6pqk1ERCqWyi2FL4Gh7l4A9ANG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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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HUu3bt3ititWrKBt27asXLmSj33sYwAcOHCAM888kxdffJHRo0fTo0fiRprXXXcdf//73z9QxyeffJIHHnggznft2hWABx98kHnz5lFVVcW2bdsoKyvDzDj77LPje3Xu3DluN2bMGE4//XQABgwYwJYtW9i9ezdlZWVcfPHFABw6dIgRI0bU225XXXUVZkZ+fj49e/YkPz8fgIEDB7J582bKy8vr3O/48eMByM/Pp7Kykk6dOtGpUyfat2/P7t27WbFiBddffz05OTn07NmTSy65hJKSEjp37kxRUVG8JiA3N5du3bqxevVq3n77bQoKCmL7V1uxYgUTJ06kY8eO8d/l2WefZfz48fTr148hQ4bEf+PNmzcfs62Z8fnPf5777ruPKVOm8Pzzz3PvvffW2z71USiINGM5OTmMHj2a0aNHk5+fz4IFC2IoVB9WysnJoaqqCoBvfetbXHrppSxatIjNmzczevTouK/jT080M9yd4uJivvvd7x6zbPHixY2u86ZNm/jBD35ASUkJXbt2ZfLkyfWeK1/9WZI/j7szduxYfve73zXo/av31aZNm2P226ZNG6qqqsjJyalzv/VtX5fqX+7VbrrpJubPn89bb73FjTfe2KjPAYk2Of7wEcCUKVO46qqr6NChA5MmTWqScQyNKYg0U+vWrWP9+vVx/uWXX6Zv3751brNnzx569eoFJMYRki1dupRdu3Zx4MABFi9ezMUXX8yYMWN4+OGH2b49cbPiXbt2sWXLFi666CKeeeYZdu7cyeHDh3nooYdqfL+xY8cyd+7cOP/OO++wd+9eOnbsyOmnn87bb7/Nn/70JwAuuOACtm3bRklJCQD79u2r85fs8OHDee6559iwYQMA+/fvj72V2267jUWLFtXZFo3ZbypGjRrFwoULOXLkCBUVFfz5z3+mqKioxnUnTpzIY489RklJCePGjatxX4sXL+bdd99l//79LFq0iFGjRqVcl3POOYdzzjmH2bNnM2VK09wuTj0FkRSlcgppU6qsrGTmzJns3r2btm3bct555zFv3rw6t7n11lspLi5m9uzZfOpTnzpmWVFREZ/+9KcpLy/nhhtuoLAw8YTc2bNnc9lll3H06FHatWvH3LlzGT58OLfffjsjRoygS5cu8TDG8b75zW8yY8YMBg0aRE5ODrNmzeKaa66hoKCACy+8kD59+sTDNKeccgoLFy5k5syZHDhwgFNPPZUnn3yy1s/So0cP5s+fz/XXX8/BgwdjXc8//3zWrl0bD/M0VF37TcXEiRN5/vnnGTx4MGbG97//fc4666w42J/slFNO4dJLL6VLly7k5OR8YPnQoUOZPHlyDJWbbrqJgoKCDxwqqsvnPvc5Kioq6N+/f8rb1MUSYw4tkx6yI+n02muvNdl/tGxrbdcCjBs3jscffzzb1ajX0aNHGTp0KA899BB5eXlpeY+vfOUrFBQUMHXq1BqX1/Q9NrOV7l5Y0/o6fCQiLU5LCISysjLOO+88xowZk7ZAGDZsGGvWrOGGG25osn2qpyBSi9bUU5CTl3oKIk2oJf/RJNKY769CQaQWHTp0YOfOnQoGaZE8PE+hQ4cODdpOZx+J1KJ3796Ul5dTUVGR7aqINEr1k9caQqEgUot27do16IlVIq2BDh+JiEikUBARkUihICIikUJBREQihYKIiEQKBRERiRQKIiISKRRERCRSKIiISKRQEBGRSKEgIiKRQkFERCKFgoiIRAoFERGJFAoiIhIpFEREJEp7KJhZjpmtNrM/hPl+ZvaimW0ws4Vmdkoobx/mN4Tluemum4iIHCsTPYWbgdeS5r8H/MjdzwPeAaaG8qnAO6H8R2E9ERHJoLSGgpn1Bj4F/DLMG/Bx4OGwygLg6jA9IcwTlo8J64uISIaku6fwY+BW4GiY7wbsdveqMF8O9ArTvYA3AMLyPWH9Y5jZNDMrNbNSPVBdRKRppS0UzOxKYLu7r2zK/br7PHcvdPfCHj16NOWuRUROem3TuO+LgfFm9kmgA9AZuBPoYmZtQ2+gN7A1rL8V6AOUm1lb4HRgZxrrJyIix0lbT8Hdb3P33u6eC3wWeNrdPwcsA64NqxUDj4bpJWGesPxpd/d01U9ERD4oG9cp/B/gq2a2gcSYwa9C+a+AbqH8q8DXs1A3EZGTWjoPH0XuvhxYHqY3AkU1rPMeMCkT9RERkZrpimYREYkUCiIiEikUREQkUiiIiEikUBARkUihICIikUJBREQihYKIiEQKBRERiRQKIiISKRRERCRSKIiISKRQEBGRSKEgIiKRQkFERCKFgoiIRAoFERGJFAoiIhIpFEREJFIoiIhIpFAQEZFIoSAiIpFCQUREIoWCiIhECgUREYkUCiIiEikUREQkUiiIiEikUBARkUihICIikUJBREQihYKIiEQKBRERiRQKIiISpS0UzKyDmb1kZq+Y2atmdkco72dmL5rZBjNbaGanhPL2YX5DWJ6brrqJiEjN0tlTOAh83N0HA0OAy81sOPA94Efufh7wDjA1rD8VeCeU/yisJyIiGdQ2lZXMrD3waSA3eRt3/8/atnF3ByrDbLvwcuDjwL+E8gXA7cDPgQlhGuBh4KdmZmE/IiKSAan2FB4l8Uu7Ctif9KqTmeWY2cvAdmAp8Dqw292rwirlQK8w3Qt4AyAs3wN0q2Gf08ys1MxKKyoqUqy+iIikIqWeAtDb3S9v6M7d/QgwxMy6AIuACxu6jxr2OQ+YB1BYWKhehIhIE0q1p/AXM8tv7Ju4+25gGTAC6GJm1WHUG9gaprcCfQDC8tOBnY19TxERabhUQ+GfgJVmts7M1pjZWjNbU9cGZtYj9BAws1OBscBrJMLh2rBaMYlDUwBLwjxh+dMaTxARyaxUDx9d0Yh9nw0sMLMcEuHzoLv/wczKgAfMbDawGvhVWP9XwG/MbAOwC/hsI95TREROQEqh4O5bzGwwMCoUPevur9SzzRqgoIbyjUBRDeXvAZNSqY+IiKRHSoePzOxm4LfAmeF1n5nNTGfFREQk81I9fDQVuMjd9wOY2feA54GfpKtiIiKSeakONBtwJGn+SCgTEZFWJNWewj3Ai2a2KMxfzfsDxCIi0kqkOtD8QzNbTuLUVIAp7r46bbUSEZGsqDMUzKyzu+81szOAzeFVvewMd9+V3uqJiEgm1ddTuB+4ElhJ4mZ21SzMn5umeomISBbUGQrufmX42S8z1RERkWxK9TqFp1IpExGRlq2+MYUOwIeA7mbWlfdPQ+3M+7e8FhGRVqK+MYUvAbcA55AYV6gOhb3AT9NXLRERyYb6xhTuBO40s5nurquXRURauVSvU/iJmQ0CBgAdksrvTVfFREQk81J9RvMsYDSJUPgjiVtprwAUCiIirUiq9z66FhgDvOXuU4DBJJ6MJiIirUiqoXDA3Y8CVWbWGdhOeHSmiIi0HqneEK80PFrz/5E4C6mSxK2zRUSkFUl1oPl/hclfmNljQOfwZDUREWlF6rt4bWhdy9x9VdNXSUREsqW+nsL/rWOZAx9vwrqIiEiW1Xfx2qWZqoiIiGRfqtcpfKGmcl28JiLSuqR69tHHkqY7kLhmYRW6eE1EpFVJ9eyjmcnz4fTUB9JRIRERyZ5UL1473n5AD94REWllUh1T+G/efxxnDtAfeDBdlRIRkexIdUzhB0nTVcAWdy9PQ31ERCSLUjp85O7PAOtI3ATvDBLBICIirUyqz2i+CXgJuIbEHVNfMLMb01kxERHJvFQPH30NKHD3nQBm1g34C/DrdFVMREQyL9Wzj3YC+5Lm94UyERFpRVLtKWwAXjSzR0mchTQBWGNmXwVw9x+mqX4iIpJBqYbC6+FV7dHws1PTVkdERLIp1Sua7wAws9PCfGU6KyUiItmR6tlHg8xsNfAq8KqZrTSzgemtmoiIZFqqA83zgK+6e1937wv8O4lHc9bKzPqY2TIzKzOzV83s5lB+hpktNbP14WfXUG5mdpeZbTCzNXU94EdERNIj1VDo6O7LqmfcfTnQsZ5tqoB/d/cBwHBghpkNAL4OPOXuecBTYR7gCiAvvKYBP0/1Q4iISNNINRQ2mtm3zCw3vL4JbKxrA3ffVv24TnffB7wG9CJx5tKCsNoC4OowPQG41xNeALqY2dkN+zgiInIiUg2FG4EewO+BR4DuoSwlZpYLFAAvAj3dfVtY9BbQM0z3At5I2qw8lB2/r2lmVmpmpRUVFalWQUREUlDn2Udm1gH4MnAesJbE4aDDDXmDcMbSI8At7r7XzOIyd3cz81o3roG7zyMxxkFhYWGDthURkbrV11NYABSSCIQrgP9qyM7NrB2JQPitu/8+FL9dfVgo/NweyrcCfZI27x3KREQkQ+oLhQHufoO7303iRnj/nOqOLdEl+BXw2nFXPC8BisN0Me9fCLcE+EI4C2k4sCfpMJOIiGRAfRevxUNF7l6VfOgnBRcDnwfWmtnLoew/gDnAg2Y2FdgCfCYs+yPwSRK31HgXmNKQNxMRkRNXXygMNrO9YdqAU8O8kRgS6Fzbhu6+IqxXkzE1rO/AjPqrLCIi6VJnKLh7TqYqIiIi2ZfqKakiInISUCiIiEikUBARkUihICIikUJBREQihYKIiEQKBRERiRQKIiISKRRERCRSKIiISKRQEBGRSKEgIiKRQkFERCKFgoiIRAoFERGJFAoiIhIpFEREJFIoiIhIpFAQEZFIoSAiIpFCQUREIoWCiIhECgUREYkUCiIiEikUREQkUiiIiEikUBARkUihICIikUJBREQihYKIiEQKBRERiRQKIiISKRRERCRKWyiY2a/NbLuZ/TWp7AwzW2pm68PPrqHczOwuM9tgZmvMbGi66iUiIrVLZ09hPnD5cWVfB55y9zzgqTAPcAWQF17TgJ+nsV4iIlKLtIWCu/8Z2HVc8QRgQZheAFydVH6vJ7wAdDGzs9NVNxERqVmmxxR6uvu2MP0W0DNM9wLeSFqvPJR9gJlNM7NSMyutqKhIX01FRE5CWRtodncHvBHbzXP3Qncv7NGjRxpqJiJy8sp0KLxdfVgo/NweyrcCfZLW6x3KREQkgzIdCkuA4jBdDDyaVP6FcBbScGBP0mEmERHJkLbp2rGZ/Q4YDXQ3s3JgFjAHeNDMpgJbgM+E1f8IfBLYALwLTElXvUREpHZpCwV3v76WRWNqWNeBGemqi4iIpEZXNIuISKRQEBGRSKEgIiKRQkFERCKFgoiIRAoFERGJFAoiIhIpFEREJFIoiIhIpFAQEZFIoSAiIpFCQUREIoWCiIhEabtLqtTO7rAGre+zGvyAOhGRRlFPQUREIoWCiIhECgUREYk0ptCC1TY2oTEIEWkshUIL0NCBaYWFiDSWDh+JiEikUBARkUiHj5qADteISGuhnoKIiETqKaRRQweIRUSyTT0FERGJFAoiIhIpFEREJNKYwklEZ0mJSH3UUxARkUg9BVEPQkQihYLUSmEhcvLR4SMREYnUUziOLjirX2PaSL0LkZbhpA0F/fLPLB2KEmkZTtpQkOZBYSHSvDSrUDCzy4E7gRzgl+4+J8tVkixRWIhkR7MJBTPLAeYCY4FyoMTMlrh7WXZrJs1JQw/71RYiCh2RmjWbUACKgA3uvhHAzB4AJgAKBWm0pnqUaW0aGjqN2VdTaY5B2FTt3VSaW30g8/9u5t48/jIys2uBy939pjD/eeAid//KcetNA6aF2QuAdRmt6Ad1B3ZkuQ7Nldqmdmqbuql9atcUbdPX3XvUtKA59RRS4u7zgHnZrkc1Myt198Js16M5UtvUTm1TN7VP7dLdNs3p4rWtQJ+k+d6hTEREMqQ5hUIJkGdm/czsFOCzwJIs10lE5KTSbA4fuXuVmX0FeJzEKam/dvdXs1ytVDSbQ1nNkNqmdmqbuql9apfWtmk2A80iIpJ9zenwkYiIZJlCQUREIoVCHczscjNbZ2YbzOzrNSz/ZzNbZWZV4TqL5GVHzOzl8Gp1A+YptM1XzazMzNaY2VNm1jdpWbGZrQ+v4szWPP1OsG1O9u/Nl81sbfj8K8xsQNKy28J268xsXGZrnn6NbRszyzWzA0nfm1+cUEXcXa8aXiQGu18HzgVOAV4BBhy3Ti7wUeBe4NrjllVm+zNkuW0uBT4UpqcDC8P0GcDG8LNrmO6a7c/UHNpG3xsH6Jw0PR54LEwPCOu3B/qF/eRk+zM1k7bJBf7aVHVRT6F28bYb7n4IqL7tRuTum919DXA0GxXMolTaZpm7vxtmXyBx3QnAOGCpu+9y93eApcDlGap3JpxI27R2qbTN3qTZjkD1mTATgAfc/aC7bwI2hP21FifSNk1KoVC7XsAbSfPloSxVHcys1MxeMLOrm7Rm2dfQtpkK/KmR27Y0J9I2oO8NZjbDzF4Hvg/8a0O2bcFOpG0A+pnZajN7xsxGnUhFms11Cq1QX3ffambnAk+b2Vp3fz3blco0M7sBKAQuyXZdmpta2uak/964+1xgrpn9C/BNoNWNOzVWLW2zDfiwu+80s2HAYjMbeFzPImXqKdTuhG674e5bw8+NwHKgoCkrl2UptY2ZfQL4BjDe3Q82ZNsW7ETaRt+bYz0AXN3IbVuaRrdNOKS2M0yvJDE2cX6ja5LtAZbm+iLRi9pIYlCreuBnYC3rzidpoJnEAGr7MN0dWM9xg0Yt+ZVK25D4ZfY6kHdc+RnAptBGXcP0Gdn+TM2kbfS9SWoT4CqgNEwP5NiB5o20roHmE2mbHtVtQWKgeuuJ/J/KemM05xfwSeDv4T/wN0LZf5L46w7gYySO/e0HdgKvhvKRwNrwD7sWmJrtz5KFtnkSeBt4ObyWJG17I4mBwg3AlGx/lubSNvreOCSevPhqaJdlyb8YSfSsXidxu/wrsv1ZmkvbAJ9OKl8FXHUi9dBtLkREJNKYgoiIRAoFERGJFAoiIhIpFEREJFIoiIhIpFAQAcysMvzMDVeLnuj+/uO4+b+c6D5FMkGhIHKsXKBBoWBmNd0u5phQcPeRJ1AnkYxRKIgcaw4wKtyX/t/MLMfM/svMSsLzD74EYGajzezZ8MyDsuQdmNkc4NSwj9+Gssqk7Z4xs0fNbKOZzTGzz5nZS+Fe+R8J6/Uws0fC+5aY2cUZbQU5aeniNRESv7Td/TQzGw38b3e/MpRPA85099lm1h54DpgE9AX+BxjkiVs517i/Wva/GOgP7CJxa4NfuvssM7sZ6Ofut5jZ/cDP3H2FmX0YeNzd+6fr84tU011SRep2GfBRe//JeqcDecAh4KWaAiEFJe6+DSDcBvmJUL6WxAN4AD4BDDCz6m06m9lp7l7ZiPcTSZlCQaRuBsx098ePKUz8xb+/kfs8mDR9NGn+KO//n2wDDHf39xr5HiKNojEFkWPtAzolzT8OTDezdgBmdr6ZdUxhP4ert2mkJ4CZ1TNmNuQE9iWSMoWCyLHWAEfM7BUz+zfglyQGkleZ2V+Bu0mthz0PWFM90NwI/woUhsHtMuDLjdyPSINooFlERCL1FEREJFIoiIhIpFAQEZFIoSAiIpFCQUREIoWCiIhECgUREYn+P0Tei+Ne8dl5AAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "#plotting the measurement context results as a histogram.\n", + "import matplotlib.mlab as mlab\n", + "import matplotlib.pyplot as plt\n", + "\n", + "plt.hist(t_a, 50, facecolor= 'r', label='Regular cache, disk DB') \n", + "plt.ylabel('Population')\n", + "plt.ylim(0, size_a)\n", + "plt.xlabel('Iter time') \n", + "plt.legend()\n", + "plt.show() \n", + "plt.hist(t_b, 50, facecolor= 'b', label='Shaped cache, disk DB')\n", + "plt.ylabel('Population')\n", + "plt.ylim(0, size_a)\n", + "plt.xlabel('Iter time') \n", + "plt.legend()\n", + "plt.show() \n", + "plt.hist(t_c, 50, facecolor= 'k', label='No cache, disk DB')\n", + "plt.ylabel('Population')\n", + "plt.ylim(0, size_a)\n", + "plt.xlabel('Iter time') \n", + "plt.legend()\n", + "plt.show() \n", + "plt.hist(t_d, 50, facecolor= 'm', label='Regular cache, memory only')\n", + "plt.ylabel('Population')\n", + "plt.ylim(0, size_a)\n", + "plt.xlabel('Iter time') \n", + "plt.legend()\n", + "plt.show() \n", + "plt.hist(t_e, 50, facecolor= 'g', label='Shaped cache, memory only')\n", + "plt.ylabel('Population')\n", + "plt.ylim(0, size_a)\n", + "plt.xlabel('Iter time') \n", + "plt.legend()\n", + "plt.show() " + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/technologies/caching/Cache_time_test_results.txt b/technologies/caching/Cache_time_test_results.txt new file mode 100644 index 0000000..948f89b --- /dev/null +++ b/technologies/caching/Cache_time_test_results.txt @@ -0,0 +1,43 @@ +Intro: Cache performance is critical when working with large datasets + obtained from several iterations of the add_results() method. In some + cases successive expansions of the existing cache result in severe + slowing of system performance. To this end Jens has added the shaped + cache feature, which pre-allocates the memory for caching, avoiding the + intensive process of cache expansion. To demonstrate and test this new + feature, we have run 7 test cases to assess cache performance featuring + contexts without cache, with the default cache, and pre-allocated cache + enabled. We have also included variants which write to the regular SQLite + database, or keep all data in memory. Lastly, these are compared to the + DoNd functions which already pre-allocate cache size based on data shape. + +Conclusions: + 1- Dynamically allocated cache underperforms in all cases. + 2- DoNd with and without cache offer equivalent performance. + 3- SQLite database writes do not hinder performance. + +Reference: +1 - Measurement with context manager with cache +2 - Measurement with context manager with shaped cache +3 - Measurement with context manager without cache +4 - Measurement with context manager with cache, dataset in memory. +5 - Measurement with context manager with shaped cache and dataset in memory. +6 - Measurement with doNd, iteration time estimated from total execution +7 - Measurement with doNd (nocache) iteration time estimated from total execution + +Timed function: add_result() (exp 1-5), DoNd() (exp 6-7). + +| Results | +| n | exp_1 | exp_2 | exp_3 | exp_4 | exp_5 | exp_6*| exp_7*| +| iter | ----------- avg ms iter^-1 -------------------------- | +| 1 | 0.934 | 0.879 | 0.321 | 0.377 | 0.473 | 60.51 | 57.48 | +| 2 | 0.413 | 0.478 | 0.256 | 0.496 | 0.471 | 45.12 | 29.89 | +| 5 | 0.418 | 0.291 | 0.295 | 0.324 | 0.488 | 16.85 | 12.11 | +| 10 | 0.452 | 0.324 | 0.283 | 0.491 | 0.363 | 7.071 | 7.071 | +| 50 | 0.311 | 0.527 | 0.309 | 0.322 | 0.341 | 2.442 | 1.532 | +| 100 | 0.288 | 0.326 | 0.127 | 0.317 | 0.346 | 1.457 | 0.753 | +| 1000 | 0.257 | 0.217 | 0.125 | 0.209 | 0.214 | 0.319 | 0.269 | +| 10000 | 0.289 | 0.267 | 0.141 | 0.227 | 0.219 | 0.238 | 0.238 | +| 20000 | 0.287 | 0.252 | 0.126 | 0.262 | 0.217 | 0.247 | 0.227 | +| 50000 | 0.342 | 0.305 | 0.142 | 0.297 | 0.230 | 0.234 | 0.234 | +| 100000| 0.591 | 0.251 | 0.180 | 0.589 | 0.293 | 0.253 | 0.228 | +| 200000| 2.042 | 0.257 | 0.180 | 1.863 | 0.203 | 0.268 | 0.229 | From 65b2f2911475b66e699cb9cf398c4b1e672cb46d Mon Sep 17 00:00:00 2001 From: thepoole Date: Tue, 16 Nov 2021 16:06:01 +0100 Subject: [PATCH 2/2] Consolidated, marked up.. down.. --- technologies/caching/Cache_time_test.ipynb | 138 +++++++++++++++++- .../caching/Cache_time_test_results.txt | 43 ------ 2 files changed, 130 insertions(+), 51 deletions(-) delete mode 100644 technologies/caching/Cache_time_test_results.txt diff --git a/technologies/caching/Cache_time_test.ipynb b/technologies/caching/Cache_time_test.ipynb index 103f758..d6b4cf4 100644 --- a/technologies/caching/Cache_time_test.ipynb +++ b/technologies/caching/Cache_time_test.ipynb @@ -1,5 +1,62 @@ { "cells": [ + { + "cell_type": "markdown", + "id": "64d2ce94", + "metadata": {}, + "source": [ + "Intro:\n", + "------ \n", + "Cache performance is critical when working with large datasets obtained from several iterations of the add_results() method. In some cases successive expansions of the existing cache result in severe slowing of system performance. To this end Jens has added the shaped cache feature, which pre-allocates the memory for caching, avoiding the intensive process of cache expansion. To demonstrate and test this new feature, we have run 7 test cases to assess cache performance featuring contexts without cache, with the default cache, and pre-allocated cache enabled. We have also included variants which write to the regular SQLite database, or keep all data in memory. Lastly, these are compared to the DoNd functions which already pre-allocate cache size based on data shape.\n", + "\n", + "Approach:\n", + "---------\n", + "We will base this on a simple dummy instrument setup used typically to introduce qcodes to new users. We will make multiple measurements of two dummy instruments via 2 nested loops within a specific measurement context. The execution time of a function is estimated by bracketing 'time.pref_counter()' calls, and these values will be averaged for each outer loop execution. These averaged execution times can be used to assess the cache and database performance as more data is recorded.\n", + "\n", + "Conclusions:\n", + "------------ \n", + "\n", + "1. Dynamically allocated cache underperforms in all cases.\n", + "2. DoNd with and without cache offer equivalent performance.\n", + "3. SQLite database writes do not hinder performance." + ] + }, + { + "cell_type": "markdown", + "id": "f252f623", + "metadata": {}, + "source": [ + "Set up dataset sizes\n", + "--------------------\n", + "Datasets are sized by a, b, and n corresponding to the outer, inner and repeat loops respectively. \n", + "Iterations times are recorded for each execution of 'add_result()' in the inner loop, and averaged with each execution of the outer loop. This averages out periodic database writes (when relevant).\n", + "\n", + "Note that no logic handles averaging over the outermost (repeat) loops, this was mostly for testing. Generally size_n should remain as 1." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "72fe8350", + "metadata": {}, + "outputs": [], + "source": [ + "#Loop sizes\n", + "size_a = 500\n", + "size_b = 200\n", + "size_n = 1" + ] + }, + { + "cell_type": "markdown", + "id": "1dafe9aa", + "metadata": {}, + "source": [ + "Environment setup\n", + "-----------------\n", + "This section imports modules and then sets up the instruments in subsequent cells." + ] + }, { "cell_type": "code", "execution_count": 1, @@ -76,6 +133,16 @@ "dmm = DummyInstrumentWithMeasurement('dmm', setter_instr=dac)\n" ] }, + { + "cell_type": "markdown", + "id": "3a86fd3c", + "metadata": {}, + "source": [ + "Measurement setups\n", + "------------------\n", + "These cells set up the experiment, and measurements with (meas_with_shape) and without (meas) pre-allocated data shapes. " + ] + }, { "cell_type": "code", "execution_count": 4, @@ -115,16 +182,13 @@ ] }, { - "cell_type": "code", - "execution_count": 5, - "id": "72fe8350", + "cell_type": "markdown", + "id": "7d3e8a6b", "metadata": {}, - "outputs": [], "source": [ - "#Setting up dataset sizes.\n", - "size_a = 500\n", - "size_b = 200\n", - "size_n = 1" + "Testing cache with context manager\n", + "----------------------------------\n", + "This section is where the for loops live. With each output is included the average, this is not as useful as the scatterplot below, but it may be nice in some cases so it was left in." ] }, { @@ -468,6 +532,16 @@ "print(sum(t_e)/len(t_e))" ] }, + { + "cell_type": "markdown", + "id": "c9d27965", + "metadata": {}, + "source": [ + "Testing cache with doNd\n", + "------------------------\n", + "This section is like those above, but it runs with the doNd function rather than the context manager. This is mostly for comparison of average execution times, see table below." + ] + }, { "cell_type": "code", "execution_count": 11, @@ -497,6 +571,18 @@ "print(sum(t_f)/len(t_f)/size_a/size_b*1000) " ] }, + { + "cell_type": "markdown", + "id": "7250ac6a", + "metadata": {}, + "source": [ + "Plots, output, data.\n", + "--------------------\n", + "This section provides the useful data from the test. Wherein you will find a scatter plot of the rolling average results obtained above, and histograms to show the distribution of the data.\n", + "\n", + "Note that historgrams are skewed by database writes, so these are not as useful compared to the scatterplot." + ] + }, { "cell_type": "code", "execution_count": 12, @@ -636,6 +722,42 @@ "plt.legend()\n", "plt.show() " ] + }, + { + "cell_type": "markdown", + "id": "a2df18b1", + "metadata": {}, + "source": [ + "Tabulated data of total execution times\n", + "---------------------------------------\n", + "Here are some details which show the total time spent for each execution. It is clear that the dynamic cache is slower with larger data sets.\n", + "\n", + "Reference:\n", + "1 - Measurement with context manager with cache \n", + "2 - Measurement with context manager with shaped cache \n", + "3 - Measurement with context manager without cache \n", + "4 - Measurement with context manager with cache, dataset in memory. \n", + "5 - Measurement with context manager with shaped cache and dataset in memory.\n", + "6 - Measurement with doNd, iteration time estimated from total execution\n", + "7 - Measurement with doNd (nocache) iteration time estimated from total execution\n", + "\n", + "Timed function: add_result() (exp 1-5), DoNd() (exp 6-7).\n", + "\n", + "|n(iter)|exp_1|exp_2|exp_3|exp_4|exp_5|exp_6|exp_7|\n", + "|-------|-----|-----|-----|-----|-----|-----|-----|\n", + "|1 |0.934|0.879|0.321|0.377|0.473|60.51|57.48|\n", + "|2 |0.413|0.478|0.256|0.496|0.471|45.12|29.89|\n", + "|5 |0.418|0.291|0.295|0.324|0.488|16.85|12.11|\n", + "|10 |0.452|0.324|0.283|0.491|0.363|7.071|7.071|\n", + "|50 |0.311|0.527|0.309|0.322|0.341|2.442|1.532|\n", + "|100 |0.288|0.326|0.127|0.317|0.346|1.457|0.753|\n", + "|1000 |0.257|0.217|0.125|0.209|0.214|0.319|0.269|\n", + "|10000 |0.289|0.267|0.141|0.227|0.219|0.238|0.238|\n", + "|20000 |0.287|0.252|0.126|0.262|0.217|0.247|0.227|\n", + "|50000 |0.342|0.305|0.142|0.297|0.230|0.234|0.234|\n", + "|100000 |0.591|0.251|0.180|0.589|0.293|0.253|0.228|\n", + "|200000 |2.042|0.257|0.180|1.863|0.203|0.268|0.229|\n" + ] } ], "metadata": { diff --git a/technologies/caching/Cache_time_test_results.txt b/technologies/caching/Cache_time_test_results.txt deleted file mode 100644 index 948f89b..0000000 --- a/technologies/caching/Cache_time_test_results.txt +++ /dev/null @@ -1,43 +0,0 @@ -Intro: Cache performance is critical when working with large datasets - obtained from several iterations of the add_results() method. In some - cases successive expansions of the existing cache result in severe - slowing of system performance. To this end Jens has added the shaped - cache feature, which pre-allocates the memory for caching, avoiding the - intensive process of cache expansion. To demonstrate and test this new - feature, we have run 7 test cases to assess cache performance featuring - contexts without cache, with the default cache, and pre-allocated cache - enabled. We have also included variants which write to the regular SQLite - database, or keep all data in memory. Lastly, these are compared to the - DoNd functions which already pre-allocate cache size based on data shape. - -Conclusions: - 1- Dynamically allocated cache underperforms in all cases. - 2- DoNd with and without cache offer equivalent performance. - 3- SQLite database writes do not hinder performance. - -Reference: -1 - Measurement with context manager with cache -2 - Measurement with context manager with shaped cache -3 - Measurement with context manager without cache -4 - Measurement with context manager with cache, dataset in memory. -5 - Measurement with context manager with shaped cache and dataset in memory. -6 - Measurement with doNd, iteration time estimated from total execution -7 - Measurement with doNd (nocache) iteration time estimated from total execution - -Timed function: add_result() (exp 1-5), DoNd() (exp 6-7). - -| Results | -| n | exp_1 | exp_2 | exp_3 | exp_4 | exp_5 | exp_6*| exp_7*| -| iter | ----------- avg ms iter^-1 -------------------------- | -| 1 | 0.934 | 0.879 | 0.321 | 0.377 | 0.473 | 60.51 | 57.48 | -| 2 | 0.413 | 0.478 | 0.256 | 0.496 | 0.471 | 45.12 | 29.89 | -| 5 | 0.418 | 0.291 | 0.295 | 0.324 | 0.488 | 16.85 | 12.11 | -| 10 | 0.452 | 0.324 | 0.283 | 0.491 | 0.363 | 7.071 | 7.071 | -| 50 | 0.311 | 0.527 | 0.309 | 0.322 | 0.341 | 2.442 | 1.532 | -| 100 | 0.288 | 0.326 | 0.127 | 0.317 | 0.346 | 1.457 | 0.753 | -| 1000 | 0.257 | 0.217 | 0.125 | 0.209 | 0.214 | 0.319 | 0.269 | -| 10000 | 0.289 | 0.267 | 0.141 | 0.227 | 0.219 | 0.238 | 0.238 | -| 20000 | 0.287 | 0.252 | 0.126 | 0.262 | 0.217 | 0.247 | 0.227 | -| 50000 | 0.342 | 0.305 | 0.142 | 0.297 | 0.230 | 0.234 | 0.234 | -| 100000| 0.591 | 0.251 | 0.180 | 0.589 | 0.293 | 0.253 | 0.228 | -| 200000| 2.042 | 0.257 | 0.180 | 1.863 | 0.203 | 0.268 | 0.229 |