From 5668e28f99426e6439eb32f6e79958b969952ef7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20R=2E=20Brodtkorb?= Date: Thu, 23 Aug 2018 16:05:23 +0200 Subject: [PATCH] Updated domain size benchmark in autotuning --- Autotuning.ipynb | 281 +++++++++++++++++++++++++++++++++- GPUSimulators/Autotuner.py | 2 +- GPUSimulators/Common.py | 3 +- GPUSimulators/IPythonMagic.py | 32 ++-- GPUSimulators/Simulator.py | 2 + 5 files changed, 303 insertions(+), 17 deletions(-) diff --git a/Autotuning.ipynb b/Autotuning.ipynb index f7a0576..d7680e0 100644 --- a/Autotuning.ipynb +++ b/Autotuning.ipynb @@ -70,7 +70,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ @@ -79,7 +79,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 5, "metadata": { "scrolled": false }, @@ -177,7 +177,7 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -186,7 +186,7 @@ "Text(0.5,1,'Simulator performance (megacells)')" ] }, - "execution_count": 40, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" }, @@ -214,6 +214,279 @@ "plt.title(\"Simulator performance (megacells)\")" ] }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Registering my_context in user workspace\n", + "PyCUDA version 2017.1.1\n", + "CUDA version (9, 1, 0)\n", + "Driver version 9010\n", + "Using 'GeForce 840M' GPU\n", + "Created context handle <879048629408>\n", + "Using CUDA cache dir c:\\Users\\anbro\\Documents\\projects\\ShallowWaterGPU\\GPUSimulators\\cuda_cache\n", + "Autotuning enabled. It may take several minutes to run the code the first time: have patience\n" + ] + } + ], + "source": [ + "%cuda_context_handler my_context" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "gen_data: 3115.227938 ms\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "def gen_test_data(nx, ny, g):\n", + " width = 100.0\n", + " height = 100.0\n", + " dx = width / float(nx)\n", + " dy = height / float(ny)\n", + "\n", + " x_center = dx*nx/2.0\n", + " y_center = dy*ny/2.0\n", + "\n", + " #Create a gaussian \"dam break\" that will not form shocks\n", + " size = width / 5.0\n", + " dt = 10**10\n", + "\n", + " h = np.zeros((ny, nx), dtype=np.float32); \n", + " hu = np.zeros((ny, nx), dtype=np.float32);\n", + " hv = np.zeros((ny, nx), dtype=np.float32);\n", + "\n", + " extent = 1.0/np.sqrt(2.0)\n", + " x = (dx*(np.arange(0, nx, dtype=np.float32)+0.5) - x_center) / size\n", + " y = (dy*(np.arange(0, ny, dtype=np.float32)+0.5) - y_center) / size\n", + " xv, yv = np.meshgrid(x, y, sparse=False, indexing='xy')\n", + " r = np.minimum(1.0, np.sqrt(xv**2 + yv**2))\n", + " xv = None\n", + " yv = None\n", + " gc.collect()\n", + "\n", + " #Generate highres\n", + " cos = np.cos(np.pi*r)\n", + " h = 0.5 + 0.1*0.5*(1.0 + cos)\n", + " hu = 0.1*0.5*(1.0 + cos)\n", + " hv = hu.copy()\n", + "\n", + " scale = 0.7\n", + " max_h_estimate = 0.6\n", + " max_u_estimate = 0.1*np.sqrt(2.0)\n", + " dx = width/nx\n", + " dy = height/ny\n", + " dt = scale * min(dx, dy) / (max_u_estimate + np.sqrt(g*max_h_estimate))\n", + "\n", + " return h, hu, hv, dx, dy, dt\n", + "\n", + "\n", + "with Common.Timer(\"gen_data\", log_level=logging.INFO) as t:\n", + " h0, hu0, hv0, dx, dy, dt = gen_test_data(4096, 4096, 9.81)\n", + " \n", + "plt.figure(figsize=(12, 8))\n", + "plt.subplot(1,3,1)\n", + "plt.imshow(h0, origin='lower', interpolation=\"none\")\n", + "plt.subplot(1,3,2)\n", + "plt.imshow(hu0, origin='lower', interpolation=\"none\")\n", + "plt.subplot(1,3,3)\n", + "plt.imshow(hv0, origin='lower', interpolation=\"none\")" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "scrolled": false + }, + "outputs": [], + "source": [ + "run_simulation = False\n", + "sizes = list(range(64, 512, 64)) + list(range(512, 2048, 128)) + list(range(2048, 4096, 256)) + [4096]\n", + "if (run_simulation):\n", + " megacells = {}\n", + " for simulator in simulators:\n", + " print(simulator.__name__)\n", + " megacells[simulator.__name__] = np.zeros(len(sizes))\n", + " g = 9.81\n", + " warmup_timesteps = 2\n", + " timesteps = 5\n", + " for k in range(len(sizes)):\n", + " nx = sizes[k] - 1\n", + " ny = sizes[k] - 1\n", + "\n", + " h0, hu0, hv0, dx, dy, dt = gen_test_data(nx, ny, g)\n", + "\n", + " arguments = {\n", + " 'context': my_context,\n", + " 'h0': h0, 'hu0': hu0, 'hv0': hv0,\n", + " 'nx': nx, 'ny': ny,\n", + " 'dx': dx, 'dy': dy, 'dt': 0.9*dt,\n", + " 'g': g\n", + " } \n", + "\n", + " sim = simulator(**arguments)\n", + "\n", + " #Create timer events\n", + " start = cuda.Event()\n", + " end = cuda.Event()\n", + "\n", + " #Warmup\n", + " for i in range(warmup_timesteps):\n", + " sim.stepEuler(sim.dt)\n", + "\n", + " #Run simulation with timer \n", + " start.record(sim.stream)\n", + " for i in range(timesteps):\n", + " sim.stepEuler(sim.dt)\n", + " end.record(sim.stream)\n", + "\n", + " #Synchronize end event\n", + " end.synchronize()\n", + "\n", + " sim = None\n", + " gc.collect()\n", + "\n", + " #Compute megacells\n", + " gpu_elapsed = end.time_since(start)*1.0e-3\n", + " megacells[simulator.__name__][k] = (nx*ny*timesteps / (1000*1000)) / gpu_elapsed\n", + " print(\"[{:d}x{:d}] => {:.1f} ({:2f})\".format(nx, ny, megacells[simulator.__name__][k], gpu_elapsed))" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Loading from file\n" + ] + } + ], + "source": [ + "datafilename = \"megacells.npz\"\n", + "if (not os.path.isfile(datafilename) and \"megacells\" in globals()):\n", + " print(\"Saving data to file\")\n", + " np.savez_compressed(datafilename, megacells=megacells)\n", + "else:\n", + " print(\"Loading from file\")\n", + " with np.load(datafilename) as file:\n", + " megacells = dict(file[\"megacells\"].tolist())" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0.5,0,'nx')" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.figure()\n", + "for simulator in simulators:\n", + " plt.plot(sizes, megacells[simulator.__name__], '.-', label=simulator.__name__)\n", + "plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.)\n", + "plt.title(\"Performance\")\n", + "plt.ylabel(\"Megacells/s\")\n", + "plt.xlabel(\"nx\")" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0.5,0,'nx')" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.figure()\n", + "for simulator in simulators:\n", + " old = megacells[simulator.__name__][0:-1]\n", + " new = megacells[simulator.__name__][1:]\n", + " change = 100*(new-old)/old\n", + " plt.plot(sizes[0:-1], change, '.-', label=simulator.__name__)\n", + "plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.)\n", + "plt.title(\"Relative performance change\")\n", + "plt.ylabel(\"Megacells/s\")\n", + "plt.xlabel(\"nx\")" + ] + }, { "cell_type": "code", "execution_count": null, diff --git a/GPUSimulators/Autotuner.py b/GPUSimulators/Autotuner.py index 41724de..44cdb00 100644 --- a/GPUSimulators/Autotuner.py +++ b/GPUSimulators/Autotuner.py @@ -29,7 +29,7 @@ from socket import gethostname import pycuda.driver as cuda -from GPUSimulators import Common, LxF, FORCE, HLL, HLL2, KP07, KP07_dimsplit, WAF +from GPUSimulators import Common, Simulator class Autotuner: def __init__(self, diff --git a/GPUSimulators/Common.py b/GPUSimulators/Common.py index f977d05..e37b85a 100644 --- a/GPUSimulators/Common.py +++ b/GPUSimulators/Common.py @@ -100,7 +100,7 @@ class CudaContext(object): self.cache_path = os.path.join(self.module_path, "cuda_cache") if not os.path.isdir(self.cache_path): os.mkdir(self.cache_path) - self.logger.debug("Using CUDA cache dir %s", self.cache_path) + self.logger.info("Using CUDA cache dir %s", self.cache_path) self.autotuner = None if (autotuning): @@ -395,6 +395,7 @@ class SWEDataArakawaA: Uploads initial data to the CL device """ def __init__(self, stream, nx, ny, halo_x, halo_y, h0, hu0, hv0): + self.logger = logging.getLogger(__name__) self.h0 = CudaArray2D(stream, nx, ny, halo_x, halo_y, h0) self.hu0 = CudaArray2D(stream, nx, ny, halo_x, halo_y, hu0) self.hv0 = CudaArray2D(stream, nx, ny, halo_x, halo_y, hv0) diff --git a/GPUSimulators/IPythonMagic.py b/GPUSimulators/IPythonMagic.py index ccda9cc..ce4c16f 100644 --- a/GPUSimulators/IPythonMagic.py +++ b/GPUSimulators/IPythonMagic.py @@ -31,33 +31,43 @@ from GPUSimulators import Common @magics_class class MyIPythonMagic(Magics): @line_magic - def cuda_context_handler(self, context_name): + @magic_arguments.magic_arguments() + @magic_arguments.argument( + 'name', type=str, help='Name of context to create') + @magic_arguments.argument( + '--blocking', '-b', action="store_true", help='Enable blocking context') + @magic_arguments.argument( + '--no_cache', '-nc', action="store_true", help='Disable caching of kernels') + @magic_arguments.argument( + '--no_autotuning', '-na', action="store_true", help='Disable autotuning of kernels') + def cuda_context_handler(self, line): + args = magic_arguments.parse_argstring(self.cuda_context_handler, line) self.logger = logging.getLogger(__name__) - self.logger.debug("Registering %s as a global context", context_name) + self.logger.info("Registering %s in user workspace", args.name) - if context_name in self.shell.user_ns.keys(): + if args.name in self.shell.user_ns.keys(): self.logger.debug("Context already registered! Ignoring") return else: self.logger.debug("Creating context") - #self.shell.ex(context_name + " = Common.CudaContext(blocking=False)") - self.shell.user_ns[context_name] = Common.CudaContext(blocking=False) + use_cache = False if args.no_cache else True + use_autotuning = False if args.no_autotuning else True + self.shell.user_ns[args.name] = Common.CudaContext(blocking=args.blocking, use_cache=use_cache, autotuning=use_autotuning) # this function will be called on exceptions in any cell def custom_exc(shell, etype, evalue, tb, tb_offset=None): - self.logger.exception("Exception caught: Resetting to CUDA context %s", context_name) + self.logger.exception("Exception caught: Resetting to CUDA context %s", args.name) while (cuda.Context.get_current() != None): context = cuda.Context.get_current() self.logger.info("Popping <%s>", str(context.handle)) cuda.Context.pop() - if context_name in self.shell.user_ns.keys(): - self.logger.info("Pushing <%s>", str(self.shell.user_ns[context_name].cuda_context.handle)) - #self.shell.ex(context_name + ".cuda_context.push()") - self.shell.user_ns[context_name].cuda_context.push() + if args.name in self.shell.user_ns.keys(): + self.logger.info("Pushing <%s>", str(self.shell.user_ns[args.name].cuda_context.handle)) + self.shell.user_ns[args.name].cuda_context.push() else: - self.logger.error("No CUDA context called %s found (something is wrong)", context_name) + self.logger.error("No CUDA context called %s found (something is wrong)", args.name) self.logger.error("CUDA will not work now") self.logger.debug("==================================================================") diff --git a/GPUSimulators/Simulator.py b/GPUSimulators/Simulator.py index 53a6bb3..9e61c91 100644 --- a/GPUSimulators/Simulator.py +++ b/GPUSimulators/Simulator.py @@ -69,6 +69,8 @@ class BaseSimulator: self.stream = cuda.Stream() #Create data by uploading to device + free, total = cuda.mem_get_info() + self.logger.debug("GPU memory: %d / %d MB available", int(free/(1024*1024)), int(total/(1024*1024))) self.data = Common.SWEDataArakawaA(self.stream, \ nx, ny, \ ghost_cells_x, ghost_cells_y, \