Skip to content
Snippets Groups Projects
test_small_block_benchmark.ipynb 33.5 KiB
Newer Older
{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "from pystencils.session import *\n",
    "from time import perf_counter\n",
    "from statistics import median\n",
    "from functools import partial"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Benchmark for Python call overhead"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAATcAAAAUBAMAAAAaQ2ctAAAAMFBMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAdt3NMolEIpm7EKvvVGZvmWXoAAAACXBIWXMAAA7EAAAOxAGVKw4bAAADSElEQVRIDc2VTUhUURiG39G583Pv3NEEyZ2DFfSzUEKCXORsgqCFIzShG73UNnAoImkRA5GM2MJFUEbQ1WhlMBYVkaZDCyNRmF2BENOiVdCPU4Zi3r57zjgz95yjzLKzuHPO+33vc9859w9Nnfg/R/S4hfPA8OgdRb4zkjbZPCJpXNB6z4mVYLI/j2BmIi4WgGSzK8p81sks+r4+C5obTp/BoMUKnsMRz8pdpGHkJdFcAvQTuCkWhmFuYxrauljAIyvUQaLMh8tilhDwhoczbERyEsL3XpTMAoIu1TOmxzaBcBoTHpUWrXms4TWwLBZwD+FxQOaDsZjlE3CFh4vEYPySEDdOipI2Dj0mivBRuKGUJOOSpRfxFliIC7XAHybIfApMLGbpB6Z4uPpNVbiEFC6wYWsF4Uwc+EBSXYEua7cthwvnWLfM5yxmGbqPAR6OeusosndEU1I4LGwPeJvclftvi6dbLLkylXC1dluoNHT20nOl4jMWsxjOl0I53BDjVFMmIYfTnK7qFj6ncHqxgBWpcvWwTVrgt1jInkIkDxW/FM61DBbtcrhjIgEJRbjVC1uW1OiGc2zctqWKtkhS3YyoZzcRWlLyS+HIYr5sX9wJF0qLBDMuh4vOoJWedWG4l3UN+G4JOi2XbSAjyQ0xRNdVfH6LMMtX+LZs9p4DWiTCY8jhIin4/0qdbrgDFK4gVK4BD/PwpQWZ9rID0W0VvxTOtbwDevI8nJkGoTxjdXZ266lHAbK0nhc0DpxT7Bxdagr3EUHxNWPkaOdU/FI4slz/ARgFHo4+JPulk0J6CdPO4a7U5+5cD91zYoHs7Sl/Gj4xnJ/uuRx1S3wejllo58IpFi54KDkWozemMDboKfRIgS5EGwWNA42EvoJsh6f7G8yfuJzseyYW8AJP8tQq8TmLWS7a+MwfiHrHcWJosz1s9Dvzonb21ghELTRXpEvdNxZH3VEPIJAZtdDtOGtiAVrmOXUq+IzFLP5XOx9+zjTF7Se5Vo0TPvAf+bhrQcWv2Pk9x9ZaRS3PatW4IVH2CZNdCyp+xVsVbrKilme1asygN5Z93smuBfpM7DWqwhUUfbVqzBpVAPYuQMWvUChc08HK8r+a+dqsf+S+/F/QsHg/AAAAAElFTkSuQmCC\n",
      "text/latex": [
       "$$\\left [ 2, \\quad 4, \\quad 8, \\quad 16, \\quad 32, \\quad 64, \\quad 128\\right ]$$"
      ],
      "text/plain": [
       "[2, 4, 8, 16, 32, 64, 128]"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "inner_repeats = 100\n",
    "outer_repeats = 5\n",
    "sizes = [2**i for i in range(1, 8)]\n",
    "sizes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "def benchmark_pure(domain_size, extract_first=False):\n",
    "    src = np.zeros(domain_size)\n",
    "    dst = np.zeros_like(src)\n",
    "    f_src, f_dst = ps.fields(\"src, dst\", src=src, dst=dst)\n",
    "    kernel = ps.create_kernel(ps.Assignment(f_dst.center, f_src.center)).compile()\n",
    "    if extract_first:\n",
    "        kernel = kernel.kernel\n",
    "        start = perf_counter()\n",
    "        for i in range(inner_repeats):\n",
    "            kernel(src=src, dst=dst)\n",
    "            src, dst = dst, src\n",
    "        end = perf_counter()\n",
    "    else:\n",
    "        start = perf_counter()\n",
    "        for i in range(inner_repeats):\n",
    "            kernel(src=src, dst=dst)\n",
    "            src, dst = dst, src\n",
    "        end = perf_counter()\n",
    "    return (end - start) / inner_repeats\n",
    "\n",
    "def benchmark_datahandling(domain_size, parallel=False):\n",
    "    dh = ps.create_data_handling(domain_size, parallel=parallel)\n",
    "    f_src = dh.add_array('src')\n",
    "    f_dst = dh.add_array('dst')\n",
    "    kernel = ps.create_kernel(ps.Assignment(f_dst.center, f_src.center)).compile()\n",
    "    start = perf_counter()\n",
    "    for i in range(inner_repeats):\n",
    "        dh.run_kernel(kernel)\n",
    "        dh.swap('src', 'dst')\n",
    "    end = perf_counter()\n",
    "    return (end - start) / inner_repeats\n",
    "   \n",
    "    \n",
    "name_to_func = {\n",
    "    'pure_extract': partial(benchmark_pure, extract_first=True),\n",
    "    'pure_no_extract': partial(benchmark_pure, extract_first=False),\n",
    "    'dh_serial': partial(benchmark_datahandling, parallel=False),\n",
    "    'dh_parallel': partial(benchmark_datahandling, parallel=True),\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Computing size  2\n",
      "Computing size  4\n",
      "Computing size  8\n",
      "Computing size  16\n",
      "Computing size  32\n",
      "Computing size  64\n",
      "Computing size  128\n"
     ]
    }
   ],
   "source": [
    "result = {'block_size': [],\n",
    "          'name': [],\n",
    "          'time': []}\n",
    "\n",
    "for bs in sizes:\n",
    "    print(\"Computing size \", bs)\n",
    "    for name, func in name_to_func.items():\n",
    "        for i in range(outer_repeats):\n",
    "            time = func((bs, bs))\n",
    "            result['block_size'].append(bs)\n",
    "            result['name'].append(name)\n",
    "            result['time'].append(time)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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w9q1a/nss89ITU3F19eX6OhoCgoKAPD29nY9t1tQUMBdd91Feno67du3Z+bMma5+pbHWMmDAAN56660Kn6OISH2mglekGtSXwl5EpCrV9CMf/fr1Iz4+nilTpuB0Olm+fDnjxo2rdJxPP/2UnJwcfHx8WLp0KQsWLCArK4uLLroIX19fvvnmG7766qtSx54ubv39/cnLy2Px4sUMGzaszGP17t2bCRMmsG/fPjp06EB+fj6ZmZl06tSp0nmLiNQHKnhFRESkXgoLC2P48OGEhoZy2WWXcfXVV/+uOH379mXUqFHs27ePESNGEB4eTnBwMC+88AIhISF07tyZ3r17lzq2RYsW3HnnnQQHBxMQEEBERES5x2rVqhUpKSnceuutHDt2DICkpCQVvCIiZVDBKyIiIvXWtGnTmDZtWrG2yZP/O9Ps7+9/zmd4W7duzT/+8Y9ibU2aNOGjjz4qtf/ZqyonJSWRlJRUol9KSopre+3ata7ta6+9lrS0tBL9z+wjIiKneNRriURERERERERO0wyviIiIyDl88sknPPjgg8XaAgMDWbJkCfHx8e5JSkREzkkFr4iIiLiNtbbMlZJrk9jYWGJjY92dRq1mrXV3CiIiJeiWZhEREXELb29vDh48qELJA1hrOXjwIN7e3u5ORUSkGM3wioiIiFu0a9eOzMxMfv31V3enIlXA29ubdu3auTsNEZFiVPCKiIiIWzRq1IjAwEB3pyEiIh5MtzSLiIiIiIiIR9IMr4iIiIiIiLiNn49Psc+qpIJXRERERERE3GZiRK9qi61bmkVERERERMQjqeAVERERERERj6SCV0RERERERDySCl4RERERERHxSCp4RURERERExCOp4BURERERERGPpIJXREREREREPJIKXhEREREREfFIKnhFRERERETEI6ngFREREREREY+kgldEREREREQ8kgpeERERERER8UgqeEVERERERMQjqeAVERERERERj6SCV0RERERERDySCl4RERERERHxSCp4RURERERExCOp4BURERERERGPpIJXRESkDjHG3GCM2W2M2WeMmVLK/ibGmLeL9m80xgScsW9qUftuY0zsuWIaYwKLYuwtitm4qP2vxphtxpgtxpgvjDFXVu9Zi4iI/D4qeEVEROoIY4wX8BxwI3AlcGspxeYdwCFrbQfgaeCJorFXArcAQcAN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wysiIiIiIiJymgpeERERERER8UgqeEVERERERMQjqeAVERERERERj1RvF62atTi1SuNNG9anSuPVNIfDwZdffsmIESOqJN7SpUu57KKL6Nq5c5XEExERERERqSzN8NYRTqezWuM7HA7efPPNKjv20qVL2bV37/mmJSIiIiIi8rt5VMFrjIkzxszLzc11dyqlcjgcdOnShbETJxJx7bXcOnYs+fn5dI6I4MDBgwBkbNlCzJAhACTNns2EyZOJiYlh9OjRnDhxggceeICIiAhCQkJ48cUXyz3ek08+6er70EMPAZCWlkZISAgFBQUcOXKEoKAgtm/fzpQpU1i/fj2hoaE8/fTTpKSkcPPNNxMXF0dMTAx5eXlcd911hIWFERwczPvvv+86zquvvkpISAjdu3dn1KhRfPnllyxbtoy/PfIIkddfz36Ho3p+oCIiIiIiIuXwqFuarbXLgeXh4eF3ujuXsuzevZvnk5O5qlcvxk2axIuvvFJu/81bt7Jh40Z8fHyYN28ezZs3Jy0tjWPHjhEVFUVMTAyBgYElxq1cuZK9e/eyadMmrLUMHDiQdevW0a9fPwYOHMj06dM5evQot912G926dePxxx9n9uzZrFixAoCUlBRSU1PZunUrLVu2xOl0smTJEi688EIOHDhA7969GThwIDt37mTWrFls2LABf39/cnJyaNmyJQMHDiSmb1+G3HRTtfwcRUREREREzsWjCt66oH379lzVqxcAtw4dynMvvVRu/z/FxuLj4wOcKmK3bt3K4sWLAcjNzWXv3r1lFrwrV66kR48eAOTl5bF371769evHjBkziIiIwNvbmzlz5pR57AEDBtCyZUsArLX87W9/Y926dTRo0ICsrCx++eUXVq9ezbBhw/D39wdw9RcREREREXE3Fbw1zBhT4nvDhg05aS0ABceOFdvv6+vr2rbW8uyzzxIbG3vO41hrmTp1KuPGjSuxLycnh7y8PAoLCykoKOCCCy4oNcaZ7W+88Qa//vorGRkZNGrUiICAAAoKCrDWljgnERERERGR2sCjnuGtC3744Qe+Sk8HYNGSJVwVGcll7duz+euvAVj6wQdljo2NjWXu3LkUFhYCsGfPHo4cOVJm3wULFpCXlwdAVlYW//73vwFISEjg0UcfZeTIkTz44IMANGvWjMOHD5d57NzcXFq3bk2jRo1Ys2YN33//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\n",
      "text/plain": [
       "<Figure size 1152x432 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "if 'is_test_run' not in globals():\n",
    "    import pandas as pd\n",
    "    import seaborn as sns\n",
    "    \n",
    "    data = pd.DataFrame.from_dict(result)\n",
    "\n",
    "    plt.subplot(1,2,1)\n",
    "    sns.barplot(x='block_size', y='time', hue='name', data=data, alpha=0.6)\n",
    "    plt.yscale('log')\n",
    "\n",
    "    plt.subplot(1,2,2)\n",
    "    data = pd.DataFrame.from_dict(result)\n",
    "    sns.barplot(x='block_size', y='time', hue='name', data=data, alpha=0.6)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "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.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}