more cleanup and doc
This commit is contained in:
parent
68e2359ad2
commit
3009d8468f
2 changed files with 50 additions and 29 deletions
16
README.md
16
README.md
|
|
@ -1,7 +1,23 @@
|
||||||
|
llvm_cbuilder
|
||||||
|
-------------
|
||||||
|
|
||||||
A llvm-py Builder wrapper for writing in slightly higher-level constructs.
|
A llvm-py Builder wrapper for writing in slightly higher-level constructs.
|
||||||
This is aiming for two usecases:
|
This is aiming for two usecases:
|
||||||
|
|
||||||
1. Emit LLVM code in a more human-readable way;
|
1. Emit LLVM code in a more human-readable way;
|
||||||
|
|
||||||
2. Writing low-level code that you can't do it properly/portably with C, e.g
|
2. Writing low-level code that you can't do it properly/portably with C, e.g
|
||||||
template (generic), atomic operations, memory ordering...
|
template (generic), atomic operations, memory ordering...
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Parallel Vectorize
|
||||||
|
------------------
|
||||||
|
|
||||||
|
`parallel_vectorize.py` implements a set of code generator that bases on
|
||||||
|
llvm_cbuilder to create specialized parallel ufunc.
|
||||||
|
|
||||||
|
See `test_parallel_vectorize_numpy*.py` for testing and demo of the code
|
||||||
|
with the new `numpy.fromfunc()`.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,7 @@ from llvm_cbuilder import *
|
||||||
import llvm_cbuilder.shortnames as C
|
import llvm_cbuilder.shortnames as C
|
||||||
|
|
||||||
class WorkQueue(CStruct):
|
class WorkQueue(CStruct):
|
||||||
'''
|
'''structure for workqueue for parallel-ufunc.
|
||||||
Structure for workqueue for parallel-ufunc.
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
_fields_ = [
|
_fields_ = [
|
||||||
|
|
@ -29,8 +28,7 @@ class WorkQueue(CStruct):
|
||||||
|
|
||||||
|
|
||||||
def Lock(self):
|
def Lock(self):
|
||||||
'''
|
'''inline the lock procedure.
|
||||||
Inline the lock procedure.
|
|
||||||
'''
|
'''
|
||||||
with self.parent.loop() as loop:
|
with self.parent.loop() as loop:
|
||||||
with loop.condition() as setcond:
|
with loop.condition() as setcond:
|
||||||
|
|
@ -45,8 +43,7 @@ class WorkQueue(CStruct):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def Unlock(self):
|
def Unlock(self):
|
||||||
'''
|
'''inline the unlock procedure.
|
||||||
Inline the unlock procedure.
|
|
||||||
'''
|
'''
|
||||||
unlocked = self.parent.constant(self.lock.type, 0)
|
unlocked = self.parent.constant(self.lock.type, 0)
|
||||||
locked = self.parent.constant(self.lock.type, 1)
|
locked = self.parent.constant(self.lock.type, 1)
|
||||||
|
|
@ -61,8 +58,7 @@ class WorkQueue(CStruct):
|
||||||
|
|
||||||
|
|
||||||
class ContextCommon(CStruct):
|
class ContextCommon(CStruct):
|
||||||
'''
|
'''structure for thread-shared context information in parallel-ufunc.
|
||||||
Structure for thread-shared context information in parallel-ufunc.
|
|
||||||
'''
|
'''
|
||||||
_fields_ = [
|
_fields_ = [
|
||||||
# loop ufunc args
|
# loop ufunc args
|
||||||
|
|
@ -77,8 +73,7 @@ class ContextCommon(CStruct):
|
||||||
]
|
]
|
||||||
|
|
||||||
class Context(CStruct):
|
class Context(CStruct):
|
||||||
'''
|
'''structure for thread-specific context information in parallel-ufunc.
|
||||||
Structure for thread-specific context information in parallel-ufunc.
|
|
||||||
'''
|
'''
|
||||||
_fields_ = [
|
_fields_ = [
|
||||||
('common', C.pointer(ContextCommon.llvm_type())),
|
('common', C.pointer(ContextCommon.llvm_type())),
|
||||||
|
|
@ -87,7 +82,11 @@ class Context(CStruct):
|
||||||
]
|
]
|
||||||
|
|
||||||
class ParallelUFunc(CDefinition):
|
class ParallelUFunc(CDefinition):
|
||||||
'''
|
'''the generic parallel vectorize mechanism
|
||||||
|
|
||||||
|
Can be specialized to the maximum number of threads on the platform.
|
||||||
|
|
||||||
|
|
||||||
Platform dependent threading function is implemented in
|
Platform dependent threading function is implemented in
|
||||||
|
|
||||||
def _dispatch_worker(self, worker, contexts, num_thread):
|
def _dispatch_worker(self, worker, contexts, num_thread):
|
||||||
|
|
@ -107,7 +106,8 @@ class ParallelUFunc(CDefinition):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def specialize(cls, num_thread):
|
def specialize(cls, num_thread):
|
||||||
print num_thread
|
'''specialize to the maximum # of thread
|
||||||
|
'''
|
||||||
cls._name_ = 'parallel_ufunc_%d' % num_thread
|
cls._name_ = 'parallel_ufunc_%d' % num_thread
|
||||||
cls.ThreadCount = num_thread
|
cls.ThreadCount = num_thread
|
||||||
|
|
||||||
|
|
@ -172,8 +172,7 @@ class ParallelUFunc(CDefinition):
|
||||||
self.ret()
|
self.ret()
|
||||||
|
|
||||||
def _populate_workqueues(self, workqueues, N, ChunkSize, num_thread):
|
def _populate_workqueues(self, workqueues, N, ChunkSize, num_thread):
|
||||||
'''
|
'''loop over all threads and populate the workqueue for each of them.
|
||||||
Loop over all threads and populate the workqueue for each of them.
|
|
||||||
'''
|
'''
|
||||||
ONE = self.constant(num_thread.type, 1)
|
ONE = self.constant(num_thread.type, 1)
|
||||||
with self.for_range(num_thread) as (loop, i):
|
with self.for_range(num_thread) as (loop, i):
|
||||||
|
|
@ -186,8 +185,7 @@ class ParallelUFunc(CDefinition):
|
||||||
last_wq.last.assign(N)
|
last_wq.last.assign(N)
|
||||||
|
|
||||||
def _populate_context(self, contexts, common, num_thread):
|
def _populate_context(self, contexts, common, num_thread):
|
||||||
'''
|
'''loop over all threads and populate contexts for each of them.
|
||||||
Loop over all threads and populate contexts for each of them.
|
|
||||||
'''
|
'''
|
||||||
ONE = self.constant(num_thread.type, 1)
|
ONE = self.constant(num_thread.type, 1)
|
||||||
with self.for_range(num_thread) as (loop, i):
|
with self.for_range(num_thread) as (loop, i):
|
||||||
|
|
@ -198,8 +196,7 @@ class ParallelUFunc(CDefinition):
|
||||||
self.constant_null(cur_ctxt.completed.type))
|
self.constant_null(cur_ctxt.completed.type))
|
||||||
|
|
||||||
class ParallelUFuncPosixMixin(object):
|
class ParallelUFuncPosixMixin(object):
|
||||||
'''
|
'''ParallelUFunc mixin that implements _dispatch_worker to use pthread.
|
||||||
Implements _dispatch_worker to use pthread.
|
|
||||||
'''
|
'''
|
||||||
def _dispatch_worker(self, worker, contexts, num_thread):
|
def _dispatch_worker(self, worker, contexts, num_thread):
|
||||||
api = PThreadAPI(self)
|
api = PThreadAPI(self)
|
||||||
|
|
@ -219,7 +216,10 @@ class ParallelUFuncPosixMixin(object):
|
||||||
api.pthread_join(threads[i], NULL)
|
api.pthread_join(threads[i], NULL)
|
||||||
|
|
||||||
class UFuncCore(CDefinition):
|
class UFuncCore(CDefinition):
|
||||||
'''
|
'''core work of a ufunc worker thread
|
||||||
|
|
||||||
|
Subclass to implement UFuncCore._do_work
|
||||||
|
|
||||||
Generates the workqueue handling and work stealing and invoke
|
Generates the workqueue handling and work stealing and invoke
|
||||||
the work function for each work item.
|
the work function for each work item.
|
||||||
'''
|
'''
|
||||||
|
|
@ -242,8 +242,7 @@ class UFuncCore(CDefinition):
|
||||||
self.ret()
|
self.ret()
|
||||||
|
|
||||||
def _do_workqueue(self, common, workqueue, tid, completed):
|
def _do_workqueue(self, common, workqueue, tid, completed):
|
||||||
'''
|
'''process local workqueue.
|
||||||
Process local workqueue.
|
|
||||||
'''
|
'''
|
||||||
ZERO = self.constant_null(C.int)
|
ZERO = self.constant_null(C.int)
|
||||||
|
|
||||||
|
|
@ -264,8 +263,7 @@ class UFuncCore(CDefinition):
|
||||||
completed += self.constant(completed.type, 1)
|
completed += self.constant(completed.type, 1)
|
||||||
|
|
||||||
def _do_work_stealing(self, common, tid, completed):
|
def _do_work_stealing(self, common, tid, completed):
|
||||||
'''
|
'''steal work from other workqueues.
|
||||||
Steal work from other workqueues.
|
|
||||||
'''
|
'''
|
||||||
# self.debug("start work stealing", tid)
|
# self.debug("start work stealing", tid)
|
||||||
steal_continue = self.var(C.int, 1)
|
steal_continue = self.var(C.int, 1)
|
||||||
|
|
@ -283,8 +281,7 @@ class UFuncCore(CDefinition):
|
||||||
|
|
||||||
def _do_work_stealing_innerloop(self, common, steal_continue, tid,
|
def _do_work_stealing_innerloop(self, common, steal_continue, tid,
|
||||||
completed):
|
completed):
|
||||||
'''
|
'''loop over all other threads and try to steal work.
|
||||||
Loop over all other threads and try to steal work.
|
|
||||||
'''
|
'''
|
||||||
with self.for_range(common.num_thread) as (loop, i):
|
with self.for_range(common.num_thread) as (loop, i):
|
||||||
with self.ifelse( i != tid ) as ifelse:
|
with self.ifelse( i != tid ) as ifelse:
|
||||||
|
|
@ -296,10 +293,10 @@ class UFuncCore(CDefinition):
|
||||||
|
|
||||||
def _do_work_stealing_check(self, common, otherqueue, steal_continue, tid,
|
def _do_work_stealing_check(self, common, otherqueue, steal_continue, tid,
|
||||||
completed):
|
completed):
|
||||||
'''
|
'''check the workqueue for any remaining work and steal it.
|
||||||
Check the workqueue for any remaining work and steal it.
|
|
||||||
'''
|
'''
|
||||||
otherqueue.Lock()
|
otherqueue.Lock()
|
||||||
|
# Acquired
|
||||||
ONE = self.constant(otherqueue.last.type, 1)
|
ONE = self.constant(otherqueue.last.type, 1)
|
||||||
STEAL_CONTINUE = self.constant(steal_continue.type, 1)
|
STEAL_CONTINUE = self.constant(steal_continue.type, 1)
|
||||||
with self.ifelse(otherqueue.next < otherqueue.last) as ifelse:
|
with self.ifelse(otherqueue.next < otherqueue.last) as ifelse:
|
||||||
|
|
@ -318,14 +315,18 @@ class UFuncCore(CDefinition):
|
||||||
|
|
||||||
with ifelse.otherwise():
|
with ifelse.otherwise():
|
||||||
otherqueue.Unlock()
|
otherqueue.Unlock()
|
||||||
|
# Released
|
||||||
|
|
||||||
def _do_work(self, common, item, tid):
|
def _do_work(self, common, item, tid):
|
||||||
'''
|
'''prepare to call the actual work function
|
||||||
Prepare to call the actual work function.
|
|
||||||
|
Implementation depends on number and type of arguments.
|
||||||
'''
|
'''
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
class SpecializedParallelUFunc(CDefinition):
|
class SpecializedParallelUFunc(CDefinition):
|
||||||
|
'''a generic ufunc that wraps ParallelUFunc, UFuncCore and the workload
|
||||||
|
'''
|
||||||
_argtys_ = [
|
_argtys_ = [
|
||||||
('args', C.pointer(C.char_p)),
|
('args', C.pointer(C.char_p)),
|
||||||
('dimensions', C.pointer(C.intp)),
|
('dimensions', C.pointer(C.intp)),
|
||||||
|
|
@ -343,12 +344,16 @@ class SpecializedParallelUFunc(CDefinition):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def specialize(cls, pufunc_def, core_def, func_def):
|
def specialize(cls, pufunc_def, core_def, func_def):
|
||||||
|
'''specialize to a combination of ParallelUFunc, UFuncCore and workload
|
||||||
|
'''
|
||||||
cls._name_ = 'specialized_%s_%s_%s'% (pufunc_def, core_def, func_def)
|
cls._name_ = 'specialized_%s_%s_%s'% (pufunc_def, core_def, func_def)
|
||||||
cls.PUFuncDef = pufunc_def
|
cls.PUFuncDef = pufunc_def
|
||||||
cls.CoreDef = core_def
|
cls.CoreDef = core_def
|
||||||
cls.FuncDef = func_def
|
cls.FuncDef = func_def
|
||||||
|
|
||||||
class PThreadAPI(CExternal):
|
class PThreadAPI(CExternal):
|
||||||
|
'''external declaration of pthread API
|
||||||
|
'''
|
||||||
pthread_t = C.void_p
|
pthread_t = C.void_p
|
||||||
|
|
||||||
pthread_create = Type.function(C.int,
|
pthread_create = Type.function(C.int,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue