{ "metadata": { "name": "Histogram" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Histogram\n", "\n", "The purpose of this code is to implement a simple histogram algorithm on the GPU." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## generate data" ] }, { "cell_type": "code", "collapsed": false, "input": [ "n = 1024 * 100\n", "nbins = 1024\n", "input_data = numpy.random.normal(0, 1, n).astype(numpy.float32)\n", "histogram_cpu, edges = numpy.histogram(input_data, nbins)\n", "\n", "\n", "\n", "figsize(14,4)\n", "\n", "matplotlib.pyplot.subplot(131);\n", "matplotlib.pyplot.plot(input_data);\n", "matplotlib.pyplot.title(\"input_data\");\n", "\n", "matplotlib.pyplot.subplot(132);\n", "matplotlib.pyplot.plot(histogram_cpu);\n", "matplotlib.pyplot.title(\"histogram_cpu\");\n", "\n", "matplotlib.pyplot.subplot(133);\n", "matplotlib.pyplot.hist(input_data, nbins);\n", "matplotlib.pyplot.title(\"matplotlib.pyplot.hist(input_data, nbins)\");" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "display_data", "png": "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\no92tQkgUKJMnA//4h3+3IZU488YnEfnKeQkKkxRSqUTmjju8O5Hu3atsPNbefx9o0MD95e0vxh95\nxPmy1vugXA9AY8e6t83ly91bTtK/v+X55s3io7NOCpyVll275lhlRM6YMWJvX/acDUZpX7VO4iyZ\ntK9656oNT9OmjqV0Fy44X96fgnnAV9KnZcuATz/17D1Dhni2vKuqqUREzihb7cu2xIZVyoKTKiUy\np07ZNnwvy59/io/WPWcp0W7CurpZoHohy8rybPktW4Bt28Tn1g1r3aFUOw1XSVpuruM068THWdet\n9m2eALFDBVfJpHVpkqvSqQMHxOqCXbsC//yn8+V80b8/0KFD2cv99pvypWBEvvDmXC7dkOjaVX5+\n/fryy7NqGRGphyU2oUATp5l+/Vw3tJYbnd3XXrmys4GqVX1bB+D5GC7WjWlLS8vuSe2nnyxdICvl\ntddsL2auXHF9h9bVZ/zlF2ViunAByMhwvYwnVdJu3AA2bBB7vAOUH2tn/Xpg+3b5efv3W56XlAD1\n6im7bSJfeHPslBITuY5UACAyUn553gAlInVwzJlQoWoic/y4+PjJJ0BmZmC3LXWtXBZpkERn5Eok\n3DViBFCpkvfv99aLL9q+lrpNlVh396wE+2qEcp0O2I9T40np06+/io/WpXz/+5/tMi+95P76JHJt\nYoqLy/5u5C72PC1NI9ISKTGxrq4qmTgRiIiwnSaNocREhoiUEe7kuTPypTGsXhZ8VOu1TBCAvn0t\nr8+fd68tRqA1amT7evduz9fhrH2GNBaMq5GzrZU6KSV11puWVCUP8KxKW8WK8gNxAs5LzlxdqNuX\n9jz6qGNnD/afwT4RceX8efFx0SLLNGfxe8r67rXBIL9ed46LM2cqEw+RP9knJBJXVcTS052/j9cM\nRKSMUifPKdRpomoZIDbOdtZuxpfukTt3dm+5n35ybzn70gx3/Pvfnr9HjrNBOeW6fM7IsJRUWHO3\nvYazQSErVnTv/WWxrn4lR65Xu9tvV2bbSvB04MDXXvNPHERKsk/UpbGv5BKZxYvFR4MBCHdyg5SJ\nDBEFDquThSJVx5GxVloqf+EN+NbjlNS17tatrpdzp0cwqecvwPc2OoDYzbK/LF0qP71PH8vz69eB\njRvllzt1yvL8xx+Vi8ufrKvIrV2r/PqPHgWio22n7d7tXocCZbWFIgqE/HxLJyDXr4vHXVftE6Oi\n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\nAAAAAElFTkSuQmCC\n" } ], "prompt_number": 1 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## hand-coded CPU loop" ] }, { "cell_type": "code", "collapsed": false, "input": [ "input_max = numpy.max(input_data)\n", "input_min = numpy.min(input_data)\n", "input_range = input_max - input_min\n", "\n", "histogram_cpu_loop = numpy.zeros_like(histogram_cpu)\n", "\n", "for i in range(n):\n", " input_value = input_data[i]\n", " bin_index = min(nbins - 1, int((nbins * (input_value - input_min)) / input_range));\n", " histogram_cpu_loop[bin_index] = histogram_cpu_loop[bin_index] + 1\n", "\n", "\n", "\n", "diff = abs(histogram_cpu_loop - histogram_cpu)\n", "\n", "print \\\n", " \"Difference between numpy and hand-coded loop as a percentage of the maximum possible difference (should be less than 1.0%%): %0.2f%%\" % \\\n", " (100 * (numpy.linalg.norm(diff) / numpy.linalg.norm(histogram_cpu)))\n", "\n", "figsize(14,4)\n", "\n", "matplotlib.pyplot.subplot(131);\n", "matplotlib.pyplot.plot(histogram_cpu);\n", "matplotlib.pyplot.title(\"histogram_cpu\");\n", "\n", "matplotlib.pyplot.subplot(132);\n", "matplotlib.pyplot.plot(histogram_cpu_loop);\n", "matplotlib.pyplot.title(\"histogram_cpu_loop\");\n", "\n", "matplotlib.pyplot.subplot(133);\n", "matplotlib.pyplot.plot(diff);\n", "matplotlib.pyplot.title(\"diff\");" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Difference between numpy and hand-coded loop as a percentage of the maximum possible difference (should be less than 1.0%): 0.06%\n" ] }, { "output_type": "display_data", "png": "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\n" } ], "prompt_number": 2 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## define GPU kernels" ] }, { "cell_type": "code", "collapsed": false, "input": [ "import pycuda.autoinit\n", "import pycuda.driver\n", "import pycuda.compiler\n", "import reduce\n", "import radixsort\n", "import prefixsum\n", "\n", "source_module = pycuda.compiler.SourceModule \\\n", "(\n", "\"\"\"\n", "\n", "#define FINE_HISTOGRAM_NUM_VALUES 32\n", "\n", "__global__ void compute_bin_ids(\n", " float* d_input_data,\n", " unsigned int* d_coarse_bin_ids,\n", " int n,\n", " int num_coarse_bins,\n", " int num_fine_bins,\n", " float min_value,\n", " float max_value,\n", " float range )\n", "{\n", " int global_index_1d = ( blockIdx.x * blockDim.x ) + threadIdx.x;\n", "\n", " if ( global_index_1d < n )\n", " {\n", " float input_value = d_input_data[ global_index_1d ];\n", " int fine_bin_index = min( num_fine_bins - 1, int( ( num_fine_bins * ( input_value - min_value ) ) / range ) );\n", " int coarse_bin_index = fine_bin_index / FINE_HISTOGRAM_NUM_VALUES;\n", "\n", " d_coarse_bin_ids[ global_index_1d ] = coarse_bin_index;\n", " }\n", "}\n", "\n", "__global__ void compute_bin_offsets(\n", " int* d_bin_offsets,\n", " unsigned int* d_sorted_coarse_bin_ids,\n", " int n )\n", "{\n", " int global_index_1d = ( blockIdx.x * blockDim.x ) + threadIdx.x;\n", "\n", " if ( global_index_1d == 0 )\n", " {\n", " d_bin_offsets[ 0 ] = 0;\n", " }\n", " else if ( global_index_1d < n )\n", " {\n", " unsigned int left_bin_id = d_sorted_coarse_bin_ids[ global_index_1d - 1 ];\n", " unsigned int right_bin_id = d_sorted_coarse_bin_ids[ global_index_1d ];\n", "\n", " if ( left_bin_id != right_bin_id )\n", " {\n", " unsigned int offset_index = right_bin_id;\n", " d_bin_offsets[ offset_index ] = global_index_1d;\n", " }\n", " }\n", "}\n", "\n", "__device__ void increment_warp_histogram( volatile unsigned int* s_warp_histogram, unsigned int warp_histogram_index, unsigned int warp_local_thread_id )\n", "{\n", " unsigned int warp_local_thread_tag = warp_local_thread_id << 24;\n", " unsigned int old_count, new_count, new_count_tagged;\n", "\n", " do\n", " { \n", " old_count = s_warp_histogram[ warp_histogram_index ] & 0x00FFFFFF; \n", " new_count = old_count + 1;\n", " new_count_tagged = warp_local_thread_tag | new_count;\n", " s_warp_histogram[ warp_histogram_index ] = new_count_tagged;\n", " }\n", " while( s_warp_histogram[ warp_histogram_index ] != new_count_tagged );\n", "\n", " new_count_tagged = s_warp_histogram[ warp_histogram_index ];\n", " s_warp_histogram[ warp_histogram_index ] = new_count_tagged & 0x00FFFFFF;\n", "}\n", "\n", "__global__ void compute_fine_histogram(\n", " unsigned int* d_histogram,\n", " unsigned int* d_sorted_coarse_bin_ids,\n", " float* d_sorted_input_data,\n", " int* d_bin_offsets,\n", " int n,\n", " int num_coarse_bins,\n", " int num_fine_bins,\n", " float min_value,\n", " float max_value,\n", " float range )\n", "{\n", " __shared__ float s_sorted_input_data[ FINE_HISTOGRAM_NUM_VALUES ];\n", " __shared__ unsigned int s_fine_histogram[ FINE_HISTOGRAM_NUM_VALUES ];\n", "\n", " //\n", " // figure out the start and end points in the sorted input data array for the current coarse bin\n", " //\n", " int start_data_index_1d = d_bin_offsets[ blockIdx.x ];\n", " int end_data_index_1d;\n", " unsigned int shared_memory_index_1d = threadIdx.x;\n", " unsigned int coarse_bin_index_1d = d_sorted_coarse_bin_ids[ start_data_index_1d ];\n", " \n", " if ( start_data_index_1d != -1 )\n", " {\n", " if ( coarse_bin_index_1d < num_coarse_bins - 1 )\n", " {\n", " int nex_bin_offset_index = 1;\n", " int next_bin_start_index_1d = d_bin_offsets[ coarse_bin_index_1d + nex_bin_offset_index ];\n", "\n", " while ( next_bin_start_index_1d == -1 )\n", " {\n", " nex_bin_offset_index++;\n", " next_bin_start_index_1d = d_bin_offsets[ coarse_bin_index_1d + nex_bin_offset_index ];\n", " }\n", "\n", " end_data_index_1d = next_bin_start_index_1d - 1;\n", " }\n", " else if ( coarse_bin_index_1d == num_coarse_bins - 1 )\n", " {\n", " end_data_index_1d = n - 1;\n", " }\n", " else\n", " {\n", " end_data_index_1d = -1;\n", " }\n", "\n", " //\n", " // initialize fine-grained histogram in shared memory\n", " //\n", " s_fine_histogram[ shared_memory_index_1d ] = 0;\n", "\n", " __syncthreads();\n", "\n", " //\n", " // loop through the sorted input data and iteratively compute the histogram in shared memory\n", " //\n", " unsigned int total_num_data_values = end_data_index_1d - start_data_index_1d + 1;\n", " int num_iterations =\n", " int( ceil( float( total_num_data_values ) / float( FINE_HISTOGRAM_NUM_VALUES ) ) );\n", " unsigned int current_iteration_data_base_index_1d = start_data_index_1d;\n", "\n", " for ( int i = 0; i < num_iterations; i++ )\n", " {\n", " //\n", " // load current chunk of data into shared memory\n", " //\n", " unsigned int current_iteration_data_thread_index_1d = current_iteration_data_base_index_1d + threadIdx.x;\n", "\n", " if ( current_iteration_data_thread_index_1d <= end_data_index_1d )\n", " {\n", " s_sorted_input_data[ shared_memory_index_1d ] = d_sorted_input_data[ current_iteration_data_thread_index_1d ];\n", " }\n", "\n", " __syncthreads();\n", "\n", " //\n", " // compute fine-grained histogram\n", " //\n", " unsigned int current_max_num_data_values = end_data_index_1d - current_iteration_data_base_index_1d + 1;\n", " unsigned int current_num_data_values = min( FINE_HISTOGRAM_NUM_VALUES, current_max_num_data_values );\n", "\n", " if ( shared_memory_index_1d < current_num_data_values )\n", " {\n", " float input_value = s_sorted_input_data[ shared_memory_index_1d ];\n", "\n", " unsigned int fine_bin_global_index_1d =\n", " min( num_fine_bins - 1, int( ( num_fine_bins * ( input_value - min_value ) ) / range ) );\n", "\n", " unsigned int fine_bin_shared_memory_index_1d =\n", " max(0, min( FINE_HISTOGRAM_NUM_VALUES - 1, fine_bin_global_index_1d - ( coarse_bin_index_1d * FINE_HISTOGRAM_NUM_VALUES ) ) );\n", "\n", " increment_warp_histogram( s_fine_histogram, fine_bin_shared_memory_index_1d, shared_memory_index_1d );\n", " }\n", "\n", " current_iteration_data_base_index_1d += FINE_HISTOGRAM_NUM_VALUES;\n", " }\n", "\n", " __syncthreads();\n", " \n", " //\n", " // copy fine-grained histogram into shared memory\n", " //\n", " unsigned int histogram_base_index_1d = coarse_bin_index_1d * FINE_HISTOGRAM_NUM_VALUES;\n", " unsigned int histogram_thread_index_1d = histogram_base_index_1d + threadIdx.x;\n", " \n", " if ( histogram_thread_index_1d < num_fine_bins )\n", " {\n", " d_histogram[ histogram_thread_index_1d ] = s_fine_histogram[ shared_memory_index_1d ];\n", " }\n", " }\n", "}\n", "\"\"\"\n", ")\n", "\n", "num_fine_bins_per_coarse_bin = 32\n", "num_bytes_per_int32 = 4\n", "num_coarse_bins = int(ceil(float(nbins) / float(num_fine_bins_per_coarse_bin)))\n", "\n", "histogram_gpu = numpy.zeros_like(histogram_cpu)\n", "\n", "input_data_device = pycuda.driver.mem_alloc(input_data.nbytes)\n", "coarse_bin_ids_device = pycuda.driver.mem_alloc(input_data.nbytes)\n", "sorted_data_device = pycuda.driver.mem_alloc(input_data.nbytes)\n", "sorted_coarse_bin_ids_device = pycuda.driver.mem_alloc(input_data.nbytes)\n", "bin_offsets_device = pycuda.driver.mem_alloc(num_coarse_bins * num_bytes_per_int32)\n", "histogram_device = pycuda.driver.mem_alloc(histogram_gpu.nbytes)\n", "\n", "compute_bin_ids_function = source_module.get_function(\"compute_bin_ids\")\n", "compute_bin_ids_function_block = (512,1,1)\n", "num_blocks = int(ceil(float(n) / float(compute_bin_ids_function_block[0])))\n", "compute_bin_ids_function_grid = (num_blocks, 1)\n", "\n", "compute_bin_offsets_function = source_module.get_function(\"compute_bin_offsets\")\n", "compute_bin_offsets_function_block = (512,1,1)\n", "num_blocks = int(ceil(float(n) / float(compute_bin_offsets_function_block[0])))\n", "compute_bin_offsets_function_grid = (num_blocks, 1)\n", "\n", "compute_fine_histogram_function = source_module.get_function(\"compute_fine_histogram\")\n", "compute_fine_histogram_function_block = (num_fine_bins_per_coarse_bin,1,1)\n", "num_blocks = num_coarse_bins\n", "compute_fine_histogram_function_grid = (num_blocks, 1)\n", "\n", "reduce_manager = reduce.ReduceManager(n)\n", "radix_sort_manager = radixsort.RadixSortManager(n)\n", "prefix_sum_manager = prefixsum.PrefixSumManager(n)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 3 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## call GPU histogram algorithm" ] }, { "cell_type": "code", "collapsed": false, "input": [ "pycuda.driver.memcpy_htod(input_data_device, input_data)\n", "\n", "input_min = reduce_manager.reduce_min_device(input_data_device, n)\n", "input_max = reduce_manager.reduce_max_device(input_data_device, n)\n", "input_range = input_max - input_min\n", "\n", "compute_bin_ids_function(\n", " input_data_device,\n", " coarse_bin_ids_device,\n", " numpy.int32(n),\n", " numpy.int32(num_coarse_bins),\n", " numpy.int32(nbins),\n", " numpy.float32(input_min),\n", " numpy.float32(input_max),\n", " numpy.float32(input_range),\n", " block=compute_bin_ids_function_block,\n", " grid=compute_bin_ids_function_grid)\n", "\n", "radix_sort_manager.radix_sort_key_value_ascending_device(coarse_bin_ids_device, input_data_device, sorted_coarse_bin_ids_device, sorted_data_device, n)\n", "\n", "pycuda.driver.memset_d32(bin_offsets_device, int(0xffffffff), num_coarse_bins)\n", "\n", "compute_bin_offsets_function(\n", " bin_offsets_device,\n", " sorted_coarse_bin_ids_device,\n", " numpy.int32(n),\n", " block=compute_bin_offsets_function_block,\n", " grid=compute_bin_offsets_function_grid)\n", "\n", "pycuda.driver.memset_d32(histogram_device, int(0), nbins)\n", "\n", "compute_fine_histogram_function(\n", " histogram_device,\n", " sorted_coarse_bin_ids_device,\n", " sorted_data_device,\n", " bin_offsets_device,\n", " numpy.int32(n),\n", " numpy.int32(num_coarse_bins),\n", " numpy.int32(nbins),\n", " numpy.float32(input_min),\n", " numpy.float32(input_max),\n", " numpy.float32(input_range),\n", " block=compute_fine_histogram_function_block,\n", " grid=compute_fine_histogram_function_grid)\n", "\n", "pycuda.driver.memcpy_dtoh(histogram_gpu, histogram_device)\n", "\n", "\n", "\n", "diff = abs(histogram_gpu - histogram_cpu_loop)\n", "\n", "print numpy.sum(histogram_gpu)\n", "print numpy.sum(histogram_cpu_loop)\n", "\n", "print \\\n", " \"Difference between GPU and CPU as a percentage of the maximum possible difference (should be less than 1.0%%): %0.2f%%\" % \\\n", " (100 * (numpy.linalg.norm(diff) / numpy.linalg.norm(histogram_cpu_loop)))\n", "\n", "figsize(14,4)\n", "\n", "matplotlib.pyplot.subplot(131);\n", "matplotlib.pyplot.plot(histogram_gpu);\n", "matplotlib.pyplot.title(\"histogram_gpu\");\n", "\n", "matplotlib.pyplot.subplot(132);\n", "matplotlib.pyplot.plot(histogram_cpu_loop);\n", "matplotlib.pyplot.title(\"histogram_cpu_loop\");\n", "\n", "matplotlib.pyplot.subplot(133);\n", "matplotlib.pyplot.plot(diff);\n", "matplotlib.pyplot.title(\"diff\");" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "102400\n", "102400\n", "Difference between GPU and CPU as a percentage of the maximum possible difference (should be less than 1.0%): 0.05%\n" ] }, { "output_type": "display_data", "png": "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\n" } ], "prompt_number": 5 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## define GPU histogram kernel using global atomics" ] }, { "cell_type": "code", "collapsed": false, "input": [ "source_module = pycuda.compiler.SourceModule \\\n", "(\n", "\"\"\"\n", "__global__ void compute_fine_histogram_global_atomic(\n", " unsigned int* d_histogram,\n", " float* d_input_data,\n", " int n,\n", " int num_bins,\n", " float min_value,\n", " float max_value,\n", " float range )\n", "{\n", " int global_index_1d = ( blockIdx.x * blockDim.x ) + threadIdx.x;\n", "\n", " if ( global_index_1d < n )\n", " {\n", " float data_value = d_input_data[ global_index_1d ];\n", " int bin_index = min( num_bins - 1, int( ( num_bins * ( data_value - min_value ) ) / range ) );\n", "\n", " atomicAdd( d_histogram + bin_index, 1 );\n", " }\n", "}\n", "\"\"\"\n", ")\n", "\n", "histogram_gpu_global_atomic = numpy.zeros_like(histogram_cpu)\n", "\n", "compute_fine_histogram_global_atomic_function = source_module.get_function(\"compute_fine_histogram_global_atomic\")\n", "compute_fine_histogram_global_atomic_function_block = (512,1,1)\n", "num_blocks = int(ceil(float(n) / float(compute_fine_histogram_global_atomic_function_block[0])))\n", "compute_fine_histogram_global_atomic_function_grid = (num_blocks, 1)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 6 }, { "cell_type": "code", "collapsed": false, "input": [ "pycuda.driver.memcpy_htod(input_data_device, input_data)\n", "\n", "input_min = reduce_manager.reduce_min_device(input_data_device, n)\n", "input_max = reduce_manager.reduce_max_device(input_data_device, n)\n", "input_range = input_max - input_min\n", "\n", "compute_bin_ids_function(\n", " input_data_device,\n", " coarse_bin_ids_device,\n", " numpy.int32(n),\n", " numpy.int32(num_coarse_bins),\n", " numpy.int32(nbins),\n", " numpy.float32(input_min),\n", " numpy.float32(input_max),\n", " numpy.float32(input_range),\n", " block=compute_bin_ids_function_block,\n", " grid=compute_bin_ids_function_grid)\n", "\n", "radix_sort_manager.radix_sort_key_value_ascending_device(coarse_bin_ids_device, input_data_device, sorted_coarse_bin_ids_device, sorted_data_device, n)\n", "\n", "pycuda.driver.memset_d32(histogram_device, int(0), nbins)\n", "\n", "compute_fine_histogram_global_atomic_function(\n", " histogram_device,\n", " sorted_data_device,\n", " numpy.int32(n),\n", " numpy.int32(nbins),\n", " numpy.float32(input_min),\n", " numpy.float32(input_max),\n", " numpy.float32(input_range),\n", " block=compute_fine_histogram_global_atomic_function_block,\n", " grid=compute_fine_histogram_global_atomic_function_grid)\n", "\n", "pycuda.driver.memcpy_dtoh(histogram_gpu_global_atomic, histogram_device)\n", "\n", "\n", "\n", "diff = abs(histogram_gpu_global_atomic - histogram_gpu)\n", "\n", "print numpy.sum(histogram_gpu_global_atomic)\n", "print numpy.sum(histogram_gpu)\n", "\n", "print \\\n", " \"Difference between GPU (global atomics) and GPU (shared memory) as a percentage of the maximum possible difference (should be 0.0%%): %0.2f%%\" % \\\n", " (100 * (numpy.linalg.norm(diff) / numpy.linalg.norm(histogram_gpu)))\n", "\n", "figsize(14,4)\n", "\n", "matplotlib.pyplot.subplot(131);\n", "matplotlib.pyplot.plot(histogram_gpu_global_atomic);\n", "matplotlib.pyplot.title(\"histogram_gpu_global_atomic\");\n", "\n", "matplotlib.pyplot.subplot(132);\n", "matplotlib.pyplot.plot(histogram_gpu);\n", "matplotlib.pyplot.title(\"histogram_gpu\");\n", "\n", "matplotlib.pyplot.subplot(133);\n", "matplotlib.pyplot.plot(diff);\n", "matplotlib.pyplot.title(\"diff\");" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "102400\n", "102400\n", "Difference between GPU (global atomics) and GPU (shared memory) as a percentage of the maximum possible difference (should be 0.0%): 0.00%\n" ] }, { "output_type": "display_data", "png": "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\n" } ], "prompt_number": 7 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## common benchmarking code" ] }, { "cell_type": "code", "collapsed": false, "input": [ "import sys\n", "import time\n", "\n", "if sys.platform == \"win32\":\n", " print \"Using time.clock for benchmarking...\\n\" \n", " system_timer_function = time.clock\n", "else:\n", " print \"Using time.time for benchmarking...\\n\" \n", " system_timer_function = time.time\n", " \n", "num_timing_iterations = 100\n", " \n", " \n", " \n", "print \"num_timing_iterations = %d\" % num_timing_iterations" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Using time.clock for benchmarking...\n", "\n", "num_timing_iterations = 100\n" ] } ], "prompt_number": 8 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## benchmark GPU (shared memory)" ] }, { "cell_type": "code", "collapsed": false, "input": [ "total_time_seconds = 0\n", "\n", "for i in range(num_timing_iterations):\n", " \n", " pycuda.driver.memcpy_htod(input_data_device, input_data)\n", "\n", " input_min = reduce_manager.reduce_min_device(input_data_device, n)\n", " input_max = reduce_manager.reduce_max_device(input_data_device, n)\n", " input_range = input_max - input_min\n", " \n", " pycuda.driver.Context.synchronize()\n", " \n", " start_time_seconds = system_timer_function()\n", "\n", " compute_bin_ids_function(\n", " input_data_device,\n", " coarse_bin_ids_device,\n", " numpy.int32(n),\n", " numpy.int32(num_coarse_bins),\n", " numpy.int32(nbins),\n", " numpy.float32(input_min),\n", " numpy.float32(input_max),\n", " numpy.float32(input_range),\n", " block=compute_bin_ids_function_block,\n", " grid=compute_bin_ids_function_grid)\n", "\n", " #\n", " # I have excluded sorting in this performance benchmark, even though it is necessary for correctness.\n", " # In the C++ version, we should replace my unoptimized sort with an optimized sort (e.g. thrust::sort)\n", " # and include it in the performance benchmark.\n", " #\n", " #radix_sort_manager.radix_sort_key_value_ascending_device(coarse_bin_ids_device, input_data_device, sorted_coarse_bin_ids_device, sorted_data_device, n)\n", " \n", " pycuda.driver.memset_d32(bin_offsets_device, int(0xffffffff), num_coarse_bins)\n", " \n", " compute_bin_offsets_function(\n", " bin_offsets_device,\n", " sorted_coarse_bin_ids_device,\n", " numpy.int32(n),\n", " block=compute_bin_offsets_function_block,\n", " grid=compute_bin_offsets_function_grid)\n", " \n", " pycuda.driver.memset_d32(histogram_device, int(0), nbins)\n", " \n", " compute_fine_histogram_function(\n", " histogram_device,\n", " sorted_coarse_bin_ids_device,\n", " sorted_data_device,\n", " bin_offsets_device,\n", " numpy.int32(n),\n", " numpy.int32(num_coarse_bins),\n", " numpy.int32(nbins),\n", " numpy.float32(input_min),\n", " numpy.float32(input_max),\n", " numpy.float32(input_range),\n", " block=compute_fine_histogram_function_block,\n", " grid=compute_fine_histogram_function_grid)\n", " \n", " pycuda.driver.Context.synchronize()\n", " \n", " end_time_seconds = system_timer_function()\n", " elapsed_time_seconds = end_time_seconds - start_time_seconds\n", " total_time_seconds = total_time_seconds + elapsed_time_seconds\n", "\n", "pycuda.driver.memcpy_dtoh(histogram_gpu, histogram_device) \n", " \n", "average_time_seconds_gpu_system = total_time_seconds / num_timing_iterations\n", "\n", "\n", "\n", "print \"Using system timer for benchmarking (see above)...\"\n", "print \"Average time elapsed executing GPU (shared memory) over %d runs: %f s\" % (num_timing_iterations,average_time_seconds_gpu_system)\n", "\n", "print\n", "\n", "figsize(4,4)\n", "\n", "matplotlib.pyplot.plot(histogram_gpu);\n", "matplotlib.pyplot.title(\"histogram_gpu\");" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Using system timer for benchmarking (see above)...\n", "Average time elapsed executing GPU (shared memory) over 100 runs: 0.001150 s\n", "\n" ] }, { "output_type": "display_data", "png": "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\n/we7hHdGMHW6pgAAAABJRU5ErkJggg==\n" } ], "prompt_number": 10 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## benchmark GPU (global atomics) code" ] }, { "cell_type": "code", "collapsed": false, "input": [ "total_time_seconds = 0\n", "\n", "for i in range(num_timing_iterations):\n", " \n", " pycuda.driver.memcpy_htod(input_data_device, input_data)\n", "\n", " input_min = reduce_manager.reduce_min_device(input_data_device, n)\n", " input_max = reduce_manager.reduce_max_device(input_data_device, n)\n", " input_range = input_max - input_min\n", " \n", " pycuda.driver.Context.synchronize()\n", " \n", " start_time_seconds = system_timer_function()\n", "\n", " pycuda.driver.memset_d32(histogram_device, int(0), nbins)\n", " \n", " compute_fine_histogram_global_atomic_function(\n", " histogram_device,\n", " sorted_data_device,\n", " numpy.int32(n),\n", " numpy.int32(nbins),\n", " numpy.float32(input_min),\n", " numpy.float32(input_max),\n", " numpy.float32(input_range),\n", " block=compute_fine_histogram_global_atomic_function_block,\n", " grid=compute_fine_histogram_global_atomic_function_grid)\n", " \n", " pycuda.driver.Context.synchronize()\n", " \n", " end_time_seconds = system_timer_function()\n", " elapsed_time_seconds = end_time_seconds - start_time_seconds\n", " total_time_seconds = total_time_seconds + elapsed_time_seconds\n", "\n", "pycuda.driver.memcpy_dtoh(histogram_gpu_global_atomic, histogram_device)\n", " \n", "average_time_seconds_gpu_global_atomic_system = total_time_seconds / num_timing_iterations\n", "\n", "\n", "\n", "print \"Using system timer for benchmarking (see above)...\"\n", "print \"Average time elapsed executing GPU (global atomic) over %d runs: %f s\" % (num_timing_iterations,average_time_seconds_gpu_global_atomic_system)\n", "\n", "print\n", "\n", "figsize(4,4)\n", "\n", "matplotlib.pyplot.plot(histogram_gpu_global_atomic);\n", "matplotlib.pyplot.title(\"histogram_gpu_global_atomic\");" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Using system timer for benchmarking (see above)...\n", "Average time elapsed executing GPU (global atomic) over 100 runs: 0.012794 s\n", "\n" ] }, { "output_type": "display_data", "png": "iVBORw0KGgoAAAANSUhEUgAAAQ8AAAEICAYAAABBKnGGAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJztnXlUFFf2x79NFNw1YBASaIHo0CgR2oiNC2rI5oY6amKM\nYk40icHxuDsz8ZefkmSOhp9jjPFEYmZEM67RmERiVOKGEk0AxW1Y3IJKlCiICiiy3t8fZe9N0910\nd/VyP+f0qapX3VW3q6u+fd97970rISICwzCMmXiIbQDDMM4JiwfDMBbB4sEwjEWweDAMYxEsHgzD\nWASLB8MwFuFS4hEUFISDBw/qlWdkZEAmk4lgEQMAV65cgYeHBxoaGpp8b2JiIuLj4y06z4YNGxAT\nE2PRZ+3F8OHDsXHjRrHNsAotxDbAmkgkEkgkEr3ymJgYFBQUNPn5xMREXL582WV+XGfE0O9nT2x9\nD+zZs8cmxxUDl/I8HJm6ujqxTXAKOGbReXA58bhw4QL69esHqVSKxMRE1NbWIj09HYGBgar3rFu3\nDv369UPHjh0hk8lw6NAh7Nu3D8uWLcPXX3+N9u3bQy6XAwDKysqQlJSE7t27Y/z48Thy5IjqOLW1\ntVizZg1CQkLQt29fJCcna50nKCgIa9asQf/+/dGpUyfU19fj448/Rrdu3eDj44NJkyYhIyND9f4N\nGzZg4MCBSExMxFNPPYU+ffrg3Llz+Oabb/DMM8+gT58+SEtLa/IaVFZWYunSpQgICEBsbCw+/vhj\nLXfew8MDGzZsQEREBHr27Ilt27apHlrdaoOpVY6SkhL89a9/hZ+fH/785z9jwYIFjVY/jF1TiUSC\nuro6vP322/Dz88P06dNRVFSk2m/s+pnK7NmzIZVK0aVLF0yfPh1nzpwBAIvugcTEREycOBEzZsyA\nr68vBg0ahOLiYnz++efo1q0bYmNjkZWVpXr/kCFDsG7dOtX24cOHMXnyZHh7e6Nnz544deqU2d9H\nNMiF6Nq1K/Xq1YuysrLowoULFBQURAcOHKDDhw9TQEAAERGVlJRQQEAAXbhwgYiIrl69SpcvXyYi\nosTERIqPj9c65pQpU+jVV1+loqIi2rlzJ3l7e1NhYSEREa1evZr69OlD586do4yMDJLJZBQYGKj6\nbFBQEPXo0YOOHj1KDx8+JCKiHTt2UHFxMT148IA++eQTlV1EROvXrydPT0/6xz/+QWVlZTR9+nQK\nCQmhKVOm0I0bN2j9+vUUEhLS5HWYP38+DRs2jAoLC+mHH34gf39/iomJUe2XSCTUr18/Onv2LB05\ncoSCgoJo3759qmswefJk1XsLCwtJIpFQfX290XOOGzeOpkyZQsXFxbRx40Zq166d6lrqHsPYNV2y\nZAm1bNmS/vnPf9KtW7do9uzZFB0drTpPU9dv4MCBTV6fTZs2UVlZGd25c4cWLlxIAwYMUO0z9x5Y\nsmQJeXp60vr166m0tJRGjRpFYWFhNGfOHCotLaWPPvqIYmNjVccaMmQIrVu3joiIcnJyyNfXl7Zs\n2UI1NTV06dIlunr1apP2OwouJR5BQUG0YsUK1fb06dPpb3/7G6Wnp6tustLSUvLx8aHdu3dTTU2N\n1ueXLFmi9eDU1dWRj48PnT9/XlU2adIk+uSTT4iIaNiwYaobgYjof//3f7Vu5qCgIPrwww8btbeh\noYECAwPpxIkTRCTc/N7e3qqH7OeffyaJREJnz54lIqLa2lpq06YNXblyxeh16NGjBx08eFC1HR8f\nr/VQSSQSLbvfe+89mjlzpsFrYIp41NbWUseOHVUiTEQUExNjUDyauqZLliwhqVSq2ldZWUmtWrWi\nW7du6Z3X0PUzRTw0KS8vp7Zt21JJSYnB72+Kvb169VLt27RpE7Vo0YLu3LlDRES///47tWrVSvXn\noSkef/3rX2n27Nlm2etIuFy1JTIyUrXu7++P69eva+338fHBxo0bsXLlSvj7+2POnDkoKSkxeKz8\n/HxUV1fjT3/6k6rs2Wefxc8//wwAyMrKUrm2ANC7d2+9YygUCq3t1NRUjB07Fk8++SS8vb1RXFyM\ns2fPqvb36NEDHh7Cz9KlSxcAwDPPPAMAaNGiBby9vfW+kybl5eXIz89v0i7N6ySXy/HLL780esym\nyM/PR0NDA0JCQlRlzz77rMH2i8auqWb1o1evXqr1tm3b4umnn1a5/k1dP1PYsGEDRowYgSeeeAJS\nqRRVVVU4d+5co9/NHHu7dOmCgIAAdOrUSbVdXV2N27dv6x07PT0dAwYMMMt2R8LlxMMUhg0bhgMH\nDiAvLw+FhYX4v//7PwDCw6l5w8tkMnh5eeH8+fOqshMnTqjaD/r27atVR83JydE7V4sW6g6t+/fv\n4+2338Ybb7yBgoIClJWV4amnnrJqI2GHDh0gk8matEt3f//+/QEAAQEBuHnzpsH3NYZMJoOHhwd+\n++03VdnJkycN9pw0dk0HDRqk2la2QQBC+83ly5ehUCiscv2Kioowb948LFq0CFevXsW1a9fQunVr\n1TFMvQc07bWU5557TvVH5Iy4tHgYuqkuXLiAQ4cOobq6Gp6envDy8kL79u0BCP8oeXl5qK6uBiDc\nSCNGjMCSJUtw/fp1fP/999i3bx/GjBkDQOizX7t2LXJzc3Hs2DHs3LnTaFdjRUUFKisr4e/vj4aG\nBixbtgw3btyw+vcePnw4VqxYgatXr2LPnj04ePCgnl0pKSn473//i4yMDHz99dcYOXIkACA2Nha/\n/vorcnJycP78eXz++edNnq9ly5Z44YUX8NFHH+HmzZvYsmULTp8+bfC9TV1TAPjjjz+wcuVKlJSU\nYPHixZDL5ejcubNVrl9JSQmICH5+fqioqMCiRYtUvzdg/j3QHF577TVs374d27dvR01NDS5duoRr\n1641+7j2wqXFQzPuQ7msrq7Ge++9hyeeeAJ9+vRBp06dMHfuXADA4MGD8ac//QnBwcHo06cPAOCT\nTz5BREQEBg8ejP/85z/YsWMHgoKCAADvvPMO4uPjMXLkSMydOxdvvvkmOnTo0Kg9fn5+WLZsGeLj\n4xEREYGamhoMHDjQoL2aZeayZMkS9OvXD/3798c///lPTJ06Vc+ud955B5MmTcL06dPxj3/8Ay++\n+CIAICQkBImJiXj11VcxceJEvPXWWybZsGbNGvj4+CAiIgLffPMNJk2ahI4dOxr8HsauqUQiwfjx\n45GXl4fw8HBUVlZi27ZtACy7frr07t0bM2bMQGxsLAYNGoTw8HCtHjJz7wFTfrPGbIqMjMTmzZvx\n7bffwtfXF2PHjsWdO3eM2u9ISMiaPrObs3DhQlRXV+Ozzz4T2xQtXnnlFfTr1w/z5s0DIHTVXrp0\nSauNwtpERUXhvffew9ixY212DkZcTPI86uvrIZfLERcXB0Bwv0ePHg2pVIoxY8agsrJS9d7PPvsM\n3bt3R48ePZy6PmcKf/zxB44dO4a6ujr88MMP2L59O1566SWxzcL58+dx9uxZVFdXY/Pmzdi/f7/N\n7Tpx4gQuX76M+/fvIzk5GefOncPzzz9v03My4mKSeKxatQo9evRQuV/JycmQSqW4ePEiAgIC8MUX\nXwAAbt26hTVr1uDgwYNITk7GrFmzbGe5A1BTU4N3330XHTt2xMqVK7Fs2TIMHTrULufu2bMn2rdv\nr/faunUrKioqMG7cOPj4+ODrr7/Gf/7zH4SHh6s+a2kIeLt27Qye89ixY/jjjz/w3HPP4cknn8TP\nP/+MtLQ0rWqLPcnIyDBop7EqJWMBTfXlFhUV0fPPP0+HDh2ikSNHEpEQEHTq1CkiIjp58iSNHz+e\niIhSU1O1+q0jIyOpvLzceh3LDMM4DE16HnPnzsXy5ctVsQcAkJ2drRqlKpPJVH3wmZmZCAsLU70v\nNDRUKzSXYRjXweio2t27d8PX1xdyuRzp6emqcjKjjdWQiyz2yEmGcWfMeX6NYdTzOH78OFJTUxEc\nHIyJEyfi0KFDiI+PR1RUFPLz8wEIEXhRUVEAhGjKvLw81ecLCgpU+wx9AUd6LVmyRHQbnMUutsl5\nbbImRsVj6dKlKCoqQmFhIbZt24bY2Fhs3LgRCoUCKSkpqKqqQkpKCqKjowEIEZdpaWm4du0a0tPT\n4eHhoQrAYhjGtTBrMiBldSMhIQGTJ09GaGgoevfujaSkJABCHH9CQgJiY2Ph6emJtWvXWt9ihmEc\nAlGCxCQSidVdqOaSnp6OIUOGiG2GHo5oF9tkGo5okzWfPRYPhnEjrPnsufTYFoZhbAeLB8MwFsHi\nwTCMRbB4MAxjESweDMNYBIsHwzAWweLBMIxFsHgwDGMRLB4Mw1gEiwfDMBbB4sEwjEWweDAMYxEs\nHi5KQwNw4oR6OzYW+PRT8exhXA8WDxclLQ2IigLKy4G7d4HDh4HvvhP2/fwzYKdJ3hkXxqzJgBjn\noaZGWMbEAKWlwvrRo8Jy1y5BXBimObB4uDi//QZo5OQCAPD804w14GqLi2NIKFg8GGvAnoeLUVQE\ntGmj3tYVCiLg3Dn72sS4JkY9j4cPH0KhUCAyMhLR0dFYuXIlACAxMREBAQGQy+WQy+XYu3ev6jPu\nlKvWEZFKgREjBJEA9MXjl18AjZ+LYSzGqOfRqlUrHD58GG3atEF1dTWeffZZjBw5EhKJBPPmzVNl\nXVeimau2sLAQs2bNQk5Ojk2/AKPP3bvqBlMPnb+Hhw/V63V1gpeyYQPw+ut2M49xEZps82jzyAeu\nrKxEXV0dvLy8ABjOOpWZmYmhQ4dCKpVi8ODBICJUVFRY2WSmKTw8gAkThHVdz6O+Xr1eVgbU1gKT\nJtnPNsZ1aFI8GhoaEBERgS5dumDmzJmQSqUAgNWrVyM6OhpJSUkqgcjKyuJctQ7Ao2R+APQ9j4YG\n+9rCuC5NNph6eHjgzJkzuHLlCoYPH44BAwYgISEBixcvRnl5ORYuXIi1a9diwYIFBr2RxvLSJiYm\nqtaHDBnicPktXAXdy68pHpz9wvVJT0/XyjNtVcgM5s+fT8nJyVplp0+fpv79+xMRUWpqKs2aNUu1\nLyIigsrLy/WOY+ZpmSaIiCBSXmZBEtSvLl20t3fvVq/fuKFeZ9wDaz57RqstpaWluHv3LgDg9u3b\n+OmnnzB69GgUFxcDAOrq6rBlyxYMHz4cAOeqFYszZ4Dffwe+/15/nzHPQ7P9g2HMxWi1pbi4GG+8\n8Qbq6+vh5+eHBQsWwN/fH1OmTMHp06fh6emJQYMGISEhAQDnqhUTIuDPf9YvZ/FgbAWnm3QBJBLg\nv/8FwsP19z35JHDjhnr722+BsWOF9YwMYewLwO0f7gKnm2RMRre3Zfp09fqj2ibDWASLh4vQ2J/J\no7AcFSUl6nUOwWGaA4uHi9O6tWnv42oLYy4sHi5Oq1amvc/DgxtQGfNg8XARGvMcTBUPgKNPGfNg\n8XARGhMPcwY2KxTWsYVxD1g83Bi5XHv71ClhuWULsHq1/e1hnAuO83ABJBJg/37gxRfN+5xuDAgg\neDCdOwO3b3MjqivCcR6MCuV9cPiw+Z+9edP4MRnGGCweTkZhIXDrlnpb+aAvXWr+sQz1rsyYweLB\nmAaLh5MREgIMG6bebqqHZONG847/r3+xeDCmweLhhNy7p15vSjw0I0xnzNDfv2iR9vZjj3GXLWMa\nLB5OTlMP+mOPqdd9ffX337mj/372PBhTYPFwckwVj9WrhbQMuowZo7394AGPeWFMg8XDyWnMS3g0\n1axqVG1Dg34DaevW2jleGMYcWDycnMY8j65dhWVdnfp9yomBWrYUlhIJZ49jLIfFw4nQTIFTXS14\nHffvG36v0uNQ5qltaFB7KWvWCEuJhNs3GMth8XAiVq0SlkTCgLelSwF/f8PvVXoUyiRP9fVqoait\nFZa6EwUxjDnw7eNE6HoJyrEomsTGCksPD+DoUSA+XtjWrN7U1ABxccD48VxtYSzHoly1FRUVGD16\nNKRSKcaMGYNKpW8MzlVrD8rKhOXOnfr7nntOWHp4CPOTKofka1ZbamqA1FQgJcX4eTRnHWMYXYyK\nhzJX7enTp3HkyBGsW7cOFy9eRHJyMqRSKS5evIiAgAB88cUXALRz1SYnJ2PWrFl2+RLuxqNsGFqk\npgJffaUWCN0qiWa1xdvb8HGVDalK+vcXluPHAydOWG4v45pYlKs2KysL06ZNg5eXF6ZOnYrMzEwA\nnKtWTOLigClT1NWTxx/X3q9ZbXnzTfW6ZrVF2TOj5FF6HuzcaTgnDOPeNJlusqGhAXK5HLm5ufj0\n008hlUqRnZ0NmUwGAJDJZKp8tJmZmQZz1T7//PN6x+V0k+ZjSs+I0uP48kvt8oYGYORI4Pz5xhtK\ndY/f0AD8+KOwzm0jzokt001alKvWnPkATMlVy5iGKZddGVHaoYN2eX098OqrwstU6uoEwWGcF90/\n5g8++MBqxza5tyUoKAjDhw9HZmYmoqKikP8oFXt+fj6ioqIAAAqFAnl5earPFBQUqPYxtuNRkxOA\nxr2KxoLJlNqemgo8ag9XoezS1XwfwyixKFetQqFASkoKqqqqkJKSgujoaACcq1YsWmj4j5oD4TTp\n3Nlwec+ewMSJQptJz56Nn4PFg9HFoly1CQkJmDx5MkJDQ9G7d28kJSUB4Fy1tqaxaoumeBjyPK5f\nNzyiFhCqN1u2NP5ZJSwejC5GxeOZZ55BjmZM9CPat2+PXbt2GfzM7NmzMXv2bOtYx5hEU57Hk0+a\ndhwWD8YcOMLUBTCl2mIKxgSCxYPRhcXDBWiq2mIq7Hkw5sDi4UQ01ubRqZN63cfH8uOz58GYA4uH\nC6AcDAcIcRyFhZYdx5jnwSNwGV2aDBJjxOfMGeMzfml6BR4eQFCQZecx5l00py2FcU34/8QJiIwE\nBg60/cQ9xsSjXTvbnptxPlg8nIRbt2wvHsaOz+kYGF1YPJyIr7+27fGV4jFvnv6+8nLbnptxPlg8\nnJiOHa17PKV4jBgByOXa+06etO65GOeHxcOBefDAeDtEcLB1z6cUj9hY/cl/Wre27rkY54d7WxyY\n6mrj+xUKoLTUeufTbPMwNBMZw2jC4uHANNVAmpxs3UZU3WPV1amjV1k8GF242uLESCTWDd7SFQ/N\n2I7btznHC6MNi4cD40gP6+HDQG6u2FYwjgSLhwNj79iKpsTq11/tYwfjHLB4ODD2bmcwJB4ffQRM\nmCCsv/22MLEQwwAsHg6NIc9DmcDaFhgSj/ffF/K2KFGmY2AYFg8HxpDnoZtSwZo0Vm3RLG/b1nbn\nZ5wLo+JRVFSE5557Dj179sSQIUOw5dFkl4mJiQgICIBcLodcLsfevXtVn+F0k9bDkOchxuhWTfGQ\nSIANG4D79+1vB+NYGI3zaNmyJVauXInIyEiUlpaib9++iIuLg0Qiwbx58zBPZxCEZrrJwsJCzJo1\ny+AcqIxpGPI8bDmvRmCg4XJN8aivFzLOtW0LvPKK7WxhHB+j4uHn5wc/Pz8AQOfOndGzZ09kZ2cD\ngMHET5rpJqVSqSrdJKdfsAxDnoctxSM01HDVRbNMMyVlXh7Qo4ft7GEcG5NvxUuXLiE3NxcKhQIA\nsHr1akRHRyMpKUmVjzYrK8tguknGMuzteTSGpnjcu6de79kT4FTE7otJ4ekVFRWYMGECVq5cibZt\n2yIhIQGLFy9GeXk5Fi5ciLVr12LBggUGvRFT0k1yrlp95swBXn9dv1wpHkVF9rNF82cdPFh7n25y\nbMaxsGWuWlAT1NTU0IsvvkgrV640uP/06dPUv39/IiJKTU2lWbNmqfZFRERQeXm53mdMOK3bIzyy\n+q/jx4VlQ4P9bNm0Sd+OHTuEZUmJ/exgmo81nz2jTjARYdq0aQgPD8ecOXNU5cWPOvvr6uqwZcsW\nDB8+HACnm7QHSkfOnrOZG2oHUbbHsOfhvhitthw7dgybNm1Cr169IH80O8zSpUuxdetWnD59Gp6e\nnhg0aBASEhIAcLpJWzJtGrBunTBAzd74++uXKcVDMxk2415IHrky9j2pRGKwfYRRo+lZvPACMGYM\nMHOmEB6+eDHw73/b154FC4AVK9TbX30FvPEGcPkyEBJiX1sYy7Hms8fi4aBoisfLLwM//gjcuNF4\nLIatycwEoqPV297eQFkZUFAgdPEyzoE1nz0OT3dAjh/X3n7sMeEllnAAwqxlvr7q7bIyYcnVFveF\nxcMBGTBAe9tREi4ZijFh8XBfWDycAEcRD0OweLgvLB5OgKOIx5NP6pexeLgvLB5OgKOIh7e3sNTM\nhcvi4b6weDAm4+UlLPv0UZexeLgvLB5OgKP0aivFo00bdRmLh/vC4uFgGBqG7yjioYzn0Mwex+Lh\nvrB4OBiOPEPXhx8Cd+5oh6uzeLgvLB4Ohm6OWMBxPI8WLYBOnYD33lOXsXi4LyweDsZbb4ltQdN4\neqrXWTzcFxYPB0NjIjangMXDfWHxcDAMTagmldrdDJNh8XBfeFStg+HhAbRrpz03aE0N0LKleDYZ\nQjnqd8gQ4J13hMRQjmYjow8PyXdhDM0Q5oiXStdOLy/g4UNxbGFMh4fkMw5HdbXYFjD2hsXDgUhN\nFZacC4VxBrja4kAoqwIXLwLdu6vLHfFSGapelZQAnTvb3xbGdOxWbWksV21FRQVGjx4NqVSKMWPG\noLKyUvUZzlXbfLp1A7ZuFdsK83niCbEtYOyKsbwMxcXFdOrUKSIiKikpoeDgYCovL6ekpCSaOXMm\nPXz4kP7yl7/Q8uXLiYjo5s2bFBoaSlevXqX09HSSy+UGj9vEad2O+/eJNm9W50QhEvKyeHiotx2N\nvDwiiUQ/nwvj2Fjz2TPqefj5+SEyMhKAdq7arKwsTJs2DV5eXpg6dSoyMzMBaOeqHTx4sCpXLWOc\nXbuASZO0yyQS4OpV4NQpcWxqirAwoFUrsa1gxMTsXLV9+/ZFdnY2ZDIZAEAmk6ny0WZmZnKuWgto\nLIFTQADwSLsdkt69xbaAEROzc9W2a9fOrAYXzlVrnPp67eTRzsSmTUBwsNhWMMZwuFy1Y8eOpZyc\nHCIiOnHiBI0bN46IOFetJSxf7rztBrduOa/t7oo1nz2LctUqFAqkpKSgqqoKKSkpiH6UDYhz1ZrP\n1atiW2A5jjK3KiMOZueqXbZsGRISEjB58mSEhoaid+/eSEpKAsC5ai3Bngmrrc3jjwuJqIqKxLaE\nEQMOEhMZZxnL0hiFhUKjbnm5sO1MtrsjPLaFcRiCg4GzZ9Xbr74KXLggnj2M/WDxYJqN5lD8HTuA\nH34QzxbGfrB4OBghIWJbYD6683hoTlPIuC4sHg7G5ctiW2A+LXSa3XlSIPeAxYNpNrpi4cw9SIzp\nsHgwzUZXPDj+wz3grlqR0f2XdsbL0tCgLxjl5QDHBzoe3FXrIuimlkxJEceO5uLhARw+rF3WoQMw\nebI49jD2gT0PEamu1h7WfuGC9gxizoauF9Wpk5CeknEc2PNwEXRznuj2WjCMI8PiYWdef13wOG7f\n1p8AyNnFwxljVBjL4WqLnZFIgCtXgJMngXHjtPfduKGdgd4ZeewxdVvO448DZWXi2sNow9UWF8BQ\ngiRXCK7S/A537gC5ueLZwtgWFg8RCAoCDM3O6OzVFkA/ND08XBw7GNvD1RY7Yyz60hViI7y99XtY\nGhqEnC6+vuLYxKjhaouL4gqRmYa8pz17gC5d7G8LY1tYPBwIVxiNaug7lJba3w7G9rB42JGmvEVX\naPNwhUZfxjRYPOxIfb3hclfwOJQYEg8eZeuaGBWPqVOnokuXLnjmmWdUZYmJiQgICIBcLodcLsfe\nvXtV+zhPrXF0x7IoOXAAWLrUvrbYCldot2FMw6h4vPnmm9i3b59WmUQiwbx583Dq1CmcOnUKw4YN\nAwDcunULa9aswcGDB5GcnIxZs2bZzmonpTHPIyYGeO89+9piK3x8xLaAsRdGxSMmJgaPP/64Xrmh\nrh7OU9s0jXkerkRqqtgWMPbCojaP1atXIzo6GklJSSqByMrK4jy1TdCY5+FKeHvzBMjugtnt+wkJ\nCVi8eDHKy8uxcOFCrF27FgsWLDDojTSWpxZwz1y17uB5AEI1TJNdu8Sxg7FtrtomI0yvXLmCuLg4\nnDt3Tm/fmTNnMGPGDBw7dgw//PADDhw4gFWrVgEAIiMjkZGRYTDdpLtGmN6+DXTurF/uapfi/n2g\nXTv9clf7ns6IqBGmxcXFAIC6ujps2bIFw4cPB8B5ak3BXTwPV4hXYZrG6M88ceJEHDlyBKWlpQgM\nDMQHH3yA9PR0nD59Gp6enhg0aBASEhIAcJ5aU/jjD7EtsA8sHu4BD4yzI6NGqRsTd+8GevQQBoz1\n7SuuXbbA2XPwuirWfPb4P8IOLFoEPPGEdvSlRCLkeQ0OFs8uhmkOLB52YNky/TL+F2acHR7bIhIs\nHoyzw+IhEu7S88K4LiwedqZrV2HpDp7HJ5+IbQFjS1g87IyyF8LVxaOuDpg7V7ssLw8ICDA8+TPj\nfLB42Jn33xeWrl5tMTQ0f/Nm4Pp1gMdLugYsHnZGmb/V1T0PQ1RWCkueHMg1YPGwA3K5el0ZfemO\n4lFdLSxZPFwDFg87oCkUSnfe1asthlCOWHBH4XRFWDzsgKF5PNztAfrqK/W6OwqnK8IRpjakrk54\nKev6mribeGgOsGbxcA1YPGxIaCjw22+G97nbA9SqlXrdHWZUcwdYPGyIrnA89ZR63Z08j7Q07UGB\n7iacrgq3ediRX38Vlp9/DsTFiWuLPXniCcDLS73N4uEasHjYEN00BMpu2hkzgA4d7G+PGDx4IHRV\na1ZbWDxcAxYPG3HvnjBnqSbuOMNW69bCksXD9WDxsBGGJqx25zyumtWWnTvFs4OxHiweNqKuTr/M\nHT0PJZpRpX/7m3h2MNbD7Fy1FRUVGD16NKRSKcaMGYNKjSAGzlWrxpB4uHMe1zZtxLaAsTZm56pN\nTk6GVCrFxYsXERAQgC+++AIA56rVpaFBmOBYyfPPA56e4tkjNn5+wPTpYlvBWBOzc9VmZWVh2rRp\n8PLywtSpU5GZmQmAc9Xq8j//A7Rtq94+cADwcPNK4qN8YACATZsEQWWcF7Nv5+zsbMhkMgCATCZT\n5aPNzMxF77yrAAAPM0lEQVTkXLUAvvlG8DoKC4UXAFy6JK5NjoJmo2l8PHDoELB3r3j2MM3D7CY8\nc3I+uGOu2ldeAbp0EdY7dQJKS4GQEHFtcmSGD3evaFt7Y8tctWaLR1RUFPLz8yGXy5Gfn4+oqCgA\ngEKhwIEDB1TvKygoUO0zhKZ4uBo3bwpLpXby/BWMWOj+MX/wwQdWO7bZ1RaFQoGUlBRUVVUhJSUF\n0dHRADhXrSFYNExDOUkQ41wYFY+JEyeif//+uHDhAgIDA7F+/XokJCTg2rVrCA0NxfXr1/Huu+8C\n0M5VO2PGDKzSbB1zU1q3Bi5eFNsKx6dfP7EtYCyBc9VaESLtHpXwcODcOfHscUQa88Zc8HZwSKz5\n7Ll556F10R2zwfNW6EOkblBmnBsWDyuSlqa9bSjKlOGBca4Ci4cV2bRJe5vFwzCGvObdu+1vB9M8\nWDysRH09sHWrfhmjj9LzWLlSXTZ7tji2MJbD4mEF8vOB48f1y9nzMIxSPObMUZe587gfZ8WNB4lb\nD80BcJqw52GY9HSgqkpYf+cd4MsvgYICUU1iLIA9j2Zy7Fjj+9jzMExEBPAothCjR4trC2M5LB7N\nZNs2/bLiYmHJnkfTuPMESc4Oi0czMdRz4OcnLFk8mkZTPDhQzLlg8Wgmujf8woXqdRaPptEUDw8P\n7bSUjGPD4tFMdAOelJMcHz0KHDxof3ucDd1qyy+/iGMHYz5c42wmuuLxaJ4kxMTY3xZnRFc8SkvF\nsYMxH/Y8molutYXjFcxDVzx27gQ2bgS+/14cexjTYc+jmeh6Hu4+T6m5GOptmTJFWHIDqmPDt7qF\n5OQA5eX6N7g7p1ewJrqpOhnHg8XDQp59FvjwQyAlRbucPQ/zqK0Vlpcva5dz9c/x4VvdAq5fF5aG\nhILFwzxqaoSlZi5bALhzx/62MObBt7oFKMPOly8HlGltFi8Wliwe5vH000BQkHaOGwB4+BDIzRXF\nJMZE+Fa3gIcP1evKf0hl/lUWD/Pw9RXy23TooL+P8904Nhbf6kFBQejVqxfkcjn69u0LwHgeW1dC\nUzyUKHOxsnhYRmNzm777LvDmm/a1hTENi291iUSC9PR0nDp1SpUZrrE8tq6Gcji5ITp3tp8drk5d\nHbB+PbBhg9iWMIZo1v+k7izMjeWxdSW+/FJ/usGXXxaWd+8CffrY3yZXZfx4dYMq43hYnHohJCQE\n7du3R3BwMKZOnYpRo0aha9euOH/+PFq1aoUHDx4gLCwMV69e1T+pE6deMOReO+lXcTjWrwemTjW8\nj6+xdbDms2dxhOmxY8fg7++P/Px8xMXFoW/fvmYZ5ay5alu2VMcmMNbF17fxfRIJC4gl2DJXrVWS\nPs2bNw9hYWHYt28f3n//fcjlcpw8eRLLli3DN998o39SJ/U8DHkdx49zxjNrUVMDpKYKycINQSR0\nje/aBQwaZF/bXAXRkz49ePAAFRUVAICSkhKkpaVh6NChjeaxdVVatGDhsCaenkI7x7x5jb/n7l0g\nO9t+NjGNY5F43Lx5EzExMYiMjMRrr72G+fPnIzAwsNE8tq7A6dP6ZdwtaxsmTjS+nxOIOwYWtXkE\nBwfjtIGnqX379ti1a1ezjXI09u8HXnpJv1wZGMZYlz59gIEDgZ9/1i5/8EBYsmg7BvwzmMDJk/pl\nCoUwMI6xDWPHqkP/lRw9KixZPBwD/hlMICdHv2zLFvvb4U7MnQuUlWmXKef+4GkPHAMWDxPYsUN7\ne9IkICREHFvcmRdfFJbc5uEYsHgYYf16oEsX7bKbN/UjTBn7wuLhGFglzsPskzpJnAdHk4qPod9g\nzBjgu+/sb4srIHqchytTXS3csHv2iG0J0xjff68/dyxjf1g8dFD2NI8YIa4djHFu3BCWubnsDYoF\ni4cG9+8DEyaIbQWjSXU18Pe/CykZNPntN+DWLSA8XD8ehLEPLB6PWL8eaNfO8L6337avLYwaT09g\n2TJ1Mi0lFy+qG7OV00Iy9oXFA8C1a9pDwQMC1Otffim8SksBA7MLMHbC319Yjh8vLN96S73PUO4X\nxvaweACYNUt728tLvf5ohkX4+ABSqf1sYrR5/HGhbUM35gYAMjOBigphRK5Eog5jZ2yL22p2SYkQ\n5uzjoy0WgHYEY+vW9rWLMZ+FCwFvb2DaNGH72jVh29j8IEzzccs4j3PngF69hCjRnBygUyft/SEh\nQoMcINyIgYH2t5FpHE9P4xMydeok7HfR+bebBcd5NAMidXfsb78ZHtymOVpWNxkRIz6BgYJ32Nhc\nKnfvCj1njG1xO88jKKjphk8iIX4gPFy4CZVpFRjHoLhY8CykUuOh6jt3CqNzGTXseZjJsWOCIGzZ\n0rRwfPqpsOzZU/gMC4fj4e9vWuP1uHGG52FhrINbNJgOHCi0c3z7reH9hw8D6elCykieK8K52LBB\nmFule3fDXbb79wtd77GxwPDhgieZnQ24aEohu+LS1ZZ794Q0hh4ewL59wPz5hvOfnjkjNKAyzs3e\nvYJANIZcLsTrFBW5b0i7NZ89lxQPIqC+XkiT8NVXwBtv6L/nqaeEiNLt24W2DfY4XANTh+uzeDQf\nmzwyR48eRVhYGLp3747Vq1fb4hRaFBcL7RoA8M03Qvb6li2FbV3h2L1bWKalAQUFgsfh4QGb5bZo\nLo5olyPbdOGCMOcK0HQeGEDoeSsvB6ZP104jun+//kxmltrkspANiIyMpCNHjtCVK1coNDSUSkpK\ntPZbctrsbKLqaqLbt4kOHya6fJkIIDp6lCgkRFgfNUpYNvYaMKDx4y9ZssRsm+yBI9rlDDbl5BDl\n5xPt2EG0d6/x+0Lz1bIlUfv2wvrkyda1yRGw5iNv9QbTe/fuAQAGPcrK89JLLyEzMxMjDIxxr6kR\nVP/GDaBjR6ExKzZW8Ap++kmIAv3sM6BtW+FfYPly4OBBof1CiWbyn9RUfXvatlX3+X/+udW+JuPg\nyOXCUiYTZGHePGDRoqYTkdfWqgPQNm0Czp8HRo4EliwRygYMEBreb98WYoCCg4XywkLg3XeFXqCW\nLYGPPxaC1P74Q4hgvndPCDiMiXGdmdCsLh7Z2dmQaQyB7NGjB3799Vc98YiLU1chdImM1N6urhaW\nCxeabkdamjCFv7c3cOeOIE7cruGeSCTAihXCenm5MA6mdWvhYY6MFP50tm8Xems2bND+bHa2dpKp\nY8e0p6YcOVJY6t7LycnCUnleAOjaVRAZV8HqDaYHDhzAunXrsHXrVgDAF198gevXr+Ojjz5Sn9RV\npJdhnBBrPfJW9zyioqKwUMNFyM3NxdChQ7XeY2W9YhhGBKzuyHfs2BGA0ONy5coV7N+/HwqFwtqn\nYRhGZGwSYfrpp59i+vTpqK2txaxZs9C5qVYqhmGcD6v125jAkSNHSCaTUbdu3eizzz6z23mvXbtG\nQ4YMoR49etDgwYNp8+bNRERUXl5Oo0aNosDAQBo9ejRVVFSoPrNq1Srq1q0bhYWFUUZGhs1sq6ur\no8jISBo5cqRD2FRZWUlTpkyh7t27U1hYGP3666+i20RE9OWXX1K/fv2od+/eNHv2bCKy/7V68803\nydfXl8LDw1VlltiQl5dHcrmcgoODadGiRVa3acGCBSSTyUgul9Ps2bPpwYMHNrHJruLRVPyHrSgu\nLqZTp04REVFJSQkFBwdTeXk5JSUl0cyZM+nhw4f0l7/8hZYvX05ERDdv3qTQ0FC6evUqpaenk1wu\nt5ltK1asoNdff53i4uKIiES3af78+fT+++9TVVUV1dbW0t27d0W36fbt2xQUFESVlZVUX19Pw4YN\no3379tndrqNHj1JOTo7Wg2qJDcOGDaNt27ZRaWkpDRgwgLKzs61q008//UT19fVUX19Pb731Fv37\n3/+2iU1267zUjP/o2rWrKv7DHvj5+SHyUf9v586d0bNnT2RnZyMrKwvTpk2Dl5cXpk6dqrInMzMT\nQ4cOhVQqxeDBg0FEqKiosLpdv//+O/bs2YO33npL1Ygstk0HDhzAokWL0KpVK7Ro0QIdO3YU3abW\nrVuDiHDv3j1UVVXhwYMH6NSpk93tiomJweM62bfNsaHy0exE58+fx4QJE+Dj44OxY8c26zkwZNOL\nL74IDw8PeHh44OWXX8aRI0dsYpPdxKOx+A97c+nSJeTm5qJv375aNslkMmRlZQEQLnJYWJjqM6Gh\noap91mTu3LlYvnw5PDQCUMS06ffff8fDhw+RkJAAhUKBpKQkVFVViX6dWrdujeTkZAQFBcHPzw8D\nBgyAQqEQ3S7AvN8rMzMTly5dgq9G3Lytn4N//etfiIuLAyAInTVtcquwqYqKCkyYMAErV65Eu3bt\nzOoytnZsyu7du+Hr6wu5XK5lh5g2PXz4EBcuXMC4ceOQnp6O3NxcbN++XVSbAKCkpAQJCQnIy8vD\nlStX8Msvv2D37t2i2wU0//cy5/Pm8uGHH6J9+/Z45ZVXGj1Xc2yym3hERUWhoKBAtZ2bm4vo6Gh7\nnR61tbUYN24c4uPjMXr0aJVN+fn5AID8/HxERUUBABQKBfLy8lSfLSgoUO2zFsePH0dqaiqCg4Mx\nceJEHDp0CPHx8aLa1K1bN4SGhiIuLg6tW7fGxIkTsW/fPlFtAoR/zOjoaHTr1g0+Pj545ZVXkJGR\nIbpdgPn3ULdu3XBTOXIPQF5enk2egw0bNiAtLQ2bNLKyW9smu4mHmPEfRIRp06YhPDwcc+bMUZUr\nFAqkpKSgqqoKKSkpqgvWt29fpKWl4dq1a0hPT4eHhwfat29vVZuWLl2KoqIiFBYWYtu2bYiNjcXG\njRtFtQkAunfvjszMTDQ0NODHH3/ECy+8ILpNMTExOHHiBMrKylBdXY29e/fipZdeEt0uwLJ7SCaT\nYdu2bSgtLcV3331n9edg3759WL58OVJTU9FKYxJeq9tkcTOvBaSnp5NMJqOnn36aVq1aZbfzZmRk\nkEQioYiICIqMjKTIyEjau3ev0W62Tz/9lJ5++mkKCwujo0eP2tS+9PR0VW+L2DadP3+eFAoFRURE\n0Pz586myslJ0m4iI1q9fT4MGDaI+ffrQ+++/T/X19Xa367XXXiN/f3/y9PSkgIAASklJsciG3Nxc\nksvlFBQURH//+9+tYlPLli0pICCA1q1bR926dSOpVKq61xMSEmxikyiTATEM4/y4VYMpwzDWg8WD\nYRiLYPFgGMYiWDwYhrEIFg+GYSyCxYNhGIv4f3LyACNFB+IwAAAAAElFTkSuQmCC\n" } ], "prompt_number": 11 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## measure speedup" ] }, { "cell_type": "code", "collapsed": false, "input": [ "speedup_gpu = average_time_seconds_gpu_global_atomic_system / average_time_seconds_gpu_system\n", "\n", "\n", "print \"Average GPU (global atomic) time: %f s\" % average_time_seconds_gpu_global_atomic_system\n", "print \"Average GPU (shared memory) time: %f s\" % average_time_seconds_gpu_system\n", "\n", "print\n", "\n", "print \"GPU (shared memory) speedup: %f x\" % speedup_gpu" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Average GPU (global atomic) time: 0.012794 s\n", "Average GPU (shared memory) time: 0.001150 s\n", "\n", "GPU (shared memory) speedup: 11.121705 x\n" ] } ], "prompt_number": 12 } ], "metadata": {} } ] }