diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1f545c62..46c5e1f6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -85,10 +85,13 @@ jobs: mkdir build mkdir inst cd build - cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_TARGETS_TO_BUILD=host -DLLVM_OPTIMIZED_TABLEGEN=On -DLLVM_ENABLE_PROJECTS=clang -DCMAKE_INSTALL_PREFIX=../inst ../llvm - make ClangDriverOptions clang-repl -j$(nproc --all) - #make install -j$(nproc --all) - cd ../.. + cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_TARGETS_TO_BUILD=host -DLLVM_OPTIMIZED_TABLEGEN=On -DLLVM_ENABLE_PROJECTS="clang" -DLLVM_ENABLE_RUNTIMES="openmp" -DCMAKE_INSTALL_PREFIX=../inst ../llvm + make ClangDriverOptions clang-repl openmp openmp-resource-headers -j$(nproc --all) + make install -j$(nproc --all) + make clean -j$(nproc --all) + cd .. + rm -rf $(find . -maxdepth 1 ! -name "inst" ! -name ".") + cd .. - name: Save Cache LLVM/Clang runtime build directory uses: actions/cache/save@v3 if: ${{ steps.cache.outputs.cache-hit != 'true' }} @@ -97,7 +100,7 @@ jobs: key: ${{ steps.cache.outputs.cache-primary-key }} - name: Set PATH_TO_LLVM_BUILD etc to Env run: | - export PATH_TO_LLVM_BUILD="$(realpath clang-dev/build)" + export PATH_TO_LLVM_BUILD="$(realpath clang-dev/inst)" export PATH=$PATH_TO_LLVM_BUILD/bin:$PATH export LD_LIBRARY_PATH=$PATH_TO_LLVM_BUILD/lib:$LD_LIBRARY_PATH echo "PATH_TO_LLVM_BUILD=$PATH_TO_LLVM_BUILD" >> $GITHUB_ENV @@ -147,8 +150,9 @@ jobs: run: | # Build CppInterOp next to cling and llvm-project. LLVM_DIR="$(realpath clang-dev)" - LLVM_BUILD_DIR="$(realpath clang-dev/build)" - CPLUS_INCLUDE_PATH="${LLVM_DIR}/llvm/include:${LLVM_DIR}/clang/include:${LLVM_BUILD_DIR}/include:${LLVM_BUILD_DIR}/tools/clang/include" + LLVM_BUILD_DIR="$(realpath clang-dev/inst)" + #CPLUS_INCLUDE_PATH="${LLVM_DIR}/llvm/include:${LLVM_DIR}/clang/include:${LLVM_BUILD_DIR}/include:${LLVM_BUILD_DIR}/tools/clang/include" + CPLUS_INCLUDE_PATH="${LLVM_BUILD_DIR}/include/llvm:${LLVM_BUILD_DIR}/include/clang" git clone https://github.com/compiler-research/CppInterOp.git export CPPINTEROP_DIR=$PWD/cppyy-backend/python/cppyy_backend/ cd CppInterOp diff --git a/CMakeLists.txt b/CMakeLists.txt index 596dcc50..35a61ae6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,30 +21,62 @@ message(STATUS "Building xeus-clang-repl v${${PROJECT_NAME}_VERSION}") # Configuration # ============= +# OpenMP config +#find_package(OpenMP PATHS "${LLVM_CMAKE_DIR}/lib/cmake/openmp") +#if (OpenMP_CXX_FOUND) +# message(STATUS "OpenMP: Found.") +# message(STATUS "OpenMP_CXX_VERSION=${OpenMP_CXX_VERSION}") +# message(STATUS "OpenMP_CXX_SPEC_DATE=${OpenMP_CXX_SPEC_DATE}") +# message(STATUS "OpenMP_CXX_FLAGS=${OpenMP_CXX_FLAGS}") +# message(STATUS "OpenMP_CXX_INCLUDE_DIRS=${OpenMP_CXX_INCLUDE_DIRS}") +# message(STATUS "OpenMP_CXX_LIB_NAMES=${OpenMP_CXX_LIB_NAMES}") +# message(STATUS "OpenMP_CXX_LIBRARIES=${OpenMP_CXX_LIBRARIES}") +# set(omp_libs "${OpenMP_CXX_LIB_NAMES}") +# list(TRANSFORM omp_libs PREPEND "-l") +# list(JOIN omp_libs " " INCLUDE_STRING) +# message(STATUS "OpenMP_CXX_LIB_NAMES(params)=${omp_libs}") +# message(STATUS "OpenMP_gomp_LIBRARY=${OpenMP_gomp_LIBRARY}") +# message(STATUS "OpenMP_pthread_LIBRARY=${OpenMP_pthread_LIBRARY}") +# set(CMAKE_OMP ",\n\"${OpenMP_CXX_FLAGS}\", \"-l${OpenMP_gomp_LIBRARY}\", \"-l${OpenMP_pthread_LIBRARY}\"") +# set(CMAKE_OMP ",\n\"${OpenMP_CXX_FLAGS}\"") +#else() +# message(STATUS "OpenMP: Not Found.") +# set(CMAKE_OMP ",\n\"-fopenmp\"") +#endif() + + include(GNUInstallDirs) -message(STATUS "Env CPLUS_INCLUDE_PATH=$ENV{CPLUS_INCLUDE_PATH}") -message(STATUS "Env LD_LIBRARY_PATH=$ENV{LD_LIBRARY_PATH}") -message(STATUS "Env PYTHONPATH=$ENV{PYTHONPATH}") set(CMAKE_CPLUS_INCLUDE_PATH "$ENV{CPLUS_INCLUDE_PATH}") set(CMAKE_LD_LIBRARY_PATH "$ENV{LD_LIBRARY_PATH}") set(CMAKE_PYTHONPATH "$ENV{PYTHONPATH}") -configure_file ( - "${CMAKE_CURRENT_SOURCE_DIR}/share/jupyter/kernels/xcpp11/kernel.json.in" - "${CMAKE_CURRENT_BINARY_DIR}/share/jupyter/kernels/xcpp11/kernel.json" -) - -configure_file ( - "${CMAKE_CURRENT_SOURCE_DIR}/share/jupyter/kernels/xcpp14/kernel.json.in" - "${CMAKE_CURRENT_BINARY_DIR}/share/jupyter/kernels/xcpp14/kernel.json" -) +message(STATUS "Debug: Replace in kernels") +message(STATUS "Debug: CMAKE_CPLUS_INCLUDE_PATH=${CMAKE_CPLUS_INCLUDE_PATH}") +message(STATUS "Debug: CMAKE_LD_LIBRARY_PATH=${CMAKE_LD_LIBRARY_PATH}") +message(STATUS "Debug: CMAKE_PYTHONPATH=${CMAKE_PYTHONPATH}") +#message(STATUS "Debug: CMAKE_OMP=${CMAKE_OMP}") -configure_file ( - "${CMAKE_CURRENT_SOURCE_DIR}/share/jupyter/kernels/xcpp17/kernel.json.in" - "${CMAKE_CURRENT_BINARY_DIR}/share/jupyter/kernels/xcpp17/kernel.json" -) +function(configure_kernel kernel) + configure_file ( + "${CMAKE_CURRENT_SOURCE_DIR}/${kernel}/kernel.json.in" + "${CMAKE_CURRENT_BINARY_DIR}/${kernel}/kernel.json" + ) + file(GLOB files "${CMAKE_CURRENT_SOURCE_DIR}/${kernel}/*.png") + foreach(file ${files}) + configure_file( + "${file}" + "${CMAKE_CURRENT_BINARY_DIR}/${kernel}/" + COPYONLY + ) + endforeach() +endfunction() + +configure_kernel("share/jupyter/kernels/xcpp11") +configure_kernel("share/jupyter/kernels/xcpp14") +configure_kernel("share/jupyter/kernels/xcpp17") +configure_kernel("share/jupyter/kernels/clad-xcpp17") ################ # Dependencies # @@ -273,12 +305,18 @@ set(XCPP_KERNELSPEC_DIR ${CMAKE_CURRENT_BINARY_DIR}/share/jupyter/kernels) install(DIRECTORY ${XCPP_KERNELSPEC_DIR} DESTINATION ${XJUPYTER_DATA_DIR} PATTERN "*.in" EXCLUDE) +install(DIRECTORY ${XCPP_KERNELSPEC_DIR} + DESTINATION ${XJUPYTER_DATA_DIR} + FILES_MATCHING PATTERN "*.png") # Extra path for installing Jupyter kernelspec if (XEXTRA_JUPYTER_DATA_DIR) install(DIRECTORY ${XCPP_KERNELSPEC_DIR} DESTINATION ${XEXTRA_JUPYTER_DATA_DIR} PATTERN "*.in" EXCLUDE) + install(DIRECTORY ${XCPP_KERNELSPEC_DIR} + DESTINATION ${XEXTRA_JUPYTER_DATA_DIR} + FILES_MATCHING PATTERN "*.png") endif(XEXTRA_JUPYTER_DATA_DIR) # Makes the project importable from the build directory diff --git a/Dockerfile b/Dockerfile index 0c55f360..31357ff3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -33,6 +33,7 @@ RUN apt-get update --yes && \ unzip \ curl \ jq \ + ###libomp-dev \ # Other "our" apt installs (development and testing) build-essential \ git \ @@ -167,7 +168,7 @@ RUN \ popd && \ # echo "Debug clang path: $PATH_TO_CLANG_DEV" && \ - export PATH_TO_LLVM_BUILD=$PATH_TO_CLANG_DEV/build && \ + export PATH_TO_LLVM_BUILD=$PATH_TO_CLANG_DEV/inst && \ export VENV=/home/jovyan/.venv && \ echo "export VENV=$VENV" >> ~/.profile && \ export PATH=$VENV/bin:$PATH_TO_LLVM_BUILD/bin:$PATH && \ @@ -175,7 +176,10 @@ RUN \ # # Build CppInterOp # - export CPLUS_INCLUDE_PATH="${PATH_TO_LLVM_BUILD}/../llvm/include:${PATH_TO_LLVM_BUILD}/../clang/include:${PATH_TO_LLVM_BUILD}/include:${PATH_TO_LLVM_BUILD}/tools/clang/include" && \ + sys_incs=$(LC_ALL=C c++ -xc++ -E -v /dev/null 2>&1 | LC_ALL=C sed -ne '/starts here/,/End of/p' | LC_ALL=C sed '/^ /!d' | cut -c2- | tr '\n' ':') && \ + #export CPLUS_INCLUDE_PATH="${PATH_TO_LLVM_BUILD}/../llvm/include:${PATH_TO_LLVM_BUILD}/../clang/include:${PATH_TO_LLVM_BUILD}/include:${PATH_TO_LLVM_BUILD}/tools/clang/include:${sys_incs%:}" + export CPLUS_INCLUDE_PATH="${PATH_TO_LLVM_BUILD}/include/llvm:${PATH_TO_LLVM_BUILD}/include/clange:${sys_incs%:}" && \ + echo $CPLUS_INCLUDE_PATH && \ git clone https://github.com/compiler-research/CppInterOp.git && \ export CB_PYTHON_DIR="$PWD/cppyy-backend/python" && \ export CPPINTEROP_DIR="$CB_PYTHON_DIR/cppyy_backend" && \ @@ -255,4 +259,8 @@ RUN \ make && \ make install && \ # install clad in all exist kernels - for i in "$KERNEL_PYTHON_PREFIX"/share/jupyter/kernels/*; do if [[ $i =~ .*/xcpp.* ]]; then jq '.argv += ["-fplugin=$KERNEL_PYTHON_PREFIX/lib/clad.so"] | .display_name += " (with clad)"' "$i"/kernel.json > tmp.$$.json && mv tmp.$$.json "$i"/kernel.json; fi; done + for i in "$KERNEL_PYTHON_PREFIX"/share/jupyter/kernels/*; do if [[ $i =~ .*/clad-xcpp.* ]]; then jq '.argv += ["-fplugin=$KERNEL_PYTHON_PREFIX/lib/clad.so"] | .display_name += " (with clad)"' "$i"/kernel.json > tmp.$$.json && mv tmp.$$.json "$i"/kernel.json; fi; done && \ + # + # Add OpenMP to all kernels + # + for i in "$KERNEL_PYTHON_PREFIX"/share/jupyter/kernels/*; do if [[ $i =~ .*/xcpp.* ]]; then jq '.argv += ["-fopenmp"] | .display_name += " (with OpenMP)"' "$i"/kernel.json > tmp.$$.json && mv tmp.$$.json "$i"/kernel.json; fi; done diff --git a/notebooks/clad-demo.ipynb b/notebooks/clad-demo.ipynb new file mode 100644 index 00000000..09af6ee0 --- /dev/null +++ b/notebooks/clad-demo.ipynb @@ -0,0 +1,87 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "74f52cc2-bfda-4fee-9cd9-94d683a8b7e1", + "metadata": {}, + "outputs": [], + "source": [ + "#include \"clad/Differentiator/Differentiator.h\"\n", + "#include " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "55453d37-e8af-4cb7-8f82-550e9cf88b3c", + "metadata": {}, + "outputs": [], + "source": [ + "// Rosenbrock function declaration\n", + "double rosenbrock_func(double x, double y) {\n", + "return (x - 1) * (x - 1) + 100 * (y - x * x) * (y - x * x);\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9098b6e4-87a7-497d-9a1b-dddeb813dc56", + "metadata": {}, + "outputs": [], + "source": [ + "double rosenbrock_forward(double x[], int size) {\n", + " double sum = 0;\n", + " auto rosenbrockX = clad::differentiate(rosenbrock_func, 0);\n", + " auto rosenbrockY = clad::differentiate(rosenbrock_func, 1);\n", + " for (int i = 0; i < size-1; i++) {\n", + " double one = rosenbrockX.execute(x[i], x[i + 1]);\n", + " double two = rosenbrockY.execute(x[i], x[i + 1]);\n", + " sum = sum + one + two;\n", + " }\n", + " return sum;\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e771bbdc-3979-43df-9ed9-3429ee713b5d", + "metadata": {}, + "outputs": [], + "source": [ + "const int size = 100000000;\n", + "double Xarray[size];\n", + "for(int i=0;i\n", + "#include \"omp.h\"\n", + "#include " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1b4dac8e-3ad2-46eb-b801-ba717e664b93", + "metadata": {}, + "outputs": [], + "source": [ + "Cpp::LoadLibrary(\"libomp\");" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5001e441-1fa5-4bdc-9fa5-2ca103ae484f", + "metadata": {}, + "outputs": [], + "source": [ + "void example1() {\n", + " std::cout << \"Hello World!\" << std::endl;\n", + "}\n", + "example1();" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "53fb7656-b72e-42bc-ade7-2ae2077142da", + "metadata": {}, + "outputs": [], + "source": [ + "void example2() {\n", + " #pragma omp parallel\n", + " {\n", + " std::cout << \"Hello World!\" << std::endl;\n", + " }\n", + "}\n", + "example2();" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "efcdfdb6-a60b-46af-8194-75ef9cc0e27f", + "metadata": {}, + "outputs": [], + "source": [ + "void example3() {\n", + " #pragma omp parallel\n", + " {\n", + " std::cout << \"Hello World! (\" << omp_get_thread_num() << \")\" << std::endl;\n", + " }\n", + "}\n", + "example3();" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d86a9efa-ba28-4cb6-bbfc-abc00ee63506", + "metadata": {}, + "outputs": [], + "source": [ + "void example4() {\n", + " #pragma omp parallel\n", + " {\n", + " std::cout << \"Hello World! (\" << omp_get_thread_num() << \")\" << std::endl;\n", + " }\n", + "\n", + " std::cout << \"This is another message! (\" << omp_get_thread_num() << \")\" << std::endl;\n", + "\n", + " #pragma omp parallel num_threads(2)\n", + " {\n", + " std::cout << \"Goodbye World! (\" << omp_get_thread_num() << \")\" << std::endl;\n", + " }\n", + "}\n", + "example4();" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5557e01a-7c7d-4b54-8545-962ad11027df", + "metadata": {}, + "outputs": [], + "source": [ + "void example5() {\n", + " double start_time = omp_get_wtime();\n", + " double start_loop;\n", + " \n", + " const int N = 1000000000;\n", + " int* a = new int[N];\n", + " int* b = new int[N];\n", + " \n", + " start_loop = omp_get_wtime();\n", + " #pragma omp parallel for\n", + " for (int i=0; i; interpreter_ptr build_interpreter(int argc, char **argv) { - int interpreter_argc = argc + 1; - const char **interpreter_argv = new const char *[interpreter_argc]; - interpreter_argv[0] = "xeus-clang-repl"; - // Copy all arguments in the new array excepting the process name. + std::vector interpreter_args; for (int i = 1; i < argc; i++) { - interpreter_argv[i] = argv[i]; + if (argv[i] == "-f") { + i++; // skip the value of -f which is a json file. + continue; + } + interpreter_args.push_back(argv[i]); } - // std::string resource_dir = - // "-resource-dir=" + std::string(CLANG_RESOURCE_DIR); - // interpreter_argv[interpreter_argc - 1] = resource_dir.c_str(); - interpreter_ptr interp_ptr = interpreter_ptr( - new xcpp::interpreter(interpreter_argc, interpreter_argv)); - delete[] interpreter_argv; + new xcpp::interpreter(interpreter_args.size(), interpreter_args.data())); return interp_ptr; } diff --git a/src/xinterpreter.cpp b/src/xinterpreter.cpp index f964be71..e742972a 100644 --- a/src/xinterpreter.cpp +++ b/src/xinterpreter.cpp @@ -38,13 +38,9 @@ using namespace std::placeholders; using Args = std::vector; void* createInterpreter(const Args &ExtraArgs = {}) { - Args ClangArgs = {"-Xclang", "-emit-llvm-only", - "-Xclang", "-diagnostic-log-file", - "-Xclang", "-", - "-xc++"}; + Args ClangArgs = {"-xc++"}; ClangArgs.insert(ClangArgs.end(), ExtraArgs.begin(), ExtraArgs.end()); - //return InterOp::CreateInterpreter(ClangArgs); - return Cpp::CreateInterpreter(); + return Cpp::CreateInterpreter(ClangArgs); } namespace xcpp { @@ -57,9 +53,9 @@ interpreter::interpreter(int argc, const char *const *argv) xmagics(), p_cout_strbuf(nullptr), p_cerr_strbuf(nullptr), m_cout_buffer(std::bind(&interpreter::publish_stdout, this, _1)), m_cerr_buffer(std::bind(&interpreter::publish_stderr, this, _1)) { - createInterpreter(Args(argv + 1, argv + argc)/*, DiagPrinter.get()*/); - // Bootstrap the execution engine + createInterpreter(Args(argv, argv + argc)); redirect_output(); + // Bootstrap the execution engine init_preamble(); init_magic(); } @@ -107,10 +103,11 @@ nl::json interpreter::execute_request_impl(int /*execution_counter*/, for (const auto &block : blocks) { // Attempt normal evaluation - std::string error_message; - std::stringstream error_stream(error_message); + std::string err; try { + Cpp::BeginStdStreamCapture(Cpp::kStdErr); compilation_result = Cpp::Process(block.c_str()); + err = Cpp::EndStdStreamCapture(); } catch (std::exception &e) { @@ -127,13 +124,9 @@ nl::json interpreter::execute_request_impl(int /*execution_counter*/, errorlevel = 1; // send the errors directly to std::cerr ename = ""; - std::cerr << error_stream.str(); - } + std::cerr << err; - // If an error was encountered, don't attempt further execution - if (errorlevel) { - error_stream.str().clear(); - //DiagnosticsOS.str().clear(); + // If an error was encountered, don't attempt further execution break; } }