-
-
Save wolfv/b5d0c6077bcbd1347b294a65b054be78 to your computer and use it in GitHub Desktop.
AVX-512 cumsum implementation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "code", | |
"execution_count": 1, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"%load_ext Cython" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 2, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"%%cython --cplus -c-std=c++11 -c-O3 -I/home/ubuntu/xsimd/include -c-march=native\n", | |
"\n", | |
"from libc.stdint cimport int32_t\n", | |
"\n", | |
"cdef extern from \"xsimd/types/xsimd_avx512_int32.hpp\":\n", | |
" pass\n", | |
"\n", | |
"cdef extern from \"xsimd/xsimd.hpp\":\n", | |
" \"\"\"\n", | |
" void inplace_cumsum_int32(int32_t* data, size_t numitems) {\n", | |
" xsimd::batch<int32_t, 16> step1({0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14});\n", | |
" unsigned int mask1 = 65534;\n", | |
"\n", | |
" xsimd::batch<int32_t, 16> step2({0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13});\n", | |
" unsigned int mask2 = 65532;\n", | |
"\n", | |
" xsimd::batch<int32_t, 16> step3({0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11});\n", | |
" unsigned int mask3 = 65520;\n", | |
"\n", | |
" xsimd::batch<int32_t, 16> step4({0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7});\n", | |
" unsigned int mask4 = 65280;\n", | |
"\n", | |
" xsimd::batch<int32_t, 16> scatter({15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15});\n", | |
" \n", | |
" xsimd::batch<int32_t, 16> v;\n", | |
" xsimd::batch<int32_t, 16> carry({0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0});\n", | |
" \n", | |
" for (size_t i = 0; i < numitems; i += 16) {\n", | |
" v.load_unaligned(&data[i]);\n", | |
" \n", | |
" v += _mm512_maskz_permutexvar_epi32(mask1, step1, v);\n", | |
" v += _mm512_maskz_permutexvar_epi32(mask2, step2, v);\n", | |
" v += _mm512_maskz_permutexvar_epi32(mask3, step3, v);\n", | |
" v += _mm512_maskz_permutexvar_epi32(mask4, step4, v);\n", | |
" v += carry;\n", | |
" \n", | |
" carry = _mm512_permutexvar_epi32(scatter, v);\n", | |
" \n", | |
" v.store_unaligned(&data[i]);\n", | |
" }\n", | |
" }\n", | |
" \"\"\"\n", | |
" void inplace_cumsum_int32(int32_t* data, size_t numitems)\n", | |
"\n", | |
"import numpy\n", | |
"\n", | |
"def cumsum(inarray, outarray=None):\n", | |
" if not isinstance(inarray, numpy.ndarray) or not inarray.dtype == numpy.dtype(numpy.int32) or len(inarray.shape) != 1:\n", | |
" raise TypeError(\"inarray must be a one-dimensional array of type int32\")\n", | |
" if outarray is None:\n", | |
" outarray = numpy.empty(len(inarray), dtype=inarray.dtype)\n", | |
" if not isinstance(outarray, numpy.ndarray) or not outarray.dtype == numpy.dtype(numpy.int32) or len(outarray.shape) != 1:\n", | |
" raise TypeError(\"outarray must be a one-dimensional array of type int32\")\n", | |
" if inarray is not outarray:\n", | |
" outarray[:] = inarray\n", | |
" inplace_cumsum_int32(<int32_t*>(<size_t>outarray.ctypes.data), <size_t>len(outarray))\n", | |
" return outarray" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 3, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"Numpy 0.7092068195343018\n", | |
"vectorized 0.07067036628723145\n", | |
"\n", | |
"Numpy 0.6970040798187256\n", | |
"vectorized 0.07094025611877441\n", | |
"\n", | |
"Numpy 0.7071859836578369\n", | |
"vectorized 0.06884312629699707\n", | |
"\n", | |
"Numpy 0.7087807655334473\n", | |
"vectorized 0.06922101974487305\n", | |
"\n", | |
"Numpy 0.7058277130126953\n", | |
"vectorized 0.06850910186767578\n", | |
"\n", | |
"Numpy 0.6960067749023438\n", | |
"vectorized 0.0703125\n", | |
"\n", | |
"Numpy 0.6977725028991699\n", | |
"vectorized 0.07039928436279297\n", | |
"\n", | |
"Numpy 0.7044193744659424\n", | |
"vectorized 0.07010054588317871\n", | |
"\n", | |
"Numpy 0.6976873874664307\n", | |
"vectorized 0.06823444366455078\n", | |
"\n", | |
"Numpy 0.6967740058898926\n", | |
"vectorized 0.06947183609008789\n", | |
"\n" | |
] | |
} | |
], | |
"source": [ | |
"import time\n", | |
"\n", | |
"a = numpy.ones(160000000, dtype=numpy.int32)\n", | |
"\n", | |
"for i in range(10):\n", | |
" startTime = time.time()\n", | |
" numpy.cumsum(a, out=a)\n", | |
" endTime = time.time()\n", | |
" print(\"Numpy \", endTime - startTime)\n", | |
"\n", | |
" startTime = time.time()\n", | |
" cumsum(a, a)\n", | |
" endTime = time.time()\n", | |
" print(\"vectorized\", endTime - startTime)\n", | |
" print()" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"## Tested on a AWS c3.large, which has AVX-512 instructions (Skylake).\n", | |
"\n", | |
"\n", | |
"```\n", | |
"cat /proc/cpuinfo\n", | |
"processor : 0\n", | |
"vendor_id : GenuineIntel\n", | |
"cpu family : 6\n", | |
"model : 85\n", | |
"model name : Intel(R) Xeon(R) Platinum 8124M CPU @ 3.00GHz\n", | |
"stepping : 3\n", | |
"microcode : 0x100013e\n", | |
"cpu MHz : 3000.002\n", | |
"cache size : 25344 KB\n", | |
"physical id : 0\n", | |
"siblings : 2\n", | |
"core id : 0\n", | |
"cpu cores : 1\n", | |
"apicid : 0\n", | |
"initial apicid : 0\n", | |
"fpu : yes\n", | |
"fpu_exception : yes\n", | |
"cpuid level : 13\n", | |
"wp : yes\n", | |
"flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch invpcid_single retpoline kaiser fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx avx512f rdseed adx smap clflushopt clwb avx512cd xsaveopt xsavec xgetbv1 ida arat\n", | |
"bugs : cpu_meltdown spectre_v1 spectre_v2\n", | |
"bogomips : 6000.00\n", | |
"clflush size : 64\n", | |
"cache_alignment : 64\n", | |
"address sizes : 46 bits physical, 48 bits virtual\n", | |
"power management:\n", | |
"\n", | |
"processor : 1\n", | |
"vendor_id : GenuineIntel\n", | |
"cpu family : 6\n", | |
"model : 85\n", | |
"model name : Intel(R) Xeon(R) Platinum 8124M CPU @ 3.00GHz\n", | |
"stepping : 3\n", | |
"microcode : 0x100013e\n", | |
"cpu MHz : 3000.002\n", | |
"cache size : 25344 KB\n", | |
"physical id : 0\n", | |
"siblings : 2\n", | |
"core id : 0\n", | |
"cpu cores : 1\n", | |
"apicid : 1\n", | |
"initial apicid : 1\n", | |
"fpu : yes\n", | |
"fpu_exception : yes\n", | |
"cpuid level : 13\n", | |
"wp : yes\n", | |
"flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch invpcid_single retpoline kaiser fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx avx512f rdseed adx smap clflushopt clwb avx512cd xsaveopt xsavec xgetbv1 ida arat\n", | |
"bugs : cpu_meltdown spectre_v1 spectre_v2\n", | |
"bogomips : 6000.00\n", | |
"clflush size : 64\n", | |
"cache_alignment : 64\n", | |
"address sizes : 46 bits physical, 48 bits virtual\n", | |
"power management:\n", | |
"```" | |
] | |
} | |
], | |
"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 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment