"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 05 - Using conda to manage C++ libraries\n",
"\n",
"The [cffi_funs](https://github.com/phaustin/parallel_python_course/tree/master/code_examples/cffi_funs) folder shows how to set up a C++ file so that it compiled with [cmake](http://preshing.com/20170511/how-to-build-a-cmake-based-project/) and also [here](http://preshing.com/20170522/learn-cmakes-scripting-language-in-15-minutes/)\n",
"\n",
"The folder contains [these files](https://github.com/phaustin/parallel_python_course/blob/master/code_examples/cffi_funs/Readme_cffi_funs.rst)\n",
"\n",
"**Demo**\n",
"\n",
"Show how to build a conda archive with:\n",
"\n",
" conda build .\n",
" \n",
"and then upload it to your [Anaconda channel](https://anaconda.org/phaustin/dashboard)\n",
"\n",
"Where it can be installed into a conda environment with:\n",
"\n",
" conda install -c phaustin cffi_funs"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Using conda to manage python libraries\n",
"\n",
"The [cffi_practice](https://github.com/phaustin/parallel_python_course/tree/master/code_examples/cffi_practice)\n",
"folder shows how to install a simple python project using conda and [setuptools](http://setuptools.readthedocs.io/en/latest/setuptools.html)\n",
"\n",
"**Demo**\n",
"\n",
"Show how to build and upload cffi_practice to my conda channel\n",
"\n",
"The purpose of this module is to provide one function:\n",
"\n",
" cffi_practice.get_paths()\n",
" \n",
"That can be used to locate the library and header from cff_funs\n",
"\n",
"The get_paths function is defined in this package in the [__init__.py](https://github.com/phaustin/parallel_python_course/blob/master/code_examples/cffi_practice/cffi_practice/__init__.py) module.\n",
"\n",
"Try:\n",
"\n",
" conda install cff_practice -c phaustin\n",
" \n",
"Then:\n",
"\n",
" python -c 'import cffi_practice;print(cffi_practice.get_paths())'\n",
" \n",
"Which should output something like:\n",
"\n",
" {'libfile': '/Users/phil/mini36/lib/libcffi_funs.so', 'libdir': '/Users/phil/mini36/lib', 'includedir': '/Users/phil/mini36/include'}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Accessing the functions from python using CFFI\n",
"\n",
"The [C foreign function interface](https://cffi.readthedocs.io/en/latest/overview.html) provides a way to call the cffi_funs from python\n",
"\n",
"Here is an example that exposes the get_thread_id and get_proces_id functions from the cffi_fun package"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"found these functions in module: ['get_process_id', 'get_thread_id']\n",
"Here is the thread id in hex: -4fdf76a5-\n",
"here is the process ide in base 10: -16502-\n"
]
}
],
"source": [
"from cffi import FFI\n",
"from joblib import Parallel\n",
"from cffi_practice import get_paths\n",
"#\n",
"# locate the library\n",
"#\n",
"lib_so_file=get_paths()['libfile']\n",
"ffi=FFI()\n",
"ffi.cdef(\"\"\"\n",
" void get_thread_id(char *thread_id);\n",
" void get_process_id(char *process_id);\n",
"\"\"\")\n",
"#\n",
"# open the library file\n",
"#\n",
"lib = ffi.dlopen(lib_so_file)\n",
"print('found these functions in module: ',dir(lib))\n",
"#\n",
"# create a 25 character C array to hold the ouput\n",
"#\n",
"arg_thread = ffi.new(\"char[]\",25) #(C++)\n",
"#\n",
"# copy the bytes into arg_thread (C++)\n",
"#\n",
"lib.get_thread_id(arg_thread) \n",
"#\n",
"# get the bytes into a python byte object\n",
"#\n",
"out_thread=ffi.string(arg_thread) #C++ to python\n",
"#\n",
"# turn the bytes into a utf-8 string\n",
"#\n",
"str_out=out_thread.decode('utf-8') #python\n",
"#\n",
"# print it out\n",
"#\n",
"print(f\"Here is the thread id in hex: -{str_out}-\")\n",
"#\n",
"# repeat for the process\n",
"#\n",
"arg_process = ffi.new(\"char[]\",25) \n",
"lib.get_process_id(arg_process)\n",
"out_process=ffi.string(arg_process)\n",
"str_out=out_process.decode('utf-8')\n",
"print(f\"here is the process ide in base 10: -{str_out}-\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Running this in a threadpool\n",
"\n",
"The following script uses joblib to create 10 jobs to call the cffi functions in parallel, returning\n",
"the pointers to the character array and convertingthem to python strings."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"here are the pointers to hold the ids: [[], [], [], [], [], [], [], [], [], []]\n",
"\n",
"here are the thread ids\n",
"thread id: 1bb9329b\n",
"thread id: 72b7e656\n",
"thread id: 7f162e70\n",
"thread id: c9742b94\n",
"thread id: 9e63eefb\n",
"thread id: 6b8afbdc\n",
"thread id: c3945c37\n",
"thread id: 425f89f8\n",
"thread id: e612e1c6\n",
"thread id: f9e7dfdc\n"
]
}
],
"source": [
"nprocs=10\n",
"arg_list=[]\n",
"fun_list=[]\n",
"dict_list=[]\n",
"for i in range(nprocs):\n",
" fun_list.append(lib.get_thread_id)\n",
" result_var=ffi.new(\"char[]\",25)\n",
" arg_list.append(result_var)\n",
" dict_list.append({})\n",
"ptr_list=[[ffi.cast(\"char*\",item)] for item in arg_list]\n",
"jobs=list(zip(fun_list,ptr_list,dict_list))\n",
"print(f'here are the pointers to hold the ids: {ptr_list}\\n')\n",
"with Parallel(n_jobs=nprocs,backend='threading') as parallel:\n",
" parallel(jobs)\n",
"print('here are the thread ids')\n",
"for item in ptr_list:\n",
" out_thread=ffi.string(item[0]).decode('utf-8')\n",
" print('thread id: ',out_thread)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"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.4"
},
"toc": {
"nav_menu": {},
"number_sections": true,
"sideBar": false,
"skip_h1_title": false,
"title_cell": "Table of Contents",
"title_sidebar": "Contents",
"toc_cell": true,
"toc_position": {},
"toc_section_display": "block",
"toc_window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 2
}