aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Kummerlaender2019-06-15 15:51:56 +0200
committerAdrian Kummerlaender2019-06-15 16:14:26 +0200
commitc43d3f38b6922d36d15e8ba2b6ce17ddb0c75b0a (patch)
tree39992e419204135a9625e662f4b5574e044d6b1f
parentc543a20179d495cb6d585c48637c24b248c29a07 (diff)
downloadsymlbm_playground-c43d3f38b6922d36d15e8ba2b6ce17ddb0c75b0a.tar
symlbm_playground-c43d3f38b6922d36d15e8ba2b6ce17ddb0c75b0a.tar.gz
symlbm_playground-c43d3f38b6922d36d15e8ba2b6ce17ddb0c75b0a.tar.bz2
symlbm_playground-c43d3f38b6922d36d15e8ba2b6ce17ddb0c75b0a.tar.lz
symlbm_playground-c43d3f38b6922d36d15e8ba2b6ce17ddb0c75b0a.tar.xz
symlbm_playground-c43d3f38b6922d36d15e8ba2b6ce17ddb0c75b0a.tar.zst
symlbm_playground-c43d3f38b6922d36d15e8ba2b6ce17ddb0c75b0a.zip
Start to record some benchmarks
-rw-r--r--lbm.py3
-rw-r--r--notebook/ldc_benchmark.ipynb287
-rw-r--r--shell.nix1
3 files changed, 290 insertions, 1 deletions
diff --git a/lbm.py b/lbm.py
index e4eaf62..546b3c7 100644
--- a/lbm.py
+++ b/lbm.py
@@ -5,6 +5,7 @@ import numpy
import sympy
from mako.template import Template
+from pathlib import Path
class Geometry:
def __init__(self, size_x, size_y):
@@ -67,7 +68,7 @@ class Lattice:
cl.enqueue_copy(self.queue, self.cl_material, self.np_material).wait();
def build_kernel(self):
- program_src = Template(filename = './template/kernel.mako').render(
+ program_src = Template(filename = str(Path(__file__).parent/'template/kernel.mako')).render(
descriptor = self.descriptor,
geometry = self.geometry,
diff --git a/notebook/ldc_benchmark.ipynb b/notebook/ldc_benchmark.ipynb
new file mode 100644
index 0000000..59f6ffb
--- /dev/null
+++ b/notebook/ldc_benchmark.ipynb
@@ -0,0 +1,287 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from lbm import Lattice, Geometry"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import symbolic.D2Q9 as D2Q9"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def cavity(geometry, x, y):\n",
+ " if x == 1 or y == 1 or x == geometry.size_x-2:\n",
+ " return 2\n",
+ " elif y == geometry.size_y-2:\n",
+ " return 3\n",
+ " else:\n",
+ " return 1"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "boundary = \"\"\"\n",
+ " if ( m == 2 ) {\n",
+ " u_0 = 0.0;\n",
+ " u_1 = 0.0;\n",
+ " }\n",
+ " if ( m == 3 ) {\n",
+ " u_0 = 0.1;\n",
+ " u_1 = 0.0;\n",
+ " }\n",
+ "\"\"\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import time\n",
+ "\n",
+ "def MLUPS(cells, steps, time):\n",
+ " return cells * steps / time * 1e-6"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def test(nX, nY, nSteps):\n",
+ " lattice = Lattice(\n",
+ " descriptor = D2Q9,\n",
+ " geometry = Geometry(nX, nY),\n",
+ " moments = D2Q9.moments(optimize = False),\n",
+ " collide = D2Q9.bgk(tau = 0.56),\n",
+ " boundary_src = boundary)\n",
+ " lattice.setup_geometry(cavity)\n",
+ " \n",
+ " start = time.time()\n",
+ " \n",
+ " for i in range(0,nSteps):\n",
+ " lattice.evolve()\n",
+ " lattice.sync()\n",
+ " \n",
+ " end = time.time()\n",
+ " \n",
+ " return MLUPS(lattice.geometry.volume, nSteps, end - start)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ " 32 : 15 MLUPS\n",
+ " 64 : 62 MLUPS\n",
+ " 96 : 135 MLUPS\n",
+ " 128 : 233 MLUPS\n",
+ " 160 : 376 MLUPS\n",
+ " 192 : 539 MLUPS\n",
+ " 224 : 744 MLUPS\n",
+ " 256 : 761 MLUPS\n",
+ " 288 : 763 MLUPS\n",
+ " 320 : 776 MLUPS\n",
+ " 352 : 726 MLUPS\n",
+ " 384 : 717 MLUPS\n",
+ " 416 : 750 MLUPS\n",
+ " 448 : 798 MLUPS\n",
+ " 480 : 797 MLUPS\n",
+ " 512 : 818 MLUPS\n",
+ " 544 : 802 MLUPS\n",
+ " 576 : 814 MLUPS\n",
+ " 608 : 814 MLUPS\n",
+ " 640 : 812 MLUPS\n",
+ " 672 : 815 MLUPS\n",
+ " 704 : 815 MLUPS\n",
+ " 736 : 804 MLUPS\n",
+ " 768 : 824 MLUPS\n",
+ " 800 : 728 MLUPS\n",
+ " 832 : 722 MLUPS\n",
+ " 864 : 819 MLUPS\n",
+ " 896 : 826 MLUPS\n",
+ " 928 : 828 MLUPS\n",
+ " 960 : 822 MLUPS\n",
+ " 992 : 824 MLUPS\n",
+ "1024 : 823 MLUPS\n",
+ "1056 : 822 MLUPS\n",
+ "1088 : 822 MLUPS\n",
+ "1120 : 825 MLUPS\n",
+ "1152 : 828 MLUPS\n",
+ "1184 : 821 MLUPS\n",
+ "1216 : 818 MLUPS\n",
+ "1248 : 813 MLUPS\n",
+ "1280 : 828 MLUPS\n",
+ "1312 : 824 MLUPS\n",
+ "1344 : 827 MLUPS\n",
+ "1376 : 826 MLUPS\n",
+ "1408 : 823 MLUPS\n",
+ "1440 : 826 MLUPS\n",
+ "1472 : 824 MLUPS\n",
+ "1504 : 826 MLUPS\n",
+ "1536 : 828 MLUPS\n",
+ "1568 : 823 MLUPS\n",
+ "1600 : 824 MLUPS\n",
+ "1632 : 825 MLUPS\n",
+ "1664 : 828 MLUPS\n",
+ "1696 : 827 MLUPS\n",
+ "1728 : 830 MLUPS\n",
+ "1760 : 831 MLUPS\n",
+ "1792 : 826 MLUPS\n",
+ "1824 : 828 MLUPS\n",
+ "1856 : 826 MLUPS\n",
+ "1888 : 825 MLUPS\n",
+ "1920 : 826 MLUPS\n",
+ "1952 : 826 MLUPS\n",
+ "1984 : 826 MLUPS\n",
+ "2016 : 827 MLUPS\n",
+ "2048 : 840 MLUPS\n",
+ "2080 : 829 MLUPS\n",
+ "2112 : 828 MLUPS\n",
+ "2144 : 828 MLUPS\n",
+ "2176 : 831 MLUPS\n",
+ "2208 : 826 MLUPS\n",
+ "2240 : 828 MLUPS\n",
+ "2272 : 829 MLUPS\n",
+ "2304 : 831 MLUPS\n",
+ "2336 : 828 MLUPS\n",
+ "2368 : 831 MLUPS\n",
+ "2400 : 829 MLUPS\n",
+ "2432 : 829 MLUPS\n",
+ "2464 : 829 MLUPS\n",
+ "2496 : 830 MLUPS\n",
+ "2528 : 830 MLUPS\n",
+ "2560 : 814 MLUPS\n",
+ "2592 : 827 MLUPS\n",
+ "2624 : 828 MLUPS\n",
+ "2656 : 828 MLUPS\n",
+ "2688 : 829 MLUPS\n",
+ "2720 : 828 MLUPS\n",
+ "2752 : 830 MLUPS\n",
+ "2784 : 827 MLUPS\n",
+ "2816 : 829 MLUPS\n",
+ "2848 : 826 MLUPS\n",
+ "2880 : 830 MLUPS\n",
+ "2912 : 829 MLUPS\n",
+ "2944 : 826 MLUPS\n",
+ "2976 : 828 MLUPS\n",
+ "3008 : 828 MLUPS\n",
+ "3040 : 829 MLUPS\n",
+ "3072 : 832 MLUPS\n",
+ "3104 : 826 MLUPS\n",
+ "3136 : 829 MLUPS\n",
+ "3168 : 827 MLUPS\n"
+ ]
+ }
+ ],
+ "source": [
+ "results = []\n",
+ "for size in [ 32*i for i in range(1,100) ]:\n",
+ " perf = test(nX = size, nY = size, nSteps = 100)\n",
+ " results.append((size, perf))\n",
+ " print(\"%4d : %3.0f MLUPS\" % (size, perf))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import matplotlib\n",
+ "import matplotlib.pyplot as plt\n",
+ "matplotlib.use('AGG')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "Text(0, 0.5, 'MLUPS')"
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ "<Figure size 1152x576 with 1 Axes>"
+ ]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "plt.figure(figsize=(16,8))\n",
+ "plt.scatter(*zip(*results))\n",
+ "plt.title('LDC Performance for various grid sizes using a Nvidia K2200')\n",
+ "plt.xlabel('Size')\n",
+ "plt.ylabel('MLUPS')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "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.7.3"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/shell.nix b/shell.nix
index 9fb5805..de62cdf 100644
--- a/shell.nix
+++ b/shell.nix
@@ -39,5 +39,6 @@ pkgs.stdenvNoCC.mkDerivation rec {
shellHook = ''
export NIX_SHELL_NAME="${name}"
export PYOPENCL_COMPILER_OUTPUT=1
+ export PYTHONPATH="$PWD:$PYTHONPATH"
'';
}