diff --git a/notebook/llvm_cbuilder_intro.pdf b/notebook/llvm_cbuilder_intro.pdf index b647a15..a7b17d4 100644 Binary files a/notebook/llvm_cbuilder_intro.pdf and b/notebook/llvm_cbuilder_intro.pdf differ diff --git a/notebook/parallel_vectorize.ipynb b/notebook/parallel_vectorize.ipynb index b0bdaff..518594a 100644 --- a/notebook/parallel_vectorize.ipynb +++ b/notebook/parallel_vectorize.ipynb @@ -78,7 +78,7 @@ }, { "cell_type": "code", - "collapsed": false, + "collapsed": true, "input": [ "from llvm.ee import *", "engine = EngineBuilder.new(m).create() # Generate JIT engine", @@ -153,6 +153,97 @@ } ], "prompt_number": 4 + }, + { + "cell_type": "markdown", + "source": [ + "* * *", + "", + "Internals", + "---------", + "", + "There are four functions behind each multithreaded _ufunc_.", + "", + "1. the workload function (user defined);", + "2. the thread worker function (`UFuncCoreGeneric`);", + "3. the thread manager function (`ParallelUFuncPlatform`);", + "4. the ufunc entry point function (`SpecializedParallelUFunc`).", + "", + "**UFuncCoreGeneric** specializes to a llvm function type.", + "**It currently understands simple builtin scalar types (integers, float, double) only as arguments and return-type for the workload function.**", + "It sends work items to the workload function and performs work-stealing when it has finished its own workqueue.", + "Work-stealing uses atomic compare-exchange (or CAS) instruction to acquire ownership of a workqueue.", + "Work-stealing is implemented in the `UFuncCore._do_work_stealing`.", + "It can be disabled on platform that does not support atomic operations.", + "", + "**ParallelUFuncPlatform** specializes to the maximum number of threads. ", + "It divides all works equally among all threads.", + "Each thread executes the function generated by `UFuncCoreGeneric` once.", + "", + "**SpecializedParallelUFunc** is the specialized _ufunc_ entry point for a specific combination of ", + "workload, UFuncCoreGeneric and ParallelUFuncPlatform.", + "", + "Here's an example that uses `SpecializedParallelUFunc` directly for the `SumOfThree` workload." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "import parallel_vectorize as pv", + "# specialize", + "def_spuf = pv.SpecializedParallelUFunc(pv.ParallelUFuncPlatform(num_thread=2),", + " pv.UFuncCoreGeneric(llvm_sum3.type.pointee),", + " CFuncRef(llvm_sum3))", + "# define", + "spuf = def_spuf(m)", + "print(spuf.name)" + ], + "language": "python", + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "specialized_parallel_ufunc_2_ufunc_worker.i32.i32.i32.i32_sum.of.three" + ] + } + ], + "prompt_number": 5 + }, + { + "cell_type": "markdown", + "source": [ + "`CFuncRef` also accepts arbitrary function pointer as long as the function type is provided." + ] + }, + { + "cell_type": "code", + "collapsed": false, + "input": [ + "# specialize", + "fnty = llvm_sum3.type.pointee", + "sum3ptr = engine.get_pointer_to_function(llvm_sum3)", + "print(\"as function pointer: %x\" % sum3ptr)", + "def_spuf = pv.SpecializedParallelUFunc(pv.ParallelUFuncPlatform(num_thread=2),", + " pv.UFuncCoreGeneric(fnty),", + " CFuncRef('sum3.as.ptr', fnty, sum3ptr)) # name, type, ptr", + "# define", + "spuf = def_spuf(m)", + "print(spuf.name)" + ], + "language": "python", + "outputs": [ + { + "output_type": "stream", + "stream": "stdout", + "text": [ + "as function pointer: 7f0bfc090740", + "specialized_parallel_ufunc_2_ufunc_worker.i32.i32.i32.i32_sum3.as.ptr" + ] + } + ], + "prompt_number": 6 } ] } diff --git a/notebook/parallel_vectorize.pdf b/notebook/parallel_vectorize.pdf new file mode 100644 index 0000000..394f364 Binary files /dev/null and b/notebook/parallel_vectorize.pdf differ