[clblas] 66/125: A proof-of-concept python wrapper for clBLAS. Only sgemm and the init functions are callable from python.

Ghislain Vaillant ghisvail-guest at moszumanska.debian.org
Fri May 29 06:57:23 UTC 2015


This is an automated email from the git hooks/post-receive script.

ghisvail-guest pushed a commit to branch master
in repository clblas.

commit 44234c71768c8eebe0cbe097fa182d43effa7d22
Author: Kent Knox <kent.knox at amd>
Date:   Wed May 7 17:56:24 2014 -0500

    A proof-of-concept python wrapper for clBLAS.  Only sgemm and the init
    functions are callable from python.
---
 src/wrappers/python/README.txt   |  61 ++++++++++++++++++++
 src/wrappers/python/pyclBLAS.pxd |  84 ++++++++++++++++++++++++++++
 src/wrappers/python/pyclBLAS.pyx | 117 +++++++++++++++++++++++++++++++++++++++
 src/wrappers/python/setup.py     |  96 ++++++++++++++++++++++++++++++++
 4 files changed, 358 insertions(+)

diff --git a/src/wrappers/python/README.txt b/src/wrappers/python/README.txt
new file mode 100644
index 0000000..f77bd66
--- /dev/null
+++ b/src/wrappers/python/README.txt
@@ -0,0 +1,61 @@
+pyclBLAS setup and installation
+(I've been pronouncing it 'pickleBLAS')
+------------------------------------------------------------------------
+A python extention wrapper around clBLAS from https://github.com/clMathLibraries/clBLAS
+
+Dependencies:
+1.  clBLAS from https://github.com/clMathLibraries/clBLAS ( develop branch )
+2.  PyOpenCL from http://mathema.tician.de/software/pyopencl/ ( 2013.2 minimum )
+3.  Cython from http://cython.org/, ( 0.18 minimum )
+4.  OpenCL runtime, such as AMD's catalyst package ( AMD v2.9 SDK tested )
+
+NOTE:  This has only been tested with 32-bit python on windows
+
+NOTE:  Only sgemm has been wrapped as proof-of-concept
+
+Build steps:
+------------------------------------------------------------------------
+1.  First, clone the clBLAS repo from github and make sure to build the 
+'install' step.  This is either 'make install' on linux derivatives or 
+the 'install' project on Visual Studio projects.  This should produce a 
+'package' directory in your build tree that contains ./include, ./libXX & 
+./bin.  
+
+Note:  it is necessary to build 32-bit clBLAS if using 32-bit python,
+and 64-bit clBLAS for 64-bit python.
+
+2.  Install pyopencl.  If your python distribution contains a version 
+of pyopencl that is a minimum of 2013.2, then just install with the 
+distributions package manager like pypm, pip, easy_install.  If not, download
+pyopencl yourself and follow its directions to build and install.
+
+3.  Install Cython.  If your python distribution contains a version 
+of cython that is a minimum of .18, then just install with the 
+distributions package manager like pypm, pip, easy_install.  If not, 
+download cython yourself and follow its directions to build and install.
+
+4.  An OpenCL SDK is required to build, which includes OpenCL header files
+and linkable libraries.  One such SDK is the AMD APP SDK, which can be 
+downloaded from http://developer.amd.com/tools-and-sdks/heterogeneous-computing/amd-accelerated-parallel-processing-app-sdk/
+
+5.  Build the pyclBLAS extention.  This is accompished by running setup.py,
+which acts as a python makefile.  An example install command: 
+'python setup.py --clBlasRoot=F:\code\GitHub\clMathLibraries\bin\clBLAS\develop\vs11x32\package build_ext --inplace'
+
+'python setup.py --help' prints additional command line parameters that extend 
+the traditional distutils options.  After successfully building the extention
+module, a pyclBLAS.pyd file appears.  As shown above, it may be necessary to provide
+the setup makefile with the paths of the clBLAS 'package' directory and the 
+OpenCL SDK directory.  Setup.py does attempt to find the OpenCL SDK through 
+the environment variable AMDAPPSDKROOT or OPENCL_ROOT.
+
+NOTE:  On windows, if using a more recent version of visual studio than 2008, 
+it may be necessary to trick python to using the newer version of your compiler, 
+by creating an environment variable that it expects to exist as such:
+set VS90COMNTOOLS=%VS110COMNTOOLS%
+
+6.  Execute demoBLAS.py file to test the pyclBLAS extention.  
+    
+NOTE: It may be necessary to copy the clBLAS shared library into 
+the same directory as the extention module so that it can find 
+clBLAS at runtime
diff --git a/src/wrappers/python/pyclBLAS.pxd b/src/wrappers/python/pyclBLAS.pxd
new file mode 100644
index 0000000..0dfbfd9
--- /dev/null
+++ b/src/wrappers/python/pyclBLAS.pxd
@@ -0,0 +1,84 @@
+################################################################################
+ # Copyright 2014 Advanced Micro Devices, Inc.
+ #
+ # Licensed under the Apache License, Version 2.0 (the "License");
+ # you may not use this file except in compliance with the License.
+ # You may obtain a copy of the License at
+ #
+ # http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+################################################################################
+
+# This pxd file defines all the enums and structs that we plan to use from
+# python.  It is used from pyclBLAS.pyx
+
+cdef extern from "clBLAS.h":
+    # These are base OpenCL enumerations that clBLAS uses
+    cdef enum:
+        CL_SUCCESS                      = 0
+        CL_INVALID_VALUE                = -30
+        CL_INVALID_COMMAND_QUEUE        = -36
+        CL_INVALID_CONTEXT              = -34
+        CL_INVALID_MEM_OBJECT           = -38
+        CL_INVALID_DEVICE               = -33
+        CL_INVALID_EVENT_WAIT_LIST      = -57
+        CL_OUT_OF_RESOURCES             = -5
+        CL_OUT_OF_HOST_MEMORY           = -6
+        CL_INVALID_OPERATION            = -59
+        CL_COMPILER_NOT_AVAILABLE       = -3
+        CL_BUILD_PROGRAM_FAILURE        = -11
+
+    cdef enum clblasStatus_:
+        clblasSuccess               = CL_SUCCESS
+        clblasInvalidValue          = CL_INVALID_VALUE
+        clblasInvalidCommandQueue   = CL_INVALID_COMMAND_QUEUE
+        clblasInvalidContext        = CL_INVALID_CONTEXT
+        clblasInvalidMemObject      = CL_INVALID_MEM_OBJECT
+        clblasInvalidDevice         = CL_INVALID_DEVICE
+        clblasInvalidEventWaitList  = CL_INVALID_EVENT_WAIT_LIST
+        clblasOutOfResources        = CL_OUT_OF_RESOURCES
+        clblasOutOfHostMemory       = CL_OUT_OF_HOST_MEMORY
+        clblasInvalidOperation      = CL_INVALID_OPERATION
+        clblasCompilerNotAvailable  = CL_COMPILER_NOT_AVAILABLE
+        clblasBuildProgramFailure   = CL_BUILD_PROGRAM_FAILURE
+        clblasNotImplemented        = -1024
+        clblasNotInitialized        = -1023
+        clblasInvalidMatA
+        clblasInvalidMatB
+        clblasInvalidMatC
+        clblasInvalidVecX
+        clblasInvalidVecY
+        clblasInvalidDim
+        clblasInvalidLeadDimA
+        clblasInvalidLeadDimB
+        clblasInvalidLeadDimC
+        clblasInvalidIncX
+        clblasInvalidIncY
+        clblasInsufficientMemMatA
+        clblasInsufficientMemMatB
+        clblasInsufficientMemMatC
+        clblasInsufficientMemVecX
+        clblasInsufficientMemVecY
+    ctypedef clblasStatus_ clblasStatus
+
+    cdef enum clblasOrder_:
+        clblasRowMajor             = 0
+        clblasColumnMajor          = 1
+    ctypedef clblasStatus_ clblasOrder
+
+    cdef enum clblasTranspose_:
+        clblasNoTrans             = 0
+        clblasTrans               = 1
+        clblasConjTrans           = 2
+    ctypedef clblasStatus_ clblasTranspose
+
+    ctypedef unsigned int cl_uint
+    ctypedef float cl_float
+    ctypedef void* cl_mem
+    ctypedef void* cl_command_queue
+    ctypedef void* cl_event
diff --git a/src/wrappers/python/pyclBLAS.pyx b/src/wrappers/python/pyclBLAS.pyx
new file mode 100644
index 0000000..2ede269
--- /dev/null
+++ b/src/wrappers/python/pyclBLAS.pyx
@@ -0,0 +1,117 @@
+################################################################################
+ # Copyright 2014 Advanced Micro Devices, Inc.
+ #
+ # Licensed under the Apache License, Version 2.0 (the "License");
+ # you may not use this file except in compliance with the License.
+ # You may obtain a copy of the License at
+ #
+ # http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+################################################################################
+
+cimport pyclBLAS
+import pyopencl
+
+# These are prototypes from clBLAS.h that we wish to call from python
+################################################################################
+################################################################################
+cdef extern from "clBLAS.h":
+   clblasStatus clblasGetVersion( cl_uint* major, cl_uint* minor, cl_uint* patch )
+
+   clblasStatus clblasSetup( )
+
+   void clblasTeardown( )
+
+   clblasStatus clblasSgemm( clblasOrder order, clblasTranspose transA, clblasTranspose transB,
+                size_t M, size_t N, size_t K, cl_float alpha, const cl_mem A, size_t offA, size_t lda,
+                const cl_mem B, size_t offB, size_t ldb, cl_float beta, cl_mem C, size_t offC, size_t ldc,
+                cl_uint numCommandQueues, cl_command_queue* commandQueues, cl_uint numEventsInWaitList,
+                const cl_event* eventWaitList, cl_event* events)
+
+################################################################################
+################################################################################
+# enums to be accessed from python
+# TODO:  is there a better way to express enums?  I like how pyopencl does it,
+# they have layers of scoped constants cl.mem_flags.READ_ONLY
+# The enums below have global scope
+RowMajor    = pyclBLAS.clblasRowMajor
+ColumnMajor = pyclBLAS.clblasColumnMajor
+NoTrans     = pyclBLAS.clblasNoTrans
+Trans       = pyclBLAS.clblasTrans
+ConjTrans   = pyclBLAS.clblasConjTrans
+
+################################################################################
+################################################################################
+# The following functions are the python callable wrapper implementations
+def Setup( ):
+   result = clblasSetup( )
+   if( result != clblasSuccess ):
+      raise RuntimeError( "clblasSetup( ) failed initialization" )
+   return result
+
+################################################################################
+def Teardown( ):
+   clblasTeardown( )
+   return
+
+################################################################################
+def GetVersion( ):
+   cdef pyclBLAS.cl_uint pyMajor
+   cdef pyclBLAS.cl_uint pyMinor
+   cdef pyclBLAS.cl_uint pyPatch
+   result = clblasGetVersion( &pyMajor, &pyMinor, &pyPatch )
+   if( result != clblasSuccess ):
+      raise RuntimeError( "clblasGetVersion( ) did not return version information" )
+   return pyMajor, pyMinor, pyPatch
+
+################################################################################
+# TODO:  Is there way to template these python callable functions, such that we
+# do not need to make a new function for every supported precision?
+def Sgemm( clblasOrder order, clblasTranspose transA, clblasTranspose transB,
+                size_t M, size_t N, size_t K, cl_float alpha, A, size_t offA, size_t lda,
+                B, size_t offB, size_t ldb, cl_float beta, C, size_t offC, size_t ldc,
+                cl_uint numCommandQueues, commandQueues, cl_uint numEventsInWaitList,
+                eventWaitList ):
+
+   # Simplify python wrapper to only handle 1 queue at this time
+   if( numCommandQueues != 1 ):
+      raise IndexError( "pyblasSgemm( ) requires the number of queues to be 1" )
+   cdef int pIntQueue = commandQueues.int_ptr
+   cdef cl_command_queue pcqQueue = <cl_command_queue>pIntQueue
+
+   # This logic does not yet work for numEventsInWaitList > (greater than) 1
+   # Need to figure out how python & pyopencl pass lists of objects
+   cdef int pIntWaitList = 0
+   cdef cl_event* pWaitList = NULL
+   if( numEventsInWaitList > 0 ):
+      if( numEventsInWaitList < 2 ):
+         pIntWaitList = eventWaitList.int_ptr
+         pWaitList = <cl_event*>pIntWaitList
+      else:
+         raise IndexError( "pyblasSgemm( ) requires numEventsInWaitList to be <= 1" )
+
+   # Pyopencl objects contain an int_ptr method to get access to the internally wrapped
+   # OpenCL object pointers
+   cdef cl_event outEvent = NULL
+   cdef int matA = A.int_ptr
+   cdef int matB = B.int_ptr
+   cdef int matC = C.int_ptr
+
+   # Transition execution to clBLAS
+   cdef clblasStatus result = clblasSgemm( order, transA, transB, M, N, K, alpha, <const cl_mem>matA, offA, lda,
+                         <const cl_mem>matB, offB, ldb, beta, <cl_mem>matC, offC, ldc,
+                         numCommandQueues, &pcqQueue, numEventsInWaitList,
+                         pWaitList, &outEvent )
+
+   if( result != clblasSuccess ):
+      raise RuntimeError( "clBLAS sgemm call failed" )
+
+   # Create a pyopencl Event object from the event returned from clBLAS and return
+   # it to the user
+   sgemmEvent = pyopencl.Event.from_int_ptr( <int>outEvent )
+   return sgemmEvent
diff --git a/src/wrappers/python/setup.py b/src/wrappers/python/setup.py
new file mode 100644
index 0000000..b87aa95
--- /dev/null
+++ b/src/wrappers/python/setup.py
@@ -0,0 +1,96 @@
+################################################################################
+ # Copyright 2014 Advanced Micro Devices, Inc.
+ #
+ # Licensed under the Apache License, Version 2.0 (the "License");
+ # you may not use this file except in compliance with the License.
+ # You may obtain a copy of the License at
+ #
+ # http://www.apache.org/licenses/LICENSE-2.0
+ #
+ # Unless required by applicable law or agreed to in writing, software
+ # distributed under the License is distributed on an "AS IS" BASIS,
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ # See the License for the specific language governing permissions and
+ # limitations under the License.
+################################################################################
+
+from distutils.core import setup
+from distutils.extension import Extension
+from Cython.Distutils import build_ext
+from os import path, environ
+import argparse
+
+def main():
+   parser = argparse.ArgumentParser(description='Set up the pyclBLAS extension module')
+   parser.add_argument('--clRoot',
+     dest='clRoot', default=None,
+     help='Root directory to find the OpenCL SDK, which should contain the include directory')
+   parser.add_argument('--clBlasRoot',
+     dest='clBlasRoot', default=None,
+     help='Root directory to find the clBLAS SDK, which should contain the include directory')
+
+   args, unknown_args = parser.parse_known_args( )
+
+##    print( "recognized args: ", args )
+##    print( "unknown args: ", unknown_args )
+
+   # First check environment variables for clRoot paths
+   clRootPath = None
+   if( environ.get('OPENCL_ROOT') is not None ):
+     clRootPath = environ['OPENCL_ROOT']
+
+   # Special check for environment variable set by AMD Catalyst installer
+   if( clRootPath is None and environ.get( 'AMDAPPSDKROOT' ) is not None ):
+     clRootPath = environ['AMDAPPSDKROOT']
+
+   # If user specifies a command line options, this trumps environment variables
+   print( "args.clRoot: ", args.clRoot )
+   if( args.clRoot is not None ):
+     clRootPath = args.clRoot
+
+   if( clRootPath is None ):
+     print( "This setup.py needs to know the root path of an OpenCL installation")
+     print( "Please specify the environment variable OPENCL_ROOT with a path" )
+     print( "Or pass the command line option --clRoot" )
+     exit( )
+
+   # First check environment variables for clRoot paths
+   clBlasRootPath = None
+   if( environ.get('CLBLAS_ROOT') is not None ):
+     clBlasRootPath = environ['CLBLAS_ROOT']
+
+   # If user specifies a command line options, this trumpts environment variables
+   print( "args.clBlasRoot: ", args.clBlasRoot )
+   if( args.clBlasRoot is not None ):
+     clBlasRootPath = args.clBlasRoot
+
+   if( clBlasRootPath is None ):
+     print( "This setup.py needs to know the root path of the clBLAS installation")
+     print( "Please specify the environment variable CLBLAS_ROOT with a path" )
+     print( "or pass the command line option --clBlasRoot" )
+     exit( )
+
+   module = [
+     Extension( name = 'pyclBLAS',
+               sources = ['pyclBLAS.pyx'],
+               include_dirs = [ path.join( clRootPath, 'include' ),
+                                path.join( clBlasRootPath, 'include' ) ],
+               library_dirs = [ path.join( clBlasRootPath, 'lib', 'import' ) ],
+               libraries=['clBLAS'] )
+   ]
+
+   setup(
+      name = 'pyclBLAS',
+      version = '0.0.1',
+      author = 'Kent Knox',
+      description = 'Python wrapper for clBLAS',
+      license = 'Apache License, Version 2.0',
+      cmdclass = {"build_ext": build_ext},
+      ext_modules = module,
+      script_args = unknown_args
+   )
+
+# This is the start of the execution of the python script
+# Useful for debuggers to step into script
+if __name__ == '__main__':
+    main( )

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/clblas.git



More information about the debian-science-commits mailing list