diff --git a/.conda/environment.yml b/.conda/environment.yml index 9fd075ec1..2010364c3 100644 --- a/.conda/environment.yml +++ b/.conda/environment.yml @@ -21,4 +21,5 @@ dependencies: - clang=10 - clangxx=10 - six + - cffi # - cudatoolkit-dev # disable temporary diff --git a/.conda/meta.yaml b/.conda/meta.yaml index 697956ce1..306b1a96d 100644 --- a/.conda/meta.yaml +++ b/.conda/meta.yaml @@ -20,6 +20,7 @@ requirements: build: - python - setuptools + - cffi host: - python - pytest-runner diff --git a/.github/workflows/eval-notebooks.yml b/.github/workflows/eval-notebooks.yml deleted file mode 100644 index 297f5412e..000000000 --- a/.github/workflows/eval-notebooks.yml +++ /dev/null @@ -1,60 +0,0 @@ -name: Eval notebooks - -on: - # Trigger the workflow on push or pull request, - # but only for the main branch - push: - branches: - - master - pull_request: - branches: - - master - -jobs: - eval-notebooks: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: 3.8 - - - uses: conda-incubator/setup-miniconda@v2 - with: - python-version: 3.8 - mamba-version: "*" - channels: conda-forge - environment-file: .conda/environment.yml - - - name: Install additional packages - shell: bash -l {0} - run: | - mamba install -c conda-forge omniscidb nbval ibis-omniscidb matplotlib pandas - - - name: Start omniscidb server - shell: bash -l {0} - run: | - mkdir data && omnisci_initdb data -f - omnisci_server --version - omnisci_server --enable-runtime-udf --enable-table-functions 2>&1 > omniscidb-output.txt & - sleep 10 - - - name: conda config - shell: bash -l {0} - run: conda config --show - - - name: conda list - shell: bash -l {0} - run: | - conda list - - - name: Execute pytest - shell: bash -l {0} - run: | - pip install -e . - pytest -v -rs --nbval notebooks/ -x - pkill -f omnisci_server - cat omniscidb-output.txt diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index c7b542c82..b85c96ce6 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -6,32 +6,65 @@ on: tags: - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 + jobs: - pypi-release: - runs-on: ubuntu-latest + build_wheels: + name: Build wheels on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] steps: - uses: actions/checkout@v2 + - name: Set up Python - uses: actions/setup-python@v1 + uses: actions/setup-python@v2 + with: + python-version: 3.9 + + # https://cibuildwheel.readthedocs.io/en/stable/options/#build-skip + - name: Install buildwheels + uses: pypa/cibuildwheel@v2.3.1 + env: # minimum version is cpython 3.7 + CIBW_BUILD: "cp37-*64 cp38-*64 cp39-* cp310-*" + CIBW_BEFORE_BUILD: python -m pip install cffi + CIBW_VERBOSITY: 3 + + - uses: actions/upload-artifact@v2 + with: + path: ./wheelhouse/*.whl + + build_sdist: + name: Build source distribution + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Build sdist + run: python setup.py sdist + + - uses: actions/upload-artifact@v2 with: - python-version: 3.8 + path: dist/*.tar.gz - - uses: conda-incubator/setup-miniconda@v2 + upload_pypi: + needs: [build_sdist, build_wheels] + runs-on: ubuntu-latest + # upload to PyPI on every tag starting with 'v' + if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags/v') + # alternatively, to publish when a GitHub Release is created, use the following rule: + # if: github.event_name == 'release' && github.event.action == 'published' + steps: + - uses: actions/download-artifact@v2 with: - python-version: 3.8 - mamba-version: "*" - channels: conda-forge - activate-environment: rbc-env - environment-file: .conda/environment.yml - - - name: Build distribution - shell: bash -l {0} - run: python setup.py sdist bdist_wheel - - - name: Publish package to PyPI - uses: pypa/gh-action-pypi-publish@master + name: artifact + path: dist + + - uses: pypa/gh-action-pypi-publish@master with: + verify_metadata: true verbose: true user: __token__ - password: ${{ secrets.PYPI_API_TOKEN }} \ No newline at end of file + password: ${{ secrets.PYPI_API_TOKEN }} + # repository_url: https://test.pypi.org/legacy/ diff --git a/.github/workflows/rbc_test.yml b/.github/workflows/rbc_test.yml index c23e89b20..205491fea 100644 --- a/.github/workflows/rbc_test.yml +++ b/.github/workflows/rbc_test.yml @@ -3,15 +3,18 @@ name: RBC on: # Trigger the workflow on push or pull request, # but only for the main branch - push: - branches: - - master pull_request: branches: - master +# kill any previous running job on a new commit +concurrency: + group: build-and-test-rbc-${{ github.head_ref }} + cancel-in-progress: true + jobs: lint: + if: ${{ !contains(github.event.pull_request.labels.*.name, 'skip-tests') }} runs-on: ubuntu-latest steps: - name: Checkout code @@ -32,11 +35,16 @@ jobs: name: ${{ matrix.os }} - Python v${{ matrix.python-version }} - Numba v${{ matrix.numba-version }} runs-on: ${{ matrix.os }} strategy: - fail-fast: true + # setting fail-fast=true seems to cause connection issues in remotejit tests + fail-fast: false matrix: os: [ubuntu-latest, windows-latest, macos-latest] - python-version: [3.9, 3.8, 3.7] - numba-version: [0.54, 0.53] + python-version: ['3.9', '3.8', '3.7'] + numba-version: ['0.55', '0.54'] + include: + - os: ubuntu-latest + python-version: '3.10' + numba-version: '0.55' needs: [lint, omniscidb] @@ -74,9 +82,15 @@ jobs: shell: bash -l {0} run: | mamba run -n rbc conda list + - name: Develop rbc shell: bash -l {0} run: | + if [ "$RUNNER_OS" == "macOS" ]; then + # workaround for + # https://github.com/conda-forge/clangdev-feedstock/issues/96 + export SDKROOT=`xcrun --sdk macosx --show-sdk-path` + fi mamba run -n rbc python setup.py develop - name: Run rbc tests shell: bash -l {0} @@ -94,28 +108,23 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest] - python-version: [3.9, 3.8, 3.7] - numba-version: [0.54, 0.53] - omniscidb-version: [5.8, 5.7, 5.6] + python-version: ['3.9', '3.8', '3.7'] + numba-version: ['0.55', '0.54'] + omniscidb-version: ['5.10', '5.9', '5.8', '5.7'] omniscidb-from: [conda] include: - os: ubuntu-latest - python-version: 3.8 - numba-version: 0.53 + python-version: '3.10' + numba-version: '0.55' omniscidb-version: dev docker-image: omnisci/core-os-cpu-dev:latest omniscidb-from: docker - os: ubuntu-latest - python-version: 3.8 - numba-version: 0.54 + python-version: '3.9' + numba-version: '0.54' omniscidb-version: dev docker-image: omnisci/core-os-cpu-dev:latest omniscidb-from: docker - - os: ubuntu-latest - python-version: 3.8 - omniscidb-version: 5.8.0 - docker-image: omnisci/core-os-cpu:v5.8.0 - omniscidb-from: docker needs: lint @@ -168,11 +177,18 @@ jobs: - name: Start Omniscidb [conda] shell: bash -l {0} if: matrix.os == 'ubuntu-latest' && matrix.omniscidb-from == 'conda' + env: + OMNISCIDB_VERSION: ${{ matrix.omniscidb-version }} run: | mkdir data mamba run -n omniscidb-env omnisci_initdb data -f mamba run -n omniscidb-env omnisci_server --version - mamba run -n omniscidb-env omnisci_server --enable-runtime-udf --enable-table-functions \> omniscidb-output.txt 2\>\&1 \& echo \$! \> omniscidb.pid + RUN_FLAGS="--enable-runtime-udf --enable-table-functions" + if [[ ${OMNISCIDB_VERSION} == "5.10" ]]; then + RUN_FLAGS="${RUN_FLAGS} --enable-dev-table-functions" + fi + echo ${RUN_FLAGS} + mamba run -n omniscidb-env omnisci_server $RUN_FLAGS \> omniscidb-output.txt 2\>\&1 \& echo \$! \> omniscidb.pid sleep 10 cat omniscidb.pid @@ -222,6 +238,14 @@ jobs: run: | mamba run -n rbc pytest -sv -r A rbc/tests/ -x -k omnisci + - name: Show Omniscidb conda logs on failure [conda] + shell: bash -l {0} + if: failure() && matrix.os == 'ubuntu-latest' && matrix.omniscidb-from == 'conda' + run: | + mamba run -n omniscidb-env cat data/mapd_log/omnisci_server.INFO + mamba run -n omniscidb-env cat data/mapd_log/omnisci_server.WARNING + mamba run -n omniscidb-env cat data/mapd_log/omnisci_server.ERROR + - name: Show Omniscidb docker logs on failure [docker] shell: bash -l {0} if: failure() && matrix.os == 'ubuntu-latest' && matrix.omniscidb-from == 'docker' @@ -249,3 +273,52 @@ jobs: run: | mamba run -n docker docker-compose logs --no-color --tail=10000 -f -t \> omniscidb-docker.log cat omniscidb-docker.log + + eval-notebooks: + runs-on: ubuntu-latest + needs: lint + + steps: + - uses: actions/checkout@v2 + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: 3.8 + + - uses: conda-incubator/setup-miniconda@v2 + with: + python-version: 3.8 + mamba-version: "*" + channels: conda-forge + environment-file: .conda/environment.yml + + - name: Install additional packages + shell: bash -l {0} + run: | + mamba install -c conda-forge omniscidb nbval ibis-omniscidb matplotlib pandas ibis-framework + + - name: Start omniscidb server + shell: bash -l {0} + run: | + mkdir data && omnisci_initdb data -f + omnisci_server --version + omnisci_server --enable-runtime-udf --enable-table-functions 2>&1 > omniscidb-output.txt & + sleep 10 + + - name: conda config + shell: bash -l {0} + run: conda config --show + + - name: conda list + shell: bash -l {0} + run: | + conda list + + - name: Execute pytest + shell: bash -l {0} + run: | + pip install -e . + pytest -v -rs --nbval notebooks/ -x + pkill -f omnisci_server + cat omniscidb-output.txt diff --git a/README.md b/README.md index f295eb64d..c698a108d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # RBC - Remote Backend Compiler -[![Travis CI](https://travis-ci.org/xnd-project/rbc.svg?branch=master)](https://travis-ci.org/xnd-project/rbc) [![Appveyor CI](https://ci.appveyor.com/api/projects/status/i9xbkqkvomhbr8n4/branch/master?svg=true)](https://ci.appveyor.com/project/pearu/rbc-mnh7b/branch/master) [![Documentation Status](https://readthedocs.org/projects/rbc/badge/?version=latest)](https://rbc.readthedocs.io/en/latest/?badge=latest) +[![GitHub Actions](https://github.com/xnd-project/rbc/actions/workflows/rbc_test.yml/badge.svg)](https://github.com/xnd-project/rbc/actions) [![Documentation Status](https://readthedocs.org/projects/rbc/badge/?version=latest)](https://rbc.readthedocs.io/en/latest/?badge=latest) ## Introduction - test diff --git a/doc/_templates/autosummary/module.rst b/doc/_templates/autosummary/module.rst index 3041ffe94..5bb41215c 100644 --- a/doc/_templates/autosummary/module.rst +++ b/doc/_templates/autosummary/module.rst @@ -13,7 +13,7 @@ {% endfor %} {% endif %} -{% if module == "rbc.externals.libdevice" %} +{% if fullname == "rbc.externals.libdevice" %} .. rubric:: Functions .. autosummary:: :toctree: diff --git a/doc/api.rst b/doc/api.rst index ed7d4e5cd..311d6ca2e 100644 --- a/doc/api.rst +++ b/doc/api.rst @@ -26,6 +26,19 @@ Top-level functions utils +Array API +========= + +.. autosummary:: + :toctree: generated/ + + stdlib.datatypes + stdlib.constants + stdlib.creation_functions + stdlib.elementwise_functions + stdlib.statistical_functions + + Externals ========= diff --git a/doc/conf.py b/doc/conf.py index fc9fc29d9..285f233de 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -14,15 +14,14 @@ # import os import sys -import datetime -sys.path.insert(0, os.path.abspath('../')) +from datetime import date from rbc import __version__ # -- Project information ----------------------------------------------------- project = 'RBC' -copyright = '2018-%s, Xnd-Project Developers' % datetime.datetime.now().year +copyright = f'2018-{date.today().year}, Quansight RBC Developers' author = 'Xnd-Project Developers' # The version info for the project you're documenting, acts as replacement for @@ -54,7 +53,6 @@ 'sphinx.ext.napoleon', 'sphinx.ext.autosectionlabel', 'sphinx_autodoc_typehints', - 'sphinx_rtd_theme', 'numbadoc', ] @@ -68,9 +66,6 @@ napoleon_google_docstring = False napoleon_numpy_docstring = True -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = "sphinx" - # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -85,24 +80,20 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = "sphinx_rtd_theme" +html_theme = 'pydata_sphinx_theme' + +# The Xnd logo +html_logo = "images/xndlogo.png" html_theme_options = { - 'canonical_url': 'https://xnd.io/', - 'analytics_id': '', - 'logo_only': False, - 'display_version': True, - 'prev_next_buttons_location': 'bottom', - # Toc options - 'collapse_navigation': True, - 'sticky_navigation': True, - # 'navigation_depth': 4, + "logo_link": "index", + "github_url": "https://github.com/xnd-project/rbc", + "use_edit_page_button": True, } -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# The Xnd logo -html_logo = "images/xndlogo.png" +html_context = { + "github_user": "xnd-project", + "github_repo": "rbc", + "github_version": "master", + "doc_path": "doc", +} diff --git a/notebooks/rbc-intro.ipynb b/notebooks/rbc-intro.ipynb index 1a808e671..0261ba63e 100644 --- a/notebooks/rbc-intro.ipynb +++ b/notebooks/rbc-intro.ipynb @@ -49,7 +49,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "staring rpc.thrift server: /home/guilhermel/.conda/envs/rbc/lib/python3.8/site-packages/rbc/remotejit.thrift" + "staring rpc.thrift server: /home/pearu/git/xnd-project/rbc/rbc/remotejit.thrift" ] } ], @@ -62,7 +62,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -72,7 +72,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -84,9 +84,38 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 4, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "--------------------------------------cpu---------------------------------------\n", + "; ModuleID = 'rbc.irtools.compile_to_IR'\n", + "source_filename = \"\"\n", + "target triple = \"x86_64-unknown-linux-gnu\"\n", + "\n", + "@_ZN08NumbaEnv8__main__7foo_241B40c8tJTC_2fWQA9HW1CcAv0EjzIkAdRoAEtoAgA_3dExx = common local_unnamed_addr global i8* null\n", + "\n", + "; Function Attrs: norecurse nounwind readnone\n", + "define i64 @foo_lallA(i64 %.1, i64 %.2) local_unnamed_addr #0 {\n", + "entry:\n", + " %.6.i = add nsw i64 %.2, %.1\n", + " ret i64 %.6.i\n", + "}\n", + "\n", + "attributes #0 = { norecurse nounwind readnone }\n", + "\n", + "!llvm.module.flags = !{!0}\n", + "\n", + "!0 = !{i32 4, !\"pass_column_arguments_by_value\", i1 false}\n", + "\n", + "--------------------------------------------------------------------------------\n" + ] + } + ], "source": [ "# NBVAL_IGNORE_OUTPUT\n", "# Generate LLVM IR, useful for debugging\n", @@ -95,7 +124,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 5, "metadata": {}, "outputs": [ { @@ -104,7 +133,7 @@ "4" ] }, - "execution_count": 28, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -119,7 +148,7 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -128,7 +157,7 @@ "6" ] }, - "execution_count": 29, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } @@ -139,14 +168,17 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "found no matching function type to given argument types `float64, float64`. Available function types: int64(int64, int64)\n" + "found no matching function signature to given argument types:\n", + " (float64, float64) -> ...\n", + " available function signatures:\n", + " int64(int64, int64)\n" ] } ], @@ -159,7 +191,7 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 8, "metadata": {}, "outputs": [], "source": [ @@ -170,7 +202,7 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 9, "metadata": {}, "outputs": [ { @@ -179,7 +211,7 @@ "(1+3.4j)" ] }, - "execution_count": 32, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } @@ -190,7 +222,7 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 10, "metadata": {}, "outputs": [ { @@ -199,7 +231,7 @@ "4.2" ] }, - "execution_count": 33, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -210,7 +242,7 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 11, "metadata": {}, "outputs": [], "source": [ diff --git a/notebooks/rbc-omnisci-black-scholes.ipynb b/notebooks/rbc-omnisci-black-scholes.ipynb index 92756416b..fafbaaf0e 100644 --- a/notebooks/rbc-omnisci-black-scholes.ipynb +++ b/notebooks/rbc-omnisci-black-scholes.ipynb @@ -470,7 +470,7 @@ "source": [ "import numba\n", "import math\n", - "from rbc import omnisci_backend as np" + "from rbc.stdlib import array_api as np" ] }, { @@ -572,7 +572,7 @@ "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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", "text/plain": [ "
" ] @@ -673,7 +673,7 @@ "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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", "text/plain": [ "
" ] diff --git a/notebooks/rbc-omnisci-udf.ipynb b/notebooks/rbc-omnisci-udf.ipynb index 568d2f0e2..6314ff305 100644 --- a/notebooks/rbc-omnisci-udf.ipynb +++ b/notebooks/rbc-omnisci-udf.ipynb @@ -280,145 +280,6 @@ "t = ibis_con.sql('select x, incr(x), i, incr(i) from mytable')\n", "t[t.i < 3].execute()" ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Advanced: defining UDFs from a LLVM IR string" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "One can implement UDF registration support to any OmnisciDB client that \n", - "is able to provide the UDF implementations in LLVM IR form.\n", - "\n", - "To demonstrate that, let's define such a UDF from a LLVM IR string:" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "foo_ir = '''\n", - "; foo(i, j) -> i * j + 55\n", - "define i32 @foo(i32 %.1, i32 %.2) {\n", - "entry:\n", - " %.18.i = mul i32 %.2, %.1\n", - " %.33.i = add i32 %.18.i, 55\n", - " ret i32 %.33.i\n", - "}\n", - "'''\n", - "foo_signature = \"foo 'int32(int32, int32)'\"" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "and register it to OmnisciDB server using its Thrift end-point:" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "omni.thrift_call('register_runtime_udf',\n", - " omni.session_id,\n", - " foo_signature,\n", - " dict(cpu = foo_ir))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Test it:" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
iEXPR$1
0055
1160
2265
3370
4475
\n", - "
" - ], - "text/plain": [ - " i EXPR$1\n", - "0 0 55\n", - "1 1 60\n", - "2 2 65\n", - "3 3 70\n", - "4 4 75" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "ibis_con.sql('select i, foo(i, 5) from mytable').execute()" - ] } ], "metadata": { diff --git a/notebooks/rbc-simple.ipynb b/notebooks/rbc-simple.ipynb index 68757c331..13cae75d7 100644 --- a/notebooks/rbc-simple.ipynb +++ b/notebooks/rbc-simple.ipynb @@ -2,6 +2,7 @@ "cells": [ { "cell_type": "markdown", + "metadata": {}, "source": [ "# Remote Backend Compiler - RBC\n", "\n", @@ -15,77 +16,77 @@ "1. decorate Python functions that implementation will be used as a template for low-level functions\n", "2. define signatures of the low-level functions\n", "3. start/stop remote JIT server" - ], - "metadata": {} + ] }, { "cell_type": "code", "execution_count": 1, + "metadata": {}, + "outputs": [], "source": [ "import warnings; warnings.filterwarnings('ignore')" - ], - "outputs": [], - "metadata": {} + ] }, { "cell_type": "code", "execution_count": 2, + "metadata": {}, + "outputs": [], "source": [ "import rbc" - ], - "outputs": [], - "metadata": {} + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "## Create Remote JIT decorator" - ], - "metadata": {} + ] }, { "cell_type": "code", "execution_count": 3, + "metadata": {}, + "outputs": [], "source": [ "rjit = rbc.RemoteJIT(host='localhost')" - ], - "outputs": [], - "metadata": {} + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "One can start the server from a separate process as well as in background of the current process:" - ], - "metadata": {} + ] }, { "cell_type": "code", "execution_count": 4, - "source": [ - "# NBVAL_IGNORE_OUTPUT\n", - "rjit.start_server(background=True)" - ], + "metadata": {}, "outputs": [ { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ - "staring rpc.thrift server: /home/guilhermeleobas/git/rbc/rbc/remotejit.thrift" + "staring rpc.thrift server: /home/pearu/git/xnd-project/rbc/rbc/remotejit.thrift" ] } ], - "metadata": {} + "source": [ + "# NBVAL_IGNORE_OUTPUT\n", + "rjit.start_server(background=True)" + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "The server will be stopped at the end of this notebook, see below." - ], - "metadata": {} + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "## Use `rjit` as decorator with signature specifications\n", "\n", @@ -97,164 +98,164 @@ "If a function uses annotations, these are also used for determining the signature of a function.\n", "\n", "For instance, the following example will define an `add` function for arguments with `int` or `float` type:" - ], - "metadata": {} + ] }, { "cell_type": "code", "execution_count": 5, + "metadata": {}, + "outputs": [], "source": [ "@rjit('f64(f64,f64)')\n", "def add(a: int, b: int) -> int:\n", " return a + b" - ], - "outputs": [], - "metadata": {} + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "#### To view the currently defined signatures" - ], - "metadata": {} + ] }, { "cell_type": "code", - "execution_count": 7, - "source": [ - "for device, target_info in rjit.targets.items():\n", - " with target_info:\n", - " print('\\n'.join(map(str, add.get_signatures())))" - ], + "execution_count": 6, + "metadata": {}, "outputs": [ { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ "float64(float64, float64)\n", "int64 add(int64, int64)\n" ] } ], - "metadata": {} + "source": [ + "for device, target_info in rjit.targets.items():\n", + " with target_info:\n", + " print('\\n'.join(map(str, add.get_signatures())))" + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "## Try it out:" - ], - "metadata": {} + ] }, { "cell_type": "code", - "execution_count": 8, - "source": [ - "add(1, 2) # int inputs" - ], + "execution_count": 7, + "metadata": {}, "outputs": [ { - "output_type": "execute_result", "data": { "text/plain": [ "3" ] }, + "execution_count": 7, "metadata": {}, - "execution_count": 8 + "output_type": "execute_result" } ], - "metadata": {} + "source": [ + "add(1, 2) # int inputs" + ] }, { "cell_type": "code", - "execution_count": 9, - "source": [ - "add(1.5, 2.0) # float inputs" - ], + "execution_count": 8, + "metadata": {}, "outputs": [ { - "output_type": "execute_result", "data": { "text/plain": [ "3.5" ] }, + "execution_count": 8, "metadata": {}, - "execution_count": 9 + "output_type": "execute_result" } ], - "metadata": {} + "source": [ + "add(1.5, 2.0) # float inputs" + ] }, { "cell_type": "code", - "execution_count": 10, - "source": [ - "try: # complex inputs\n", - " add(1j, 2) # expect a failure\n", - "except Exception as msg:\n", - " print(msg)" - ], + "execution_count": 9, + "metadata": {}, "outputs": [ { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ - "found no matching function type to given argument types `complex128, int64`. Available function types: float64(float64, float64); int64 add(int64, int64)\n" + "found no matching function signature to given argument types:\n", + " (complex128, int64) -> ...\n", + " available function signatures:\n", + " float64(float64, float64)\n", + " int64 add(int64, int64)\n" ] } ], - "metadata": {} + "source": [ + "try: # complex inputs\n", + " add(1j, 2) # expect a failure\n", + "except Exception as msg:\n", + " print(msg)" + ] }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 10, + "metadata": {}, + "outputs": [], "source": [ "# add support for complex inputs:\n", "_ = add.signature('complex128(complex128, complex128)')" - ], - "outputs": [], - "metadata": {} + ] }, { "cell_type": "code", - "execution_count": 12, - "source": [ - "add(1j, 2) # now it works" - ], + "execution_count": 11, + "metadata": {}, "outputs": [ { - "output_type": "execute_result", "data": { "text/plain": [ "(2+1j)" ] }, + "execution_count": 11, "metadata": {}, - "execution_count": 12 + "output_type": "execute_result" } ], - "metadata": {} + "source": [ + "add(1j, 2) # now it works" + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "## Debugging\n", "\n", "For debugging, one can view the generated LLVM IR using the `add.describe` method or just printing the `add` object:" - ], - "metadata": {} + ] }, { "cell_type": "code", - "execution_count": 13, - "source": [ - "# NBVAL_IGNORE_OUTPUT\n", - "print(add)" - ], + "execution_count": 12, + "metadata": {}, "outputs": [ { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ "\n", "--------------------------------------cpu---------------------------------------\n", @@ -262,9 +263,9 @@ "source_filename = \"\"\n", "target triple = \"x86_64-unknown-linux-gnu\"\n", "\n", - "@\"_ZN08NumbaEnv8__main__7add$244Edd\" = common local_unnamed_addr global i8* null\n", - "@\"_ZN08NumbaEnv8__main__7add$245E10complex12810complex128\" = common local_unnamed_addr global i8* null\n", - "@\"_ZN08NumbaEnv8__main__7add$246Exx\" = common local_unnamed_addr global i8* null\n", + "@_ZN08NumbaEnv8__main__7add_244B40c8tJTC_2fWQA9HW1CcAv0EjzIkAdRoAEtoAgA_3dEdd = common local_unnamed_addr global i8* null\n", + "@_ZN08NumbaEnv8__main__7add_245B40c8tJTC_2fWQA9HW1CcAv0EjzIkAdRoAEtoAgA_3dE10complex12810complex128 = common local_unnamed_addr global i8* null\n", + "@_ZN08NumbaEnv8__main__7add_246B40c8tJTC_2fWQA9HW1CcAv0EjzIkAdRoAEtoAgA_3dExx = common local_unnamed_addr global i8* null\n", "\n", "; Function Attrs: norecurse nounwind readnone\n", "define double @add_daddA(double %.1, double %.2) local_unnamed_addr #0 {\n", @@ -304,37 +305,44 @@ ] } ], - "metadata": {} + "source": [ + "# NBVAL_IGNORE_OUTPUT\n", + "print(add)" + ] }, { "cell_type": "markdown", + "metadata": {}, "source": [ "## Stopping the RBC server" - ], - "metadata": {} + ] }, { "cell_type": "code", - "execution_count": 14, - "source": [ - "rjit.stop_server()" - ], + "execution_count": 13, + "metadata": {}, "outputs": [ { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ "... stopping rpc.thrift server\n" ] } ], - "metadata": {} + "source": [ + "rjit.stop_server()" + ] } ], "metadata": { + "interpreter": { + "hash": "d5f7c970bbb39fa37ad8320758958011db57178b67e8623b46fd6c0065ba8519" + }, "kernelspec": { - "name": "python3", - "display_name": "Python 3.8.12 64-bit ('rbc': conda)" + "display_name": "Python 3", + "language": "python", + "name": "python3" }, "language_info": { "codemirror_mode": { @@ -346,12 +354,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.12" - }, - "interpreter": { - "hash": "d5f7c970bbb39fa37ad8320758958011db57178b67e8623b46fd6c0065ba8519" + "version": "3.7.3" } }, "nbformat": 4, "nbformat_minor": 4 -} \ No newline at end of file +} diff --git a/rbc/errors.py b/rbc/errors.py index d8617a148..2428a5aa0 100644 --- a/rbc/errors.py +++ b/rbc/errors.py @@ -3,6 +3,10 @@ """ +from rbc.utils import get_version +from numba.core.errors import TypingError + + class OmnisciServerError(Exception): """ Raised when OmnisciDB server raises a runtime error that RBC knows @@ -13,10 +17,14 @@ class OmnisciServerError(Exception): class UnsupportedError(Exception): """ - Raised when an attempt to use a feature that is not supported - for a given target. + Raised when an attempt to use a feature that is not supported for + a given target. The attempt may be made both in lowering as well + as in typing phase. """ - pass + def __init__(self, *args, **kwargs): + # numba mangles exception messages. Here we insert the exception + # name so that irtools can demangle the messages. + Exception.__init__(self, type(self).__name__, *args, **kwargs) class ForbiddenNameError(Exception): @@ -35,3 +43,13 @@ class ForbiddenIntrinsicError(Exception): https://github.com/xnd-project/rbc/issues/207 """ pass + + +if get_version('numba') < (0, 55): + class NumbaTypeError(TypingError): + pass + + class NumbaNotImplementedError(TypingError): + pass +else: + from numba.core.errors import NumbaTypeError, NumbaNotImplementedError # noqa: F401 diff --git a/rbc/extension_functions.thrift b/rbc/extension_functions.thrift index 613ea3e79..2889412cf 100644 --- a/rbc/extension_functions.thrift +++ b/rbc/extension_functions.thrift @@ -60,7 +60,8 @@ enum TOutputBufferSizeType { kConstant, kUserSpecifiedConstantParameter, kUserSpecifiedRowMultiplier, - kTableFunctionSpecifiedParameter + kTableFunctionSpecifiedParameter, + kPreFlightParameter } struct TUserDefinedFunction { diff --git a/rbc/externals/__init__.py b/rbc/externals/__init__.py index 07cb41529..ac933cf17 100644 --- a/rbc/externals/__init__.py +++ b/rbc/externals/__init__.py @@ -1,15 +1,17 @@ -import types as py_types from rbc.targetinfo import TargetInfo -from rbc.typesystem import Type -from numba.core import funcdesc, typing +from numba.core import funcdesc def gen_codegen(fn_name): - def codegen(context, builder, sig, args): - # Need to retrieve the function name again - fndesc = funcdesc.ExternalFunctionDescriptor(fn_name, sig.return_type, sig.args) - func = context.declare_external_function(builder.module, fndesc) - return builder.call(func, args) + if fn_name.startswith('llvm.'): + def codegen(context, builder, sig, args): + func = builder.module.declare_intrinsic(fn_name, [a.type for a in args]) + return builder.call(func, args) + else: + def codegen(context, builder, sig, args): + fndesc = funcdesc.ExternalFunctionDescriptor(fn_name, sig.return_type, sig.args) + func = context.declare_external_function(builder.module, fndesc) + return builder.call(func, args) return codegen @@ -29,37 +31,25 @@ def sanitize(name): return name -def register_external( - fname, - retty, - argtys, - module_name, - module_globals, - typing_registry, - lowering_registry, - doc, -): - - # expose - fn = eval(f'lambda {",".join(map(lambda x: sanitize(x.name), argtys))}: None', {}, {}) - _key = py_types.FunctionType(fn.__code__, {}, fname) - _key.__module__ = __name__ - globals()[fname] = _key - - # typing - @typing_registry.register_global(_key) - class ExternalTemplate(typing.templates.AbstractTemplate): - key = _key - - def generic(self, args, kws): - retty_ = Type.fromobject(retty).tonumba() - argtys_ = tuple(map(lambda x: Type.fromobject(x.ty).tonumba(), argtys)) - codegen = gen_codegen(fname) - lowering_registry.lower(_key, *argtys_)(codegen) - return retty_(*argtys_) +def make_intrinsic(fname, retty, argnames, module_name, module_globals, doc): + argnames = tuple(map(lambda x: sanitize(x), argnames)) + fn_str = f''' +from numba.core.extending import intrinsic +@intrinsic +def {fname}(typingctx, {", ".join(argnames)}): + from rbc.typesystem import Type + retty_ = Type.fromobject("{retty}").tonumba() + argnames_ = tuple(map(lambda x: Type.fromobject(x).tonumba(), [{", ".join(argnames)}])) # noqa: E501 + signature = retty_(*argnames_) + def codegen(context, builder, sig, args): + from numba.core import funcdesc + fndesc = funcdesc.ExternalFunctionDescriptor("{fname}", sig.return_type, sig.args) # noqa: E501 + func = context.declare_external_function(builder.module, fndesc) + return builder.call(func, args) + return signature, codegen +''' - module_globals[fname] = _key - _key.__module__ = module_name - _key.__doc__ = doc - del globals()[fname] - return _key + exec(fn_str, module_globals) + fn = module_globals[fname] + fn.__doc__ = doc + return fn diff --git a/rbc/externals/cmath.py b/rbc/externals/cmath.py index 8b231dac5..e1cbe6c7f 100644 --- a/rbc/externals/cmath.py +++ b/rbc/externals/cmath.py @@ -3,17 +3,10 @@ from collections import namedtuple -from . import register_external -from numba.core import imputils, typing +from . import make_intrinsic arg = namedtuple("arg", ("name", "ty")) -# Typing -typing_registry = typing.templates.Registry() - -# Lowering -lowering_registry = imputils.Registry() - cmath = { # Trigonometric "cos": ("double", [arg(name="x", ty="double")]), @@ -166,7 +159,7 @@ # Other functions "fabs": ("double", [arg(name="x", ty="double")]), "fabsf": ("float", [arg(name="x", ty="float")]), - "abs": ("long long", [arg(name="x", ty="double")]), + "abs": ("long long int", [arg(name="x", ty="double")]), "absf": ("long", [arg(name="x", ty="float")]), "fma": ( "double", @@ -188,7 +181,6 @@ for fname, (retty, args) in cmath.items(): + argnames = [arg.name for arg in args] doc = f"C math function {fname}" - register_external( - fname, retty, args, __name__, globals(), typing_registry, lowering_registry, doc - ) + fn = make_intrinsic(fname, retty, argnames, __name__, globals(), doc) diff --git a/rbc/externals/libdevice.py b/rbc/externals/libdevice.py index 0ed6e570e..fe09b6a3c 100644 --- a/rbc/externals/libdevice.py +++ b/rbc/externals/libdevice.py @@ -1,20 +1,10 @@ """https://docs.nvidia.com/cuda/libdevice-users-guide/index.html """ -from . import register_external -from numba.core import imputils, typing # noqa: E402 +from . import make_intrinsic from numba.cuda import libdevicefuncs # noqa: E402 -# Typing -typing_registry = typing.templates.Registry() - -# Lowering -lowering_registry = imputils.Registry() - for fname, (retty, args) in libdevicefuncs.functions.items(): + argnames = [arg.name for arg in args] doc = f"libdevice function {fname}" - fn = register_external( - fname, retty, args, __name__, globals(), typing_registry, lowering_registry, doc - ) - - fn.__name__ = fname # for sphinx + fn = make_intrinsic(fname, retty, argnames, __name__, globals(), doc) diff --git a/rbc/externals/macros.py b/rbc/externals/macros.py index e48124e31..a8ab06316 100644 --- a/rbc/externals/macros.py +++ b/rbc/externals/macros.py @@ -16,15 +16,14 @@ __all__ = ["sizeof", "cast"] -import functools from llvmlite import ir from numba.core import extending, imputils, typing, typeconv from numba.core import types as nb_types from rbc.typesystem import Type -typing_registry = typing.templates.Registry() -lowering_registry = imputils.Registry() +typing_registry = typing.templates.builtin_registry +lowering_registry = imputils.builtin_registry @extending.intrinsic @@ -64,13 +63,6 @@ def codegen(context, builder, signature, args): return sig, codegen -# fix docstring for intrinsics -# TODO: remove this after Numba 0.54 is released -# https://github.com/numba/numba/pull/6915 -for __func in (sizeof, cast): - functools.update_wrapper(__func, __func._defn) - - @extending.overload_method(type(nb_types.voidptr), "cast") def voidptr_cast_to_any(ptr, typ): """Convenience method for casting voidptr to any pointer type.""" diff --git a/rbc/externals/omniscidb.py b/rbc/externals/omniscidb.py index c2d3611cc..e4e290365 100644 --- a/rbc/externals/omniscidb.py +++ b/rbc/externals/omniscidb.py @@ -1,10 +1,8 @@ """External functions defined by the OmniSciDB server """ - -import functools from rbc import irutils -from rbc.errors import UnsupportedError +from rbc.errors import UnsupportedError, NumbaTypeError from rbc.targetinfo import TargetInfo from numba.core import extending, types as nb_types from numba.core.cgutils import make_bytearray, global_constant @@ -45,7 +43,7 @@ def table_function_error(typingctx, message): ``message`` must be a string literal. """ if not isinstance(message, nb_types.StringLiteral): - raise TypeError(f"expected StringLiteral but got {type(message).__name__}") + raise NumbaTypeError(f"expected StringLiteral but got {type(message).__name__}") def codegen(context, builder, sig, args): int8ptr = ir.PointerType(ir.IntType(8)) @@ -63,8 +61,3 @@ def codegen(context, builder, sig, args): sig = nb_types.int32(message) return sig, codegen - - -# fix docstring for intrinsics -for __func in (set_output_row_size, table_function_error): - functools.update_wrapper(__func, __func._defn) diff --git a/rbc/externals/stdio.py b/rbc/externals/stdio.py index fe0d96ec1..e6889a8d1 100644 --- a/rbc/externals/stdio.py +++ b/rbc/externals/stdio.py @@ -1,12 +1,12 @@ """https://en.cppreference.com/w/c/io """ -import functools from rbc import irutils from llvmlite import ir from rbc.targetinfo import TargetInfo from numba.core import cgutils, extending from numba.core import types as nb_types +from rbc.errors import NumbaTypeError # some errors are available for Numba >= 0.55 int32_t = ir.IntType(32) @@ -56,9 +56,4 @@ def codegen(context, builder, signature, args): return sig, codegen else: - raise TypeError(f"expected StringLiteral but got {type(format_type).__name__}") - - -# fix docstring for intrinsics -for __func in (printf, fflush): - functools.update_wrapper(__func, __func._defn) + raise NumbaTypeError(f"expected StringLiteral but got {type(format_type).__name__}") diff --git a/rbc/irtools.py b/rbc/irtools.py index 235bf145f..7a19a1fe0 100644 --- a/rbc/irtools.py +++ b/rbc/irtools.py @@ -3,21 +3,31 @@ import re import warnings -from contextlib import contextmanager from collections import defaultdict -import types as py_types from llvmlite import ir import llvmlite.binding as llvm from .targetinfo import TargetInfo from .errors import UnsupportedError from .utils import get_version -from . import libfuncs, structure_type +from . import libfuncs from rbc import externals -from rbc.omnisci_backend import mathimpl -from numba.core import codegen, cpu, compiler_lock, \ - registry, typing, compiler, sigutils, cgutils, \ - extending +from .irutils import switch_target +from numba.core import ( + registry, + compiler, + sigutils, + cgutils, + extending, + typing, + target_extension, + cpu) from numba.core import errors as nb_errors +from rbc.omnisci_backend import ( + JITRemoteTypingContext, + JITRemoteTargetContext, + omniscidb_cpu_target, + omniscidb_gpu_target, +) int32_t = ir.IntType(32) @@ -67,129 +77,6 @@ def get_called_functions(library, funcname=None): # --------------------------------------------------------------------------- -class JITRemoteCodeLibrary(codegen.JITCodeLibrary): - """JITRemoteCodeLibrary was introduce to prevent numba from calling functions - that checks if the module is final. See xnd-project/rbc issue #87. - """ - - def get_pointer_to_function(self, name): - """We can return any random number here! This is just to prevent numba from - trying to check if the symbol given by "name" is defined in the module. - In cases were RBC is calling an external function (i.e. allocate_varlen_buffer) - the symbol will not be defined in the module, resulting in an error. - """ - return 0 - - def _finalize_specific(self): - """Same as codegen.JITCodeLibrary._finalize_specific but without - calling _ensure_finalize at the end - """ - self._codegen._scan_and_fix_unresolved_refs(self._final_module) - - -class JITRemoteCodegen(codegen.JITCPUCodegen): - _library_class = JITRemoteCodeLibrary - - def _get_host_cpu_name(self): - target_info = TargetInfo() - return target_info.device_name - - def _get_host_cpu_features(self): - target_info = TargetInfo() - features = target_info.device_features - server_llvm_version = target_info.llvm_version - if server_llvm_version is None or target_info.is_gpu: - return '' - client_llvm_version = llvm.llvm_version_info - - # See https://github.com/xnd-project/rbc/issues/45 - remove_features = { - (11, 8): ['tsxldtrk', 'amx-tile', 'amx-bf16', 'serialize', 'amx-int8', - 'avx512vp2intersect', 'tsxldtrk', 'amx-tile', 'amx-bf16', - 'serialize', 'amx-int8', 'avx512vp2intersect', 'tsxldtrk', - 'amx-tile', 'amx-bf16', 'serialize', 'amx-int8', - 'avx512vp2intersect', 'cx8', 'enqcmd', 'avx512bf16'], - (11, 10): ['tsxldtrk', 'amx-tile', 'amx-bf16', 'serialize', 'amx-int8'], - (9, 8): ['cx8', 'enqcmd', 'avx512bf16'], - }.get((server_llvm_version[0], client_llvm_version[0]), []) - for f in remove_features: - features = features.replace('+' + f, '').replace('-' + f, '') - return features - - def _customize_tm_options(self, options): - super()._customize_tm_options(options) - # fix reloc_model as the base method sets it using local target - target_info = TargetInfo() - if target_info.arch.startswith('x86'): - reloc_model = 'static' - else: - reloc_model = 'default' - options['reloc'] = reloc_model - - def set_env(self, env_name, env): - return None - - -class JITRemoteTypingContext(typing.Context): - def load_additional_registries(self): - for module in externals.__dict__.values(): - if not isinstance(module, py_types.ModuleType): - continue - - typing_registry = getattr(module, 'typing_registry', None) - if typing_registry: - self.install_registry(typing_registry) - - self.install_registry(mathimpl.typing_registry) - self.install_registry(structure_type.typing_registry) - super().load_additional_registries() - - -class JITRemoteTargetContext(cpu.CPUContext): - - @compiler_lock.global_compiler_lock - def init(self): - target_info = TargetInfo() - self.address_size = target_info.bits - self.is32bit = (self.address_size == 32) - self._internal_codegen = JITRemoteCodegen("numba.exec") - - def load_additional_registries(self): - for module in externals.__dict__.values(): - if not isinstance(module, py_types.ModuleType): - continue - - if 'rbc.externals' not in module.__name__: - continue - - lowering_registry = getattr(module, 'lowering_registry', None) - if lowering_registry: - self.install_registry(lowering_registry) - - self.install_registry(mathimpl.lowering_registry) - self.install_registry(structure_type.lowering_registry) - super().load_additional_registries() - - def get_executable(self, library, fndesc, env): - return None - - def post_lowering(self, mod, library): - pass - - -# --------------------------------------------------------------------------- -# Code generation methods - - -@contextmanager -def replace_numba_internals_hack(): - # Hackish solution to prevent numba from calling _ensure_finalize. See issue #87 - _internal_codegen_bkp = registry.cpu_target.target_context._internal_codegen - registry.cpu_target.target_context._internal_codegen = JITRemoteCodegen("numba.exec") - yield - registry.cpu_target.target_context._internal_codegen = _internal_codegen_bkp - - def make_wrapper(fname, atypes, rtype, cres, target: TargetInfo, verbose=False): """Make wrapper function to numba compile result. @@ -267,7 +154,7 @@ def make_wrapper(fname, atypes, rtype, cres, target: TargetInfo, verbose=False): def compile_instance(func, sig, - target: TargetInfo, + target_info: TargetInfo, typing_context, target_context, pipeline_class, @@ -299,13 +186,9 @@ def compile_instance(func, sig, library=main_library, locals={}, pipeline_class=pipeline_class) - except UnsupportedError as msg: - for m in re.finditer(r'[|]UnsupportedError[|](.*?)\n', str(msg), re.S): - warnings.warn(f'Skipping {fname}: {m.group(0)[18:]}') - return - except nb_errors.TypingError as msg: - for m in re.finditer(r'[|]UnsupportedError[|](.*?)\n', str(msg), re.S): - warnings.warn(f'Skipping {fname}: {m.group(0)[18:]}') + except (UnsupportedError, nb_errors.TypingError, nb_errors.LoweringError) as msg: + for m in re.finditer(r'UnsupportedError(.*?)\n', str(msg), re.S): + warnings.warn(f'Skipping {fname}:{m.group(0)[18:]}') break else: raise @@ -316,7 +199,7 @@ def compile_instance(func, sig, result = get_called_functions(cres.library, cres.fndesc.llvm_func_name) for f in result['declarations']: - if target.supports(f): + if target_info.supports(f): continue warnings.warn(f'Skipping {fname} that uses undefined function `{f}`') return @@ -324,18 +207,18 @@ def compile_instance(func, sig, nvvmlib = libfuncs.Library.get('nvvm') llvmlib = libfuncs.Library.get('llvm') for f in result['intrinsics']: - if target.is_gpu: + if target_info.is_gpu: if f in nvvmlib: continue - if target.is_cpu: + if target_info.is_cpu: if f in llvmlib: continue warnings.warn(f'Skipping {fname} that uses unsupported intrinsic `{f}`') return - make_wrapper(fname, args, return_type, cres, target, verbose=debug) + make_wrapper(fname, args, return_type, cres, target_info, verbose=debug) main_module = main_library._final_module for lib in result['libraries']: @@ -380,81 +263,91 @@ def compile_to_LLVM(functions_and_signatures, LLVM module instance. To get the IR string, use `str(module)`. """ - target_desc = registry.cpu_target - - typing_context = JITRemoteTypingContext() - target_context = JITRemoteTargetContext(typing_context) + device = target_info.name + software = target_info.software[0] + + if software == 'OmnisciDB': + target_name = f'omniscidb_{device}' + target_desc = omniscidb_cpu_target if device == 'cpu' else omniscidb_gpu_target + typing_context = JITRemoteTypingContext() + target_context = JITRemoteTargetContext(typing_context, target_name) + else: + target_name = 'cpu' + target_desc = registry.cpu_target + typing_context = typing.Context() + target_context = cpu.CPUContext(typing_context, target_name) # Bring over Array overloads (a hack): target_context._defns = target_desc.target_context._defns - with replace_numba_internals_hack(): - codegen = target_context.codegen() - main_library = codegen.create_library('rbc.irtools.compile_to_IR') - main_module = main_library._final_module - - if user_defined_llvm_ir is not None: - if isinstance(user_defined_llvm_ir, str): - user_defined_llvm_ir = llvm.parse_assembly(user_defined_llvm_ir) - assert isinstance(user_defined_llvm_ir, llvm.ModuleRef) - main_module.link_in(user_defined_llvm_ir, preserve=True) - - succesful_fids = [] - function_names = [] - for func, signatures in functions_and_signatures: - for fid, sig in signatures.items(): - fname = compile_instance(func, sig, target_info, typing_context, - target_context, pipeline_class, - main_library, - debug=debug) - if fname is not None: - succesful_fids.append(fid) - function_names.append(fname) - - add_byval_metadata(main_library) - main_library._optimize_final_module() + codegen = target_context.codegen() + main_library = codegen.create_library(f'rbc.irtools.compile_to_IR_{software}_{device}') + main_module = main_library._final_module - # Remove unused defined functions and declarations - used_symbols = defaultdict(set) - for fname in function_names: - for k, v in get_called_functions(main_library, fname).items(): - used_symbols[k].update(v) + if user_defined_llvm_ir is not None: + if isinstance(user_defined_llvm_ir, str): + user_defined_llvm_ir = llvm.parse_assembly(user_defined_llvm_ir) + assert isinstance(user_defined_llvm_ir, llvm.ModuleRef) + main_module.link_in(user_defined_llvm_ir, preserve=True) + + succesful_fids = [] + function_names = [] + for func, signatures in functions_and_signatures: + for fid, sig in signatures.items(): + with switch_target(target_name): + with target_extension.target_override(target_name): + fname = compile_instance(func, sig, target_info, typing_context, + target_context, pipeline_class, + main_library, + debug=debug) + if fname is not None: + succesful_fids.append(fid) + function_names.append(fname) + + add_byval_metadata(main_library) + main_library._optimize_final_module() + + # Remove unused defined functions and declarations + used_symbols = defaultdict(set) + for fname in function_names: + for k, v in get_called_functions(main_library, fname).items(): + used_symbols[k].update(v) + + all_symbols = get_called_functions(main_library) + + unused_symbols = defaultdict(set) + for k, lst in all_symbols.items(): + if k == 'libraries': + continue + for fn in lst: + if fn not in used_symbols[k]: + unused_symbols[k].add(fn) + + changed = False + for f in main_module.functions: + fn = f.name + if fn.startswith('llvm.'): + if f.name in unused_symbols['intrinsics']: + f.linkage = llvm.Linkage.external + changed = True + elif f.is_declaration: + if f.name in unused_symbols['declarations']: + f.linkage = llvm.Linkage.external + changed = True + else: + if f.name in unused_symbols['defined']: + f.linkage = llvm.Linkage.private + changed = True - all_symbols = get_called_functions(main_library) + # TODO: determine unused global_variables and struct_types - unused_symbols = defaultdict(set) - for k, lst in all_symbols.items(): - if k == 'libraries': - continue - for fn in lst: - if fn not in used_symbols[k]: - unused_symbols[k].add(fn) - - changed = False - for f in main_module.functions: - fn = f.name - if fn.startswith('llvm.'): - if f.name in unused_symbols['intrinsics']: - f.linkage = llvm.Linkage.external - changed = True - elif f.is_declaration: - if f.name in unused_symbols['declarations']: - f.linkage = llvm.Linkage.external - changed = True - else: - if f.name in unused_symbols['defined']: - f.linkage = llvm.Linkage.private - changed = True - - # TODO: determine unused global_variables and struct_types - - if changed: - main_library._optimize_final_module() - - main_module.verify() - main_library._finalized = True - main_module.triple = target_info.triple - main_module.data_layout = target_info.datalayout + if changed: + main_library._optimize_final_module() + + main_module.verify() + main_library._finalized = True + main_module.triple = target_info.triple + main_module.data_layout = target_info.datalayout return main_module, succesful_fids diff --git a/rbc/irutils.py b/rbc/irutils.py index df182d549..666beeab6 100644 --- a/rbc/irutils.py +++ b/rbc/irutils.py @@ -1,5 +1,5 @@ from rbc.utils import get_version -from numba.core import cgutils +from numba.core import cgutils, dispatcher, retarget from llvmlite import ir @@ -29,3 +29,28 @@ def get_member_value(builder, data, idx): assert data.opname == 'load', data.opname struct = data.operands[0] return builder.load(builder.gep(struct, [int32_t(0), int32_t(idx)])) + + +class Retarget(retarget.BasicRetarget): + + def __init__(self, target_name): + self.target_name = target_name + super().__init__() + + @property + def output_target(self): + return self.target_name + + def compile_retarget(self, cpu_disp): + from numba import njit + kernel = njit(_target=self.target_name)(cpu_disp.py_func) + return kernel + + +def switch_target(target_name): + if get_version('numba') > (0, 55): + tc = dispatcher.TargetConfigurationStack + else: + tc = dispatcher.TargetConfig + + return tc.switch_target(Retarget(target_name)) diff --git a/rbc/libfuncs.py b/rbc/libfuncs.py index a41c3446b..35b512d8e 100644 --- a/rbc/libfuncs.py +++ b/rbc/libfuncs.py @@ -1,6 +1,8 @@ """Collections of library function names. """ +import rbc.rbclib + class Library: """Base class for a collection of library function names. @@ -24,6 +26,8 @@ def get(libname, _cache={}): r = LLVMIntrinsics() elif libname == 'omniscidb': r = OmnisciDB() + elif libname == 'rbclib': + r = RBCLib() else: raise ValueError(f'Unknown library {libname}') _cache[libname] = r @@ -307,3 +311,14 @@ def check(self, fname): ull2double_ru ull2double_rz ull2float_rd ull2float_rn ull2float_ru ull2float_rz ullmax ullmin umax umin umul24 umul64hi umulhi urhadd usad y0 y0f y1 y1f yn ynf '''.strip().split()) + + +class RBCLib(Library): + + name = 'rbclib' + # _function_names contains the list of functions which is exported by the + # library. See Library.check() + from rbc.rbclib import FUNCTION_NAMES as _function_names + + def __init__(self): + rbc.rbclib.load_inside_llvm() diff --git a/rbc/omnisci_backend/__init__.py b/rbc/omnisci_backend/__init__.py index d9640a911..3be6346b8 100644 --- a/rbc/omnisci_backend/__init__.py +++ b/rbc/omnisci_backend/__init__.py @@ -1,12 +1,18 @@ -from .numpy_funcs import * # noqa: F401, F403 -from .npyimpl import * # noqa: F401, F403 from .omnisci_array import * # noqa: F401, F403 from .omnisci_column import * # noqa: F401, F403 from .omnisci_bytes import * # noqa: F401, F403 from .omnisci_metatype import * # noqa: F401, F403 from .omnisci_text_encoding import * # noqa: F401, F403 -from .numpy_ufuncs import * # noqa: F401, F403 from .omnisci_pipeline import * # noqa: F401, F403 -from .python_operators import * # noqa: F401, F403 from .omnisci_column_list import * # noqa: F401, F403 from .omnisci_table_function_manager import * # noqa: F401, F403 +from .omnisci_compiler import * # noqa: F401, F403 + +import rbc.omnisci_backend.mathimpl as math # noqa: F401 +import rbc.omnisci_backend.npyimpl as np # noqa: F401 +import rbc.omnisci_backend.python_operators as operators # noqa: F401 + +# initialize the array api +from rbc.stdlib import array_api # noqa: F401 + +__all__ = [s for s in dir() if not s.startswith('_')] diff --git a/rbc/omnisci_backend/mathimpl.py b/rbc/omnisci_backend/mathimpl.py index f376516a9..1ccee26d6 100644 --- a/rbc/omnisci_backend/mathimpl.py +++ b/rbc/omnisci_backend/mathimpl.py @@ -1,13 +1,18 @@ import math -from rbc.externals import gen_codegen, dispatch_codegen -from numba.core import imputils +from rbc.externals import gen_codegen from numba.core.typing.templates import ConcreteTemplate, signature, Registry from numba.types import float32, float64, int32, int64, uint64, intp +from numba.core.intrinsics import INTR_TO_CMATH +from .omnisci_compiler import omnisci_cpu_registry, omnisci_gpu_registry -# Typing -typing_registry = Registry() -infer_global = typing_registry.register_global +lower_cpu = omnisci_cpu_registry.lower +lower_gpu = omnisci_gpu_registry.lower + + +registry = Registry() +infer_global = registry.register_global + # Adding missing cases in Numba @infer_global(math.log2) # noqa: E302 @@ -41,11 +46,6 @@ class Math_converter(ConcreteTemplate): ] -# Lowering -lowering_registry = imputils.Registry() -lower = lowering_registry.lower - - booleans = [] booleans += [("isnand", "isnanf", math.isnan)] booleans += [("isinfd", "isinff", math.isinf)] @@ -83,22 +83,31 @@ class Math_converter(ConcreteTemplate): binarys = [] binarys += [("copysign", "copysignf", math.copysign)] binarys += [("atan2", "atan2f", math.atan2)] -binarys += [("pow", "powf", math.pow)] binarys += [("fmod", "fmodf", math.fmod)] binarys += [("hypot", "hypotf", math.hypot)] binarys += [("remainder", "remainderf", math.remainder)] def impl_unary(fname, key, typ): - cpu = gen_codegen(fname) + if fname in INTR_TO_CMATH.values(): + # use llvm intrinsics when possible + cpu = gen_codegen(f'llvm.{fname}') + else: + cpu = gen_codegen(fname) gpu = gen_codegen(f"__nv_{fname}") - lower(key, typ)(dispatch_codegen(cpu, gpu)) + lower_cpu(key, typ)(cpu) + lower_gpu(key, typ)(gpu) def impl_binary(fname, key, typ): - cpu = gen_codegen(fname) + if fname in INTR_TO_CMATH.values(): + # use llvm intrinsics when possible + cpu = gen_codegen(f'llvm.{fname}') + else: + cpu = gen_codegen(fname) gpu = gen_codegen(f"__nv_{fname}") - lower(key, typ, typ)(dispatch_codegen(cpu, gpu)) + lower_cpu(key, typ, typ)(cpu) + lower_gpu(key, typ, typ)(gpu) for fname64, fname32, key in unarys: @@ -113,17 +122,42 @@ def impl_binary(fname, key, typ): # manual mapping def impl_ldexp(): + # cpu ldexp_cpu = gen_codegen('ldexp') - ldexp_gpu = gen_codegen('__nv_ldexp') - ldexpf_cpu = gen_codegen('ldexpf') - ldexpf_gpu = gen_codegen('__nv_ldexpf') + lower_cpu(math.ldexp, float64, int32)(ldexp_cpu) + lower_cpu(math.ldexp, float32, int32)(ldexpf_cpu) - lower(math.ldexp, float64, int32)(dispatch_codegen(ldexp_cpu, ldexp_gpu)) - lower(math.ldexp, float32, int32)(dispatch_codegen(ldexpf_cpu, ldexpf_gpu)) + # gpu + ldexp_gpu = gen_codegen('__nv_ldexp') + ldexpf_gpu = gen_codegen('__nv_ldexpf') + lower_gpu(math.ldexp, float64, int32)(ldexp_gpu) + lower_gpu(math.ldexp, float32, int32)(ldexpf_gpu) + + +def impl_pow(): + # cpu + pow_cpu = gen_codegen('pow') + powf_cpu = gen_codegen('powf') + lower_cpu(math.pow, float64, float64)(pow_cpu) + lower_cpu(math.pow, float32, float32)(powf_cpu) + lower_cpu(math.pow, float64, int32)(pow_cpu) + lower_cpu(math.pow, float32, int32)(powf_cpu) + + # gpu + pow_gpu = gen_codegen('__nv_pow') + powf_gpu = gen_codegen('__nv_powf') + powi_gpu = gen_codegen('__nv_powi') + powif_gpu = gen_codegen('__nv_powif') + lower_gpu(math.pow, float64, float64)(pow_gpu) + lower_gpu(math.pow, float32, float32)(powf_gpu) + lower_gpu(math.pow, float64, int32)(powi_gpu) + lower_gpu(math.pow, float32, int32)(powif_gpu) impl_ldexp() +impl_pow() + # CPU only: # math.gcd diff --git a/rbc/omnisci_backend/numpy_funcs.py b/rbc/omnisci_backend/numpy_funcs.py deleted file mode 100644 index 96b77437d..000000000 --- a/rbc/omnisci_backend/numpy_funcs.py +++ /dev/null @@ -1,300 +0,0 @@ -import numpy as np -from rbc.externals.stdio import printf -from rbc import typesystem -from .omnisci_array import Array, ArrayPointer -from numba import njit -from numba.core import extending, types, errors -from numba.np import numpy_support - - -def expose_and_overload(func): - name = func.__name__ - s = f'def {name}(*args, **kwargs): pass' - exec(s, globals()) - - fn = globals()[name] - decorate = extending.overload(fn) - - def wrapper(overload_func): - return decorate(overload_func) - - return wrapper - - -@expose_and_overload(np.full) -def omnisci_np_full(shape, fill_value, dtype=None): - - # XXX: dtype should be infered from fill_value - if dtype is None: - nb_dtype = types.double - else: - nb_dtype = typesystem.Type.fromobject(dtype).tonumba() - - def impl(shape, fill_value, dtype=None): - a = Array(shape, nb_dtype) - a.fill(nb_dtype(fill_value)) - return a - return impl - - -@expose_and_overload(np.full_like) -def omnisci_np_full_like(a, fill_value, dtype=None): - if isinstance(a, ArrayPointer): - if dtype is None: - nb_dtype = a.eltype - else: - nb_dtype = typesystem.Type.fromobject(dtype).tonumba() - - def impl(a, fill_value, dtype=None): - sz = len(a) - other = Array(sz, nb_dtype) - other.fill(nb_dtype(fill_value)) - return other - return impl - - -@expose_and_overload(np.empty_like) -def omnisci_np_empty_like(a, dtype=None): - if isinstance(a, ArrayPointer): - if dtype is None: - nb_dtype = a.eltype - else: - nb_dtype = typesystem.Type.fromobject(dtype).tonumba() - - def impl(a, dtype=None): - other = Array(0, nb_dtype) - other.set_null() - return other - return impl - - -@expose_and_overload(np.empty) -def omnisci_np_empty(shape, dtype=None): - - if dtype is None: - nb_dtype = types.double - else: - nb_dtype = typesystem.Type.fromobject(dtype).tonumba() - - def impl(shape, dtype=None): - arr = Array(shape, nb_dtype) - arr.set_null() - return arr - return impl - - -@expose_and_overload(np.zeros) -def omnisci_np_zeros(shape, dtype=None): - - if dtype is None: - nb_dtype = types.double - else: - nb_dtype = typesystem.Type.fromobject(dtype).tonumba() - - fill_value = False if isinstance(nb_dtype, types.Boolean) else 0 - - def impl(shape, dtype=None): - return full(shape, fill_value, nb_dtype) # noqa: F821 - return impl - - -@expose_and_overload(np.zeros_like) -def omnisci_np_zeros_like(a, dtype=None): - if isinstance(a, ArrayPointer): - if dtype is None: - nb_dtype = a.eltype - else: - nb_dtype = typesystem.Type.fromobject(dtype).tonumba() - - fill_value = False if isinstance(nb_dtype, types.Boolean) else 0 - - def impl(a, dtype=None): - return full_like(a, fill_value, nb_dtype) # noqa: F821 - return impl - - -@expose_and_overload(np.ones) -def omnisci_np_ones(shape, dtype=None): - - if dtype is None: - nb_dtype = types.double - else: - nb_dtype = typesystem.Type.fromobject(dtype).tonumba() - - fill_value = True if isinstance(nb_dtype, types.Boolean) else 1 - - def impl(shape, dtype=None): - return full(shape, fill_value, nb_dtype) # noqa: F821 - return impl - - -@expose_and_overload(np.ones_like) -def omnisci_np_ones_like(a, dtype=None): - if isinstance(a, ArrayPointer): - if dtype is None: - nb_dtype = a.eltype - else: - nb_dtype = dtype - - fill_value = True if isinstance(nb_dtype, types.Boolean) else 1 - - def impl(a, dtype=None): - return full_like(a, fill_value, nb_dtype) # noqa: F821 - return impl - - -@expose_and_overload(np.array) -def omnisci_np_array(a, dtype=None): - - @njit - def omnisci_array_non_empty_copy(a, nb_dtype): - """Implement this here rather than inside "impl". - LLVM DCE pass removes everything if we implement stuff inside "impl" - """ - other = Array(len(a), nb_dtype) - for i in range(len(a)): - other[i] = a[i] - return other - - if isinstance(a, ArrayPointer): - if dtype is None: - nb_dtype = a.eltype - else: - nb_dtype = dtype - - def impl(a, dtype=None): - if a.is_null(): - return empty_like(a) # noqa: F821 - else: - return omnisci_array_non_empty_copy(a, nb_dtype) - return impl - - -def get_type_limits(eltype): - np_dtype = numpy_support.as_dtype(eltype) - if isinstance(eltype, types.Integer): - return np.iinfo(np_dtype) - elif isinstance(eltype, types.Float): - return np.finfo(np_dtype) - else: - msg = 'Type {} not supported'.format(eltype) - raise errors.TypingError(msg) - - -@extending.overload_method(ArrayPointer, 'fill') -def omnisci_array_fill(x, v): - if isinstance(x, ArrayPointer): - def impl(x, v): - for i in range(len(x)): - x[i] = v - return impl - - -@extending.overload(max) -@expose_and_overload(np.max) -@extending.overload_method(ArrayPointer, 'max') -def omnisci_array_max(x, initial=None): - if isinstance(x, ArrayPointer): - min_value = get_type_limits(x.eltype).min - - def impl(x, initial=None): - if len(x) <= 0: - printf("omnisci_array_max: cannot find max of zero-sized array") # noqa: E501 - return min_value - if initial is not None: - m = initial - else: - m = x[0] - for i in range(len(x)): - v = x[i] - if v > m: - m = v - return m - return impl - - -@extending.overload(min) -@extending.overload_method(ArrayPointer, 'min') -def omnisci_array_min(x, initial=None): - if isinstance(x, ArrayPointer): - max_value = get_type_limits(x.eltype).max - - def impl(x, initial=None): - if len(x) <= 0: - printf("omnisci_array_min: cannot find min of zero-sized array") # noqa: E501 - return max_value - if initial is not None: - m = initial - else: - m = x[0] - for i in range(len(x)): - v = x[i] - if v < m: - m = v - return m - return impl - - -@extending.overload(sum) -@expose_and_overload(np.sum) -@extending.overload_method(ArrayPointer, 'sum') -def omnisci_np_sum(a, initial=None): - if isinstance(a, ArrayPointer): - def impl(a, initial=None): - if initial is not None: - s = initial - else: - s = 0 - n = len(a) - for i in range(n): - s += a[i] - return s - return impl - - -@expose_and_overload(np.prod) -@extending.overload_method(ArrayPointer, 'prod') -def omnisci_np_prod(a, initial=None): - if isinstance(a, ArrayPointer): - def impl(a, initial=None): - if initial is not None: - s = initial - else: - s = 1 - n = len(a) - for i in range(n): - s *= a[i] - return s - return impl - - -@expose_and_overload(np.mean) -@extending.overload_method(ArrayPointer, 'mean') -def omnisci_array_mean(x): - if isinstance(x.eltype, types.Integer): - zero_value = 0 - elif isinstance(x.eltype, types.Float): - zero_value = np.nan - - if isinstance(x, ArrayPointer): - def impl(x): - if len(x) == 0: - printf("Mean of empty array") - return zero_value - return sum(x) / len(x) - return impl - - -@expose_and_overload(np.cumsum) -def omnisci_np_cumsum(a): - if isinstance(a, ArrayPointer): - eltype = a.eltype - - def impl(a): - sz = len(a) - out = Array(sz, eltype) - out[0] = a[0] - for i in range(sz): - out[i] = out[i-1] + a[i] - return out - return impl diff --git a/rbc/omnisci_backend/numpy_ufuncs.py b/rbc/omnisci_backend/numpy_ufuncs.py deleted file mode 100644 index a1d0c4941..000000000 --- a/rbc/omnisci_backend/numpy_ufuncs.py +++ /dev/null @@ -1,262 +0,0 @@ -import numpy as np -from .omnisci_array import Array, ArrayPointer -from .. import typesystem -from numba.core import extending, types - - -def determine_dtype(a, dtype): - if isinstance(a, ArrayPointer): - return a.eltype if dtype is None else dtype - else: - return a if dtype is None else dtype - - -def determine_input_type(argty): - if isinstance(argty, ArrayPointer): - return determine_input_type(argty.eltype) - - if argty == typesystem.boolean8: - return bool - else: - return argty - - -def overload_elementwise_binary_ufunc(ufunc, name=None, dtype=None): - """ - Wrapper for binary ufuncs that returns an array - """ - if name is None: - name = ufunc.__name__ - globals()[name] = ufunc - - def binary_ufunc_impl(a, b): - typA = determine_input_type(a) - typB = determine_input_type(b) - - # XXX: raise error if len(a) != len(b) - @extending.register_jitable(_nrt=False) - def binary_impl(a, b, nb_dtype): - sz = len(a) - x = Array(sz, nb_dtype) - for i in range(sz): - cast_a = typA(a[i]) - cast_b = typB(b[i]) - x[i] = nb_dtype(ufunc(cast_a, cast_b)) - return x - - @extending.register_jitable(_nrt=False) - def broadcast(e, sz, dtype): - b = Array(sz, dtype) - b.fill(e) - return b - - if isinstance(a, ArrayPointer) and isinstance(b, ArrayPointer): - nb_dtype = determine_dtype(a, dtype) - - def impl(a, b): - return binary_impl(a, b, nb_dtype) - return impl - elif isinstance(a, ArrayPointer): - nb_dtype = determine_dtype(a, dtype) - other_dtype = b - - def impl(a, b): - b = broadcast(b, len(a), other_dtype) - return binary_impl(a, b, nb_dtype) - return impl - elif isinstance(b, ArrayPointer): - nb_dtype = determine_dtype(b, dtype) - other_dtype = a - - def impl(a, b): - a = broadcast(a, len(b), other_dtype) - return binary_impl(a, b, nb_dtype) - return impl - else: - nb_dtype = determine_dtype(a, dtype) - - def impl(a, b): - cast_a = typA(a) - cast_b = typB(b) - return nb_dtype(ufunc(cast_a, cast_b)) - return impl - - decorate = extending.overload(ufunc) - - def wrapper(overload_func): - return decorate(binary_ufunc_impl) - - return wrapper - - -# math functions -@overload_elementwise_binary_ufunc(np.add) -@overload_elementwise_binary_ufunc(np.subtract) -@overload_elementwise_binary_ufunc(np.multiply) -@overload_elementwise_binary_ufunc(np.divide, name='divide') -@overload_elementwise_binary_ufunc(np.logaddexp) -@overload_elementwise_binary_ufunc(np.logaddexp2) -@overload_elementwise_binary_ufunc(np.true_divide) -@overload_elementwise_binary_ufunc(np.floor_divide) -@overload_elementwise_binary_ufunc(np.power) -# @overload_elementwise_binary_ufunc(np.float_power) # not supported by numba -@overload_elementwise_binary_ufunc(np.remainder) -@overload_elementwise_binary_ufunc(np.mod, name='mod') -@overload_elementwise_binary_ufunc(np.fmod) -# @overload_elementwise_binary_ufunc(np.divmod) # not supported by numba -@overload_elementwise_binary_ufunc(np.gcd) -@overload_elementwise_binary_ufunc(np.lcm) -# Bit-twiddling functions -@overload_elementwise_binary_ufunc(np.bitwise_and) -@overload_elementwise_binary_ufunc(np.bitwise_or) -@overload_elementwise_binary_ufunc(np.bitwise_xor) -@overload_elementwise_binary_ufunc(np.bitwise_not, name='bitwise_not') -@overload_elementwise_binary_ufunc(np.left_shift) -@overload_elementwise_binary_ufunc(np.right_shift) -# trigonometric functions -@overload_elementwise_binary_ufunc(np.arctan2) -@overload_elementwise_binary_ufunc(np.hypot) -# Comparison functions -@overload_elementwise_binary_ufunc(np.greater, dtype=typesystem.boolean8) -@overload_elementwise_binary_ufunc(np.greater_equal, dtype=typesystem.boolean8) -@overload_elementwise_binary_ufunc(np.less, dtype=typesystem.boolean8) -@overload_elementwise_binary_ufunc(np.less_equal, dtype=typesystem.boolean8) -@overload_elementwise_binary_ufunc(np.not_equal, dtype=typesystem.boolean8) -@overload_elementwise_binary_ufunc(np.equal, dtype=typesystem.boolean8) -@overload_elementwise_binary_ufunc(np.logical_and, dtype=typesystem.boolean8) -@overload_elementwise_binary_ufunc(np.logical_or, dtype=typesystem.boolean8) -@overload_elementwise_binary_ufunc(np.logical_xor, dtype=typesystem.boolean8) -@overload_elementwise_binary_ufunc(np.maximum) -@overload_elementwise_binary_ufunc(np.minimum) -@overload_elementwise_binary_ufunc(np.fmax) -@overload_elementwise_binary_ufunc(np.fmin) -# Floating functions -@overload_elementwise_binary_ufunc(np.nextafter) -@overload_elementwise_binary_ufunc(np.ldexp) -def dummy_binary_ufunc(a, b): - pass - - -def overload_elementwise_unary_ufunc(ufunc, name=None, dtype=None): - """ - Wrapper for unary ufuncs that returns an array - """ - if name is None: - name = ufunc.__name__ - globals()[name] = ufunc - - def unary_elementwise_ufunc_impl(a): - nb_dtype = determine_dtype(a, dtype) - typ = determine_input_type(a) - - if isinstance(a, ArrayPointer): - def impl(a): - sz = len(a) - x = Array(sz, nb_dtype) - for i in range(sz): - # Convert the value to type "typ" - cast = typ(a[i]) - x[i] = nb_dtype(ufunc(cast)) - return x - return impl - else: - def impl(a): - # Convert the value to type typ - cast = typ(a) - return nb_dtype(ufunc(cast)) - return impl - - decorate = extending.overload(ufunc) - - def wrapper(overload_func): - return decorate(unary_elementwise_ufunc_impl) - - return wrapper - - -# Math operations -@overload_elementwise_unary_ufunc(np.negative) -@overload_elementwise_unary_ufunc(np.positive) -@overload_elementwise_unary_ufunc(np.absolute) -@overload_elementwise_unary_ufunc(np.fabs) -@overload_elementwise_unary_ufunc(np.rint) -@overload_elementwise_unary_ufunc(np.sign) -@overload_elementwise_unary_ufunc(np.absolute) -@overload_elementwise_unary_ufunc(np.conj) -@overload_elementwise_unary_ufunc(np.conjugate) -@overload_elementwise_unary_ufunc(np.exp) -@overload_elementwise_unary_ufunc(np.exp2) -@overload_elementwise_unary_ufunc(np.log) -@overload_elementwise_unary_ufunc(np.log2) -@overload_elementwise_unary_ufunc(np.log10) -@overload_elementwise_unary_ufunc(np.expm1) -@overload_elementwise_unary_ufunc(np.log1p) -@overload_elementwise_unary_ufunc(np.sqrt) -@overload_elementwise_unary_ufunc(np.square) -# @overload_elementwise_unary_ufunc(np.cbrt) # not supported by numba -@overload_elementwise_unary_ufunc(np.reciprocal) -# Bit-twiddling functions -@overload_elementwise_unary_ufunc(np.invert) -# trigonometric functions -@overload_elementwise_unary_ufunc(np.sin) -@overload_elementwise_unary_ufunc(np.cos) -@overload_elementwise_unary_ufunc(np.tan) -@overload_elementwise_unary_ufunc(np.arcsin) -@overload_elementwise_unary_ufunc(np.arccos) -@overload_elementwise_unary_ufunc(np.arctan) -@overload_elementwise_unary_ufunc(np.sinh) -@overload_elementwise_unary_ufunc(np.cosh) -@overload_elementwise_unary_ufunc(np.tanh) -@overload_elementwise_unary_ufunc(np.arcsinh) -@overload_elementwise_unary_ufunc(np.arccosh) -@overload_elementwise_unary_ufunc(np.arctanh) -@overload_elementwise_unary_ufunc(np.degrees) -@overload_elementwise_unary_ufunc(np.radians) -@overload_elementwise_unary_ufunc(np.deg2rad) -@overload_elementwise_unary_ufunc(np.rad2deg) -# Comparison functions -@overload_elementwise_unary_ufunc(np.logical_not, dtype=typesystem.boolean8) -# Floating functions -@overload_elementwise_unary_ufunc(np.isfinite, dtype=typesystem.boolean8) -@overload_elementwise_unary_ufunc(np.isinf, dtype=typesystem.boolean8) -@overload_elementwise_unary_ufunc(np.isnan, dtype=typesystem.boolean8) -@overload_elementwise_unary_ufunc(np.fabs, dtype=types.double) -@overload_elementwise_unary_ufunc(np.floor, dtype=types.double) -@overload_elementwise_unary_ufunc(np.ceil, dtype=types.double) -@overload_elementwise_unary_ufunc(np.trunc, dtype=types.double) -# not supported? -# @overload_elementwise_unary_ufunc(np.isnat, dtype=types.int8) -# issue 152: -@overload_elementwise_unary_ufunc(np.signbit, dtype=typesystem.boolean8) -@overload_elementwise_unary_ufunc(np.copysign) -@overload_elementwise_unary_ufunc(np.spacing, dtype=types.double) -def dummy_unary_ufunc(a): - pass - - -def heaviside(x1, x2): - pass - - -@extending.overload(heaviside) -def impl_np_heaviside(x1, x2): - nb_dtype = types.double - typA = determine_input_type(x1) - typB = determine_input_type(x2) - if isinstance(x1, ArrayPointer): - def impl(x1, x2): - sz = len(x1) - r = Array(sz, nb_dtype) - for i in range(sz): - r[i] = heaviside(x1[i], x2) - return r - return impl - else: - def impl(x1, x2): - if typA(x1) < 0: - return nb_dtype(0) - elif typA(x1) == 0: - return nb_dtype(typB(x2)) - else: - return nb_dtype(1) - return impl diff --git a/rbc/omnisci_backend/omnisci_array.py b/rbc/omnisci_backend/omnisci_array.py index a0317e677..ac0573fc7 100644 --- a/rbc/omnisci_backend/omnisci_array.py +++ b/rbc/omnisci_backend/omnisci_array.py @@ -3,7 +3,7 @@ __all__ = ['ArrayPointer', 'Array', 'OmnisciArrayType'] -from rbc import typesystem +from rbc import typesystem, errors from .omnisci_buffer import (BufferPointer, Buffer, OmnisciBufferType, omnisci_buffer_constructor) @@ -48,6 +48,6 @@ def typer(size, dtype): elif isinstance(dtype, types.NumberClass): element_type = typesystem.Type.fromobject(dtype) else: - raise NotImplementedError(repr(dtype)) + raise errors.NumbaNotImplementedError(repr(dtype)) return OmnisciArrayType((element_type,)).tonumba() return typer diff --git a/rbc/omnisci_backend/omnisci_buffer.py b/rbc/omnisci_backend/omnisci_buffer.py index 801af1f2d..d619678c3 100644 --- a/rbc/omnisci_backend/omnisci_buffer.py +++ b/rbc/omnisci_backend/omnisci_buffer.py @@ -31,8 +31,8 @@ from rbc import typesystem, irutils from rbc.targetinfo import TargetInfo from llvmlite import ir as llvm_ir -from numba.core import datamodel, cgutils, extending, types - +from numba.core import datamodel, cgutils, extending, types, imputils +from rbc.errors import UnsupportedError int8_t = ir.IntType(8) int32_t = ir.IntType(32) @@ -97,7 +97,7 @@ def eltype(self): return self.members[0].dtype -class BufferPointer(types.Type): +class BufferPointer(types.IterableType): """Numba type class for pointers to Omnisci buffer structures. We are not deriving from CPointer because BufferPointer getitem is @@ -116,6 +116,26 @@ def __init__(self, dtype): def key(self): return self.dtype + @property + def iterator_type(self): + return BufferPointerIteratorType(self) + + +class BufferPointerIteratorType(types.SimpleIteratorType): + + def __init__(self, buffer_type): + name = f"iter_buffer({buffer_type})" + self.buffer_type = buffer_type + super().__init__(name, self.buffer_type.eltype) + + +@datamodel.register_default(BufferPointerIteratorType) +class BufferPointerIteratorModel(datamodel.StructModel): + def __init__(self, dmm, fe_type): + members = [('index', types.EphemeralPointer(types.uintp)), + ('buffer', fe_type.buffer_type)] + super(BufferPointerIteratorModel, self).__init__(dmm, fe_type, members) + class BufferMeta(OmnisciMetaType): pass @@ -154,6 +174,12 @@ def omnisci_buffer_constructor(context, builder, sig, args): b = MyBuffer(, ...) """ + target_info = TargetInfo() + try: + alloc_fn_name = target_info.info['fn_allocate_varlen_buffer'] + except KeyError as msg: + raise UnsupportedError(f'{target_info} does not provide {msg}') + ptr_type, sz_type = sig.return_type.dtype.members[:2] if len(sig.return_type.dtype.members) > 2: assert len(sig.return_type.dtype.members) == 3 @@ -166,7 +192,7 @@ def omnisci_buffer_constructor(context, builder, sig, args): alloc_fnty = ir.FunctionType(int8_t.as_pointer(), [int64_t, int64_t]) - alloc_fn = irutils.get_or_insert_function(builder.module, alloc_fnty, "allocate_varlen_buffer") + alloc_fn = irutils.get_or_insert_function(builder.module, alloc_fnty, alloc_fn_name) ptr8 = builder.call(alloc_fn, [element_count, element_size]) # remember possible temporary allocations so that when leaving a # UDF/UDTF, these will be deallocated, see omnisci_pipeline.py. @@ -188,35 +214,78 @@ def omnisci_buffer_constructor(context, builder, sig, args): @extending.intrinsic -def free_omnisci_buffer(typingctx, ret): - sig = types.void(ret) +def free_all_other_buffers(typingctx, value_to_keep_alive): + """ + Black magic function which automatically frees all the buffers which were + allocated in the function apart the given one. + + value_to_keep_alive can be of any type: + - if it's of a Buffer type, it will be kept alive and not freed + - if it's of any other type, all buffers will be freed unconditionally + + The end user should never call this function explicitly: it is + automatically inserted by omnisci_pipeline.AutoFreeBuffers. + """ + + sig = types.void(value_to_keep_alive) def codegen(context, builder, signature, args): buffers = builder_buffers[builder] # TODO: using stdlib `free` that works only for CPU. For CUDA # devices, we need to use omniscidb provided deallocator. - free_fnty = llvm_ir.FunctionType(void_t, [int8_t.as_pointer()]) - free_fn = irutils.get_or_insert_function(builder.module, free_fnty, "free") - - # We skip the ret pointer iff we're returning a Buffer - # otherwise, we free everything - if isinstance(ret, BufferPointer): - [arg] = args - ptr = builder.load(builder.gep(arg, [int32_t(0), int32_t(0)])) - ptr = builder.bitcast(ptr, int8_t.as_pointer()) + target_info = TargetInfo() + try: + free_buffer_fn_name = target_info.info['fn_free_buffer'] + except KeyError as msg: + raise UnsupportedError(f'{target_info} does not provide {msg}') + free_buffer_fnty = llvm_ir.FunctionType(void_t, [int8_t.as_pointer()]) + free_buffer_fn = irutils.get_or_insert_function( + builder.module, free_buffer_fnty, free_buffer_fn_name) + + if isinstance(value_to_keep_alive, BufferPointer): + # free all the buffers apart value_to_keep_alive + [keep_alive] = args + keep_alive_ptr = builder.load(builder.gep(keep_alive, [int32_t(0), int32_t(0)])) + keep_alive_ptr = builder.bitcast(keep_alive_ptr, int8_t.as_pointer()) for ptr8 in buffers: - with builder.if_then(builder.icmp_signed('!=', ptr, ptr8)): - builder.call(free_fn, [ptr8]) + with builder.if_then(builder.icmp_signed('!=', keep_alive_ptr, ptr8)): + builder.call(free_buffer_fn, [ptr8]) else: + # free all the buffers unconditionally for ptr8 in buffers: - builder.call(free_fn, [ptr8]) + builder.call(free_buffer_fn, [ptr8]) del builder_buffers[builder] return sig, codegen +@extending.intrinsic +def free_buffer(typingctx, buf): + """ + Free a buffer + """ + sig = types.void(buf) + assert isinstance(buf, BufferPointer) + + def codegen(context, builder, signature, args): + # TODO: using stdlib `free` that works only for CPU. For CUDA + # devices, we need to use omniscidb provided deallocator. + target_info = TargetInfo() + free_buffer_fn_name = target_info.info['fn_free_buffer'] + free_buffer_fnty = llvm_ir.FunctionType(void_t, [int8_t.as_pointer()]) + free_buffer_fn = irutils.get_or_insert_function( + builder.module, free_buffer_fnty, free_buffer_fn_name) + + [buf] = args + buf_ptr = builder.load(builder.gep(buf, [int32_t(0), int32_t(0)])) # buf.ptr + buf_ptr = builder.bitcast(buf_ptr, int8_t.as_pointer()) + builder.call(free_buffer_fn, [buf_ptr]) + + return sig, codegen + + @extending.intrinsic def omnisci_buffer_ptr_get_ptr_(typingctx, data): eltype = data.eltype @@ -517,6 +586,7 @@ def codegen(context, builder, signature, args): nv = ir.Constant(ir.IntType(T.bitwidth), null_value) if isinstance(T, types.Float): nv = builder.bitcast(nv, ty) + intrinsic(builder, (data, index, nv,)) return sig, codegen @@ -533,3 +603,81 @@ def impl(x, row_idx=None): return omnisci_buffer_idx_set_null(x, row_idx) return impl return impl + + +@extending.overload_method(BufferPointer, 'free') +def omnisci_buffer_free(x): + if isinstance(x, BufferPointer): + def impl(x): + return free_buffer(x) + return impl + + +@extending.overload(operator.eq) +def dtype_eq(a, b): + if isinstance(a, types.DTypeSpec) and isinstance(b, types.DTypeSpec): + eq = (a == b) + + def impl(a, b): + return eq + return impl + + +@extending.overload_attribute(BufferPointer, 'dtype') +def omnisci_buffer_dtype(x): + if isinstance(x, BufferPointer): + dtype = x.eltype + + def impl(x): + return dtype + return impl + + +@extending.lower_builtin('iternext', BufferPointerIteratorType) +@imputils.iternext_impl(imputils.RefType.UNTRACKED) +def iternext_BufferPointer(context, builder, sig, args, result): + [iterbufty] = sig.args + [bufiter] = args + + iterval = context.make_helper(builder, iterbufty, value=bufiter) + + buf = iterval.buffer + idx = builder.load(iterval.index) + + len_fn = context.typing_context.resolve_value_type(len) + len_sig = types.intp(sig.args[0].buffer_type) + # if the intrinsic was not called before, one need to "register" it first + len_fn.get_call_type(context.typing_context, len_sig.args, {}) + count = context.get_function(len_fn, len_sig)(builder, [buf]) + + is_valid = builder.icmp_signed('<', idx, count) + result.set_valid(is_valid) + + with builder.if_then(is_valid): + getitem_fn = context.typing_context.resolve_value_type(operator.getitem) + getitem_sig = iterbufty.buffer_type.eltype(iterbufty.buffer_type, types.intp) + # same here, "register" the intrinsic before calling it + getitem_fn.get_call_type(context.typing_context, getitem_sig.args, {}) + getitem_out = context.get_function(getitem_fn, getitem_sig)(builder, [buf, idx]) + result.yield_(getitem_out) + nidx = builder.add(idx, context.get_constant(types.intp, 1)) + builder.store(nidx, iterval.index) + + +@extending.lower_builtin('getiter', BufferPointer) +def getiter_buffer_pointer(context, builder, sig, args): + [buffer] = args + + iterobj = context.make_helper(builder, sig.return_type) + + # set the index to zero + zero = context.get_constant(types.uintp, 0) + indexptr = cgutils.alloca_once_value(builder, zero) + + iterobj.index = indexptr + + # wire in the buffer type data + iterobj.buffer = buffer + + res = iterobj._getvalue() + return imputils.impl_ret_new_ref(context, builder, sig.return_type, res) diff --git a/rbc/omnisci_backend/omnisci_bytes.py b/rbc/omnisci_backend/omnisci_bytes.py index ac97c4f4c..201c9e1f6 100644 --- a/rbc/omnisci_backend/omnisci_bytes.py +++ b/rbc/omnisci_backend/omnisci_bytes.py @@ -25,6 +25,14 @@ class OmnisciBytesType(OmnisciBufferType): def buffer_extra_members(self): return ('bool is_null',) + def match(self, other): + if type(self) is type(other): + return self[0] == other[0] + if other.is_pointer and other[0].is_char and other[0].bits == 8: + return 1 + if other.is_string: + return 2 + BytesPointer = BufferPointer diff --git a/rbc/omnisci_backend/omnisci_column.py b/rbc/omnisci_backend/omnisci_column.py index f8ee00e91..2f3f3246b 100644 --- a/rbc/omnisci_backend/omnisci_column.py +++ b/rbc/omnisci_backend/omnisci_column.py @@ -26,6 +26,10 @@ def pass_by_value(self): omnisci_version = TargetInfo().software[1][:3] return omnisci_version <= (5, 7, 0) + def match(self, other): + if type(self) is type(other): + return self[0] == other[0] + class OmnisciOutputColumnType(OmnisciColumnType): """Omnisci OutputColumn type for RBC typesystem. @@ -114,7 +118,10 @@ def preprocess_args(cls, args): params = [] for p in args[0]: if not isinstance(p, (OmnisciColumnType, OmnisciColumnListType)): - p = OmnisciColumnType((p,)) + # map Cursor to Cursor ...> + c = p.copy() + p = OmnisciColumnType((c,), **c._params) + c._params.clear() params.append(p) return (tuple(params),) diff --git a/rbc/omnisci_backend/omnisci_compiler.py b/rbc/omnisci_backend/omnisci_compiler.py new file mode 100644 index 000000000..1ef688b67 --- /dev/null +++ b/rbc/omnisci_backend/omnisci_compiler.py @@ -0,0 +1,352 @@ +from contextlib import contextmanager +import llvmlite.binding as llvm +from rbc.targetinfo import TargetInfo +from numba.np import ufunc_db +from numba import _dynfunc +from numba.core import ( + codegen, compiler_lock, typing, + base, cpu, utils, descriptors, + dispatcher, callconv, imputils, + options,) +from numba.core.target_extension import ( + Generic, + target_registry, + dispatcher_registry, +) + + +class OmniSciDB_CPU(Generic): + """Mark the target as OmniSciDB CPU + """ + + +class OmniSciDB_GPU(Generic): + """Mark the target as OmniSciDB GPU + """ + + +target_registry['omniscidb_cpu'] = OmniSciDB_CPU +target_registry['omniscidb_gpu'] = OmniSciDB_GPU + +omnisci_cpu_registry = imputils.Registry(name='omnisci_cpu_registry') +omnisci_gpu_registry = imputils.Registry(name='omnisci_gpu_registry') + + +class _NestedContext(object): + _typing_context = None + _target_context = None + + @contextmanager + def nested(self, typing_context, target_context): + old_nested = self._typing_context, self._target_context + try: + self._typing_context = typing_context + self._target_context = target_context + yield + finally: + self._typing_context, self._target_context = old_nested + + +_options_mixin = options.include_default_options( + "no_rewrites", + "no_cpython_wrapper", + "no_cfunc_wrapper", + "fastmath", + "inline", + "boundscheck", + "nopython", + # Add "target_backend" as a accepted option for the CPU in @jit(...) + "target_backend", +) + + +class OmnisciTargetOptions(_options_mixin, options.TargetOptions): + def finalize(self, flags, options): + flags.enable_pyobject = False + flags.enable_looplift = False + flags.nrt = False + flags.debuginfo = False + flags.boundscheck = False + flags.enable_pyobject_looplift = False + flags.no_rewrites = True + flags.auto_parallel = cpu.ParallelOptions(False) + flags.inherit_if_not_set("fastmath") + flags.inherit_if_not_set("error_model", default="python") + # Add "target_backend" as a option that inherits from the caller + flags.inherit_if_not_set("target_backend") + + +class OmnisciTarget(descriptors.TargetDescriptor): + options = OmnisciTargetOptions + _nested = _NestedContext() + + @utils.cached_property + def _toplevel_target_context(self): + # Lazily-initialized top-level target context, for all threads + return JITRemoteTargetContext(self.typing_context, self._target_name) + + @utils.cached_property + def _toplevel_typing_context(self): + # Lazily-initialized top-level typing context, for all threads + return JITRemoteTypingContext() + + @property + def target_context(self): + """ + The target context for CPU/GPU targets. + """ + nested = self._nested._target_context + if nested is not None: + return nested + else: + return self._toplevel_target_context + + @property + def typing_context(self): + """ + The typing context for CPU targets. + """ + nested = self._nested._typing_context + if nested is not None: + return nested + else: + return self._toplevel_typing_context + + def nested_context(self, typing_context, target_context): + """ + A context manager temporarily replacing the contexts with the + given ones, for the current thread of execution. + """ + return self._nested.nested(typing_context, target_context) + + +# Create a target instance +omniscidb_cpu_target = OmnisciTarget("omniscidb_cpu") +omniscidb_gpu_target = OmnisciTarget("omniscidb_gpu") + + +# Declare a dispatcher for the CPU/GPU targets +class OmnisciCPUDispatcher(dispatcher.Dispatcher): + targetdescr = omniscidb_cpu_target + + +class OmnisciGPUDispatcher(dispatcher.Dispatcher): + targetdescr = omniscidb_gpu_target + + +# Register a dispatcher for the target, a lot of the code uses this +# internally to work out what to do RE compilation +dispatcher_registry[target_registry["omniscidb_cpu"]] = OmnisciCPUDispatcher +dispatcher_registry[target_registry["omniscidb_gpu"]] = OmnisciGPUDispatcher + + +class JITRemoteCodeLibrary(codegen.JITCodeLibrary): + """JITRemoteCodeLibrary was introduce to prevent numba from calling functions + that checks if the module is final. See xnd-project/rbc issue #87. + """ + + def get_pointer_to_function(self, name): + """We can return any random number here! This is just to prevent numba from + trying to check if the symbol given by "name" is defined in the module. + In cases were RBC is calling an external function (i.e. allocate_varlen_buffer) + the symbol will not be defined in the module, resulting in an error. + """ + return 0 + + def _finalize_specific(self): + """Same as codegen.JITCodeLibrary._finalize_specific but without + calling _ensure_finalize at the end + """ + self._codegen._scan_and_fix_unresolved_refs(self._final_module) + + +class JITRemoteCodegen(codegen.JITCPUCodegen): + _library_class = JITRemoteCodeLibrary + + def _get_host_cpu_name(self): + target_info = TargetInfo() + return target_info.device_name + + def _get_host_cpu_features(self): + target_info = TargetInfo() + features = target_info.device_features + server_llvm_version = target_info.llvm_version + if server_llvm_version is None or target_info.is_gpu: + return '' + client_llvm_version = llvm.llvm_version_info + + # See https://github.com/xnd-project/rbc/issues/45 + remove_features = { + (11, 8): ['tsxldtrk', 'amx-tile', 'amx-bf16', 'serialize', 'amx-int8', + 'avx512vp2intersect', 'tsxldtrk', 'amx-tile', 'amx-bf16', + 'serialize', 'amx-int8', 'avx512vp2intersect', 'tsxldtrk', + 'amx-tile', 'amx-bf16', 'serialize', 'amx-int8', + 'avx512vp2intersect', 'cx8', 'enqcmd', 'avx512bf16'], + (11, 10): ['tsxldtrk', 'amx-tile', 'amx-bf16', 'serialize', 'amx-int8'], + (9, 8): ['cx8', 'enqcmd', 'avx512bf16'], + }.get((server_llvm_version[0], client_llvm_version[0]), []) + for f in remove_features: + features = features.replace('+' + f, '').replace('-' + f, '') + return features + + def _customize_tm_options(self, options): + super()._customize_tm_options(options) + # fix reloc_model as the base method sets it using local target + target_info = TargetInfo() + if target_info.arch.startswith('x86'): + reloc_model = 'static' + else: + reloc_model = 'default' + options['reloc'] = reloc_model + + def set_env(self, env_name, env): + return None + + +class JITRemoteTypingContext(typing.Context): + """JITRemote Typing Context + """ + + def load_additional_registries(self): + from rbc.omnisci_backend import mathimpl + self.install_registry(mathimpl.registry) + return super().load_additional_registries() + + +class JITRemoteTargetContext(base.BaseContext): + # Whether dynamic globals (CPU runtime addresses) is allowed + allow_dynamic_globals = True + + def __init__(self, typing_context, target): + if target not in ('omniscidb_cpu', 'omniscidb_gpu'): + raise ValueError(f'Target "{target}" not supported') + super().__init__(typing_context, target) + + @compiler_lock.global_compiler_lock + def init(self): + target_info = TargetInfo() + self.address_size = target_info.bits + self.is32bit = (self.address_size == 32) + self._internal_codegen = JITRemoteCodegen("numba.exec") + self._target_data = llvm.create_target_data(target_info.datalayout) + + def refresh(self): + if self.target_name == 'omniscidb_cpu': + registry = omnisci_cpu_registry + else: + registry = omnisci_gpu_registry + + try: + loader = self._registries[registry] + except KeyError: + loader = imputils.RegistryLoader(registry) + self._registries[registry] = loader + + self.install_registry(registry) + # Also refresh typing context, since @overload declarations can + # affect it. + self.typing_context.refresh() + super().refresh() + + def load_additional_registries(self): + # Add implementations that work via import + from numba.cpython import (builtins, charseq, enumimpl, hashing, heapq, # noqa: F401 + iterators, listobj, numbers, rangeobj, + setobj, slicing, tupleobj, unicode,) + + self.install_registry(imputils.builtin_registry) + + # uncomment as needed! + # from numba.core import optional + # from numba.np import linalg, polynomial, arraymath, arrayobj # noqa: F401 + # from numba.typed import typeddict, dictimpl + # from numba.typed import typedlist, listobject + # from numba.experimental import jitclass, function_type + # from numba.np import npdatetime + + # Add target specific implementations + from numba.np import npyimpl + from numba.cpython import mathimpl + # from numba.cpython import cmathimpl, mathimpl, printimpl, randomimpl + # from numba.misc import cffiimpl + # from numba.experimental.jitclass.base import ClassBuilder as \ + # jitclassimpl + # self.install_registry(cmathimpl.registry) + # self.install_registry(cffiimpl.registry) + self.install_registry(mathimpl.registry) + self.install_registry(npyimpl.registry) + # self.install_registry(printimpl.registry) + # self.install_registry(randomimpl.registry) + # self.install_registry(jitclassimpl.class_impl_registry) + + def codegen(self): + return self._internal_codegen + + @utils.cached_property + def call_conv(self): + return callconv.CPUCallConv(self) + + @property + def target_data(self): + return self._target_data + + def create_cpython_wrapper(self, + library, + fndesc, + env, + call_helper, + release_gil=False): + # There's no cpython wrapper on omniscidb + pass + + def create_cfunc_wrapper(self, + library, + fndesc, + env, + call_helper, + release_gil=False): + # There's no cfunc wrapper on omniscidb + pass + + def get_executable(self, library, fndesc, env): + """ + Returns + ------- + (cfunc, fnptr) + + - cfunc + callable function (Can be None) + - fnptr + callable function address + - env + an execution environment (from _dynfunc) + """ + # although we don't use this function, it seems to be required + # by some parts of codegen in Numba. + + # Code generation + fnptr = library.get_pointer_to_function( + fndesc.llvm_cpython_wrapper_name + ) + + # Note: we avoid reusing the original docstring to avoid encoding + # issues on Python 2, see issue #1908 + doc = "compiled wrapper for %r" % (fndesc.qualname,) + cfunc = _dynfunc.make_function( + fndesc.lookup_module(), + fndesc.qualname.split(".")[-1], + doc, + fnptr, + env, + # objects to keepalive with the function + (library,), + ) + library.codegen.set_env(self.get_env_name(fndesc), env) + return cfunc + + def post_lowering(self, mod, library): + pass + + # Overrides + def get_ufunc_info(self, ufunc_key): + return ufunc_db.get_ufunc_info(ufunc_key) diff --git a/rbc/omnisci_backend/omnisci_pipeline.py b/rbc/omnisci_backend/omnisci_pipeline.py index 1dce02260..be6d27840 100644 --- a/rbc/omnisci_backend/omnisci_pipeline.py +++ b/rbc/omnisci_backend/omnisci_pipeline.py @@ -1,17 +1,33 @@ -from .omnisci_buffer import BufferMeta, free_omnisci_buffer -from numba.core import ir +import operator + +from rbc.errors import NumbaTypeError +from .omnisci_buffer import BufferMeta, free_all_other_buffers +from numba.core import ir, types from numba.core.compiler import CompilerBase, DefaultPassBuilder from numba.core.compiler_machinery import FunctionPass, register_pass -from numba.core.untyped_passes import IRProcessing, DeadBranchPrune, SimplifyCFG -from numba.core.typed_passes import InlineOverloads +from numba.core.untyped_passes import (IRProcessing, + RewriteSemanticConstants, + ReconstructSSA, + DeadBranchPrune,) +from numba.core.typed_passes import PartialTypeInference, DeadCodeElimination # Register this pass with the compiler framework, declare that it will not # mutate the control flow graph and that it is not an analysis_only pass (it # potentially mutates the IR). @register_pass(mutates_CFG=False, analysis_only=False) -class FreeOmnisciBuffer(FunctionPass): - _name = "free_omnisci_buffers" # the common name for the pass +class AutoFreeBuffers(FunctionPass): + """ + Black magic at work. + + The goal of this pass is to "automagically" free all the buffers which + were allocated, apart the one which is used as a return value (if any). + + NOTE: at the moment of writing there are very few tests for this and it's + likely that it is broken and/or does not work properly in the general + case. [Remove this note once we are confident that it works well] + """ + _name = "auto_free_buffers" # the common name for the pass def __init__(self): FunctionPass.__init__(self) @@ -39,8 +55,8 @@ def run_pass(self, state): scope = blk.scope for ret in blk.find_insts(ir.Return): - name = "free_omnisci_buffer_fn" - value = ir.Global(name, free_omnisci_buffer, loc) + name = "free_all_other_buffers_fn" + value = ir.Global(name, free_all_other_buffers, loc) target = scope.make_temp(loc) stmt = ir.Assign(value, target, loc) blk.insert_before_terminator(stmt) @@ -54,6 +70,87 @@ def run_pass(self, state): return True # we changed the IR +@register_pass(mutates_CFG=False, analysis_only=False) +class CheckRaiseStmts(FunctionPass): + _name = "check_raise_stmts" + + def __init__(self): + FunctionPass.__init__(self) + + def run_pass(self, state): + func_ir = state.func_ir + for blk in func_ir.blocks.values(): + for _raise in blk.find_insts(ir.Raise): + msg = ('raise statement is not supported in ' + 'UDF/UDTFs. Please, use `return table_function_error(msg)` ' + 'to raise an error.') + loc = _raise.loc + raise NumbaTypeError(msg, loc=loc) + return False + + +@register_pass(mutates_CFG=False, analysis_only=False) +class DTypeComparison(FunctionPass): + _name = "DTypeComparison" + + def __init__(self): + FunctionPass.__init__(self) + + def is_dtype_comparison(self, func_ir, binop): + """ Return True if binop is a dtype comparison + """ + def is_getattr(expr): + return isinstance(expr, ir.Expr) and expr.op == 'getattr' + + if binop.fn != operator.eq: + return False + + lhs = func_ir.get_definition(binop.lhs.name) + rhs = func_ir.get_definition(binop.lhs.name) + + return (is_getattr(lhs) and lhs.attr == 'dtype') or \ + (is_getattr(rhs) and rhs.attr == 'dtype') + + def run_pass(self, state): + # run as subpipeline + from numba.core.compiler_machinery import PassManager + pm = PassManager("subpipeline") + pm.add_pass(PartialTypeInference, "performs partial type inference") + pm.finalize() + pm.run(state) + + mutated = False + + func_ir = state.func_ir + for block in func_ir.blocks.values(): + for assign in block.find_insts(ir.Assign): + binop = assign.value + if not (isinstance(binop, ir.Expr) and binop.op == 'binop'): + continue + if self.is_dtype_comparison(func_ir, binop): + var = func_ir.get_assignee(binop) + typ = state.typemap.get(var.name, None) + if isinstance(typ, types.BooleanLiteral): + loc = binop.loc + rhs = ir.Const(typ.literal_value, loc) + new_assign = ir.Assign(rhs, var, loc) + + # replace instruction + block.insert_after(new_assign, assign) + block.remove(assign) + mutated = True + + if mutated: + pm = PassManager("subpipeline") + # rewrite consts / dead branch pruning + pm.add_pass(DeadCodeElimination, "dead code elimination") + pm.add_pass(RewriteSemanticConstants, "rewrite semantic constants") + pm.add_pass(DeadBranchPrune, "dead branch pruning") + pm.finalize() + pm.run(state) + return mutated + + class OmnisciCompilerPipeline(CompilerBase): def define_pipelines(self): # define a new set of pipelines (just one in this case) and for ease @@ -61,10 +158,9 @@ def define_pipelines(self): # namely the "nopython" pipeline pm = DefaultPassBuilder.define_nopython_pipeline(self.state) # Add the new pass to run after IRProcessing - pm.add_pass_after(FreeOmnisciBuffer, IRProcessing) - # prune opt - pm.add_pass_after(SimplifyCFG, DeadBranchPrune) - pm.add_pass_after(DeadBranchPrune, InlineOverloads) + pm.add_pass_after(AutoFreeBuffers, IRProcessing) + pm.add_pass_after(CheckRaiseStmts, IRProcessing) + pm.add_pass_after(DTypeComparison, ReconstructSSA) # finalize pm.finalize() # return as an iterable, any number of pipelines may be defined! diff --git a/rbc/omnisci_backend/omnisci_text_encoding.py b/rbc/omnisci_backend/omnisci_text_encoding.py index 1b7de5fb6..7459907d3 100644 --- a/rbc/omnisci_backend/omnisci_text_encoding.py +++ b/rbc/omnisci_backend/omnisci_text_encoding.py @@ -11,9 +11,6 @@ class OmnisciTextEncodingDictType(typesystem.Type): """Omnisci Text Encoding Dict type for RBC typesystem. """ - def tostring(self, use_typename=False, use_annotation=True): - return 'TextEncodingDict' - @property def __typesystem_type__(self): return typesystem.Type('int32') diff --git a/rbc/omniscidb.py b/rbc/omniscidb.py index 585184824..702e8d05e 100644 --- a/rbc/omniscidb.py +++ b/rbc/omniscidb.py @@ -9,10 +9,11 @@ import configparser import numpy from collections import defaultdict, namedtuple -from .remotejit import RemoteJIT +from .remotejit import RemoteJIT, RemoteCallCapsule from .thrift.utils import resolve_includes from . import omnisci_backend from .omnisci_backend import ( + OmnisciArrayType, OmnisciBytesType, OmnisciTextEncodingDictType, OmnisciOutputColumnType, OmnisciColumnType, OmnisciCompilerPipeline, OmnisciCursorType, BufferMeta, OmnisciColumnListType, OmnisciTableFunctionManagerType) @@ -212,6 +213,107 @@ def get_client_config(**config): return config +def is_udtf(sig): + """Check if signature is a table function signature. + """ + if sig[0].annotation().get('kind') == 'UDTF': + return True + for a in sig[1]: + if isinstance(a, (OmnisciOutputColumnType, OmnisciColumnType, + OmnisciColumnListType, OmnisciTableFunctionManagerType)): + return True + return False + + +def is_sizer(t): + """Check if type is a type of a sizer argument: + int32_t | sizer=... + """ + return t.is_int and t.bits == 32 and 'sizer' in t.annotation() + + +def get_sizer_enum(t): + """Return sizer enum value as defined by the omniscidb server. + """ + sizer = t.annotation()['sizer'] + sizer = output_buffer_sizer_map.get(sizer or None, sizer) + for shortname, fullname in output_buffer_sizer_map.items(): + if sizer == fullname: + return sizer + raise ValueError(f'unknown sizer value ({sizer}) in {t}') + + +output_buffer_sizer_map = dict( + ConstantParameter='kUserSpecifiedConstantParameter', + RowMultiplier='kUserSpecifiedRowMultiplier', + Constant='kConstant', + SpecifiedParameter='kTableFunctionSpecifiedParameter', + PreFlight='kPreFlightParameter') + +# Default sizer is RowMultiplier: +output_buffer_sizer_map[None] = output_buffer_sizer_map['RowMultiplier'] + +user_specified_output_buffer_sizers = { + 'kUserSpecifiedConstantParameter', 'kUserSpecifiedRowMultiplier', +} + + +def type_to_type_name(typ: typesystem.Type): + """Return typesystem.Type as DatumType name. + """ + styp = typ.tostring(use_annotation=False, use_name=False) + type_name = dict( + int8='TINYINT', + int16='SMALLINT', + int32='INT', + int64='BIGINT', + float32='FLOAT', + float64='DOUBLE', + ).get(styp) + if type_name is not None: + return type_name + raise NotImplementedError(f'converting `{styp}` to DatumType not supported') + + +def type_name_to_dtype(type_name): + """Return DatumType name as the corresponding numpy dtype. + """ + dtype = dict( + SMALLINT=numpy.int16, + INT=numpy.int32, + BIGINT=numpy.int64, + FLOAT=numpy.float32, + # DECIMAL=, + DOUBLE=numpy.float32, + STR=numpy.str0, + # TIME=, + # TIMESTAMP=, + # DATE=, + BOOL=numpy.bool8, + # INTERVAL_DAY_TIME=, + # INTERVAL_YEAR_MONTH=, + # POINT=, + # LINESTRING=, + # POLYGON=, + # MULTIPOLYGON=, + TINYINT=numpy.int8, + # GEOMETRY=, + # GEOGRAPHY= + ).get(type_name) + if dtype is not None: + return dtype + raise NotImplementedError( + f'convert DatumType `{type_name}` to numpy dtype') + + +class OmnisciQueryCapsule(RemoteCallCapsule): + + use_execute_cache = True + + def __repr__(self): + return f'{type(self).__name__}({str(self)!r})' + + class RemoteOmnisci(RemoteJIT): """Usage: @@ -241,12 +343,19 @@ def add(a, b): OutputColumn='OmnisciOutputColumnType', RowMultiplier='int32|sizer=RowMultiplier', ConstantParameter='int32|sizer=ConstantParameter', + SpecifiedParameter='int32|sizer=SpecifiedParameter', Constant='int32|sizer=Constant', + PreFlight='int32|sizer=PreFlight', ColumnList='OmnisciColumnListType', TextEncodingDict='OmnisciTextEncodingDictType', TableFunctionManager='OmnisciTableFunctionManagerType<>', + UDTF='int32|kind=UDTF' ) + remote_call_capsule_cls = OmnisciQueryCapsule + default_remote_call_hold = True + supports_local_caller = False + def __init__(self, user='admin', password='HyperInteractive', @@ -289,12 +398,17 @@ def _init_thrift_typemap(self): if hasattr(typ, '_NAMES_TO_VALUES'): for name, value in typ._NAMES_TO_VALUES.items(): typemap[typename][name] = value + typemap[typename+'-inverse'][value] = name @property def version(self): if self._version is None: version = self.thrift_call('get_version') self._version = parse_version(version) + if self._version[:2] < (5, 6): + msg = (f'OmniSciDB server v.{version} is too old (expected v.5.6 or newer) ' + 'and some features might not be available.') + warnings.warn(msg, PendingDeprecationWarning) return self._version @property @@ -357,9 +471,27 @@ def thrift_call(self, name, *args, **kwargs): m = re.match(r'.*Exception: (.*)', msg.error_msg) if m: raise OmnisciServerError(f'{m.group(1)}') + m = re.match( + r'(.*)\: No match found for function signature (.*)\(.*\)', + msg.error_msg + ) + if m: + msg = (f"Undefined function call {m.group(2)!r} in" + f" SQL statement: {m.group(1)}") + raise OmnisciServerError(msg) m = re.match(r'.*SQL Error: (.*)', msg.error_msg) if m: raise OmnisciServerError(f'{m.group(1)}') + m = re.match(r'Could not bind *', msg.error_msg) + if m: + raise OmnisciServerError(msg.error_msg) + m = re.match(r'Runtime extension functions registration is disabled.', + msg.error_msg) + if m: + msg = (f"{msg.error_msg} Please use server options --enable-runtime-udf" + " and/or --enable-table-functions") + raise OmnisciServerError(msg) + # TODO: catch more known server failures here. raise @@ -610,10 +742,13 @@ def sql_execute(self, query): result = self.thrift_call( 'sql_execute', self.session_id, query, columnar, "", -1, -1) - Description = namedtuple("Description", ["name", "type_code", "null_ok"]) + type_code_to_type_name = self.thrift_typemap['TDatumType-inverse'] + Description = namedtuple("Description", ["name", "type_name", "null_ok"]) descr = [] for col in result.row_set.row_desc: - descr.append(Description(col.col_name, col.col_type.type, col.col_type.nullable)) + descr.append(Description(col.col_name, + type_code_to_type_name[col.col_type.type], + col.col_type.nullable)) return descr, self._make_row_results_set(result) _ext_arguments_map = None @@ -690,6 +825,8 @@ def _get_ext_arguments_map(self): ('int64', 'int64_t'), ('float32', 'float'), ('float64', 'double'), + ('TextEncodingDict', 'TextEncodingDict'), + ('OmnisciTextEncodingDictType<>', 'TextEncodingDict'), ]: ext_arguments_map['OmnisciArrayType<%s>' % ptr_type] \ = ext_arguments_map.get('Array<%s>' % T) @@ -704,15 +841,6 @@ def _get_ext_arguments_map(self): ext_arguments_map['OmnisciBytesType'] = ext_arguments_map.get('Bytes') - ext_arguments_map['OmnisciColumnType'] \ - = ext_arguments_map.get('Column') - ext_arguments_map['OmnisciOutputColumnType'] \ - = ext_arguments_map.get('Column') - ext_arguments_map['OmnisciColumnListType'] \ - = ext_arguments_map.get('ColumnList') - # ext_arguments_map['OmnisciOutputColumnListType<%s>' % size] \ - # = ext_arguments_map.get('ColumnList<%s>' % size) - values = list(ext_arguments_map.values()) for v, n in thrift.TExtArgumentType._VALUES_TO_NAMES.items(): if v not in values: @@ -723,10 +851,10 @@ def _get_ext_arguments_map(self): def type_to_extarg(self, t): if isinstance(t, typesystem.Type): - s = t.tostring(use_annotation=False) + s = t.tostring(use_annotation=False, use_name=False) extarg = self._get_ext_arguments_map().get(s) if extarg is None: - raise ValueError(f'cannot convert {t} to ExtArgumentType') + raise ValueError(f'cannot convert {t}(={s}) to ExtArgumentType') return extarg elif isinstance(t, str): extarg = self._get_ext_arguments_map().get(t) @@ -825,6 +953,11 @@ def retrieve_targets(self): target_info.add_library('stdio') target_info.add_library('stdlib') target_info.add_library('omniscidb') + # NOTE: eventually, we want omniscidb to provide a + # 'free_buffer' function, but in the meantime we just call + # free() + target_info.set('fn_allocate_varlen_buffer', 'allocate_varlen_buffer') + target_info.set('fn_free_buffer', 'free') elif target_info.is_gpu and self.version >= (5, 5): target_info.add_library('libdevice') @@ -859,13 +992,7 @@ def _make_udtf(self, caller, orig_sig, sig): 'omniscidb 5.4 or newer, currently ' 'connected to ', v) thrift = self.thrift_client.thrift - sizer_map = dict( - ConstantParameter='kUserSpecifiedConstantParameter', - RowMultiplier='kUserSpecifiedRowMultiplier', - Constant='kConstant', - SpecifiedParameter='kTableFunctionSpecifiedParameter') - unspecified = object() inputArgTypes = [] outputArgTypes = [] sqlArgTypes = [] @@ -877,19 +1004,13 @@ def _make_udtf(self, caller, orig_sig, sig): consumed_index = 0 name = caller.func.__name__ for i, a in enumerate(orig_sig[1]): - annot = a.annotation() - _sizer = annot.get('sizer', unspecified) - if _sizer is not unspecified: - if not (a.is_int and a.bits == 32): - raise ValueError( - 'sizer argument must have type int32') - if _sizer is None: - _sizer = 'RowMultiplier' - _sizer = sizer_map[_sizer] - # cannot have multiple sizer arguments + if is_sizer(a): + sizer = get_sizer_enum(a) + # cannot have multiple sizer arguments: assert sizer_index == -1 sizer_index = consumed_index + 1 - sizer = _sizer + + annot = a.annotation() # process function annotations first to avoid appending annotations twice if isinstance(a, OmnisciTableFunctionManagerType): @@ -991,6 +1112,7 @@ def _make_udf(self, caller, orig_sig, sig): atypes, rtype) def register(self): + """Register caller cache to the server.""" with typesystem.Type.alias(**self.typesystem_aliases): return self._register() @@ -998,12 +1120,6 @@ def _register(self): if self.have_last_compile: return - def is_udtf(sig): - for a in sig[1]: - if isinstance(a, (OmnisciOutputColumnType, OmnisciColumnType)): - return True - return False - device_ir_map = {} llvm_function_names = [] fid = 0 # UDF/UDTF id @@ -1106,6 +1222,11 @@ def is_udtf(sig): 'register_runtime_extension_functions', self.session_id, udfs, udtfs, device_ir_map) + def unregister(self): + """Unregister caller cache locally and on the server.""" + self.reset() + self.register() + def preprocess_callable(self, func): func = super().preprocess_callable(func) if 'omnisci_backend' not in func.__code__.co_names: @@ -1133,3 +1254,166 @@ def compiler(self): print(f'compiler={compiler}') self._compiler = compiler return self._compiler + + def caller_signature(self, signature: typesystem.Type): + """Return signature of a caller. + + See RemoteJIT.caller_signature.__doc__. + """ + if is_udtf(signature): + rtype = signature[0] + if not (rtype.is_int and rtype.bits == 32): + raise ValueError( + f'UDTF implementation return type must be int32, got {rtype}') + rtypes = [] + atypes = [] + for atype in signature[1]: + if is_sizer(atype): + sizer = get_sizer_enum(atype) + if sizer not in user_specified_output_buffer_sizers: + continue + atype.annotation(sizer=sizer) + elif isinstance(atype, OmnisciTableFunctionManagerType): + continue + elif isinstance(atype, OmnisciOutputColumnType): + rtypes.append(atype.copy(OmnisciColumnType)) + continue + atypes.append(atype) + rtype = typesystem.Type(*rtypes, **dict(struct_is_tuple=True)) + return rtype(*atypes, **signature._params) + return signature + + def get_types(self, *values): + """Convert values to the corresponding typesystem types. + + See RemoteJIT.get_types.__doc__. + """ + types = [] + for value in values: + if isinstance(value, RemoteCallCapsule): + typ = value.__typesystem_type__ + if typ.is_struct and typ._params.get('struct_is_tuple'): + types.extend(typ) + else: + types.append(typ) + else: + types.append(typesystem.Type.fromvalue(value)) + return tuple(types) + + def normalize_function_type(self, ftype: typesystem.Type): + """Normalize typesystem function type. + + See RemoteJIT.normalize_function_type.__doc__. + """ + assert ftype.is_function, ftype + for atype in ftype[1]: + # convert `T foo` to `T | name=foo` + if 'name' not in atype.annotation() and atype.name is not None: + atype.annotation(name=atype.name) + atype._params.pop('name') + return ftype + + def format_type(self, typ: typesystem.Type): + """Convert typesystem type to formatted string. + + See RemoteJIT.format_type.__doc__. + """ + if typ.is_function: + args = map(self.format_type, typ[1]) + if is_udtf(typ): + return f'UDTF({", ".join(args)})' + else: + return f'({", ".join(args)}) -> {self.format_type(typ[0])}' + use_typename = False + if typ.is_struct and typ._params.get('struct_is_tuple'): + return f'({", ".join(map(self.format_type, typ))})' + if isinstance(typ, OmnisciOutputColumnType): + p = tuple(map(self.format_type, typ[0])) + typ = typesystem.Type(('OutputColumn',) + p, **typ._params) + elif isinstance(typ, OmnisciColumnType): + p = tuple(map(self.format_type, typ[0])) + typ = typesystem.Type(('Column',) + p, **typ._params) + elif isinstance(typ, OmnisciColumnListType): + p = tuple(map(self.format_type, typ[0])) + typ = typesystem.Type(('ColumnList',) + p, **typ._params) + elif isinstance(typ, OmnisciArrayType): + p = tuple(map(self.format_type, typ[0])) + typ = typesystem.Type(('Array',) + p, **typ._params) + elif isinstance(typ, OmnisciCursorType): + p = tuple(map(self.format_type, typ[0])) + typ = typesystem.Type(('Cursor',) + p, **typ._params) + elif isinstance(typ, OmnisciBytesType): + typ = typ.copy().params(typename='Bytes') + use_typename = True + elif isinstance(typ, OmnisciTextEncodingDictType): + typ = typ.copy().params(typename='TextEncodingDict') + use_typename = True + elif isinstance(typ, OmnisciTableFunctionManagerType): + typ = typ.copy().params(typename='TableFunctionManager') + use_typename = True + elif is_sizer(typ): + sizer = get_sizer_enum(typ) + for shortname, fullname in output_buffer_sizer_map.items(): + if fullname == sizer: + use_typename = True + typ = typ.copy().params(typename=shortname) + typ.annotation().pop('sizer') + break + + return typ.tostring(use_typename=use_typename, use_annotation_name=True) + + # We define remote_compile and remote_call for Caller.__call__ method. + def remote_compile(self, func, ftype: typesystem.Type, target_info: TargetInfo): + """Remote compile function and signatures to machine code. + + See RemoteJIT.remote_compile.__doc__. + """ + if self.query_requires_register(func.__name__): + self.register() + + def remote_call(self, func, ftype: typesystem.Type, arguments: tuple, hold=False): + """ + See RemoteJIT.remote_call.__doc__. + """ + sig = self.caller_signature(ftype) + assert len(arguments) == len(sig[1]), (sig, arguments) + rtype = sig[0] + args = [] + for a, atype in zip(arguments, sig[1]): + if isinstance(a, RemoteCallCapsule): + if is_udtf(a.ftype): + a = a.execute(hold=True) + else: + a = a.execute(hold=True).lstrip('SELECT ') + + if isinstance(atype, (OmnisciColumnType, OmnisciColumnListType)): + args.append(f'CURSOR({a})') + elif isinstance(atype, OmnisciBytesType): + if isinstance(a, bytes): + a = repr(a.decode()) + elif isinstance(a, str): + a = repr(a) + args.append(f'{a}') + else: + args.append(f'CAST({a} AS {type_to_type_name(atype)})') + args = ', '.join(args) + is_udtf_call = is_udtf(ftype) + if is_udtf_call: + colnames = [] + if rtype.is_struct and rtype._params.get('struct_is_tuple'): + for i, t in enumerate(rtype): + n = t.annotation().get('name', f'out{i}') + colnames.append(n) + else: + colnames.append(rtype.annotation().get('name', '*')) + q = f'SELECT {", ".join(colnames)} FROM TABLE({func.__name__}({args}))' + else: + q = f'SELECT {func.__name__}({args})' + if hold: + return q + descrs, result = self.sql_execute(q + ';') + dtype = [(descr.name, type_name_to_dtype(descr.type_name)) for descr in descrs] + if is_udtf_call: + return numpy.array(list(result), dtype).view(numpy.recarray) + else: + return dtype[0][1](list(result)[0][0]) diff --git a/rbc/rbclib/__init__.py b/rbc/rbclib/__init__.py new file mode 100644 index 000000000..21047d46e --- /dev/null +++ b/rbc/rbclib/__init__.py @@ -0,0 +1,70 @@ +""" +rbclib is a C runtime library for rbc. + +Sometimes the IR code generated by rbc needs to call some external helper +function written in C; rbclib makes it possible to write such functions. + +This is the file layout: + + - _rbclib.c contains the actual C source code + + - _rbclib_build.py is the CFFI build script which is called by setup.py + + - _rbclib.abi3.so (_rbclib.pyd on Windows) is the native extension produced + by _rbclib_build.py and that can be imported by 'import rbc.rbclib._rbclib' + +rbclib functions can be called in two ways: + + 1. From pure Python, through CFFI: for this you need to call + e.g. lib._rbclib_add_ints(). This is useful e.g. inside tests + + 2. From an @rjit function, through rbc. For this you need to call + e.g. rbclib.add_ints. The codegen logic is in rbclib/intrinsic.py. In + this case, the generated LLVM will contain a direct call to the + underlying C function (_rbclib_add_ints), which means that such a + function must be loaded in memory and LLVM must be aware of it. This is + done by load_inside_llvm(), which is called from + libfuncs.RBCLib.__init__(). + +NOTE: rbclib is based on CFFI, but this is not strictly necessary: in theory, +it is enough to dlopen() a C library which contains the desired +functions. However, using CFFI has many advantages: + + 1. It is very easy to integrate the build process with setup.py + + 2. You can call the functions also from Python (useful for testing) + + 3. Loading the shared library in memory is as simple as importing the + _rbclib module, instead of having to load the library explicitly + e.g. through ctypes +""" + +import llvmlite.binding +try: + from . import _rbclib +except ImportError as e: + # improve the ImportError error message + msg = (f"{e}\nThis probably indicates " + "that rbc has not been built/installed correctly, possibly " + "because cffi was not available at compilation time") + e.msg = msg + e.args = (msg,) + raise + +from ._rbclib import lib, ffi # noqa: F401 +from .intrinsic import add_ints # noqa: F401 +from . import tracing_allocator # noqa: F401, side effects + +# this contains all the C names which we want to expose to the RBC +# compiler. See libfuncs.RBCLib. +FUNCTION_NAMES = [ + '_rbclib_add_ints', + 'rbclib_allocate_varlen_buffer', + 'rbclib_free_buffer', + 'rbclib_tracing_allocate_varlen_buffer', + 'rbclib_tracing_free_buffer', +] + + +def load_inside_llvm(): + llvmlite.binding.load_library_permanently(_rbclib.__file__) diff --git a/rbc/rbclib/_rbclib.c b/rbc/rbclib/_rbclib.c new file mode 100644 index 000000000..cb4c149ab --- /dev/null +++ b/rbc/rbclib/_rbclib.c @@ -0,0 +1,24 @@ +#include +#include "_rbclib.h" + + +// trivial function, used to test that the basic machinery works +RBC_DLLEXPORT int64_t _rbclib_add_ints(int64_t a, int64_t b) { + return a + b; +} + +// NOTE: allocate_varlen_buffer must have the same signature as the one +// defined by omniscidb +RBC_DLLEXPORT int8_t *rbclib_allocate_varlen_buffer(int64_t element_count, int64_t element_size) { + size_t size = element_count * element_size; + // malloc(0) is allowed to return NULL. But here we want to ensure that we + // return NULL only to signal an out of memory error, so we make sure to + // always allocate at least 1 byte + if (size == 0) + size = 1; + return (int8_t *)malloc(size); +} + +RBC_DLLEXPORT void rbclib_free_buffer(int8_t *addr) { + free((void*)addr); +} diff --git a/rbc/rbclib/_rbclib.h b/rbc/rbclib/_rbclib.h new file mode 100644 index 000000000..a9cc1bd0a --- /dev/null +++ b/rbc/rbclib/_rbclib.h @@ -0,0 +1,18 @@ +#include + +#if defined(_MSC_VER) +# define RBC_DLLEXPORT extern __declspec(dllexport) +#else +# define RBC_DLLEXPORT extern +#endif + +/* functions implemented in C */ +RBC_DLLEXPORT int64_t _rbclib_add_ints(int64_t a, int64_t b); +RBC_DLLEXPORT int8_t* rbclib_allocate_varlen_buffer(int64_t element_count, int64_t element_size); +RBC_DLLEXPORT void rbclib_free_buffer(int8_t *addr); + +/* functions implemented in Python and declared as extern "C+Python" in + ffibuilder.cdef() */ +RBC_DLLEXPORT int8_t* rbclib_tracing_allocate_varlen_buffer(int64_t element_count, + int64_t element_size); +RBC_DLLEXPORT void rbclib_tracing_free_buffer(int8_t *addr); diff --git a/rbc/rbclib/_rbclib_build.py b/rbc/rbclib/_rbclib_build.py new file mode 100644 index 000000000..3eb97507c --- /dev/null +++ b/rbc/rbclib/_rbclib_build.py @@ -0,0 +1,45 @@ +""" +CFFI builder for _rbclib. + +This is meant to be listed inside cffi_modules=[...] in setup.py. + +To rebuild, run setup.py develop or equivalent. +""" + +from cffi import FFI +ffibuilder = FFI() + +# rbclib defines two kind of functions: +# +# 1. functions written in C: these are implemented in _rbclib.c and exposed +# to CFFI by calling ffibuilder.cdef() +# +# 2. functions written in Python: these are exposed to CFFI by using +# declaring them as extern "C+Python" in ffibuilder.cdef(). CFFI +# generates a C stub which can be called from C and from JIT-generated +# code, and which in turns call the Python function which is defined using +# @ffi.def_extern. +# +# Moreover, we need to take extra care to support Windows. Contrarily to +# Unix-like systems, Windows requires symbols to be explicitly exported in +# order to be visible in the generated DLL/.pyd file. RBC_DLLEXPORT + + +ffibuilder.cdef(""" +int64_t _rbclib_add_ints(int64_t a, int64_t b); +int8_t* rbclib_allocate_varlen_buffer(int64_t element_count, int64_t element_size); +void rbclib_free_buffer(int8_t *addr); + +extern "C+Python" { + int8_t* rbclib_tracing_allocate_varlen_buffer(int64_t element_count, + int64_t element_size); + void rbclib_tracing_free_buffer(int8_t *addr); +} +""") + +ffibuilder.set_source( + "rbc.rbclib._rbclib", + source='#include "_rbclib.h"', + include_dirs=['rbc/rbclib'], + sources=['rbc/rbclib/_rbclib.c'], +) diff --git a/rbc/rbclib/errors.py b/rbc/rbclib/errors.py new file mode 100644 index 000000000..c802808c4 --- /dev/null +++ b/rbc/rbclib/errors.py @@ -0,0 +1,17 @@ +class TracingAllocatorError(Exception): + pass + + +class InvalidFreeError(TracingAllocatorError): + pass + + +class MemoryLeakError(TracingAllocatorError): + + def __init__(self, leaks): + lines = [f'Found {len(leaks)} memory leaks:'] + for addr, seq in leaks: + lines.append(f' {addr} (seq = {seq})') + message = '\n'.join(lines) + super().__init__(message) + self.leaks = leaks diff --git a/rbc/rbclib/intrinsic.py b/rbc/rbclib/intrinsic.py new file mode 100644 index 000000000..def0f0155 --- /dev/null +++ b/rbc/rbclib/intrinsic.py @@ -0,0 +1,24 @@ +from llvmlite import ir +from numba.core import extending +from numba.core import types as nb_types +from numba.core.errors import TypingError +from rbc import irutils + + +@extending.intrinsic +def add_ints(typingctx, a_type, b_type): + if (a_type, b_type) != (nb_types.int64, nb_types.int64): + raise TypingError('add_ints(i64, i64)') + + sig = nb_types.int64(nb_types.int64, nb_types.int64) + + def codegen(context, builder, signature, args): + assert len(args) == 2 + arg_a, arg_b = args + int64_t = ir.IntType(64) + fntype = ir.FunctionType(int64_t, [int64_t, int64_t]) + fn = irutils.get_or_insert_function(builder.module, fntype, + name="_rbclib_add_ints") + return builder.call(fn, [arg_a, arg_b]) + + return sig, codegen diff --git a/rbc/rbclib/tracing_allocator.py b/rbc/rbclib/tracing_allocator.py new file mode 100644 index 000000000..66e38891f --- /dev/null +++ b/rbc/rbclib/tracing_allocator.py @@ -0,0 +1,84 @@ +from ._rbclib import lib, ffi +from .errors import TracingAllocatorError, InvalidFreeError, MemoryLeakError # noqa: F401 + + +class TracingAllocator: + """ + Provide debug versions of allocate_varlen_buffer and free_buffer which + keep trace of all the allocation/deallocations in order to detect memory + leaks. + + The logic is written in pure Python, and it is exposed to the C world + through CFFI's @def_extern() mechanism. + """ + + def __init__(self): + # alive_memory is a dictionary which contains all the addresses which + # have been allocated but not yet freed. For each address we record + # an unique sequence number which acts as a timestamp, so that we can + # inspect them in allocation order. + self.seq = 0 + self.alive_memory = {} # {address: seq} + + def record_allocate(self, addr): + self.seq += 1 + assert addr not in self.alive_memory + self.alive_memory[addr] = self.seq + + def record_free(self, addr): + if addr not in self.alive_memory: + raise InvalidFreeError('Trying to free() a dangling pointer?') + del self.alive_memory[addr] + + +class LeakDetector: + """ + Context manager to detect memory leaks on the given allocator. + + When we enter the context manager, we record the current sequence + number. Upon exit, we check that all the new allocations have been freed. + """ + + def __init__(self, allocator): + self.allocator = allocator + self.start_seq = None + + def __enter__(self): + if self.start_seq is not None: + raise ValueError('LeakDetector already active') + self.start_seq = self.allocator.seq + + def __exit__(self, etype, evalue, tb): + leaks = [] + for addr, seq in self.allocator.alive_memory.items(): + if seq > self.start_seq: + leaks.append((addr, seq)) + self.start_seq = None + if leaks: + leaks.sort(key=lambda t: t[1]) # sort by seq + raise MemoryLeakError(leaks) + + +# global singleton +_ALLOCATOR = TracingAllocator() + + +def new_leak_detector(): + """ + Return a new instance of LeakDetector associated to the global tracing + allocator + """ + return LeakDetector(_ALLOCATOR) + + +@ffi.def_extern() +def rbclib_tracing_allocate_varlen_buffer(element_count, element_size): + addr = lib.rbclib_allocate_varlen_buffer(element_count, element_size) + _ALLOCATOR.record_allocate(addr) + return addr + + +@ffi.def_extern() +def rbclib_tracing_free_buffer(addr): + _ALLOCATOR.record_free(addr) + lib.rbclib_free_buffer(addr) diff --git a/rbc/remotejit.py b/rbc/remotejit.py index 469805306..80684f127 100644 --- a/rbc/remotejit.py +++ b/rbc/remotejit.py @@ -7,11 +7,19 @@ import inspect import warnings import ctypes +from contextlib import nullcontext +from collections import defaultdict from . import irtools +from .errors import UnsupportedError from .typesystem import Type, get_signature from .thrift import Server, Dispatcher, dispatchermethod, Data, Client -from .utils import get_local_ip +from .utils import get_local_ip, UNSPECIFIED from .targetinfo import TargetInfo +from .rbclib import tracing_allocator +# XXX WIP: the OmnisciCompilerPipeline is no longer omnisci-specific because +# we support Arrays even without omnisci, so it must be renamed and moved +# somewhere elsef +from .omnisci_backend import OmnisciCompilerPipeline def isfunctionlike(obj): @@ -60,7 +68,7 @@ def extract_templates(options): return new_options, templates -class Signature(object): +class Signature: """Signature decorator for Python functions. A Signature decorator may contain many signature objects @@ -110,9 +118,20 @@ def local(self): assert not self.signature_templates return sig + def __repr__(self): + return f'{type(self).__name__}({str(self)})' + def __str__(self): - lst = ["'%s'" % (s,) for s in self.signatures] - return '%s(%s)' % (self.__class__.__name__, ', '.join(lst)) + lst = [] + for t in self.signatures: + s = str(t) + for k, types in self.signature_templates.get(t, {}).items(): + s += f', {k}={"|".join(map(str, types))}' + devices = self.signature_devices.get(t, []) + if devices: + s += f', device={"|".join(devices)}' + lst.append(repr(s)) + return f'{"; ".join(lst)}' def __call__(self, obj, **options): """Decorate signatures or a function. @@ -204,19 +223,19 @@ def best_match(self, func, atypes: tuple) -> Type: ftype = None match_penalty = None available_types = self.normalized(func).signatures + for typ in available_types: - penalty = typ.match(atypes) + sig = self.remotejit.caller_signature(typ) + penalty = sig.match(atypes) if penalty is not None: if ftype is None or penalty < match_penalty: ftype = typ match_penalty = penalty - if ftype is None: - satypes = ', '.join(map(str, atypes)) - available = '; '.join(map(str, available_types)) - raise TypeError( - f'found no matching function type to given argument types' - f' `{satypes}`. Available function types: {available}') - return ftype + return ftype, match_penalty + + def add(self, sig): + if sig not in self.signatures: + self.signatures.append(sig) def normalized(self, func=None): """Return a copy of Signature object where all signatures are @@ -263,18 +282,18 @@ def normalized(self, func=None): if not sig.is_concrete: for csig in sig.apply_templates(templates): assert isinstance(csig, Type), (sig, csig, type(csig)) - if csig not in signature.signatures: - signature.signatures.append(csig) + csig = self.remotejit.normalize_function_type(csig) + signature.add(csig) else: - if sig not in signature.signatures: - signature.signatures.append(sig) + sig = self.remotejit.normalize_function_type(sig) + signature.add(sig) if fsig is not None and fsig.is_complete: - if fsig not in signature.signatures: - signature.signatures.append(fsig) + fsig = self.remotejit.normalize_function_type(fsig) + signature.add(fsig) return signature -class Caller(object): +class Caller: """Remote JIT caller, holds the decorated function that can be executed remotely. """ @@ -310,14 +329,20 @@ def local(self): """Return Caller instance that executes function calls on the local host. Useful for debugging. """ + if not self.remotejit.supports_local_caller: + msg = ( + "Cannot create a local `Caller` when using " + f"{type(self.remotejit).__name__}." + ) + raise UnsupportedError(msg) + return Caller(self.func, self.signature.local) def __repr__(self): - return '%s(%s, %s, local=%s)' % (type(self).__name__, self.func, - self.signature, self.local) + return f"{type(self).__name__}({self.func}, {self.signature!r})" def __str__(self): - return self.describe() + return f"{self.func.__name__}[{self.signature}]" def describe(self): """Return LLVM IRs of all target devices. @@ -336,6 +361,7 @@ def describe(self): llvm_module, succesful_fids = irtools.compile_to_LLVM( [(self.func, signatures_map)], target_info, + pipeline_class=OmnisciCompilerPipeline, debug=self.remotejit.debug) lst.append(str(llvm_module)) lst.append(f'{"":-^80}') @@ -348,29 +374,132 @@ def get_signatures(self): # RBC user-interface - def __call__(self, *arguments, **options): + def __call__(self, *arguments, device=UNSPECIFIED, hold=UNSPECIFIED): """Return the result of a remote JIT compiled function call. """ - device = options.get('device') - targets = self.remotejit.targets - if device is None: - if len(targets) > 1: - raise TypeError( - f'specifying device is required when target has more than' - f' one device. Available devices: {", ".join(targets)}') - device = tuple(targets)[0] - target_info = targets[device] - with target_info: - atypes = tuple(map(Type.fromvalue, arguments)) - ftype = self.signature.best_match(self.func, atypes) - key = self.func.__name__, ftype - if key not in self._is_compiled: - self.remotejit.remote_compile(self.func, ftype, target_info) - self._is_compiled.add(key) - return self.remotejit.remote_call(self.func, ftype, arguments) + caller = self.remotejit.get_caller(self.func.__name__) + return caller(*arguments, device=device, hold=hold) + +class RemoteDispatcher: + """A collection of Caller instances holding functions with a common name. + """ + def __init__(self, name, callers): + self.name = name + assert callers # at least one caller must be specified + self.remotejit = callers[0].remotejit + self.callers = callers + + def __repr__(self): + lst = [str(caller.signature) for caller in self.callers] + return f'{type(self).__name__}({self.name!r}, [{", ".join(lst)}])' + + def __str__(self): + lst = [str(caller.signature) for caller in self.callers] + return f'{self.name}[{", ".join(lst)}]' -class RemoteJIT(object): + def __call__(self, *arguments, device=UNSPECIFIED, hold=UNSPECIFIED): + """Perform remote call with given arguments. + + If `hold` is True, return an object that encapsulates the + remote call to postpone the remote execution. + """ + if hold is UNSPECIFIED: + hold = self.remotejit.default_remote_call_hold + + penalty_device_caller_ftype = [] + atypes = None + for device_, target_info in self.remotejit.targets.items(): + if device is not UNSPECIFIED and device != device_: + continue + with target_info: + atypes = self.remotejit.get_types(*arguments) + for caller_id, caller in enumerate(self.callers): + with Type.alias(**self.remotejit.typesystem_aliases): + ftype, penalty = caller.signature.best_match(caller.func, atypes) + if ftype is None: + continue + penalty_device_caller_ftype.append((penalty, device_, caller_id, ftype)) + if atypes is None: + raise ValueError(f'no target info found for given device {device}') + + penalty_device_caller_ftype.sort() + + if not penalty_device_caller_ftype: + available_types_devices = defaultdict(set) + for device_, target_info in self.remotejit.targets.items(): + if device is not UNSPECIFIED and device != device_: + continue + with target_info: + for caller in self.callers: + with Type.alias(**self.remotejit.typesystem_aliases): + for t in caller.signature.normalized(caller.func).signatures: + available_types_devices[t].add(device_) + lines = self.remotejit._format_available_function_types(available_types_devices) + available = '\n ' + '\n '.join(lines) + satypes = ', '.join(map(str, atypes)) + raise TypeError( + f'found no matching function signature to given argument types:' + f'\n ({satypes}) -> ...\n available function signatures:{available}') + + _, device, caller_id, ftype = penalty_device_caller_ftype[0] + target_info = self.remotejit.targets[device] + caller = self.callers[caller_id] + r = self.remotejit.remote_call_capsule_cls(caller, target_info, ftype, arguments) + + return r if hold else r.execute() + + +class RemoteCallCapsule: + """Encapsulates remote call execution. + """ + + use_execute_cache = False + + def __init__(self, caller, target_info, ftype, arguments): + self.caller = caller + self.target_info = target_info + self.ftype = ftype + self.arguments = arguments + self._execute_cache = UNSPECIFIED + + @property + def __typesystem_type__(self): + """The typesystem Type instance of the return value of the remote + call. + """ + return self.caller.remotejit.caller_signature(self.ftype)[0] + + def __repr__(self): + return (f'{type(self).__name__}({self.caller!r}, {self.target_info},' + f' {self.ftype}, {self.arguments})') + + def __str__(self): + return f'{self.execute(hold=True)}' + + def execute(self, hold=False): + """Trigger the remote call execution. + + When `hold` is True, return an object that represents the + remote call. + """ + if not hold: + if self.use_execute_cache and self._execute_cache is not UNSPECIFIED: + return self._execute_cache + + key = self.caller.func.__name__, self.ftype + if key not in self.caller._is_compiled: + self.caller.remotejit.remote_compile( + self.caller.func, self.ftype, self.target_info) + self.caller._is_compiled.add(key) + result = self.caller.remotejit.remote_call(self.caller.func, self.ftype, + self.arguments, hold=hold) + if not hold and self.use_execute_cache: + self._execute_cache = result + return result + + +class RemoteJIT: """RemoteJIT is a decorator generator for user functions to be remotely JIT compiled. @@ -403,8 +532,16 @@ def bar(a, b): typesystem_aliases = dict() + remote_call_capsule_cls = RemoteCallCapsule + + # Some callers cannot be called locally + supports_local_caller = True + + # Should calling RemoteDispatcher hold the execution: + default_remote_call_hold = False + def __init__(self, host='localhost', port=11532, - local=False, debug=False): + local=False, debug=False, use_tracing_allocator=False): """Construct remote JIT function decorator. The decorator is re-usable for different functions. @@ -419,11 +556,17 @@ def __init__(self, host='localhost', port=11532, When True, use local client. Useful for debugging. debug : bool When True, output debug messages. + use_tracing_allocator : bool + When True, enable the automatic detection of memory leaks. """ if host == 'localhost': host = get_local_ip() + if use_tracing_allocator and not local: + raise ValueError('use_tracing_allocator=True can be used only with local=True') + self.debug = debug + self.use_tracing_allocator = use_tracing_allocator self.host = host self.port = int(port) self.server_process = None @@ -435,7 +578,8 @@ def __init__(self, host='localhost', port=11532, self._targets = None if local: - self._client = LocalClient(debug=debug) + self._client = LocalClient(debug=debug, + use_tracing_allocator=use_tracing_allocator) else: self._client = None @@ -446,11 +590,26 @@ def local(self): return localjit def add_caller(self, caller): - self._callers.append(caller) + name = caller.func.__name__ + for c in self._callers: + if c.name == name: + c.callers.append(caller) + break + else: + self._callers.append(RemoteDispatcher(name, [caller])) self.discard_last_compile() def get_callers(self): - return self._callers + callers = [] + for c in self._callers: + callers.extend(c.callers) + return callers + + def get_caller(self, name): + for c in self._callers: + if c.name == name: + return c + return def reset(self): """Drop all callers definitions and compilation results. @@ -550,12 +709,12 @@ def targets(self): self._targets = self.retrieve_targets() return self._targets - def __call__(self, *signatures, **options): + def __call__(self, *signatures, devices=None, local=False, **templates): """Define a remote JIT function signatures and template. Parameters ---------- - signatures : tuple + signatures : str or object Specify signatures of a remote JIT function, or a Python function as a template from which the remote JIT function will be compiled. @@ -564,8 +723,9 @@ def __call__(self, *signatures, **options): ------------------ local : bool devices : list - Specify device names for the given set of signatures. - templates : dict + Specify device names for the given set of signatures. Possible + values are 'cpu', 'gpu'. + templates : dict(str, list(str)) Specify template types mapping. Returns @@ -582,12 +742,20 @@ def __call__(self, *signatures, **options): or any other object that can be converted to function type, see `Type.fromobject` for more information. """ - if options.get('local'): + if local: s = Signature(self.local) else: s = Signature(self) - devices = options.get('devices') - options, templates = extract_templates(options) + options = dict( + local=local, + devices=devices, + templates=templates.get('templates') or templates + ) + if devices is not None and not {'cpu', 'gpu'}.issuperset(devices): + raise ValueError("'devices' can only be a list with possible " + f"values 'cpu', 'gpu' but got {devices}") + + _, templates = extract_templates(options) for sig in signatures: s = s(sig, devices=devices, templates=templates) return s @@ -648,8 +816,12 @@ def remote_compile(self, func, ftype: Type, target_info: TargetInfo): """ if self.debug: print(f'remote_compile({func}, {ftype})') - llvm_module, succesful_fids = irtools.compile_to_LLVM( - [(func, {0: ftype})], target_info, debug=self.debug) + with target_info: + llvm_module, succesful_fids = irtools.compile_to_LLVM( + [(func, {0: ftype})], + target_info, + pipeline_class=OmnisciCompilerPipeline, + debug=self.debug) ir = str(llvm_module) mangled_signatures = ';'.join([s.mangle() for s in [ftype]]) response = self.client(remotejit=dict( @@ -657,18 +829,25 @@ def remote_compile(self, func, ftype: Type, target_info: TargetInfo): assert response['remotejit']['compile'], response return llvm_module - def remote_call(self, func, ftype: Type, arguments: tuple): + def remote_call(self, func, ftype: Type, arguments: tuple, hold=False): """Call function remotely on given arguments. The input function `func` is called remotely by sending the arguments data to remote host where the previously compiled function (see `remote_compile` method) is applied to the arguments, and the result is returned to local process. + + If `hold` is True then return an object that specifies remote + call but does not execute it. The type of return object is + custom to particular RemoteJIT specialization. """ if self.debug: print(f'remote_call({func}, {ftype}, {arguments})') fullname = func.__name__ + ftype.mangle() - response = self.client(remotejit=dict(call=(fullname, arguments))) + call = dict(call=(fullname, arguments)) + if hold: + return call + response = self.client(remotejit=call) return response['remotejit']['call'] def python(self, statement): @@ -677,6 +856,22 @@ def python(self, statement): response = self.client(remotejit=dict(python=(statement,))) return response['remotejit']['python'] + def normalize_function_type(self, ftype: Type): + """Apply RemoteJIT specific hooks to normalized function Type. + + Parameters + ---------- + ftype: Type + typesystem type of a function + + Returns + ------- + ftype: Type + typesystem type of a function with normalization hools applied + """ + assert ftype.is_function, ftype + return ftype + def preprocess_callable(self, func): """Preprocess func to be used as a remotejit function definition. @@ -691,13 +886,54 @@ def preprocess_callable(self, func): """ return func + def caller_signature(self, signature: Type): + """Return signature of a caller. + + Parameters + ---------- + signature: Type + Signature of function implementation + + Returns + ------- + signature: Type + Signature of function caller + """ + return signature + + def get_types(self, *values): + """Convert values to the corresponding typesystem types. + """ + return tuple(map(Type.fromvalue, values)) + + def format_type(self, typ: Type): + """Convert typesystem type to formatted string. + """ + return str(typ) + + def _format_available_function_types(self, available_types_devices): + all_devices = set() + list(map(all_devices.update, available_types_devices.values())) + lines = [] + for typ, devices in available_types_devices.items(): + sig = self.caller_signature(typ) + d = ' ' + '|'.join(devices) + ' only' if len(devices) != len(all_devices) else '' + s = self.format_type(sig) + t = self.format_type(typ) + if sig == typ: + lines.append(f'{s}{d}') + else: + lines.append(f'{s}{d}\n - {t}') + return lines + class DispatcherRJIT(Dispatcher): """Implements remotejit service methods. """ - def __init__(self, server, debug=False): + def __init__(self, server, debug=False, use_tracing_allocator=False): super().__init__(server, debug=debug) + self.use_tracing_allocator = use_tracing_allocator self.compiled_functions = dict() self.engines = dict() self.python_globals = dict() @@ -712,9 +948,14 @@ def targets(self) -> dict: info : dict Map of target devices and their properties. """ - target_info = TargetInfo.host() + if self.use_tracing_allocator: + target_info = TargetInfo.host(name='host_cpu_tracing_allocator', + use_tracing_allocator=True) + else: + target_info = TargetInfo.host() target_info.set('has_numba', True) target_info.set('has_cpython', True) + target_info.set('software', 'remotejit') return dict(cpu=target_info.tojson()) @dispatchermethod @@ -762,6 +1003,16 @@ def call(self, fullname: str, arguments: tuple) -> Data: arguments : tuple Specify the arguments to the function. """ + # if we are using a tracing allocator, automatically detect memory leaks + # at each call. + if self.use_tracing_allocator: + leak_detector = tracing_allocator.new_leak_detector() + else: + leak_detector = nullcontext() + with leak_detector: + return self._do_call(fullname, arguments) + + def _do_call(self, fullname, arguments): if self.debug: print(f'call({fullname}, {arguments})') ef = self.compiled_functions.get(fullname) @@ -820,14 +1071,15 @@ class DebugDispatcherRJIT(DispatcherRJIT): debug = True -class LocalClient(object): +class LocalClient: """Pretender of thrift.Client. All calls will be made in a local process. Useful for debbuging. """ - def __init__(self, debug=False): - self.dispatcher = DispatcherRJIT(None, debug=debug) + def __init__(self, debug=False, use_tracing_allocator=False): + self.dispatcher = DispatcherRJIT(None, debug=debug, + use_tracing_allocator=use_tracing_allocator) def __call__(self, **services): results = {} diff --git a/rbc/stdlib/__init__.py b/rbc/stdlib/__init__.py new file mode 100644 index 000000000..2be91e9ff --- /dev/null +++ b/rbc/stdlib/__init__.py @@ -0,0 +1,203 @@ +import functools +from enum import Enum +from numba.core import extending +from rbc.omnisci_backend import Array, ArrayPointer +from rbc import typesystem + + +ARRAY_API_ADDRESS = ("https://data-apis.org/array-api/latest/API_specification" + "/generated/signatures.{0}.{1}.html" + "#signatures.{0}.{1}") +NUMPY_API_ADDRESS = ("https://numpy.org/doc/stable/reference/generated/numpy.{0}.html") +ADDRESS = ARRAY_API_ADDRESS + + +class API(Enum): + NUMPY_API = 0 + ARRAY_API = 1 + + +def determine_dtype(a, dtype): + if isinstance(a, ArrayPointer): + return a.eltype if dtype is None else dtype + else: + return a if dtype is None else dtype + + +def determine_input_type(argty): + if isinstance(argty, ArrayPointer): + return determine_input_type(argty.eltype) + + if argty == typesystem.boolean8: + return bool + else: + return argty + + +class Expose: + def __init__(self, globals, module_name): + self._globals = globals + self.module_name = module_name + + def create_function(self, func_name): + s = f'def {func_name}(*args, **kwargs): pass' + exec(s, self._globals) + fn = self._globals.get(func_name) + return fn + + def format_docstring(self, ov_func, func_name, api): + original_docstring = ov_func.__doc__ + if api == API.NUMPY_API: + # Numpy + link = ( + f"`NumPy '{func_name}' " + f"doc <{NUMPY_API_ADDRESS.format(func_name)}>`_") + else: + # Array API + link = ( + f"`Array-API '{func_name}' " + f"doc <{ARRAY_API_ADDRESS.format(self.module_name, func_name)}>`_") + + if original_docstring is not None: + new_doctring = f"{original_docstring}\n\n{link}" + else: + new_doctring = link + return new_doctring + + def implements(self, func_name, api=API.ARRAY_API): + fn = self.create_function(func_name) + decorate = extending.overload(fn) + + def wrapper(overload_func): + overload_func.__doc__ = self.format_docstring(overload_func, func_name, api) + functools.update_wrapper(fn, overload_func) + return decorate(overload_func) + + return wrapper + + def not_implemented(self, func_name): + s = f'def {func_name}(*args, **kwargs): pass' + exec(s, self._globals) + + fn = self._globals.get(func_name) + + def wraps(func): + func.__doc__ = "❌ Not implemented" + functools.update_wrapper(fn, func) + return func + return wraps + + +class BinaryUfuncExpose(Expose): + + def implements(self, ufunc, ufunc_name=None, dtype=None, api=API.ARRAY_API): + """ + Wrapper for binary ufuncs that returns an array + """ + if ufunc_name is None: + ufunc_name = ufunc.__name__ + + def binary_ufunc_impl(a, b): + typA = determine_input_type(a) + typB = determine_input_type(b) + + # XXX: raise error if len(a) != len(b) + @extending.register_jitable(_nrt=False) + def binary_impl(a, b, nb_dtype): + sz = len(a) + x = Array(sz, nb_dtype) + for i in range(sz): + cast_a = typA(a[i]) + cast_b = typB(b[i]) + x[i] = nb_dtype(ufunc(cast_a, cast_b)) + return x + + @extending.register_jitable(_nrt=False) + def broadcast(e, sz, dtype): + b = Array(sz, dtype) + b.fill(e) + return b + + if isinstance(a, ArrayPointer) and isinstance(b, ArrayPointer): + nb_dtype = determine_dtype(a, dtype) + + def impl(a, b): + return binary_impl(a, b, nb_dtype) + return impl + elif isinstance(a, ArrayPointer): + nb_dtype = determine_dtype(a, dtype) + other_dtype = b + + def impl(a, b): + b = broadcast(b, len(a), other_dtype) + return binary_impl(a, b, nb_dtype) + return impl + elif isinstance(b, ArrayPointer): + nb_dtype = determine_dtype(b, dtype) + other_dtype = a + + def impl(a, b): + a = broadcast(a, len(b), other_dtype) + return binary_impl(a, b, nb_dtype) + return impl + else: + nb_dtype = determine_dtype(a, dtype) + + def impl(a, b): + cast_a = typA(a) + cast_b = typB(b) + return nb_dtype(ufunc(cast_a, cast_b)) + return impl + + fn = self.create_function(ufunc_name) + + def wrapper(overload_func): + overload_func.__doc__ = self.format_docstring(overload_func, ufunc_name, api) + functools.update_wrapper(fn, overload_func) + + decorate = extending.overload(fn) + return decorate(binary_ufunc_impl) + + return wrapper + + +class UnaryUfuncExpose(BinaryUfuncExpose): + + def implements(self, ufunc, ufunc_name=None, dtype=None, api=API.ARRAY_API): + """ + Wrapper for unary ufuncs that returns an array + """ + if ufunc_name is None: + ufunc_name = ufunc.__name__ + + def unary_ufunc_impl(a): + nb_dtype = determine_dtype(a, dtype) + typ = determine_input_type(a) + + if isinstance(a, ArrayPointer): + def impl(a): + sz = len(a) + x = Array(sz, nb_dtype) + for i in range(sz): + # Convert the value to type "typ" + cast = typ(a[i]) + x[i] = nb_dtype(ufunc(cast)) + return x + return impl + else: + def impl(a): + # Convert the value to type typ + cast = typ(a) + return nb_dtype(ufunc(cast)) + return impl + + fn = self.create_function(ufunc_name) + + def wrapper(overload_func): + overload_func.__doc__ = self.format_docstring(overload_func, ufunc_name, api) + functools.update_wrapper(fn, overload_func) + + decorate = extending.overload(fn) + return decorate(unary_ufunc_impl) + + return wrapper diff --git a/rbc/stdlib/array_api.py b/rbc/stdlib/array_api.py new file mode 100644 index 000000000..498de8a07 --- /dev/null +++ b/rbc/stdlib/array_api.py @@ -0,0 +1,11 @@ +""" +Array API for rbc. +""" + +from .datatypes import * # noqa: F401, F403 +from .constants import * # noqa: F401, F403 +from .creation_functions import * # noqa: F401, F403 +from .elementwise_functions import * # noqa: F401, F403 +from .statistical_functions import * # noqa: F401, F403 + +__all__ = [s for s in dir() if not s.startswith('_')] diff --git a/rbc/stdlib/constants.py b/rbc/stdlib/constants.py new file mode 100644 index 000000000..8473411de --- /dev/null +++ b/rbc/stdlib/constants.py @@ -0,0 +1,17 @@ +""" +https://data-apis.org/array-api/latest/API_specification/constants.html +""" +import numpy as np + + +__all__ = [ + 'e', 'inf', 'nan', 'pi' +] + + +# it doesn't seem to be possible to document constants with autosummary +# https://github.com/sphinx-doc/sphinx/issues/6794 +e = np.e +inf = np.inf +nan = np.nan +pi = np.pi diff --git a/rbc/stdlib/creation_functions.py b/rbc/stdlib/creation_functions.py new file mode 100644 index 000000000..4dbaed0be --- /dev/null +++ b/rbc/stdlib/creation_functions.py @@ -0,0 +1,286 @@ +""" +Array API specification for creation functions. + +https://data-apis.org/array-api/latest/API_specification/creation_functions.html +""" + +from rbc import typesystem +from rbc.omnisci_backend.omnisci_array import Array, ArrayPointer +from rbc.stdlib import Expose +from numba import njit +from numba.core import extending, types + +__all__ = [ + 'full', 'full_like', 'empty_like', 'empty', 'zeros', 'zeros_like', + 'ones', 'ones_like', 'array', 'cumsum' +] + + +expose = Expose(globals(), 'creation_functions') + + +@expose.not_implemented('arange') +def arange(start, stop=None, step=1, dtype=None, device=None): + """ + Return evenly spaced values within a given interval. + """ + pass + + +@expose.not_implemented('asarray') +def asarray(obj, dtype=None, device=None, copy=None): + """ + Convert the input to an array. + """ + pass + + +@expose.not_implemented('eye') +def eye(n_rows, n_cols=None, k=0, dtype=None, device=None): + """ + Return a 2-D array with ones on the diagonal and zeros elsewhere. + """ + pass + + +@expose.not_implemented('from_dlpack') +def from_dlpack(x): + """ + """ + pass + + +@expose.not_implemented('linspace') +def linspace(start, stop, num, dtype=None, device=None, endpoint=True): + """ + Return evenly spaced numbers over a specified interval. + """ + pass + + +@expose.not_implemented('meshgrid') +def meshgrid(*arrays, indexing='xy'): + """ + Return coordinate matrices from coordinate vectors. + """ + pass + + +@expose.not_implemented('tril') +def tril(x, k=0): + """ + Lower triangle of an array. + """ + pass + + +@expose.not_implemented('triu') +def triu(x, k=0): + """ + Upper triangle of an array. + """ + pass + + +@expose.implements('full') +def _omnisci_np_full(shape, fill_value, dtype=None): + """ + Return a new array of given shape and type, filled with fill_value. + """ + + # XXX: dtype should be infered from fill_value + if dtype is None: + nb_dtype = types.double + else: + nb_dtype = typesystem.Type.fromobject(dtype).tonumba() + + def impl(shape, fill_value, dtype=None): + a = Array(shape, nb_dtype) + a.fill(nb_dtype(fill_value)) + return a + return impl + + +@expose.implements('full_like') +def _omnisci_np_full_like(a, fill_value, dtype=None): + """ + Return a full array with the same shape and type as a given array. + """ + if isinstance(a, ArrayPointer): + if dtype is None: + nb_dtype = a.eltype + else: + nb_dtype = typesystem.Type.fromobject(dtype).tonumba() + + def impl(a, fill_value, dtype=None): + sz = len(a) + other = Array(sz, nb_dtype) + other.fill(nb_dtype(fill_value)) + return other + return impl + + +@expose.implements('empty_like') +def _omnisci_np_empty_like(a, dtype=None): + """ + Return a new array with the same shape and type as a given array. + """ + if isinstance(a, ArrayPointer): + if dtype is None: + nb_dtype = a.eltype + else: + nb_dtype = typesystem.Type.fromobject(dtype).tonumba() + + def impl(a, dtype=None): + return empty(len(a), nb_dtype) # noqa: F821 + return impl + + +@expose.implements('empty') +def _omnisci_np_empty(shape, dtype=None): + """ + Return a new array of given shape and type, without initializing entries. + """ + if dtype is None: + nb_dtype = types.double + else: + nb_dtype = typesystem.Type.fromobject(dtype).tonumba() + + def impl(shape, dtype=None): + arr = Array(shape, nb_dtype) + for i in range(shape): + arr.set_null(i) + return arr + return impl + + +@expose.implements('zeros') +def _omnisci_np_zeros(shape, dtype=None): + """ + Return a new array of given shape and type, filled with zeros. + """ + + if dtype is None: + nb_dtype = types.double + else: + nb_dtype = typesystem.Type.fromobject(dtype).tonumba() + + fill_value = False if isinstance(nb_dtype, types.Boolean) else 0 + + def impl(shape, dtype=None): + return full(shape, fill_value, nb_dtype) # noqa: F821 + return impl + + +@expose.implements('zeros_like') +def _omnisci_np_zeros_like(a, dtype=None): + """ + Return an array of zeros with the same shape and type as a given array. + """ + if isinstance(a, ArrayPointer): + if dtype is None: + nb_dtype = a.eltype + else: + nb_dtype = typesystem.Type.fromobject(dtype).tonumba() + + fill_value = False if isinstance(nb_dtype, types.Boolean) else 0 + + def impl(a, dtype=None): + return full_like(a, fill_value, nb_dtype) # noqa: F821 + return impl + + +@expose.implements('ones') +def _omnisci_np_ones(shape, dtype=None): + """ + Return a new array of given shape and type, filled with ones. + """ + + if dtype is None: + nb_dtype = types.double + else: + nb_dtype = typesystem.Type.fromobject(dtype).tonumba() + + fill_value = True if isinstance(nb_dtype, types.Boolean) else 1 + + def impl(shape, dtype=None): + return full(shape, fill_value, nb_dtype) # noqa: F821 + return impl + + +@expose.implements('ones_like') +def _omnisci_np_ones_like(a, dtype=None): + """ + Return an array of ones with the same shape and type as a given array. + """ + if isinstance(a, ArrayPointer): + if dtype is None: + nb_dtype = a.eltype + else: + nb_dtype = dtype + + fill_value = True if isinstance(nb_dtype, types.Boolean) else 1 + + def impl(a, dtype=None): + return full_like(a, fill_value, nb_dtype) # noqa: F821 + return impl + + +@expose.implements('array') +def _omnisci_np_array(a, dtype=None): + """ + Create an array. + """ + + @njit + def _omnisci_array_non_empty_copy(a, nb_dtype): + """Implement this here rather than inside "impl". + LLVM DCE pass removes everything if we implement stuff inside "impl" + """ + other = Array(len(a), nb_dtype) + for i in range(len(a)): + other[i] = a[i] + return other + + if isinstance(a, ArrayPointer): + if dtype is None: + nb_dtype = a.eltype + else: + nb_dtype = dtype + + def impl(a, dtype=None): + if a.is_null(): + return empty_like(a) # noqa: F821 + else: + return _omnisci_array_non_empty_copy(a, nb_dtype) + return impl + + +@extending.overload_method(ArrayPointer, 'fill') +def _omnisci_array_fill(x, v): + """ + Fill the array with a scalar value. + """ + if isinstance(x, ArrayPointer): + def impl(x, v): + for i in range(len(x)): + x[i] = v + return impl + + +@expose.implements('cumsum') +def _omnisci_np_cumsum(a): + """ + Return the cumulative sum of the elements along a given axis. + """ + if isinstance(a, ArrayPointer): + eltype = a.eltype + + def impl(a): + sz = len(a) + out = Array(sz, eltype) + out[0] = a[0] + for i in range(sz): + out[i] = out[i-1] + a[i] + return out + return impl diff --git a/rbc/stdlib/datatypes.py b/rbc/stdlib/datatypes.py new file mode 100644 index 000000000..5a1197f0c --- /dev/null +++ b/rbc/stdlib/datatypes.py @@ -0,0 +1,37 @@ +""" +https://data-apis.org/array-api/latest/API_specification/data_types.html +""" + +__all__ = [ + 'Array', + 'bool', + 'int8', + 'int16', + 'int32', + 'int64', + 'uint8', + 'uint16', + 'uint32', + 'uint64', + 'float32', + 'float64' +] + +# NOTE: currently the code lives in rbc.omnisci_backend, but eventually we +# should move it here and leave rbc.omnisci_backend.Array only for backwards +# compatibility +from rbc.omnisci_backend import Array + +# array API data types +from numba.types import ( + boolean as bool, + int8, + int16, + int32, + int64, + uint8, + uint16, + uint32, + uint64, + float32, + float64) diff --git a/rbc/stdlib/elementwise_functions.py b/rbc/stdlib/elementwise_functions.py new file mode 100644 index 000000000..c5b01fce3 --- /dev/null +++ b/rbc/stdlib/elementwise_functions.py @@ -0,0 +1,834 @@ +""" +Array API specification for element-wise functions. + +https://data-apis.org/array- api/latest/API_specification/elementwise_functions.html. +""" + +from rbc.stdlib import Expose, BinaryUfuncExpose, UnaryUfuncExpose, API, determine_input_type +import numpy as np +from rbc import typesystem +from rbc.omnisci_backend import ArrayPointer, Array +from numba.core import types + + +__all__ = [ + 'add', 'subtract', 'multiply', 'divide', 'logaddexp', 'logaddexp2', + 'true_divide', 'floor_divide', 'pow', 'remainder', 'mod', + 'fmod', 'gcd', 'lcm', 'bitwise_and', 'bitwise_or', 'bitwise_xor', + 'bitwise_not', 'atan2', 'hypot', + 'greater', 'greater_equal', 'less', 'less_equal', 'not_equal', + 'equal', 'logical_and', 'logical_or', 'logical_xor', 'maximum', + 'minimum', 'fmax', 'fmin', 'nextafter', 'ldexp', 'negative', + 'positive', 'rint', 'sign', 'abs', 'conj', + 'conjugate', 'exp', 'exp2', 'log', 'log2', 'log10', 'expm1', + 'log1p', 'sqrt', 'square', 'reciprocal', 'bitwise_not', 'sin', 'cos', + 'tan', 'asin', 'acos', 'atan', 'sinh', 'cosh', 'tanh', + 'asinh', 'acosh', 'atanh', 'degrees', 'radians', 'deg2rad', + 'rad2deg', 'logical_not', 'isfinite', 'isinf', 'isnan', 'fabs', + 'floor', 'ceil', 'trunc', 'signbit', 'copysign', 'spacing', + 'heaviside', 'bitwise_left_shift', 'bitwise_right_shift', + 'round', + # numpy specifics + 'power', 'arctan2', 'left_shift', 'right_shift', 'absolute', + 'invert', 'arcsin', 'arctan', 'arccos', 'arcsinh', 'arccosh', 'arctanh' +] + + +expose = Expose(globals(), 'elementwise_functions') +binary_expose = BinaryUfuncExpose(globals(), 'elementwise_functions') +unary_expose = UnaryUfuncExpose(globals(), 'elementwise_functions') + + +# math functions +@binary_expose.implements(np.add) +def _omnisci_add(x1, x2): + """ + Calculates the sum for each element x1_i of the input array x1 with the respective element + x2_i of the input array x2. + """ + pass + + +@binary_expose.implements(np.subtract) +def _omnisci_ufunc_subtract(x1, x2): + """ + Calculates the difference for each element x1_i of the input array x1 with the respective + element x2_i of the input array x2. + """ + pass + + +@binary_expose.implements(np.multiply) +def _omnisci_ufunc_multiply(x1, x2): + """ + Calculates the product for each element x1_i of the input array x1 with the respective element + x2_i of the input array x2. + """ + pass + + +@binary_expose.implements(np.divide, ufunc_name='divide') +def _omnisci_ufunc_divide(x1, x2): + """ + Calculates the division for each element x1_i of the input array x1 with the respective + element x2_i of the input array x2. + """ + pass + + +@binary_expose.implements(np.logaddexp) +def _omnisci_ufunc_logaddexp(x1, x2): + """ + Calculates the logarithm of the sum of exponentiations ``log(exp(x1) + exp(x2))`` for each + element x1_i of the input array x1 with the respective element x2_i of the input array x2. + """ + pass + + +@binary_expose.implements(np.copysign, api=API.NUMPY_API) +def _omnisci_ufunc_copysign(x1, x2): + pass + + +@binary_expose.implements(np.logaddexp2, api=API.NUMPY_API) +def _omnisci_ufunc_logaddexp2(x1, x2): + pass + + +@binary_expose.implements(np.true_divide, api=API.NUMPY_API) +def _omnisci_ufunc_true_divide(x1, x2): + pass + + +@binary_expose.implements(np.floor_divide) +def _omnisci_ufunc_floor_divide(x1, x2): + """ + Rounds the result of dividing each element x1_i of the input array x1 by the respective + element x2_i of the input array x2 to the greatest (i.e., closest to +infinity) integer-value + number that is not greater than the division result. + """ + pass + + +@binary_expose.implements(np.power, ufunc_name='power', api=API.NUMPY_API) +def _omnisci_ufunc_power(x1, x2): + pass + + +@binary_expose.implements(np.power, ufunc_name='pow') +def _omnisci_ufunc_pow(x1, x2): + """ + Calculates an implementation-dependent approximation of exponentiation by raising each element + x1_i (the base) of the input array x1 to the power of x2_i (the exponent), where x2_i is the + corresponding element of the input array x2. + """ + pass + + +@binary_expose.not_implemented('float_power') # not supported by Numba +def _omnisci_ufunc_float_power(x1, x2): + pass + + +@binary_expose.implements(np.remainder) +def _omnisci_ufunc_remainder(x1, x2): + """ + Returns the remainder of division for each element x1_i of the input array x1 and the + respective element x2_i of the input array x2. + """ + pass + + +@binary_expose.implements(np.mod, ufunc_name='mod', api=API.NUMPY_API) +def _omnisci_ufunc_mod(x1, x2): + pass + + +@binary_expose.implements(np.fmod, api=API.NUMPY_API) +def _omnisci_ufunc_fmod(x1, x2): + pass + + +@binary_expose.not_implemented('divmod') # not supported by Numba +def _omnisci_ufunc_divmod(x1, x2): + pass + + +@binary_expose.implements(np.gcd, api=API.NUMPY_API) +def _omnisci_ufunc_gcd(x1, x2): + pass + + +@binary_expose.implements(np.lcm, api=API.NUMPY_API) +def _omnisci_ufunc_lcm(x1, x2): + pass + + +# Bit-twiddling functions +@binary_expose.implements(np.bitwise_and) +def _omnisci_ufunc_bitwise_and(x1, x2): + """ + Computes the bitwise AND of the underlying binary representation of each element x1_iof the + input array x1 with the respective element x2_i of the input array x2. + """ + pass + + +@binary_expose.implements(np.bitwise_or) +def _omnisci_ufunc_bitwise_or(x1, x2): + """ + Computes the bitwise OR of the underlying binary representation of each element x1_i of the + input array x1 with the respective element x2_i of the input array x2. + """ + pass + + +@binary_expose.implements(np.bitwise_xor) +def _omnisci_ufunc_bitwise_xor(x1, x2): + """ + Computes the bitwise XOR of the underlying binary representation of each element x1_i of the + input array x1 with the respective element x2_i of the input array x2. + """ + pass + + +@binary_expose.implements(np.bitwise_not, ufunc_name='bitwise_not') +def _omnisci_ufunc_bitwise_not(x1, x2): + """ + Computes the bitwise NOR of the underlying binary representation of each element x1_i of the + input array x1 with the respective element x2_i of the input array x2. + """ + pass + + +@binary_expose.implements(np.left_shift, api=API.NUMPY_API) +def _omnisci_ufunc_left_shift(x1, x2): + pass + + +@binary_expose.implements(np.left_shift, ufunc_name='bitwise_left_shift') +def _omnisci_ufunc_bitwise_left_shift(x1, x2): + """ + Shifts the bits of each element x1_i of the input array x1 to the left by appending x2_i + (i.e., the respective element in the input array x2) zeros to the right of x1_i. + """ + pass + + +@binary_expose.implements(np.right_shift, api=API.NUMPY_API) +def _omnisci_ufunc_right_shift(x1, x2): + pass + + +@binary_expose.implements(np.right_shift, ufunc_name='bitwise_right_shift') +def _omnisci_ufunc_bitwise_right_shift(x1, x2): + """ + Shifts the bits of each element x1_i of the input array x1 to the right by appending x2_i + (i.e., the respective element in the input array x2) zeros to the right of x1_i. + """ + pass + + +# trigonometric functions +@binary_expose.implements(np.arctan2, api=API.NUMPY_API) +def _omnisci_ufunc_arctan2(x1, x2): + pass + + +@binary_expose.implements(np.arctan2, ufunc_name='atan2') +def _omnisci_ufunc_atan2(x1, x2): + """ + Calculates an implementation-dependent approximation of the inverse tangent of the quotient + x1/x2, having domain [-infinity, +infinity] x ``[-infinity, +infinity]`` (where the x notation + denotes the set of ordered pairs of elements (x1_i, x2_i)) and codomain [-π, +π], for each + pair of elements (x1_i, x2_i) of the input arrays x1 and x2, respectively. + """ + pass + + +@binary_expose.implements(np.hypot, api=API.NUMPY_API) +def _omnisci_ufunc_hypot(x1, x2): + pass + + +# Comparison functions +@binary_expose.implements(np.greater, dtype=typesystem.boolean8) +def _omnisci_ufunc_greater(x1, x2): + """ + Computes the truth value of x1_i > x2_i for each element x1_i of the input array x1 with the + respective element x2_i of the input array x2. + """ + pass + + +@binary_expose.implements(np.greater_equal, dtype=typesystem.boolean8) +def _omnisci_ufunc_greater_equal(x1, x2): + """ + Computes the truth value of x1_i >= x2_i for each element x1_i of the input array x1 with the + respective element x2_i of the input array x2. + """ + pass + + +@binary_expose.implements(np.less, dtype=typesystem.boolean8) +def _omnisci_ufunc_less(x1, x2): + """ + Computes the truth value of x1_i < x2_i for each element x1_i of the input array x1 with the + respective element x2_i of the input array x2. + """ + pass + + +@binary_expose.implements(np.less_equal, dtype=typesystem.boolean8) +def _omnisci_ufunc_less_equal(x1, x2): + """ + Computes the truth value of x1_i <= x2_i for each element x1_i of the input array x1 with the + respective element x2_i of the input array x2. + """ + pass + + +@binary_expose.implements(np.not_equal, dtype=typesystem.boolean8) +def _omnisci_ufunc_not_equal(x1, x2): + """ + Computes the truth value of x1_i != x2_i for each element x1_i of the input array x1 with the + respective element x2_i of the input array x2. + """ + pass + + +@binary_expose.implements(np.equal, dtype=typesystem.boolean8) +def _omnisci_ufunc_equal(x1, x2): + """ + Computes the truth value of x1_i == x2_i for each element x1_i of the input array x1 with the + respective element x2_i of the input array x2. + """ + pass + + +@binary_expose.implements(np.logical_and, dtype=typesystem.boolean8) +def _omnisci_ufunc_logical_and(x1, x2): + """ + Computes the logical AND for each element x1_i of the input array x1 with the respective + element x2_i of the input array x2. + """ + pass + + +@binary_expose.implements(np.logical_or, dtype=typesystem.boolean8) +def _omnisci_ufunc_logical_or(x1, x2): + """ + Computes the logical OR for each element x1_i of the input array x1 with the respective + element x2_i of the input array x2. + """ + pass + + +@binary_expose.implements(np.logical_xor, dtype=typesystem.boolean8) +def _omnisci_ufunc_logical_xor(x1, x2): + """ + "Computes the logical XOR for each element x1_i of the input array x1 with the respective + element x2_i of the input array x2. + """ + pass + + +@binary_expose.implements(np.maximum, api=API.NUMPY_API) +def _omnisci_ufunc_maximum(x1, x2): + pass + + +@binary_expose.implements(np.minimum, api=API.NUMPY_API) +def _omnisci_ufunc_minimum(x1, x2): + pass + + +@binary_expose.implements(np.fmax, api=API.NUMPY_API) +def _omnisci_ufunc_fmax(x1, x2): + pass + + +@binary_expose.implements(np.fmin, api=API.NUMPY_API) +def _omnisci_ufunc_fmin(x1, x2): + pass + + +# Floating functions +@binary_expose.implements(np.nextafter, api=API.NUMPY_API) +def _omnisci_ufunc_nextafter(x1, x2): + pass + + +@binary_expose.implements(np.ldexp, api=API.NUMPY_API) +def _omnisci_ufunc_ldexp(x1, x2): + pass + + +################################################################## + + +@unary_expose.implements(np.around, ufunc_name='round') +def _omnisci_ufunc_round(a): + """ + Rounds each element x_i of the input array x to the nearest integer-valued number. + """ + pass + + +@unary_expose.implements(np.negative) +def _omnisci_ufunc_negative(a): + """Computes the numerical negative of each element x_i (i.e., y_i = -x_i) of the + input array x.""" + pass + + +@unary_expose.implements(np.positive) +def _omnisci_ufunc_positive(a): + """Computes the numerical positive of each element x_i (i.e., y_i = +x_i) of the + input array x.""" + pass + + +@unary_expose.implements(np.absolute, api=API.NUMPY_API) +def _omnisci_ufunc_absolute(a): + pass + + +@unary_expose.implements(np.absolute, ufunc_name='abs') +def _omnisci_ufunc_abs(a): + """ + Calculates the absolute value for each element x_i of the input array x (i.e., the element- + wise result has the same magnitude as the respective element in x but has positive sign). + """ + pass + + +@unary_expose.implements(np.rint, api=API.NUMPY_API) +def _omnisci_ufunc_rint(a): + pass + + +@unary_expose.implements(np.sign) +def _omnisci_ufunc_sign(a): + """ + Returns an indication of the sign of a number for each element x_i of the input array x. + """ + pass + + +@unary_expose.implements(np.conj, ufunc_name='conj', api=API.NUMPY_API) +def _omnisci_ufunc_conj(a): + pass + + +@unary_expose.implements(np.conjugate, api=API.NUMPY_API) +def _omnisci_ufunc_conjugate(a): + pass + + +@unary_expose.implements(np.exp) +def _omnisci_ufunc_exp(a): + """Calculates an implementation-dependent approximation to the exponential function, having + domain. + + [-infinity, +infinity] and codomain [+0, +infinity], for each + element x_i of the input array x (e raised to the power of x_i, + where e is the base of the natural logarithm). + + """ + pass + + +@unary_expose.implements(np.exp2, api=API.NUMPY_API) +def _omnisci_ufunc_exp2(a): + pass + + +@unary_expose.implements(np.log) +def _omnisci_ufunc_log(a): + """ + Calculates an implementation-dependent approximation to the natural (base e) logarithm, having + domain [0, +infinity] and codomain [-infinity, +infinity], for each element x_i of the input + array x. + """ + pass + + +@unary_expose.implements(np.log2) +def _omnisci_ufunc_log2(a): + """Calculates an implementation-dependent approximation to the base 2 logarithm, having + domain. + + [0, + + +infinity] and codomain [-infinity, +infinity], for each element x_i + of the input array x. + + """ + pass + + +@unary_expose.implements(np.log10) +def _omnisci_ufunc_log10(a): + """Calculates an implementation-dependent approximation to the base 10 logarithm, having + domain. + + [0, + + +infinity] and codomain [-infinity, +infinity], for each element x_i + of the input array x. + + """ + pass + + +@unary_expose.implements(np.expm1) +def _omnisci_ufunc_expm1(a): + """Calculates an implementation-dependent approximation to exp(x)-1, having domain [-infinity, + + +infinity] and codomain [-1, +infinity], for each element x_i of the + input array x. + + """ + pass + + +@unary_expose.implements(np.log1p) +def _omnisci_ufunc_log1p(a): + """ + Calculates an implementation-dependent approximation to log(1+x), where log refers to the + natural (base e) logarithm, having domain [-1, +infinity] and codomain [-infinity, +infinity], + for each element x_i of the input array x. + """ + pass + + +@unary_expose.implements(np.sqrt) +def _omnisci_ufunc_sqrt(a): + """ + Calculates the square root, having domain [0, +infinity] and codomain [0, +infinity], for each + element x_i of the input array x. + """ + pass + + +@unary_expose.implements(np.square) +def _omnisci_ufunc_square(a): + """Squares (x_i * x_i) each element x_i of the input array x.""" + pass + + +# @unary_expose.implements(np.cbrt) # not supported by numba +@unary_expose.not_implemented('cbrt') +def _omnisci_ufunc_cbrt(a): + pass + + +@unary_expose.implements(np.reciprocal, api=API.NUMPY_API) +def _omnisci_ufunc_reciprocal(a): + pass + + +# Bit-twiddling functions +@unary_expose.implements(np.invert, api=API.NUMPY_API) +def _omnisci_ufunc_invert(a): + pass + + +@unary_expose.implements(np.invert, ufunc_name='bitwise_invert') +def _omnisci_ufunc_bitwise_invert(a): + """ + Inverts (flips) each bit for each element x_i of the input array x. + """ + pass + + +# trigonometric functions +@unary_expose.implements(np.sin) +def _omnisci_ufunc_sin(a): + """Calculates an implementation-dependent approximation to the sine, having domain (-infinity, + + +infinity) and codomain [-1, +1], for each element x_i of the input + array x. + + """ + pass + + +@unary_expose.implements(np.cos) +def _omnisci_ufunc_cos(a): + """Calculates an implementation-dependent approximation to the cosine, having domain + (-infinity, + + +infinity) and codomain [-1, +1], for each element x_i of the input + array x. + + """ + pass + + +@unary_expose.implements(np.tan) +def _omnisci_ufunc_tan(a): + """Calculates an implementation-dependent approximation to the tangent, having domain + (-infinity, + + +infinity) and codomain (-infinity, +infinity), for each element x_i + of the input array x. + + """ + pass + + +@unary_expose.implements(np.arcsin, api=API.NUMPY_API) +def _omnisci_ufunc_arcsin(a): + pass + + +@unary_expose.implements(np.arcsin, ufunc_name='asin') +def _omnisci_ufunc_asin(a): + """ + Calculates an implementation-dependent approximation of the principal value of the inverse + sine, having domain [-1, +1] and codomain [-π/2, +π/2] for each element x_i of the input array + x. + """ + pass + + +@unary_expose.implements(np.arccos, api=API.NUMPY_API) +def _omnisci_ufunc_arccos(a): + pass + + +@unary_expose.implements(np.arccos, ufunc_name='acos') +def _omnisci_ufunc_acos(a): + """ + Calculates an implementation-dependent approximation of the principal value of the inverse + cosine, having domain [-1, +1] and codomain [+0, +π], for each element x_i of the input array + x. + """ + pass + + +@unary_expose.implements(np.arctan, api=API.NUMPY_API) +def _omnisci_ufunc_arctan(a): + pass + + +@unary_expose.implements(np.arctan, ufunc_name='atan') +def _omnisci_ufunc_atan(a): + """ + Calculates an implementation-dependent approximation of the principal value of the inverse + tangent, having domain [-infinity, +infinity] and codomain [-π/2, +π/2], for each element x_i + of the input array x. + """ + pass + + +@unary_expose.implements(np.sinh) +def _omnisci_ufunc_sinh(a): + """Calculates an implementation-dependent approximation to the hyperbolic sine, having domain. + + [-infinity, +infinity] and codomain [-infinity, +infinity], for each + element x_i of the input array x. + + """ + pass + + +@unary_expose.implements(np.cosh) +def _omnisci_ufunc_cosh(a): + """Calculates an implementation-dependent approximation to the hyperbolic cosine, having + domain. + + [-infinity, +infinity] and codomain [-infinity, +infinity], for each + element x_i in the input array x. + + """ + pass + + +@unary_expose.implements(np.tanh) +def _omnisci_ufunc_tanh(a): + """Calculates an implementation-dependent approximation to the hyperbolic tangent, having + domain. + + [-infinity, +infinity] and codomain [-1, +1], for each element x_i + of the input array x. + + """ + pass + + +@unary_expose.implements(np.arcsinh, api=API.NUMPY_API) +def _omnisci_ufunc_arcsinh(a): + pass + + +@unary_expose.implements(np.arcsinh, ufunc_name='asinh') +def _omnisci_ufunc_asinh(a): + """ + Calculates an implementation-dependent approximation to the inverse hyperbolic sine, having + domain [-infinity, +infinity] and codomain [-infinity, +infinity], for each element x_i in the + input array x. + """ + pass + + +@unary_expose.implements(np.arccosh, api=API.NUMPY_API) +def _omnisci_ufunc_arccosh(a): + pass + + +@unary_expose.implements(np.arccosh, ufunc_name='acosh') +def _omnisci_ufunc_acosh(a): + """ + Calculates an implementation-dependent approximation to the inverse hyperbolic cosine, having + domain [+1, +infinity] and codomain [+0, +infinity], for each element x_i of the input array + x. + """ + pass + + +@unary_expose.implements(np.arctanh, api=API.NUMPY_API) +def _omnisci_ufunc_arctanh(a): + pass + + +@unary_expose.implements(np.arctanh, ufunc_name='atanh') +def _omnisci_ufunc_atanh(a): + """ + Calculates an implementation-dependent approximation to the inverse hyperbolic tangent, having + domain [-1, +1] and codomain [-infinity, +infinity], for each element x_i of the input array + x. + """ + pass + + +@unary_expose.implements(np.degrees, api=API.NUMPY_API) +def _omnisci_ufunc_degrees(a): + pass + + +@unary_expose.implements(np.radians, api=API.NUMPY_API) +def _omnisci_ufunc_radians(a): + pass + + +@unary_expose.implements(np.deg2rad, api=API.NUMPY_API) +def _omnisci_ufunc_deg2rad(a): + pass + + +@unary_expose.implements(np.rad2deg, api=API.NUMPY_API) +def _omnisci_ufunc_rad2deg(a): + pass + + +# Comparison functions +@unary_expose.implements(np.logical_not, dtype=typesystem.boolean8) +def _omnisci_ufunc_logical_not(a): + """ + Computes the logical NOT for each element x_i of the input array x. + """ + pass + + +# Floating functions +@unary_expose.implements(np.isfinite, dtype=typesystem.boolean8) +def _omnisci_ufunc_isfinite(a): + """ + Tests each element x_i of the input array x to determine if finite (i.e., not NaN and not + equal to positive or negative infinity). + """ + pass + + +@unary_expose.implements(np.isinf, dtype=typesystem.boolean8) +def _omnisci_ufunc_isinf(a): + """ + Tests each element x_i of the input array x to determine if equal to positive or negative + infinity. + """ + pass + + +@unary_expose.implements(np.isnan, dtype=typesystem.boolean8) +def _omnisci_ufunc_isnan(a): + """ + Tests each element x_i of the input array x to determine whether the element is NaN. + """ + pass + + +@unary_expose.implements(np.fabs, dtype=types.double, api=API.NUMPY_API) +def _omnisci_ufunc_fabs(a): + pass + + +@unary_expose.implements(np.floor, dtype=types.double) +def _omnisci_ufunc_floor(a): + """ + Rounds each element x_i of the input array x to the greatest (i.e., closest to +infinity) + integer-valued number that is not greater than x_i. + """ + pass + + +@unary_expose.implements(np.ceil, dtype=types.double) +def _omnisci_ufunc_ceil(a): + """ + Rounds each element x_i of the input array x to the smallest (i.e., closest to -infinity) + integer-valued number that is not less than x_i. + """ + pass + + +@unary_expose.implements(np.trunc, dtype=types.double) +def _omnisci_ufunc_trunc(a): + """ + Rounds each element x_i of the input array x to the integer-valued number that is closest to + but no greater than x_i. + """ + pass + + +# not supported? +# @unary_expose.implements(np.isnat, dtype=types.int8) +@unary_expose.not_implemented('isnat') +def _omnisci_ufunc_isnat(a): + pass + + +# issue 152: +@unary_expose.implements(np.signbit, dtype=typesystem.boolean8, api=API.NUMPY_API) +def _omnisci_ufunc_signbit(a): + pass + + +@unary_expose.implements(np.spacing, dtype=types.double, api=API.NUMPY_API) +def _omnisci_ufunc_spacing(a): + pass + + +@expose.implements('heaviside', api=API.NUMPY_API) +def _impl_heaviside(x1, x2): + nb_dtype = types.double + typA = determine_input_type(x1) + typB = determine_input_type(x2) + if isinstance(x1, ArrayPointer): + def impl(x1, x2): + sz = len(x1) + r = Array(sz, nb_dtype) + for i in range(sz): + r[i] = heaviside(x1[i], x2) # noqa: F821 + return r + return impl + else: + def impl(x1, x2): + if typA(x1) < 0: + return nb_dtype(0) + elif typA(x1) == 0: + return nb_dtype(typB(x2)) + else: + return nb_dtype(1) + return impl diff --git a/rbc/stdlib/statistical_functions.py b/rbc/stdlib/statistical_functions.py new file mode 100644 index 000000000..c6d58d177 --- /dev/null +++ b/rbc/stdlib/statistical_functions.py @@ -0,0 +1,151 @@ +""" +Array API specification for statistical functions. + +https://data-apis.org/array-api/latest/API_specification/statistical_functions.html +""" +from rbc.externals.stdio import printf +from rbc import typesystem +from rbc.omnisci_backend import ArrayPointer +from rbc.stdlib import Expose +from numba.core import extending, types, errors +from numba.np import numpy_support +import numpy as np + + +__all__ = [ + 'min', 'max', 'mean', 'prod', 'sum' +] + + +expose = Expose(globals(), 'statistical_functions') + + +def _get_type_limits(eltype): + np_dtype = numpy_support.as_dtype(eltype) + if isinstance(eltype, types.Integer): + return np.iinfo(np_dtype) + elif isinstance(eltype, types.Float): + return np.finfo(np_dtype) + else: + msg = 'Type {} not supported'.format(eltype) + raise errors.TypingError(msg) + + +@extending.overload(max) +@expose.implements('max') +@extending.overload_method(ArrayPointer, 'max') +def _omnisci_array_max(x): + """ + Calculates the maximum value of the input array x + """ + if isinstance(x, ArrayPointer): + # the array api standard says this is implementation specific + limits = _get_type_limits(x.eltype) + t = typesystem.Type.fromobject(x.eltype) + if t.is_float: + min_value = limits.min + elif t.is_int or t.is_uint: + min_value = 0 if t.is_uint else limits.min + 1 + else: + raise TypeError(f'Unsupported type {t}') + + def impl(x): + if len(x) <= 0: + printf("omnisci_array_max: cannot find max of zero-sized array") # noqa: E501 + return min_value + m = x[0] + for i in range(len(x)): + v = x[i] + if v > m: + m = v + return m + return impl + + +@extending.overload(min) +@expose.implements('min') +@extending.overload_method(ArrayPointer, 'min') +def _omnisci_array_min(x): + """ + Calculates the minimum value of the input array x. + """ + if isinstance(x, ArrayPointer): + max_value = _get_type_limits(x.eltype).max + + def impl(x): + if len(x) <= 0: + printf("omnisci_array_min: cannot find min of zero-sized array") # noqa: E501 + return max_value + m = x[0] + for i in range(len(x)): + v = x[i] + if v < m: + m = v + return m + return impl + + +@extending.overload(sum) +@expose.implements('sum') +@extending.overload_method(ArrayPointer, 'sum') +def _omnisci_np_sum(a): + """ + Calculates the sum of the input array x. + """ + if isinstance(a, ArrayPointer): + def impl(a): + s = 0 + n = len(a) + for i in range(n): + s += a[i] + return s + return impl + + +@expose.implements('prod') +@extending.overload_method(ArrayPointer, 'prod') +def _omnisci_np_prod(a): + """ + Calculates the product of input array x elements. + """ + if isinstance(a, ArrayPointer): + def impl(a): + s = 1 + n = len(a) + for i in range(n): + s *= a[i] + return s + return impl + + +@expose.implements('mean') +@extending.overload_method(ArrayPointer, 'mean') +def _omnisci_array_mean(x): + """ + Calculates the arithmetic mean of the input array x. + """ + zero_value = np.nan + + if isinstance(x, ArrayPointer): + def impl(x): + if len(x) == 0: + printf("Mean of empty array") + return zero_value + return sum(x) / len(x) + return impl + + +@expose.not_implemented('std') +def _omnisci_array_std(x, axis=None, correction=0.0, keepdims=False): + """ + Calculates the standard deviation of the input array x. + """ + pass + + +@expose.not_implemented('var') +def _omnisci_array_var(x, axis=None, correction=0.0, keepdims=False): + """ + Calculates the variance of the input array x. + """ + pass diff --git a/rbc/structure_type.py b/rbc/structure_type.py index 879c5a501..0ead718d2 100644 --- a/rbc/structure_type.py +++ b/rbc/structure_type.py @@ -7,10 +7,8 @@ from numba.core import datamodel, extending, types, imputils, typing, cgutils, typeconv -""" TODO: use local registries, currently blocked by overloading -operator.getitem that should use rbc pipeline class. """ -typing_registry = typing.templates.builtin_registry # TODO: Registry() -lowering_registry = imputils.builtin_registry # TODO: Registry() +typing_registry = typing.templates.builtin_registry +lowering_registry = imputils.builtin_registry int8_t = ir.IntType(8) int32_t = ir.IntType(32) diff --git a/rbc/targetinfo.py b/rbc/targetinfo.py index e30879fc9..573e6bcc6 100644 --- a/rbc/targetinfo.py +++ b/rbc/targetinfo.py @@ -79,7 +79,8 @@ def __new__(cls, *args, **kwargs): obj._init(*args, **kwargs) return obj - def _init(self, name: str, strict: bool = False, nested: bool = False): + def _init(self, name: str, strict: bool = False, nested: bool = False, + use_tracing_allocator: bool = False): """ Parameters ---------- @@ -90,16 +91,22 @@ def _init(self, name: str, strict: bool = False, nested: bool = False): typesystem. nested: bool When True, allow nested target info contexts. + use_tracing_allocator: bool + When True, use the tracing allocator, to enable the LeakDetector """ self.name = name self.strict = strict self.nested = nested + self.use_tracing_allocator = use_tracing_allocator self._parent = None self.info = {} self.type_sizeof = {} self._supported_libraries = set() # libfuncs.Library instances self._userdefined_externals = set() + def __repr__(self): + return f'{self.__class__.__name__}(name={self.name!r})' + def add_external(self, *names): self._userdefined_externals.update(names) @@ -123,7 +130,9 @@ def supports(self, name): return False def todict(self): - return dict(name=self.name, strict=self.strict, info=self.info, + return dict(name=self.name, strict=self.strict, + use_tracing_allocator=self.use_tracing_allocator, + info=self.info, type_sizeof=self.type_sizeof, libraries=[lib.name for lib in self._supported_libraries], externals=list(self._userdefined_externals)) @@ -131,7 +140,8 @@ def todict(self): @classmethod def fromdict(cls, data): target_info = cls(data.get('name', 'somedevice'), - strict=data.get('strict', False)) + strict=data.get('strict', False), + use_tracing_allocator=data.get('use_tracing_allocator', False)) target_info.update(data) return target_info @@ -142,7 +152,7 @@ def update(self, data): if isinstance(data, type(self)): data = data.todict() self.info.update(data.get('info', {})) - self.type_sizeof.update(data.get('typeof_sizeof', {})) + self.type_sizeof.update(data.get('type_sizeof', {})) for lib in data.get('libraries', []): self.add_library(lib) self.add_external(*data.get('externals', [])) @@ -168,17 +178,18 @@ def dummy(cls): _host_target_info_cache = {} @classmethod - def host(cls, name='host_cpu', strict=False): + def host(cls, name='host_cpu', strict=False, use_tracing_allocator=False): """Return target info for host CPU. """ - key = (name, strict) + key = (name, strict, use_tracing_allocator) target_info = TargetInfo._host_target_info_cache.get(key) if target_info is not None: return target_info import llvmlite.binding as ll - target_info = cls(name=name, strict=strict) + target_info = cls(name=name, strict=strict, + use_tracing_allocator=use_tracing_allocator) target_info.set('name', ll.get_host_cpu_name()) target_info.set('triple', ll.get_default_triple()) features = ','.join(['-+'[int(v)] + k @@ -213,7 +224,15 @@ def host(cls, name='host_cpu', strict=False): target_info.add_library('m') target_info.add_library('stdio') target_info.add_library('stdlib') - + target_info.add_library('rbclib') + if use_tracing_allocator: + target_info.set('fn_allocate_varlen_buffer', + 'rbclib_tracing_allocate_varlen_buffer') + target_info.set('fn_free_buffer', + 'rbclib_tracing_free_buffer') + else: + target_info.set('fn_allocate_varlen_buffer', 'rbclib_allocate_varlen_buffer') + target_info.set('fn_free_buffer', 'rbclib_free_buffer') cls._host_target_info_cache[key] = target_info return target_info @@ -224,7 +243,8 @@ def set(self, prop, value): supported_keys = ('name', 'triple', 'datalayout', 'features', 'bits', 'compute_capability', 'count', 'threads', 'cores', 'has_cpython', 'has_numba', 'driver', 'software', - 'llvm_version', 'null_values') + 'llvm_version', 'null_values', + 'fn_allocate_varlen_buffer', 'fn_free_buffer') if prop not in supported_keys: print(f'rbc.{type(self).__name__}:' f' unsupported property {prop}={value}.') @@ -280,7 +300,7 @@ def bits(self): return bits # expand this dict as needed return dict(x86_64=64, nvptx64=64, - x86=32, nvptx=32)[self.arch] + x86=32, nvptx=32, arm64=64)[self.arch] @property def datalayout(self): diff --git a/rbc/tests/__init__.py b/rbc/tests/__init__.py index 6434dd940..2ef36a5a7 100644 --- a/rbc/tests/__init__.py +++ b/rbc/tests/__init__.py @@ -4,9 +4,24 @@ import os import pytest import warnings +import numpy from collections import defaultdict +def assert_equal(actual, desired): + """Test equality of actual and desired. + + When both inputs are numpy array or number objects, test equality + of dtype attributes as well. + """ + numpy.testing.assert_equal(actual, desired) + + if isinstance(actual, numpy.ndarray) and isinstance(desired, numpy.ndarray): + numpy.testing.assert_equal(actual.dtype, desired.dtype) + elif isinstance(actual, numpy.number) and isinstance(desired, numpy.number): + numpy.testing.assert_equal(actual.dtype, desired.dtype) + + def sql_execute(query): """Execute a SQL statement to omniscidb server using global instance. @@ -19,7 +34,7 @@ def sql_execute(query): def omnisci_fixture(caller_globals, minimal_version=(0, 0), suffices=['', '10', 'null', 'array', 'arraynull'], - load_columnar=True, debug=False): + load_columnar=True, load_test_data=True, debug=False): """Usage from a rbc/tests/test_xyz.py file: .. code-block:: python @@ -99,7 +114,7 @@ def require_version(version, message=None, label=None): pytest.skip(reason) # Requires update when omniscidb-internal bumps up version number: - current_development_version = (5, 9, 0) + current_development_version = (6, 0, 0) if available_version[:3] > current_development_version: warnings.warn(f'{available_version}) is newer than development version' f' ({current_development_version}), please update the latter!') @@ -151,6 +166,10 @@ def require_version(version, message=None, label=None): config = rbc_omnisci.get_client_config(debug=debug) m = rbc_omnisci.RemoteOmnisci(**config) + if not load_test_data: + yield m + return + sqltypes = ['FLOAT', 'DOUBLE', 'TINYINT', 'SMALLINT', 'INT', 'BIGINT', 'BOOLEAN'] arrsqltypes = [t + '[]' for t in sqltypes] diff --git a/rbc/tests/stdlib/__init__.py b/rbc/tests/stdlib/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/rbc/tests/stdlib/test_array_api.py b/rbc/tests/stdlib/test_array_api.py new file mode 100644 index 000000000..58180e034 --- /dev/null +++ b/rbc/tests/stdlib/test_array_api.py @@ -0,0 +1,48 @@ +from rbc.stdlib import array_api as xp +from rbc.omnisci_backend.omnisci_buffer import free_buffer +from ..test_rbclib import djit # noqa: F401 + + +def test_array_free_function_call(djit): # noqa: F811 + + @djit('int32(int32)') + def fn(size): + a = xp.Array(size, xp.float64) + free_buffer(a) + return size + + res = fn(10) + assert res == 10 + + +def test_array_free_method(djit): # noqa: F811 + + @djit('int32(int32)') + def fn(size): + a = xp.Array(size, xp.float64) + a.free() + return size + + res = fn(10) + assert res == 10 + + +def test_array_constructor_noreturn(djit): # noqa: F811 + + @djit('float64(int32)') + def array_noreturn(size): + a = xp.Array(size, xp.float64) + b = xp.Array(size, xp.float64) + c = xp.Array(size, xp.float64) + for i in range(size): + a[i] = b[i] = c[i] = i + 3.0 + s = 0.0 + for i in range(size): + s += a[i] + b[i] + c[i] - a[i] * b[i] + a.free() + b.free() + c.free() + return s + + res = array_noreturn(10) + assert res == -420 diff --git a/rbc/tests/test_externals_libdevice.py b/rbc/tests/test_externals_libdevice.py index e36ebae8d..17807cd2f 100644 --- a/rbc/tests/test_externals_libdevice.py +++ b/rbc/tests/test_externals_libdevice.py @@ -15,6 +15,9 @@ funcs.append((fname, str(retty), argtys, has_ptr_arg)) +fns = {} + + @pytest.fixture(scope="module") def omnisci(): @@ -48,6 +51,7 @@ def fn(a, b, c): fn.__name__ = f"{omnisci.table_name}_{fname[5:]}" fn = omnisci(f"{retty}({', '.join(argtypes)})", devices=["gpu"])(fn) + fns[fname] = fn for fname, retty, argtys, has_ptr_arg in funcs: if has_ptr_arg: @@ -83,4 +87,7 @@ def test_externals_libdevice(omnisci, fname, retty, argtys, has_ptr_arg): cols = ", ".join(tuple(map(lambda x: cols_dict[x], argtys))) query = f"SELECT {func_name}({cols}) FROM {table}" - _, _ = omnisci.sql_execute(query) + _, result = omnisci.sql_execute(query) + + assert fname in str(fns[fname]) + # to-do: check results diff --git a/rbc/tests/test_omnisci.py b/rbc/tests/test_omnisci.py index e56ee359a..099bab8d0 100644 --- a/rbc/tests/test_omnisci.py +++ b/rbc/tests/test_omnisci.py @@ -1,9 +1,11 @@ import os -from rbc import errors import itertools -import numpy as np import pytest -from rbc.tests import omnisci_fixture +import numpy as np + +from rbc.errors import UnsupportedError, OmnisciServerError +from rbc.tests import omnisci_fixture, assert_equal +from rbc.typesystem import Type rbc_omnisci = pytest.importorskip('rbc.omniscidb') available_version, reason = rbc_omnisci.is_available() @@ -65,6 +67,29 @@ def omnisci(): yield o +def test_direct_call(omnisci): + omnisci.reset() + + @omnisci('double(double)') + def farhenheit2celcius(f): + return (f - 32) * 5 / 9 + + assert_equal(farhenheit2celcius(40).execute(), np.float32(40 / 9)) + + +def test_local_caller(omnisci): + omnisci.reset() + + def func(f): + return f + + caller = omnisci('double(double)')(func) + + msg = "Cannot create a local `Caller`" + with pytest.raises(UnsupportedError, match=msg): + _ = caller.local + + def test_redefine(omnisci): omnisci.reset() @@ -88,36 +113,6 @@ def incr(x): # noqa: F811 assert x1 == x + 2 -def test_forbidden_define(omnisci): - if omnisci.version > (5, 1): - pytest.skip( - f'forbidden defines not required for OmnisciDB {omnisci.version}') - - omnisci.reset() - - msg = "Attempt to define function with name `{name}`" - - @omnisci('double(double)') - def sinh(x): - return np.sinh(x) - - with pytest.raises(errors.ForbiddenNameError) as excinfo: - omnisci.register() - assert msg.format(name='sinh') in str(excinfo.value) - - omnisci.reset() - - @omnisci('double(double)') - def trunc(x): - return np.trunc(x) - - with pytest.raises(errors.ForbiddenNameError) as excinfo: - omnisci.register() - assert msg.format(name='trunc') in str(excinfo.value) - - omnisci.reset() - - def test_single_argument_overloading(omnisci): omnisci.reset() @@ -153,44 +148,6 @@ def mydecr(x): assert isinstance(x1, type(x)) -def test_numpy_forbidden_ufunc(omnisci, nb_version): - omnisci.reset() - - if omnisci.version >= (5, 5) and nb_version >= (0, 52): - pytest.skip( - f'forbidden ufunc not required for OmniSciDB {omnisci.version} ' - f'and Numba {nb_version}') - - if not omnisci.has_cuda: - pytest.skip('forbidden ufunc not required for CUDA-disabled OmniSciDB') - - if omnisci.version >= (5, 5): - # Requires: https://github.com/omnisci/omniscidb-internal/pull/4955 - pytest.skip('forbidden ufunc not required if CPU ufuncs work [omniscidb-interal PR 4955]') - - msg = "Attempt to use function with name `{ufunc}`" - - @omnisci('double(double)') - def arcsin(x): - return np.arcsin(x) - - with pytest.raises(errors.ForbiddenIntrinsicError) as excinfo: - omnisci.register() - assert msg.format(ufunc='asin') in str(excinfo.value) - - omnisci.reset() - - @omnisci('float32(float32, float32)') - def logaddexp(x, y): - return np.logaddexp(x, y) - - with pytest.raises(errors.ForbiddenIntrinsicError) as excinfo: - omnisci.register() - assert msg.format(ufunc='log1pf') in str(excinfo.value) - - omnisci.reset() - - def test_thrift_api_doc(omnisci): omnisci.reset() @@ -209,113 +166,6 @@ def foo(i, v): assert isinstance(x1, type(x)) -def test_manual_ir(omnisci): - omnisci.reset() - descr, result = omnisci.sql_execute( - 'SELECT * FROM {omnisci.table_name}'.format(**locals())) - result = list(result) - assert result == [(0.0, 0.0, 0, 0, 0, 0, 1), (1.0, 1.0, 1, 1, 1, 1, 0), - (2.0, 2.0, 2, 2, 2, 2, 1), (3.0, 3.0, 3, 3, 3, 3, 0), - (4.0, 4.0, 4, 4, 4, 4, 1)] - device_params = omnisci.thrift_call('get_device_parameters', - omnisci.session_id) - cpu_target_triple = device_params['cpu_triple'] - cpu_target_datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" - gpu_target_triple = device_params.get('gpu_triple') - gpu_target_datalayout = ("e-p:64:64:64-i1:8:8-i8:8:8-" - "i16:16:16-i32:32:32-i64:64:64-" - "f32:32:32-f64:64:64-v16:16:16-" - "v32:32:32-v64:64:64-v128:128:128-n16:32:64") - - foo_ir = '''\ -define i32 @foobar(i32 %.1, i32 %.2) { -entry: - %.18.i = mul i32 %.2, %.1 - %.33.i = add i32 %.18.i, 55 - ret i32 %.33.i -} -''' - ast_signatures = "foobar 'int32(int32, int32)'" - device_ir_map = dict() - device_ir_map['cpu'] = ''' -target datalayout = "{cpu_target_datalayout}" -target triple = "{cpu_target_triple}" -{foo_ir} -'''.format(**locals()) - - if gpu_target_triple is not None: - device_ir_map['gpu'] = ''' -target datalayout = "{gpu_target_datalayout}" -target triple = "{gpu_target_triple}" -{foo_ir} -'''.format(**locals()) - - omnisci.thrift_call('register_runtime_udf', omnisci.session_id, - ast_signatures, device_ir_map) - omnisci._last_ir_map = {} # hack - descr, result = omnisci.sql_execute( - 'SELECT i4, foobar(i4, i4) FROM {omnisci.table_name}' - .format(**locals())) - result = list(result) - assert len(result) > 0 - for x, r in result: - assert r == x * x + 55 - - -def test_ir_parse_error(omnisci): - device_params = omnisci.thrift_call('get_device_parameters', - omnisci.session_id) - foo_ir = '''\ -define i32 @foobar(i32 %.1, i32 %.2) { -entry: - %.18.i = mul i32 %.2, %.1 - %.33.i = add i32 %.18.i, 55 - ret i32 %.33.i - -''' - ast_signatures = "foobar 'int32(int32, int32)'" - device_ir_map = dict() - device_ir_map['cpu'] = foo_ir - - gpu_target_triple = device_params.get('gpu_triple') - if gpu_target_triple is not None: - device_ir_map['gpu_triple'] = foo_ir - - with pytest.raises(Exception, match=r".*LLVM IR ParseError:"): - omnisci.thrift_call('register_runtime_udf', omnisci.session_id, - ast_signatures, device_ir_map) - - -def test_ir_query_error(omnisci): - pytest.skip("requires omniscidb-internal catching undefined symbols") - - device_params = omnisci.thrift_call('get_device_parameters', - omnisci.session_id) - gpu_target_triple = device_params.get('gpu_triple') - foo_ir = '''\ -define i32 @foobarrr(i32 %.1, i32 %.2) { -entry: - %.18.i = mul i32 %.2, %.1 - %.33.i = add i32 %.18.i, 55 - ret i32 %.33.i -} -''' - ast_signatures = "foobar 'int32(int32, int32)'" - device_ir_map = dict() - device_ir_map['cpu'] = foo_ir - if gpu_target_triple is not None: - device_ir_map['gpu'] = foo_ir - - omnisci.thrift_call('register_runtime_udf', omnisci.session_id, - ast_signatures, device_ir_map) - try: - omnisci.sql_execute( - 'SELECT i4, foobar(i4, i4) FROM {omnisci.table_name}' - .format(**locals())) - except errors.OmnisciServerError as msg: - assert "use of undefined value '@foobar'" in str(msg) - - def test_multiple_implementation(omnisci): omnisci.reset() @@ -351,7 +201,7 @@ def test_loadtime_udf(omnisci): 'select i4, udf_diff2(i4, i4) from {omnisci.table_name}' .format(**locals())) except Exception as msg: - assert 'No match found for function signature udf_diff' in str(msg) + assert "Undefined function call 'udf_diff2'" in str(msg) return result = list(result) for i_, (i, d) in enumerate(result): @@ -418,7 +268,7 @@ def test_binding(omnisci): column_vars_types = argument_types if available_version[:2] >= (5, 9): - omnisci.require_version((5, 9), 'Requires omniscidb-internal PR 6003', label='docker-dev') + omnisci.require_version((5, 9), 'Requires omniscidb-internal PR 6003') def get_result(overload_types, input_type, is_literal): overload_types_ = overload_types[::-1 if is_literal else 1] @@ -884,3 +734,92 @@ def bits(x): # noqa: F811 ' from {omnisci.table_name} limit 1' .format(**locals())) assert list(result)[0] == (64,) + + +def test_unregistering(omnisci): + omnisci.reset() + + @omnisci('i32(i32)') + def fahrenheit2celsius(f): + return (f - 32) * 5 / 9 + + _, result = omnisci.sql_execute('select fahrenheit2celsius(40)') + assert list(result)[0] == (4,) + + omnisci.unregister() + + msg = "Undefined function call" + with pytest.raises(OmnisciServerError, match=msg): + omnisci.sql_execute('select fahrenheit2celsius(40)') + + +def test_format_type(omnisci): + def test(s, caller=False): + with omnisci.targets['cpu']: + with Type.alias(**omnisci.typesystem_aliases): + typ = Type.fromobject(s) + if caller: + typ = omnisci.caller_signature(typ) + return omnisci.format_type(typ) + + assert test('int32 x') == 'int32 x' + assert test('Column') == 'Column' + assert test('Column') == 'Column' + assert test('Column') == 'Column' + assert test('Column') == 'Column' + assert test('Column z') == 'Column z' + assert test('Column | name=z') == 'Column z' + assert test('Column x | name=z') == 'Column x | name=z' + assert test('Column') == 'Column' + assert test('Column>') == 'Column>' + assert test('Column>') == 'Column>' + + assert test('OutputColumn') == 'OutputColumn' + assert test('ColumnList') == 'ColumnList' + + assert test('UDTF(ColumnList)') == 'UDTF(ColumnList)' + assert test('int32(ColumnList)') == 'UDTF(ColumnList)' + assert (test('UDTF(int32 x, Column y, OutputColumn z)') + == 'UDTF(int32 x, Column y, OutputColumn z)') + assert test('UDTF(RowMultiplier)') == 'UDTF(RowMultiplier)' + assert test('UDTF(RowMultiplier m)') == 'UDTF(RowMultiplier m)' + assert test('UDTF(RowMultiplier | name=m)') == 'UDTF(RowMultiplier m)' + assert test('UDTF(Constant m)') == 'UDTF(Constant m)' + assert test('UDTF(ConstantParameter m)') == 'UDTF(ConstantParameter m)' + assert test('UDTF(SpecifiedParameter m)') == 'UDTF(SpecifiedParameter m)' + assert test('UDTF(PreFlight m)') == 'UDTF(PreFlight m)' + assert test('UDTF(TableFunctionManager mgr)') == 'UDTF(TableFunctionManager mgr)' + assert test('UDTF(Cursor)') == 'UDTF(Cursor, Column>)' + assert test('UDTF(Cursor)') == 'UDTF(Cursor x>)' + assert test('UDTF(Cursor)') == 'UDTF(Cursor x>)' + assert test('UDTF(Cursor)') == 'UDTF(Cursor x>)' + + assert test('int32(int32)') == '(int32) -> int32' + assert test('int32(int32 x)') == '(int32 x) -> int32' + assert test('int32(Array)') == '(Array) -> int32' + assert test('int32(int32[])') == '(Array) -> int32' + assert test('int32(Array x)') == '(Array x) -> int32' + assert test('int32(Bytes)') == '(Bytes) -> int32' + assert test('int32(Bytes x)') == '(Bytes x) -> int32' + assert test('int32(TextEncodingDict)') == '(TextEncodingDict) -> int32' + assert test('int32(TextEncodingDict x)') == '(TextEncodingDict x) -> int32' + assert test('int32(Array x)') == '(Array x) -> int32' + + def test2(s): + return test(s, caller=True) + + assert test2('UDTF(int32, OutputColumn)') == '(int32) -> (Column)' + assert test2('UDTF(OutputColumn)') == '(void) -> (Column)' + assert (test2('UDTF(int32 | sizer, OutputColumn)') + == '(RowMultiplier) -> (Column)') + assert (test2('UDTF(ConstantParameter, OutputColumn)') + == '(ConstantParameter) -> (Column)') + assert test2('UDTF(SpecifiedParameter, OutputColumn)') == '(void) -> (Column)' + assert test2('UDTF(Constant, OutputColumn)') == '(void) -> (Column)' + assert test2('UDTF(PreFlight, OutputColumn)') == '(void) -> (Column)' + assert test2('UDTF(TableFunctionManager, OutputColumn)') == '(void) -> (Column)' + assert (test2('UDTF(RowMultiplier, OutputColumn>)') + == '(RowMultiplier) -> (Column>)') + + assert test2('UDTF(Cursor)') == '(Cursor>) -> void' + assert test2('UDTF(Cursor)') == '(Cursor x>) -> void' diff --git a/rbc/tests/test_omnisci_array.py b/rbc/tests/test_omnisci_array.py index f54599642..30eeca8da 100644 --- a/rbc/tests/test_omnisci_array.py +++ b/rbc/tests/test_omnisci_array.py @@ -1,6 +1,8 @@ import os from collections import defaultdict from rbc.omnisci_backend import Array +from rbc.errors import OmnisciServerError +from rbc.stdlib import array_api from numba import types as nb_types import pytest @@ -48,64 +50,6 @@ def omnisci(): print('%s in deardown' % (type(msg))) -def _test_get_array_size_ir1(omnisci): - omnisci.reset() - # register an empty set of UDFs in order to avoid unregistering - # UDFs created directly from LLVM IR strings when executing SQL - # queries: - omnisci.register() - - device_params = omnisci.thrift_call('get_device_parameters') - cpu_target_triple = device_params['cpu_triple'] - cpu_target_datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" - - # The following are codelets from clang --emit-llvm output with - # attributes removed and change of function names: - Array_getSize_i32_ir = '''\ -define dso_local i64 @Array_getSize_i32(%struct.Array*) align 2 { - %2 = alloca %struct.Array*, align 8 - store %struct.Array* %0, %struct.Array** %2, align 8 - %3 = load %struct.Array*, %struct.Array** %2, align 8 - %4 = getelementptr inbounds %struct.Array, %struct.Array* %3, i32 0, i32 1 - %5 = load i64, i64* %4, align 8 - ret i64 %5 -} -''' - - array_sz_i32_ir = '''\ -define dso_local i32 @array_sz_int32(%struct.Array* byval align 8) { - %2 = call i64 @Array_getSize_i32(%struct.Array* %0) - %3 = trunc i64 %2 to i32 - ret i32 %3 -}''' - - ast_signatures = "array_sz_int32 'int32_t(Array)'" - - device_ir_map = dict() - device_ir_map['cpu'] = f'''\ -target datalayout = "{cpu_target_datalayout}" -target triple = "{cpu_target_triple}" - -%struct.Array = type {{ i32*, i64, i8 }} - -{Array_getSize_i32_ir} - -{array_sz_i32_ir} -''' - - omnisci.thrift_call('register_runtime_udf', - omnisci.session_id, - ast_signatures, device_ir_map) - - desrc, result = omnisci.sql_execute( - f'select i4, array_sz_int32(i4) from {omnisci.table_name}') - for a, sz in result: - assert len(a) == sz - - -@pytest.mark.skipif(available_version[:2] < (5, 2), - reason="test requires 5.2 or newer (got %s)" % ( - available_version,)) @pytest.mark.parametrize('c_name', ['int8_t i1', 'int16_t i2', 'int32_t i4', 'int64_t i8', 'float f4', 'double f8']) @pytest.mark.parametrize('device', ['cpu', 'gpu']) @@ -310,10 +254,6 @@ def array_even_sum_int32(b, x): def test_array_setitem(omnisci): - if omnisci.has_cuda and omnisci.version < (5, 5): - pytest.skip( - 'test_array_setitem: crashes CUDA enabled omniscidb server' - ' [rbc issue 72]') omnisci.reset() @omnisci('double(double[], int32)') @@ -334,20 +274,15 @@ def array_setitem_sum(b, c): def test_array_constructor_noreturn(omnisci): - if omnisci.has_cuda and omnisci.version < (5, 5): - pytest.skip( - 'crashes CUDA enabled omniscidb server [issue 94]') - omnisci.reset() from rbc.omnisci_backend import Array - from numba import types @omnisci('float64(int32)') def array_noreturn(size): - a = Array(size, types.float64) - b = Array(size, types.float64) - c = Array(size, types.float64) + a = Array(size, nb_types.float64) + b = Array(size, nb_types.float64) + c = Array(size, nb_types.float64) for i in range(size): a[i] = b[i] = c[i] = i + 3.0 s = 0.0 @@ -362,21 +297,16 @@ def array_noreturn(size): def test_array_constructor_return(omnisci): - if available_version[:3] == (5, 3, 1): - pytest.skip( - 'crashes CPU-only omniscidb server v 5.3.1 [issue 112]') - omnisci.reset() from rbc.omnisci_backend import Array - from numba import types from rbc.externals.stdio import printf @omnisci('float64[](int32)') def array_return(size): printf("entering array_return(%i)\n", size) - a = Array(size, types.float64) - b = Array(size, types.float64) + a = Array(size, nb_types.float64) + b = Array(size, nb_types.float64) for i in range(size): a[i] = float(i) b[i] = float(size - i - 1) @@ -399,11 +329,10 @@ def test_array_constructor_len(omnisci): omnisci.reset() from rbc.omnisci_backend import Array - from numba import types @omnisci('int64(int32)') def array_len(size): - a = Array(size, types.float64) + a = Array(size, nb_types.float64) return len(a) query = 'select array_len(30)' @@ -413,10 +342,6 @@ def array_len(size): def test_array_constructor_getitem(omnisci): - if omnisci.has_cuda and omnisci.version < (5, 5): - pytest.skip( - 'test_array_constructor_getitem: crashes CUDA enabled omniscidb' - ' server [rbc issue 72]') omnisci.reset() from rbc.omnisci_backend import Array @@ -461,18 +386,15 @@ def array_is_null(size): def test_issue197(omnisci, typ, col, suffix): omnisci.reset() - import rbc.omnisci_backend as np - from numba import types - cast = dict( - trunc=types.int64, - sext=types.int8, - zext=types.uint8, - fptrunc=types.float64, - fpext=types.float32)[suffix] + trunc=nb_types.int64, + sext=nb_types.int8, + zext=nb_types.uint8, + fptrunc=nb_types.float64, + fpext=nb_types.float32)[suffix] def fn_issue197(x): - y = np.zeros_like(x) + y = array_api.zeros_like(x) for i in range(len(x)): y[i] = cast(x[i] + 3) return y @@ -494,11 +416,9 @@ def fn_issue197(x): def test_issue197_bool(omnisci): omnisci.reset() - import rbc.omnisci_backend as np - @omnisci('bool[](bool[])') def fn_issue197_bool(x): - y = np.zeros_like(x) + y = array_api.zeros_like(x) for i in range(len(x)): y[i] = bool(x[i]) return y @@ -526,3 +446,51 @@ def issue109(size): _, result = omnisci.sql_execute('select issue109(3);') assert list(result) == [([0.0, 1.0, 2.0, 3.0, 4.0],)] + + +def test_issue77(omnisci): + + @omnisci('int64[]()') + def issue77(): + a = Array(5, 'int64') + a.fill(1) + return a + + if omnisci.version[:2] >= (5, 8): + _, result = omnisci.sql_execute('select issue77();') + assert list(result)[0][0] == [1, 1, 1, 1, 1] + else: + with pytest.raises(OmnisciServerError) as exc: + _, result = omnisci.sql_execute('select issue77();') + + assert exc.match('Could not bind issue77()') + + +def test_array_dtype(omnisci): + table = omnisci.table_name + + @omnisci('T(T[])', T=['int32', 'int64']) + def array_dtype_fn(x): + if x.dtype == nb_types.int32: + return 32 + else: + return 64 + + for col, r in (('i4', 32), ('i8', 64)): + _, result = omnisci.sql_execute(f'select array_dtype_fn({col}) from {table}') + assert list(result) == [(r,)] * 5 + + +def test_array_enumerate(omnisci): + table = omnisci.table_name + + @omnisci('T(T[])', T=['int32']) + def array_enumerate(x): + s = 0 + for i, e in enumerate(x): + s += e + return s + + _, result = omnisci.sql_execute(f'select i4, array_enumerate(i4) from {table}') + for arr, s in result: + assert sum(arr) == s diff --git a/rbc/tests/test_omnisci_array_functions.py b/rbc/tests/test_omnisci_array_functions.py index 161d2747a..82e2c65f9 100644 --- a/rbc/tests/test_omnisci_array_functions.py +++ b/rbc/tests/test_omnisci_array_functions.py @@ -1,6 +1,6 @@ import pytest import numpy as np -import rbc.omnisci_backend as omni +from rbc.stdlib import array_api from numba.core import types @@ -56,56 +56,68 @@ def row_value(row, col, colname): def np_ones(sz): - return omni.ones(sz, types.int32) + return array_api.ones(sz, types.int32) def np_ones_dtype(sz): - return omni.ones(sz) + return array_api.ones(sz) def np_ones_like_dtype(i4): - return omni.ones_like(i4, dtype=types.double) + return array_api.ones_like(i4, dtype=types.double) def np_ones_like(i4): - return omni.ones_like(i4) + return array_api.ones_like(i4) + + +def np_empty(sz): + return array_api.empty(sz, np.int32) + + +def np_empty_dtype(sz): + return array_api.empty(sz) + + +def np_empty_like(i4): + return array_api.empty_like(i4) def np_zeros(sz): - return omni.zeros(sz, np.int32) + return array_api.zeros(sz, np.int32) def np_zeros_dtype(sz): - return omni.zeros(sz) + return array_api.zeros(sz) def np_zeros_like(i4): - return omni.zeros_like(i4) + return array_api.zeros_like(i4) def np_zeros_like_dtype(i4): - return omni.zeros_like(i4, dtype=types.double) + return array_api.zeros_like(i4, dtype=types.double) def np_full(sz, fill_value): - return omni.full(sz, fill_value, types.double) + return array_api.full(sz, fill_value, dtype=types.double) def np_full_dtype(sz, fill_value): - return omni.full(sz, fill_value) + return array_api.full(sz, fill_value) def np_full_like(i1, fill_value): - return omni.full_like(i1, fill_value) + return array_api.full_like(i1, fill_value) def np_full_like_dtype(i1, fill_value): - return omni.full_like(i1, fill_value, dtype=types.double) + return array_api.full_like(i1, fill_value, dtype=types.double) def np_cumsum(sz): - a = omni.ones(sz) - return omni.cumsum(a) + a = array_api.ones(sz) + return array_api.cumsum(a) array_methods = [ @@ -121,6 +133,9 @@ def np_cumsum(sz): ('zeros_like', 'int32[](int32[])', ('i4',), np.zeros(6, dtype='i')), ('zeros_like_dtype', 'double[](int32[])', ('i4',), np.zeros(6, dtype='q')), ('zeros_dtype', 'double[](int64)', (5,), np.zeros(5)), + ('empty', 'int32[](int64)', (5,), np.empty(5, dtype=np.int32)), + ('empty_like', 'int32[](int32[])', ('i4',), np.empty(6, dtype='i')), + ('empty_dtype', 'double[](int64)', (5,), np.empty(5)), ('cumsum', 'double[](int32)', (5,), np.arange(1, 6)), ] @@ -128,11 +143,6 @@ def np_cumsum(sz): @pytest.mark.parametrize("method, signature, args, expected", array_methods, ids=[item[0] for item in array_methods]) def test_array_methods(omnisci, method, signature, args, expected): - if (available_version[:3] == (5, 3, 1) - and method in ['full', 'full_dtype', 'ones', 'ones_dtype', 'zeros', - 'zeros_dtype', 'cumsum']): - pytest.skip( - f'{method}: crashes CPU-only omniscidb server v 5.4 [issue 113]') omnisci.reset() fn = omnisci(signature)(eval('np_{}'.format(method))) @@ -144,4 +154,21 @@ def test_array_methods(omnisci, method, signature, args, expected): _, result = omnisci.sql_execute(query) out = list(result)[0] - assert np.array_equal(expected, out[0]), 'np_' + method + if 'empty' in method: + assert out == ([None] * len(expected),) + else: + assert np.array_equal(expected, out[0]), 'np_' + method + + +@pytest.mark.parametrize('col', ('i4', 'i8', 'f4')) +def test_dtype(omnisci, col): + omnisci.reset() + + @omnisci('T[](T[])', T=['int32', 'int64', 'float32'], devices=['cpu']) + def zeros_like(x): + z = array_api.zeros(len(x), x.dtype) + return z + + query = f'select zeros_like({col}) from {omnisci.table_name} limit 1;' + _, result = omnisci.sql_execute(query) + assert np.all(list(result)[0][0] == np.zeros(6, dtype=col)) diff --git a/rbc/tests/test_omnisci_array_math.py b/rbc/tests/test_omnisci_array_math.py index 2fb86e458..554ce5f9d 100644 --- a/rbc/tests/test_omnisci_array_math.py +++ b/rbc/tests/test_omnisci_array_math.py @@ -1,6 +1,7 @@ import pytest import numpy as np import rbc.omnisci_backend as omni # noqa: F401 +from rbc.stdlib import array_api rbc_omnisci = pytest.importorskip('rbc.omniscidb') @@ -113,7 +114,7 @@ def is_number(s): def test_omnisci_array_binary_math(omnisci, method, signature, columns): omnisci.reset() - s = f'def np_{method}(a, b): return omni.{method}(a, b)' + s = f'def np_{method}(a, b): return array_api.{method}(a, b)' exec(s, globals()) omnisci(signature)(eval('np_{}'.format(method))) @@ -175,7 +176,7 @@ def test_omnisci_array_binary_math(omnisci, method, signature, columns): def test_omnisci_array_binary_math_scalar(omnisci, method, signature, args): omnisci.reset() - s = f'def np_{method}(a, b): return omni.{method}(a, b)' + s = f'def np_{method}(a, b): return array_api.{method}(a, b)' exec(s, globals()) omnisci(signature)(eval('np_{}'.format(method))) @@ -258,7 +259,7 @@ def test_omnisci_array_binary_math_scalar(omnisci, method, signature, args): def test_omnisci_array_unary_math_fns(omnisci, method, signature, column): omnisci.reset() - s = f'def np_{method}(a): return omni.{method}(a)' + s = f'def np_{method}(a): return array_api.{method}(a)' exec(s, globals()) omnisci(signature)(eval('np_{}'.format(method))) @@ -282,7 +283,7 @@ def test_heaviside(omnisci): @omnisci('double[](int64[], int64)') def heaviside(x1, x2): - return omni.heaviside(x1, x2) + return array_api.heaviside(x1, x2) query = f'select i8, heaviside(i8, 1) from {omnisci.table_name}' _, result = omnisci.sql_execute(query) diff --git a/rbc/tests/test_omnisci_array_methods.py b/rbc/tests/test_omnisci_array_methods.py index a55ac9548..ff7b60d8a 100644 --- a/rbc/tests/test_omnisci_array_methods.py +++ b/rbc/tests/test_omnisci_array_methods.py @@ -9,6 +9,9 @@ pytestmark = pytest.mark.skipif(not available_version, reason=reason) +NUMERIC_TYPES = ['int8', 'int16', 'int32', 'int64', 'float32', 'float64'] + + @pytest.fixture(scope='module') def omnisci(): for o in omnisci_fixture(globals()): @@ -19,18 +22,29 @@ def omnisci(): ndarray_methods = [ ('fill', (5, 4), [4.0, 4.0, 4.0, 4.0, 4.0]), ('max', (5, 4.0), 4.0), - ('max_empty', (0, ), -128), - ('max_initial', (5, 4.0, 30.0), 30.0), + ('max_empty_int8', (0, ), np.iinfo(np.int8).min + 1), + ('max_empty_int16', (0, ), np.iinfo(np.int16).min + 1), + ('max_empty_int32', (0, ), np.iinfo(np.int32).min + 1), + ('max_empty_int64', (0, ), np.iinfo(np.int64).min + 1), + ('max_empty_float32', (0, ), np.finfo(np.float32).min), + ('max_empty_float64', (0, ), np.finfo(np.float64).min), + ('mean', (5, 2), 2.0), ('mean', (5, 2.0), 2.0), - ('mean_empty_float', (0, ), np.nan), - ('mean_empty_int', (0, ), 0), + ('mean_empty_int8', (0, ), np.nan), + ('mean_empty_int16', (0, ), np.nan), + ('mean_empty_int32', (0, ), np.nan), + ('mean_empty_int64', (0, ), np.nan), + ('mean_empty_float32', (0, ), np.nan), + ('mean_empty_float64', (0, ), np.nan), ('min', (5, 4.0), 4.0), - ('min_empty', (0, ), 32767), - ('min_initial', (5, 4.0, -3.0), -3.0), + ('min_empty_int8', (0, ), np.iinfo(np.int8).max), + ('min_empty_int16', (0, ), np.iinfo(np.int16).max), + ('min_empty_int32', (0, ), np.iinfo(np.int32).max), + ('min_empty_int64', (0, ), np.iinfo(np.int64).max), + ('min_empty_float32', (0, ), np.finfo(np.float32).max), + ('min_empty_float64', (0, ), np.finfo(np.float64).max), ('sum', (5, 2.0), 10.0), - ('sum_initial', (5, 2.0, 2.0), 12.0), ('prod', (5, 3.0), 243.0), - ('prod_initial', (5, 3.0, 2), 486.0), ] @@ -48,16 +62,18 @@ def ndarray_max(size, v): a.fill(v) return a.max() - @omnisci('int8(int32)') - def ndarray_max_empty(size): - a = Array(size, 'int8') - return a.max() - - @omnisci('double(int64, double, double)') - def ndarray_max_initial(size, v, initial): - a = Array(size, 'double') - a.fill(v) - return a.max(initial=initial) + for retty in NUMERIC_TYPES: + for op in ('min', 'max', 'mean'): + fn_name = f'ndarray_{op}_empty_{retty}' + fn = (f'def {fn_name}(size):\n' + f' a = Array(size, "{retty}")\n' + f' return a.{op}()\n') + exec(fn) + fn = locals()[fn_name] + if op == 'mean': + omnisci('float64(int32)')(fn) + else: + omnisci(f'{retty}(int32)')(fn) @omnisci('double(int64, double)') def ndarray_mean(size, v): @@ -65,74 +81,28 @@ def ndarray_mean(size, v): a.fill(v) return a.mean() - @omnisci('float64(int64)') - def ndarray_mean_empty_float(size): - a = Array(size, 'float64') - return a.mean() - - @omnisci('float64(int64)') - def ndarray_mean_empty_int(size): - a = Array(size, 'int32') - return a.mean() - @omnisci('double(int64, double)') def ndarray_min(size, v): a = Array(size, 'double') a.fill(v) return a.min() - @omnisci('int16(int64)') - def ndarray_min_empty(size): - a = Array(size, 'int16') - return a.min() - - @omnisci('double(int64, double, double)') - def ndarray_min_initial(size, v, initial): - a = Array(size, 'double') - a.fill(v) - return a.min(initial=initial) - @omnisci('double(int64, double)') def ndarray_sum(size, v): a = Array(size, 'double') a.fill(v) return a.sum() - @omnisci('double(int64, double, double)') - def ndarray_sum_initial(size, v, initial): - a = Array(size, 'double') - a.fill(v) - return a.sum(initial=initial) - @omnisci('double(int64, double)') def ndarray_prod(size, v): a = Array(size, 'double') a.fill(v) return a.prod() - @omnisci('double(int64, double, double)') - def ndarray_prod_initial(size, v, initial): - a = Array(size, 'double') - a.fill(v) - return a.prod(initial=initial) - @pytest.mark.parametrize("method, args, expected", ndarray_methods, ids=[item[0] for item in ndarray_methods]) def test_ndarray_methods(omnisci, method, args, expected): - if omnisci.has_cuda and omnisci.version < (5, 5): - pytest.skip( - f'{method}: crashes CUDA enabled omniscidb server [issue 93]') - - if available_version[:3] == (5, 3, 1) and method in ['fill']: - pytest.skip( - f'{method}: crashes CPU-only omniscidb server v 5.3.1 [issue 113]') - - if available_version[:3] >= (5, 3, 1) and method in ['max_empty']: - pytest.skip( - f'{method}: fails on CPU-only omniscidb server' - ' v 5.3.1+ [issue 114]') - query_args = ', '.join(map(str, args)) query = f'SELECT ndarray_{method}({query_args})' diff --git a/rbc/tests/test_omnisci_array_null.py b/rbc/tests/test_omnisci_array_null.py index 4cdf1345f..fabd22823 100644 --- a/rbc/tests/test_omnisci_array_null.py +++ b/rbc/tests/test_omnisci_array_null.py @@ -8,7 +8,7 @@ @pytest.fixture(scope='module') def omnisci(): - for o in omnisci_fixture(globals(), minimal_version=(5, 5)): + for o in omnisci_fixture(globals(), minimal_version=(5, 6)): define(o) yield o @@ -29,8 +29,6 @@ def array_null_check(x, index): @pytest.mark.parametrize('col', colnames) def test_array_null(omnisci, col): - omnisci.require_version((5, 5), - 'Requires omniscidb-internal PR 5104 [rbc issue 240]') if col in ['i2', 'i8', 'f8']: omnisci.require_version((5, 7, 0), 'Requires omniscidb-internal PR 5465 [rbc PR 330]') diff --git a/rbc/tests/test_omnisci_array_operators.py b/rbc/tests/test_omnisci_array_operators.py index e6ce1c0e7..521487d98 100644 --- a/rbc/tests/test_omnisci_array_operators.py +++ b/rbc/tests/test_omnisci_array_operators.py @@ -490,23 +490,6 @@ def operator_xor(size): @pytest.mark.parametrize("suffix, args, expected", operator_methods, ids=[item[0] for item in operator_methods]) def test_array_operators(omnisci, suffix, args, expected): - - if omnisci.has_cuda and suffix in ['countOf', 'in', 'not_in'] and omnisci.version < (5, 5): - # https://github.com/xnd-project/rbc/issues/107 - pytest.skip(f'operator_{suffix}: crashes CUDA enabled omniscidb server' - ' [rbc issue 107]') - - if (available_version[:3] == (5, 3, 1) - and suffix in ['abs', 'add', 'and_bw', 'eq', 'floordiv', 'floordiv2', - 'ge', 'gt', 'iadd', 'iand', 'ifloordiv', 'ifloordiv2', - 'ilshift', 'imul', 'ior', 'isub', 'ipow', 'irshift', - 'itruediv', 'itruediv2', 'imod', 'ixor', 'le', 'lshift', - 'lt', 'mul', 'mod', 'ne', 'neg', 'or_bw', 'pos', 'pow', - 'rshift', 'sub', 'truediv', 'truediv2', 'xor']): - pytest.skip( - f'operator_{suffix}: crashes CPU-only omniscidb server v 5.3.1' - ' [issue 115]') - query = 'select operator_{suffix}'.format(**locals()) + \ '(' + ', '.join(map(str, args)) + ')' _, result = omnisci.sql_execute(query) diff --git a/rbc/tests/test_omnisci_black_scholes.py b/rbc/tests/test_omnisci_black_scholes.py index 684295036..8b6a06932 100644 --- a/rbc/tests/test_omnisci_black_scholes.py +++ b/rbc/tests/test_omnisci_black_scholes.py @@ -6,12 +6,6 @@ rbc_omnisci = pytest.importorskip('rbc.omniscidb') available_version, reason = rbc_omnisci.is_available() -if available_version and available_version < (5, 4): - reason = ('New-style UDTFs (with Column arguments) are available' - ' for omniscidb 5.4 or newer, ' - 'currently connected to omniscidb ' - + '.'.join(map(str, available_version))) - available_version = () pytestmark = pytest.mark.skipif(not available_version, reason=reason) @@ -78,10 +72,6 @@ def cnd_numba(d): def test_black_scholes_udf(omnisci): - if omnisci.has_cuda and omnisci.version < (5, 5): - pytest.skip('crashes CUDA enabled omniscidb server' - ' [issue 60]') - omnisci.reset() # register an empty set of UDFs in order to avoid unregistering # UDFs created directly from LLVM IR strings when executing SQL @@ -114,10 +104,6 @@ def black_scholes_UDF(S, X, T, r, sigma): def test_black_scholes_udtf(omnisci): - if omnisci.has_cuda and omnisci.version < (5, 5): - pytest.skip('crashes CUDA enabled omniscidb server' - ' [issue 169]') - omnisci.reset() # register an empty set of UDFs in order to avoid unregistering # UDFs created directly from LLVM IR strings when executing SQL diff --git a/rbc/tests/test_omnisci_caller.py b/rbc/tests/test_omnisci_caller.py new file mode 100644 index 000000000..1a680da0d --- /dev/null +++ b/rbc/tests/test_omnisci_caller.py @@ -0,0 +1,227 @@ +import numpy as np +import pytest +from rbc.externals.omniscidb import set_output_row_size +from rbc.omnisci_backend import Bytes +from rbc.tests import omnisci_fixture, assert_equal + + +@pytest.fixture(scope='module') +def omnisci(): + for o in omnisci_fixture(globals(), minimal_version=(5, 8)): + define(o) + yield o + + +def define(omnisci): + + @omnisci('T(T)', T=['int32', 'int64', 'float32', 'float64']) + def myincr(x): + return x + 1 + + T = ['int64', 'float64', 'int32'] + + @omnisci('UDTF(int32 size, T x0, OutputColumn x)', T=T, devices=['cpu']) + def arange(size, x0, x): + set_output_row_size(size) + for i in range(size): + x[i] = x0 + x.dtype(i) + return size + + T = ['int64', 'float32'] + + @omnisci('UDTF(Column x, T dx, OutputColumn y)', T=T, devices=['cpu']) + def aincr(x, dx, y): + size = len(x) + set_output_row_size(size) + for i in range(size): + y[i] = x[i] + dx + return size + + @omnisci('Bytes(Bytes)') + def myupper(s): + r = Bytes(len(s)) + for i in range(len(s)): + c = s[i] + if c >= 97 and c <= 122: + c = c - 32 + r[i] = c + return r + + +def test_udf_string_repr(omnisci): + myincr = omnisci.get_caller('myincr') + + assert_equal(repr(myincr), + "RemoteDispatcher('myincr', ['T(T), T=int32|int64|float32|float64'])") + assert_equal(str(myincr), "myincr['T(T), T=int32|int64|float32|float64']") + + assert_equal(repr(myincr(5)), + "OmnisciQueryCapsule('SELECT myincr(CAST(5 AS BIGINT))')") + assert_equal(str(myincr(5)), "SELECT myincr(CAST(5 AS BIGINT))") + + assert_equal(repr(myincr(myincr(5))), + "OmnisciQueryCapsule('SELECT myincr(CAST(myincr(CAST(5 AS BIGINT)) AS BIGINT))')") + assert_equal(str(myincr(myincr(5))), + "SELECT myincr(CAST(myincr(CAST(5 AS BIGINT)) AS BIGINT))") + + +def test_udtf_string_repr(omnisci): + arange = omnisci.get_caller('arange') + + assert_equal(repr(arange), + ("RemoteDispatcher('arange', ['UDTF(int32 size, T x0, OutputColumn x)," + " T=int64|float64|int32, device=cpu'])")) + assert_equal(str(arange), + ("arange['UDTF(int32 size, T x0, OutputColumn x)," + " T=int64|float64|int32, device=cpu']")) + + assert_equal(repr(arange(5, 0)), + ("OmnisciQueryCapsule('SELECT x FROM" + " TABLE(arange(CAST(5 AS INT), CAST(0 AS BIGINT)))')")) + assert_equal(str(arange(5, 0)), + "SELECT x FROM TABLE(arange(CAST(5 AS INT), CAST(0 AS BIGINT)))") + + +def test_remote_udf_evaluation(omnisci): + myincr = omnisci.get_caller('myincr') + + assert_equal(str(myincr(3)), 'SELECT myincr(CAST(3 AS BIGINT))') + assert_equal(myincr(3, hold=False), 4) + assert_equal(myincr(3).execute(), 4) + + assert_equal(myincr(3.5).execute(), 4.5) + assert_equal(myincr(np.int64(3)).execute(), np.int64(4)) + assert_equal(myincr(np.float32(3.5)).execute(), np.float32(4.5)) + + +def test_remote_int32_evaluation(omnisci): + myincr = omnisci.get_caller('myincr') + arange = omnisci.get_caller('arange') + + pytest.xfail('SELECT upcasts int32 to int64') + assert_equal(myincr(np.int32(3)), np.int32(4)) + assert_equal(arange(3, np.int32(1))['x'], np.arange(3, dtype=np.int32) + 1) + + +def test_remote_float64_evaluation(omnisci): + myincr = omnisci.get_caller('myincr') + arange = omnisci.get_caller('arange') + + pytest.xfail('SELECT downcasts float64 to float32') + assert_equal(myincr(np.float64(3.5)), np.float64(4.5)) + assert_equal(arange(3, np.float64(1))['x'], np.arange(3, dtype=np.float64) + 1) + + +def test_remote_bytes_evaluation(omnisci): + myupper = omnisci.get_caller('myupper') + assert str(myupper) == "myupper['Bytes(Bytes)']" + assert str(myupper("abc")) == "SELECT myupper('abc')" + assert str(myupper("abc").execute()) == 'ABC' + assert str(myupper(b"abc")) == "SELECT myupper('abc')" + assert str(myupper(b"abc").execute()) == 'ABC' + + +def test_remote_composite_udf_evaluation(omnisci): + myincr = omnisci.get_caller('myincr') + + assert_equal(str(myincr(myincr(3))), + 'SELECT myincr(CAST(myincr(CAST(3 AS BIGINT)) AS BIGINT))') + assert_equal(str(myincr(myincr(3, hold=False))), 'SELECT myincr(CAST(4 AS BIGINT))') + assert_equal(myincr(myincr(3), hold=False), 5) + assert_equal(myincr(myincr(3)).execute(), 5) + + +def test_remote_udtf_evaluation(omnisci): + arange = omnisci.get_caller('arange') + + assert_equal(str(arange(3, 1)), + 'SELECT x FROM TABLE(arange(CAST(3 AS INT), CAST(1 AS BIGINT)))') + + assert_equal(arange(3, 1).execute()['x'], list(np.arange(3, dtype=np.int64) + 1)) + assert_equal(arange(3, 1.5).execute()['x'], list(np.arange(3, dtype=np.float64) + 1.5)) + assert_equal(arange(np.int32(3), 1).execute()['x'], list(np.arange(3, dtype=np.int32) + 1)) + assert_equal(arange(3, np.float32(1)).execute()['x'], np.arange(3, dtype=np.float32) + 1) + assert_equal(arange(3, np.int64(1)).execute()['x'], np.arange(3, dtype=np.int64) + 1) + + +def test_remote_composite_udtf_evaluation(omnisci): + arange = omnisci.get_caller('arange') + aincr = omnisci.get_caller('aincr') + myincr = omnisci.get_caller('myincr') + + r = aincr(arange(3, 1), 2) + assert_equal(str(r), 'SELECT y FROM TABLE(aincr(CURSOR(SELECT x FROM' + ' TABLE(arange(CAST(3 AS INT), CAST(1 AS BIGINT)))), CAST(2 AS BIGINT)))') + + r = r.execute() + assert_equal(r['y'], np.arange(3, dtype=np.int64) + 1 + 2) + + r = arange(3, myincr(2, hold=False)) + assert_equal(str(r), 'SELECT x FROM TABLE(arange(CAST(3 AS INT), CAST(3 AS BIGINT)))') + assert_equal(r.execute()['x'], np.arange(3, dtype=np.int64) + 2 + 1) + + +def test_remote_composite_udtf_udf(omnisci): + """ + TableFunctionExecutionContext.cpp:277 Check failed: + col_buf_ptrs.size() == exe_unit.input_exprs.size() (1 == 2) + """ + myincr = omnisci.get_caller('myincr') + arange = omnisci.get_caller('arange') + + r = arange(3, myincr(2)) + assert_equal(str(r), ('SELECT x FROM TABLE(arange(CAST(3 AS INT),' + ' CAST(myincr(CAST(2 AS BIGINT)) AS BIGINT)))')) + + pytest.xfail('udtf(udf) crashes omniscidb server') + assert_equal(r['x'], np.arange(3, dtype=np.int64) + 2 + 1) + + +def test_remote_udf_typeerror(omnisci): + myincr = omnisci.get_caller('myincr') + try: + myincr("abc") + except TypeError as msg: + assert_equal(str(msg), '''\ +found no matching function signature to given argument types: + (string) -> ... + available function signatures: + (int32) -> int32 + (int64) -> int64 + (float32) -> float32 + (float64) -> float64''') + else: + assert 0 # expected TypeError + + +def test_remote_udtf_typeerror(omnisci): + arange = omnisci.get_caller('arange') + try: + arange(1.2, 0) + except TypeError as msg: + assert_equal(str(msg), '''\ +found no matching function signature to given argument types: + (float64, int64) -> ... + available function signatures: + (int32 size, int64 x0) -> (Column x) + - UDTF(int32 size, int64 x0, OutputColumn x) + (int32 size, float64 x0) -> (Column x) + - UDTF(int32 size, float64 x0, OutputColumn x) + (int32 size, int32 x0) -> (Column x) + - UDTF(int32 size, int32 x0, OutputColumn x)''') + else: + assert 0 # expected TypeError + + +def test_remote_udf_overload(omnisci): + + @omnisci('int32(int32)') # noqa: F811 + def incr_ol(x): # noqa: F811 + return x + 1 + + @omnisci('int32(int32, int32)') # noqa: F811 + def incr_ol(x, dx): # noqa: F811 + return x + dx + + assert incr_ol(1).execute() == 2 + assert incr_ol(1, 2).execute() == 3 diff --git a/rbc/tests/test_omnisci_column_arguments.py b/rbc/tests/test_omnisci_column_arguments.py index fb7116af4..5e3d00784 100644 --- a/rbc/tests/test_omnisci_column_arguments.py +++ b/rbc/tests/test_omnisci_column_arguments.py @@ -5,7 +5,7 @@ @pytest.fixture(scope='module') def omnisci(): - for o in omnisci_fixture(globals(), minimal_version=(5, 5)): + for o in omnisci_fixture(globals(), minimal_version=(5, 6)): define(o) yield o @@ -84,7 +84,6 @@ def text_rbc_copy_cccc_rowmul(x, x2, x3, x4, m, y, y2, y3, y4): def test_copy(omnisci, use_default, inputs): if use_default: omnisci.require_version((5, 7), 'Requires omnisci-internal PR 5403') - omnisci.require_version((5, 5), 'Requires omniscidb-internal PR 5134') groups = inputs.split(';') table_names = [f'{omnisci.table_name}'] * len(groups) @@ -136,7 +135,6 @@ def test_ct_binding_constant_sizer(omnisci, kind): def test_ct_binding_row_multiplier(omnisci, use_default, kind): if use_default: omnisci.require_version((5, 7), 'Requires omnisci-internal PR 5403') - omnisci.require_version((5, 5, 5), 'Requires omniscidb-internal PR 5403/5274') if omnisci.version < (5, 7): suffix = {'91': '2', '369': '2', '169': '3'}.get(kind, '') diff --git a/rbc/tests/test_omnisci_column_basic.py b/rbc/tests/test_omnisci_column_basic.py index 4a562623e..4351ac01b 100644 --- a/rbc/tests/test_omnisci_column_basic.py +++ b/rbc/tests/test_omnisci_column_basic.py @@ -3,16 +3,12 @@ from collections import defaultdict import pytest import numpy as np +import math +from numba import njit rbc_omnisci = pytest.importorskip('rbc.omniscidb') available_version, reason = rbc_omnisci.is_available() -if available_version and available_version < (5, 4): - reason = ('New-style UDTFs (with Column arguments) are available' - ' for omniscidb 5.4 or newer, ' - 'currently connected to omniscidb ' - + '.'.join(map(str, available_version))) - available_version = () pytestmark = pytest.mark.skipif(not available_version, reason=reason) @@ -130,12 +126,6 @@ def my_row_copier_mul_param2(alpha, x, beta, m, y): assert r == ((i % 5) * alpha + 4,) -@pytest.mark.skipif( - available_version < (5, 5), - reason=( - "test requires omniscidb with constant parameter" - " support (got %s) [issue 124]" % ( - available_version,))) def test_sizer_constant_parameter(omnisci): omnisci.reset() # register an empty set of UDFs in order to avoid unregistering @@ -168,12 +158,6 @@ def my_row_copier_cp(x, m, y): assert r == ((i % 5) * 2,) -@pytest.mark.skipif( - available_version < (5, 5), - reason=( - "test requires omniscidb with constant parameter" - " support (got %s) [issue 124]" % ( - available_version,))) def test_sizer_return_size(omnisci): omnisci.reset() # register an empty set of UDFs in order to avoid unregistering @@ -197,11 +181,6 @@ def my_row_copier_c(x, y): assert r == ((i % 5) * 2,), repr((i, r)) -@pytest.mark.skipif( - available_version < (5, 4), - reason=( - "test requires omniscidb v 5.4 or newer (got %s) [issue 148]" % ( - available_version,))) def test_rowmul_add_columns(omnisci): omnisci.reset() # register an empty set of UDFs in order to avoid unregistering @@ -231,12 +210,6 @@ def add_columns(x, y, alpha, m, r): assert r == (i + alpha * (i + 1.5),) -@pytest.mark.skipif( - available_version <= (5, 4), - reason=( - "test requires omniscidb with multiple output" - " columns support (got %s) [issue 150]" % ( - available_version,))) def test_rowmul_return_mixed_columns(omnisci): omnisci.reset() # register an empty set of UDFs in order to avoid unregistering @@ -280,12 +253,6 @@ def ret_mixed_columns(x, m, y, z): assert r[0] == float(3 * i) -@pytest.mark.skipif( - available_version < (5, 4), - reason=( - "test requires omniscidb with multiple output" - " columns support (got %s) [issue 150]" % ( - available_version,))) @pytest.mark.parametrize("max_n", [-1, 3]) @pytest.mark.parametrize("sizer", [1, 2]) @pytest.mark.parametrize("num_columns", [1, 2, 3, 4]) @@ -371,12 +338,6 @@ def ret_4_columns(n, x1, m, y1, y2, y3, y4): assert v == float((i+1) * (j+1)) -@pytest.mark.skipif( - available_version < (5, 5), - reason=( - "test requires omniscidb with single cursor" - " support (got %s) [issue 173]" % ( - available_version,))) @pytest.mark.parametrize("variant", [1, 2, 3]) def test_issue173(omnisci, variant): omnisci.reset() @@ -427,12 +388,6 @@ def mask_zero(x, b, m, y): assert result[i][0] == (0.0 if b[i] else f8[i]) -@pytest.mark.skipif( - available_version < (5, 5), - reason=( - "test requires omniscidb with udtf redefine" - " support (got %s) [issue 175]" % ( - available_version,))) def test_redefine(omnisci): omnisci.reset() # register an empty set of UDFs in order to avoid unregistering @@ -495,12 +450,6 @@ def redefined_udtf(x, m, y): # noqa: E501, F811 assert result[i][0] == f8[i] + 2 -@pytest.mark.skipif( - available_version < (5, 5), - reason=( - "test requires omniscidb with udtf redefine" - " support (got %s) [issue 175]" % ( - available_version,))) @pytest.mark.parametrize("step", [1, 2, 3]) def test_overload_nonuniform(omnisci, step): pytest.xfail('Test failing due to the introduction of default sizer. See PR 313') @@ -561,12 +510,6 @@ def overloaded_udtf(x1, x2, m, y): # noqa: E501, F811 descr, result = omnisci.sql_execute(sql_query) -@pytest.mark.skipif( - available_version < (5, 5), - reason=( - "test requires omniscidb with udtf overload" - " support (got %s) [issue 182]" % ( - available_version,))) def test_overload_uniform(omnisci): omnisci.reset() omnisci.register() @@ -603,28 +546,15 @@ def mycopy(x, m, y): # noqa: E501, F811 omnisci_binary_operations = ['+', '-', '*', '/'] -@pytest.mark.skipif( - available_version < (5, 5), - reason=( - "test requires omniscidb with aggregate udtf column" - " support (got %s) [issue 174]" % ( - available_version,))) @pytest.mark.parametrize("prop", ['', 'groupby']) @pytest.mark.parametrize("oper", omnisci_aggregators + omnisci_aggregators2) def test_column_aggregate(omnisci, prop, oper): - if not omnisci.has_cuda and oper in omnisci_aggregators2 and prop == 'groupby': - pytest.skip(f'{oper}-{prop} test crashes CPU-only omnisci server [rbc issue 237]') - if omnisci.has_cuda and oper in ['sample', 'stddev', 'stddev_pop', 'stddev_samp', - 'correlation', 'corr']: - # unreliable means that the results computed on CPU and on - # CUDA device may slightly vary causing test failures. - pytest.skip(f'{oper}-{prop} test result unreliable when on CUDA') - if omnisci.has_cuda and oper in ['covar_samp', 'covar_pop']: - pytest.skip(f'{oper}-{prop} test crashes CUDA enabled omnisci server') - omnisci.reset() omnisci.register() + if prop == 'groupby': + pytest.skip('omniscidb server crashes') + if oper == 'single_value': if prop: return @@ -717,12 +647,6 @@ def test_rbc_mycopy3(x1, x2, x3, m, y1, y2, y3): assert result == result_expected -@pytest.mark.skipif( - available_version < (5, 5), - reason=( - "test requires omniscidb with aggregate udtf column" - " support (got %s) [issue 174]" % ( - available_version,))) @pytest.mark.parametrize("oper", omnisci_functions + omnisci_functions2) def test_column_function(omnisci, oper): omnisci.reset() @@ -768,12 +692,6 @@ def test_rbc_mycopy2(x1, x2, m, y1, y2): assert result == result_expected -@pytest.mark.skipif( - available_version < (5, 5), - reason=( - "test requires omniscidb with aggregate udtf column" - " support (got %s) [issue 174]" % ( - available_version,))) @pytest.mark.parametrize("oper", omnisci_binary_operations) def test_column_binary_operation(omnisci, oper): omnisci.reset() @@ -803,12 +721,6 @@ def test_rbc_mycopy2(x1, x2, m, y1, y2): assert result == result_expected -@pytest.mark.skipif( - available_version < (5, 5), - reason=( - "test requires omniscidb with aggregate udtf column" - " support (got %s) [issue 174]" % ( - available_version,))) @pytest.mark.parametrize("oper", omnisci_unary_operations) def test_column_unary_operation(omnisci, oper): omnisci.reset() @@ -837,12 +749,6 @@ def test_rbc_mycopy(x1, m, y1): assert result == result_expected -@pytest.mark.skipif( - available_version < (5, 5), - reason=( - "test requires omniscidb create as support" - " (got %s)" % ( - available_version,))) def test_create_as(omnisci): omnisci.reset() omnisci.register() @@ -891,15 +797,12 @@ def create_columns(omnisci): omnisci.sql_execute('DROP TABLE IF EXISTS kerneltable;') -@pytest.mark.skipif( - available_version < (5, 5), - reason=( - "test with different column sizes requires omnisci 5.5" - " support (got %s) [issue 176]" % ( - available_version,))) @pytest.mark.usefixtures('create_columns') def test_column_different_sizes(omnisci): + if omnisci.has_cuda and omnisci.version[:2] == (5, 10): + pytest.xfail('Different result') + @omnisci('int32(Column, Column, RowMultiplier, OutputColumn)') def convolve(x, kernel, m, y): for i in range(len(y)): @@ -919,3 +822,75 @@ def convolve(x, kernel, m, y): expected = [(10.0,), (60.0,), (180.0,), (240.0,), (300.0,)] assert list(result) == expected + + +def test_issue343(omnisci): + # Before generating llvm code, the irtools entry point needs + # to switch the target context from CPU to GPU, so that functions + # are bind to the correct target. In the case below, math.exp + # is bind to '@llvm.exp.f64' on CPU and '@__nv_exp' on GPU. + if not omnisci.has_cuda: + pytest.skip('test requires omniscidb build with GPU support') + + @njit + def bar(x): + return math.exp(x) + + @omnisci('double(double)', devices=['cpu', 'gpu']) + def foo(x): + return math.exp(x) + bar(x) + + assert '__nv_exp' in str(foo) + assert 'llvm.exp.f64' in str(foo) + + +def test_column_dtype(omnisci): + from numba import types + table = omnisci.table_name + + @omnisci('int32(Column, RowMultiplier, OutputColumn)', + T=['int32', 'int64', 'float', 'double']) + def col_dtype_fn(x, m, y): + sz = len(x) + for i in range(sz): + if x.dtype == types.int32: + y[i] = 1 + elif x.dtype == types.int64: + y[i] = 2 + elif x.dtype == types.float32: + y[i] = 3.0 + elif x.dtype == types.float64: + y[i] = 4.0 + else: + y[i] = 'hello world' # this ought be removed by DCE + return sz + + inpts = ( + ('i4', 1), + ('i8', 2), + ('f4', 3.0), + ('f8', 4.0), + ) + for col, r in inpts: + query = f'select * from table(col_dtype_fn(cursor(select {col} from {table}), 1))' + _, result = omnisci.sql_execute(query) + assert list(result) == [(r,)] * 5 + + +def test_column_enumerate(omnisci): + from rbc.externals.omniscidb import set_output_row_size + + @omnisci('int32(Column, OutputColumn)') + def col_enumerate(x, y): + sz = len(x) + set_output_row_size(sz) + for i, e in enumerate(x): + y[i] = e + return sz + + _, result = omnisci.sql_execute( + f'select * from table(col_enumerate(cursor(select i4 from {omnisci.table_name})))') + _, expected_result = omnisci.sql_execute( + f'select rowid, i4 from {omnisci.table_name} order by rowid;') + for (r,), (_, e) in zip(list(result), list(expected_result)): + assert r == e diff --git a/rbc/tests/test_omnisci_column_default.py b/rbc/tests/test_omnisci_column_default.py index 3980d5bae..e01d96d53 100644 --- a/rbc/tests/test_omnisci_column_default.py +++ b/rbc/tests/test_omnisci_column_default.py @@ -4,7 +4,7 @@ @pytest.fixture(scope="module") def omnisci(): - for o in omnisci_fixture(globals(), minimal_version=(5, 5, 5)): + for o in omnisci_fixture(globals(), minimal_version=(5, 6)): define(o) yield o diff --git a/rbc/tests/test_omnisci_column_list.py b/rbc/tests/test_omnisci_column_list.py index 816da6025..a5c407e27 100644 --- a/rbc/tests/test_omnisci_column_list.py +++ b/rbc/tests/test_omnisci_column_list.py @@ -11,7 +11,7 @@ @pytest.fixture(scope='module') def omnisci(): - for o in omnisci_fixture(globals(), minimal_version=(5, 5, 5)): + for o in omnisci_fixture(globals(), minimal_version=(5, 6)): define(o) yield o diff --git a/rbc/tests/test_omnisci_column_null.py b/rbc/tests/test_omnisci_column_null.py index dd775f3b5..73e450dcd 100644 --- a/rbc/tests/test_omnisci_column_null.py +++ b/rbc/tests/test_omnisci_column_null.py @@ -5,7 +5,7 @@ @pytest.fixture(scope='module') def omnisci(): - for o in omnisci_fixture(globals(), minimal_version=(5, 5)): + for o in omnisci_fixture(globals(), minimal_version=(5, 6)): define(o) yield o @@ -42,9 +42,6 @@ def my_row_copier_mul_bool(x, m, y): @pytest.mark.parametrize('col', colnames) def test_null_value(omnisci, col): - omnisci.require_version((5, 5), - 'Requires omniscidb-internal PR 5104 [rbc issue 188]') - typ = dict(f4='float32', f8='float64', i1='int8', i2='int16', i4='int32', i8='int64', b='bool')[col] @@ -69,9 +66,6 @@ def test_null_value(omnisci, col): def test_row_adder(omnisci): - omnisci.require_version((5, 5), - 'Requires omniscidb-internal PR 5104 [rbc issue 188]') - descr, expected = omnisci.sql_execute( f'select f8, f8 + f8 from {omnisci.table_name}null') data, expected = zip(*list(expected)) diff --git a/rbc/tests/test_omnisci_constants.py b/rbc/tests/test_omnisci_constants.py new file mode 100644 index 000000000..bf5bf0e08 --- /dev/null +++ b/rbc/tests/test_omnisci_constants.py @@ -0,0 +1,40 @@ +import pytest +import numpy as np +from rbc.tests import omnisci_fixture +from rbc.stdlib import array_api +from collections import OrderedDict + + +@pytest.fixture(scope='module') +def omnisci(): + + for o in omnisci_fixture(globals(), load_test_data=False): + define(o) + yield o + + +def define(omnisci): + @omnisci('float64(int32)') + def get_constant(typ): + if typ == 0: + return array_api.e + if typ == 1: + return array_api.inf + if typ == 2: + return array_api.nan + return array_api.pi + + +constants_map = OrderedDict(e=np.e, inf=np.inf, nan=np.nan, pi=np.pi) + + +@pytest.mark.parametrize('C', constants_map) +def test_constants(omnisci, C): + idx = list(constants_map.keys()).index(C) + _, result = omnisci.sql_execute(f'select get_constant({idx});') + + expected = constants_map[C] + if np.isnan(expected): + assert np.isnan(list(result)[0]) + else: + assert list(result) == [(expected,)] diff --git a/rbc/tests/test_omnisci_device_selection.py b/rbc/tests/test_omnisci_device_selection.py index fa9fff672..1c64d156b 100644 --- a/rbc/tests/test_omnisci_device_selection.py +++ b/rbc/tests/test_omnisci_device_selection.py @@ -5,7 +5,7 @@ @pytest.fixture(scope='module') def omnisci(): - for o in omnisci_fixture(globals(), minimal_version=(5, 5)): + for o in omnisci_fixture(globals(), minimal_version=(5, 6)): define(o) def require_loadtime(kind, _cache=[None]): @@ -184,7 +184,6 @@ def rt_device_selection_udtf_both(x, out): # NOQA @pytest.mark.parametrize("ext", ['udf', 'udtf']) @pytest.mark.parametrize("kind", ['rt', 'ct', 'lt']) def test_device_selection_single(omnisci, func, ext, kind): - omnisci.require_version((5, 5), 'omniscidb-internal PR 5026') omnisci.require_loadtime(kind) if kind == 'lt' and ext == 'udtf': @@ -205,7 +204,6 @@ def test_device_selection_single(omnisci, func, ext, kind): @pytest.mark.parametrize("kind2", kinds) @pytest.mark.parametrize("kind1", kinds) def test_device_selection_pair(omnisci, func12, ext, kind2, kind1): - omnisci.require_version((5, 5), 'omniscidb-internal PR 5026') func12 = tuple(func12.split('/')) func1, func2 = func12 diff --git a/rbc/tests/test_external.py b/rbc/tests/test_omnisci_external.py similarity index 100% rename from rbc/tests/test_external.py rename to rbc/tests/test_omnisci_external.py diff --git a/rbc/tests/test_omnisci_math.py b/rbc/tests/test_omnisci_math.py index f4f0f12ca..d66a84a4d 100644 --- a/rbc/tests/test_omnisci_math.py +++ b/rbc/tests/test_omnisci_math.py @@ -1,11 +1,11 @@ import math import pytest import sys -import rbc.omnisci_backend as omni # noqa: F401 +import numpy as np +import numba as nb +import rbc.omniscidb as rbc_omnisci +from rbc.stdlib import array_api -rbc_omnisci = pytest.importorskip('rbc.omniscidb') -np = pytest.importorskip('numpy') -nb = pytest.importorskip('numba') available_version, reason = rbc_omnisci.is_available() pytestmark = pytest.mark.skipif(not available_version, reason=reason) @@ -53,7 +53,7 @@ def omnisci(): math_functions = [ # Number-theoretic and representation functions - ('ceil', 'int64(double)'), + ('ceil', 'double(double)'), ('comb', 'int64(int64, int64)'), ('copysign', 'double(double, double)'), ('fabs', 'double(double)'), @@ -138,25 +138,9 @@ def test_math_function(omnisci, device, nb_version, fn_name, signature): 'fmod', 'isclose', 'isqrt', 'modf', 'dist', 'perm']: pytest.skip(f'{fn_name}: Numba uses cpython implementation! [rbc issue 156]') - if omnisci.version < (5, 5) and omnisci.has_cuda and \ - fn_name in ['gcd', 'comb', 'factorial', 'fsum', 'isclose', 'isfinite', - 'isqrt', 'ldexp', 'modf', 'perm', 'prod', - 'dist', 'fmod']: - pytest.skip(f'CUDA target does not support {fn_name} function [rbc issue 156]') - - if omnisci.version < (5, 5) and omnisci.has_cuda and fn_name in ['pow', 'gamma', 'lgamma']: - pytest.skip(f'{fn_name} crashes with CUDA-enabled server [rbc issue 156/158]') - if fn_name in ['frexp']: pytest.skip(f'{fn_name} returns a pair (m, e) [rbc issue 156/202]') - if omnisci.version < (5, 5) and omnisci.has_cuda and nb_version < (0, 52): - if fn_name in ['expm1', 'log1p', 'hypot', 'acosh', 'asinh', 'atanh', - 'cosh', 'sinh', 'tanh', 'erf', 'erfc', 'acos', 'asin', - 'atan', 'atan2']: - pytest.skip(f'{fn_name} requires numba version 0.52, currently using' - f' {".".join(map(str, nb_version))}') - arity = signature.count(',') + 1 kind = signature.split('(')[1].split(',')[0].split(')')[0] @@ -350,10 +334,10 @@ def test_numpy_function(omnisci, device, nb_version, fn_name, signature, np_func if isinstance(np_func, np.ufunc): # numba does not support jitting ufunc-s directly if arity == 1: - fn = eval(f'lambda x: omni.{np_func.__name__}(x)', dict(omni=omni)) + fn = eval(f'lambda x: array_api.{np_func.__name__}(x)', dict(array_api=array_api)) elif arity == 2: - fn = eval(f'lambda x, y: omni.{np_func.__name__}(x, y)', - dict(omni=omni)) + fn = eval(f'lambda x, y: array_api.{np_func.__name__}(x, y)', + dict(array_api=array_api)) else: raise NotImplementedError((signature, arity)) else: @@ -363,12 +347,6 @@ def test_numpy_function(omnisci, device, nb_version, fn_name, signature, np_func # give lambda function a name fn.__name__ = fn_name - if omnisci.version[:2] < (5, 4) and fn_name in \ - ['logical_or', 'logical_xor', 'logical_and', 'logical_not']: - pytest.skip( - f"using boolean arguments requires omniscidb v 5.4 or newer" - f" (got {omnisci.version}) [issue 108]") - if fn_name in ['positive', 'divmod0', 'frexp0']: try: if arity == 1: @@ -383,35 +361,6 @@ def test_numpy_function(omnisci, device, nb_version, fn_name, signature, np_func # Skipping spacing__cpu_0 that uses undefined function `npy_spacing` pytest.skip(f'{fn_name}: FIXME') - if omnisci.version < (5, 5) and omnisci.has_cuda and fn_name in ['lcm']: - # https://github.com/xnd-project/rbc/issues/71 - pytest.skip(f'{fn_name}: crashes CUDA enabled omniscidb server' - ' [rbc issue 71]') - - if omnisci.version < (5, 2) and nb_version < (0, 52) and omnisci.has_cuda and fn_name in [ - 'arcsin', 'arccos', 'arctan', 'arctan2', 'hypot', 'sinh', 'cosh', - 'tanh', 'arcsinh', 'arccosh', 'arctanh', 'expm1', 'exp2', 'log2', - 'log1p', 'logaddexp2', 'ldexp', 'lcm', 'logaddexp', 'nextafter']: - pytest.skip(f"{fn_name}: libdevice bindings requires numba 0.52 or newer," - f" got Numba v{'.'.join(map(str, nb_version))}") - - if omnisci.version < (5, 2) and fn_name in [ - 'sinh', 'cosh', 'tanh', 'rint', 'trunc', 'expm1', 'exp2', 'log2', - 'log1p', 'gcd', 'lcm', 'around', 'fmod', 'hypot']: - # fix forbidden names - fn_name += 'FIX' - fn.__name__ = fn_name - - if omnisci.version < (5, 2) and omnisci.has_cuda and fn_name in [ - 'fmax', 'fmin', 'power', 'sqrt', 'tan', 'radians', 'degrees' - ]: - # NativeCodegen.cpp:849 use of undefined value '@llvm.maxnum.f64' - # NativeCodegen.cpp:849 invalid redefinition of function 'power' - # NativeCodegen.cpp:849 invalid redefinition of function - # 'llvm.lifetime.start.p0i8' - # NativeCodegen.cpp:849 invalid redefinition of function 'radians' - pytest.skip(f'{fn_name}: crashes CUDA enabled omniscidb server < 5.2') - if device == 'gpu' and fn_name in ['floor_divide', 'around', 'round2', 'round_']: pytest.skip(f'Missing libdevice bindigs for {fn_name}') diff --git a/rbc/tests/test_omnisci_mlpack.py b/rbc/tests/test_omnisci_mlpack.py index 1a9180352..4b8291705 100644 --- a/rbc/tests/test_omnisci_mlpack.py +++ b/rbc/tests/test_omnisci_mlpack.py @@ -25,7 +25,7 @@ def test_mlpack(omnisci, func): try: _, result = omnisci.sql_execute(query) except OmnisciServerError as msg: - m = re.match(r'.*No match found for function signature ' + func + r'[(]', + m = re.match(fr'.*Undefined function call {func!r}', msg.args[0]) if m is not None: pytest.skip(f'test requires omniscidb server with MLPACK support: {msg}') diff --git a/rbc/tests/test_omnisci_template.py b/rbc/tests/test_omnisci_template.py index a1763ab61..cd462c6fa 100644 --- a/rbc/tests/test_omnisci_template.py +++ b/rbc/tests/test_omnisci_template.py @@ -53,7 +53,7 @@ def test_template_text(omnisci, size): if omnisci.has_cuda: omnisci.require_version( - (5, 8), "Requires omniscidb-internal PR 5809", label='PR5809') + (5, 8), "Requires omniscidb-internal PR 5809") fn = "ct_binding_template" table = f"{omnisci.base_name}_{size}" @@ -77,7 +77,7 @@ def test_template_number(omnisci, col): if omnisci.has_cuda: omnisci.require_version( - (5, 8), "Requires omniscidb-internal PR 5809", label='PR5809') + (5, 8), "Requires omniscidb-internal PR 5809") fn = "ct_binding_template" table = omnisci.table_name diff --git a/rbc/tests/test_omnisci_text.py b/rbc/tests/test_omnisci_text.py index fb20ba10c..fb506dfc4 100644 --- a/rbc/tests/test_omnisci_text.py +++ b/rbc/tests/test_omnisci_text.py @@ -4,11 +4,6 @@ rbc_omnisci = pytest.importorskip('rbc.omniscidb') available_version, reason = rbc_omnisci.is_available() -if available_version and available_version < (5, 5): - reason = ("test file requires omniscidb version 5.5+ with bytes support" - "(got %s)" % (available_version, )) - available_version = None - pytestmark = pytest.mark.skipif(not available_version, reason=reason) diff --git a/rbc/tests/test_omnisci_treelite.py b/rbc/tests/test_omnisci_treelite.py index 55d830a5d..f97528d91 100644 --- a/rbc/tests/test_omnisci_treelite.py +++ b/rbc/tests/test_omnisci_treelite.py @@ -6,7 +6,7 @@ @pytest.fixture(scope='module') def omnisci(): - for o in omnisci_fixture(globals(), minimal_version=(5, 5), debug=not True): + for o in omnisci_fixture(globals(), minimal_version=(5, 6), debug=not True): yield o diff --git a/rbc/tests/test_omnisci_udtf.py b/rbc/tests/test_omnisci_udtf.py index 5461c26bd..2be758909 100644 --- a/rbc/tests/test_omnisci_udtf.py +++ b/rbc/tests/test_omnisci_udtf.py @@ -1,4 +1,5 @@ import pytest +from rbc.errors import NumbaTypeError from rbc.tests import omnisci_fixture, sql_execute from rbc.externals.omniscidb import table_function_error import numpy as np @@ -15,51 +16,49 @@ def define(omnisci): T = ['int64', 'int32', 'int16', 'int8', 'float64', 'float32'] - if omnisci.version >= (5, 6): - - @omnisci('int32(Cursor, T, RowMultiplier,' - ' OutputColumn, OutputColumn)', T=T) - def sqlmultiply(rowid, col, alpha, row_multiplier, rowid_out, out): - for i in range(len(col)): - j = rowid[i] - out[j] = col[i] * alpha - rowid_out[j] = i - return len(col) - - @omnisci('int32(Cursor, T, RowMultiplier,' - ' OutputColumn, OutputColumn)', T=T) - def sqladd(rowid, col, alpha, row_multiplier, rowid_out, out): - for i in range(len(col)): - j = rowid[i] - out[j] = col[i] + alpha - rowid_out[j] = i - return len(col) - - @omnisci('int32(Cursor, Cursor, RowMultiplier,' - ' OutputColumn, OutputColumn)', T=T) - def sqladd2(rowid1, col1, rowid2, col2, row_multiplier, rowid_out, out): - for i1 in range(len(col1)): - j1 = rowid1[i1] - for i2 in range(len(col2)): - j2 = rowid2[i2] - if j1 == j2: - out[j1] = col1[i1] + col2[i2] - rowid_out[j1] = i1 - break - return len(col1) - - @omnisci('int32(Cursor, Cursor, RowMultiplier,' - ' OutputColumn, OutputColumn)', T=T) - def sqlmultiply2(rowid1, col1, rowid2, col2, row_multiplier, rowid_out, out): - for i1 in range(len(col1)): - j1 = rowid1[i1] - for i2 in range(len(col2)): - j2 = rowid2[i2] - if j1 == j2: - out[j1] = col1[i1] * col2[i2] - rowid_out[j1] = i1 - break - return len(col1) + @omnisci('int32(Cursor, T, RowMultiplier,' + ' OutputColumn, OutputColumn)', T=T) + def sqlmultiply(rowid, col, alpha, row_multiplier, rowid_out, out): + for i in range(len(col)): + j = rowid[i] + out[j] = col[i] * alpha + rowid_out[j] = i + return len(col) + + @omnisci('int32(Cursor, T, RowMultiplier,' + ' OutputColumn, OutputColumn)', T=T) + def sqladd(rowid, col, alpha, row_multiplier, rowid_out, out): + for i in range(len(col)): + j = rowid[i] + out[j] = col[i] + alpha + rowid_out[j] = i + return len(col) + + @omnisci('int32(Cursor, Cursor, RowMultiplier,' + ' OutputColumn, OutputColumn)', T=T) + def sqladd2(rowid1, col1, rowid2, col2, row_multiplier, rowid_out, out): + for i1 in range(len(col1)): + j1 = rowid1[i1] + for i2 in range(len(col2)): + j2 = rowid2[i2] + if j1 == j2: + out[j1] = col1[i1] + col2[i2] + rowid_out[j1] = i1 + break + return len(col1) + + @omnisci('int32(Cursor, Cursor, RowMultiplier,' + ' OutputColumn, OutputColumn)', T=T) + def sqlmultiply2(rowid1, col1, rowid2, col2, row_multiplier, rowid_out, out): + for i1 in range(len(col1)): + j1 = rowid1[i1] + for i2 in range(len(col2)): + j2 = rowid2[i2] + if j1 == j2: + out[j1] = col1[i1] * col2[i2] + rowid_out[j1] = i1 + break + return len(col1) @pytest.mark.parametrize("kind", ['i8', 'i4', 'i2', 'i1', 'f8', 'f4']) @@ -131,99 +130,8 @@ def __repr__(self): assert ((a + 2) * a + 3).isok() -def test_simple(omnisci): - if omnisci.version >= (5, 4): - reason = ('Old-style UDTFs are available for omniscidb 5.3 or older, ' - 'currently connected to omniscidb ' - + '.'.join(map(str, omnisci.version))) - pytest.skip(reason) - - omnisci.reset() - # register an empty set of UDFs in order to avoid unregistering - # UDFs created directly from LLVM IR strings when executing SQL - # queries: - omnisci.register() - - def my_row_copier1(x, input_row_count_ptr, output_row_count, y): - # sizer type is Constant - m = 5 - input_row_count = input_row_count_ptr[0] - n = m * input_row_count - for i in range(input_row_count): - for c in range(m): - y[i + c * input_row_count] = x[i] - output_row_count[0] = n - return 0 - - if 0: - omnisci('int32|table(double*|cursor, int64*, int64*, double*|output)')( - my_row_copier1) - # Exception: Failed to allocate 5612303629517800 bytes of memory - descr, result = omnisci.sql_execute( - 'select * from table(my_row_copier1(cursor(select f8 ' - 'from {omnisci.table_name})));' - .format(**locals())) - - for i, r in enumerate(result): - print(i, r) - - def my_row_copier2(x, - n_ptr: dict(sizer='kUserSpecifiedConstantParameter'), # noqa: F821,E501 - input_row_count_ptr, output_row_count, y): - n = n_ptr[0] - m = 5 - input_row_count = input_row_count_ptr[0] - for i in range(input_row_count): - for c in range(m): - j = i + c * input_row_count - if j < n: - y[j] = x[i] - else: - break - output_row_count[0] = n - return 0 - - if 0: - omnisci('int32|table(double*|cursor, int32*|input, int64*, int64*,' - ' double*|output)')(my_row_copier2) - # Exception: Failed to allocate 5612303562962920 bytes of memory - descr, result = omnisci.sql_execute( - 'select * from table(my_row_copier2(cursor(select f8 ' - 'from {omnisci.table_name}), 2));' - .format(**locals())) - - for i, r in enumerate(result): - print(i, r) - - @omnisci('double(double)') - def myincr(x): - return x + 1.0 - - @omnisci('int32|table(double*|cursor, int32*|input, int64*, int64*,' - ' double*|output)') - def my_row_copier3(x, - m_ptr: dict(sizer='kUserSpecifiedRowMultiplier'), # noqa: F821,E501 - input_row_count_ptr, output_row_count, y): - m = m_ptr[0] - input_row_count = input_row_count_ptr[0] - for i in range(input_row_count): - for c in range(m): - j = i + c * input_row_count - y[j] = x[i] * 2 - output_row_count[0] = m * input_row_count - return 0 - - descr, result = omnisci.sql_execute( - 'select f8, myincr(f8) from table(my_row_copier3(cursor(select f8 ' - 'from {omnisci.table_name}), 2));' - .format(**locals())) - - for i, r in enumerate(result): - assert r == ((i % 5) * 2, (i % 5) * 2 + 1) - - def test_table_function_manager(omnisci): - omnisci.require_version((5, 9), 'Requires omniscidb-internal PR 6035', label='master') + omnisci.require_version((5, 9), 'Requires omniscidb-internal PR 6035') @omnisci('int32(TableFunctionManager, Column, OutputColumn)') def my_manager_error(mgr, col, out): @@ -261,8 +169,7 @@ def test_parallel_execution(omnisci, sleep, mode): (ct_sleep1). """ - omnisci.require_version((5, 8), 'Requires omniscidb-internal PR 5901', - label='qe-99') + omnisci.require_version((5, 9), 'Requires omniscidb-internal PR 5901') from multiprocessing import Process, Array def func(seconds, mode, a): @@ -351,3 +258,43 @@ def my_divide(column, k, row_multiplier, out): ); """) assert exc.match('Error executing table function: division by zero') + + +def test_raise_error(omnisci): + omnisci.require_version((5, 8), 'Requires omniscidb-internal PR 5879') + omnisci.reset() + + with pytest.raises(NumbaTypeError) as exc: + @omnisci('int32(Column, double, RowMultiplier, OutputColumn)') + def my_divide(column, k, row_multiplier, out): + if k == 0: + raise ValueError('division by zero') + for i in range(len(column)): + out[i] = column[i] / k + return len(column) + + omnisci.register() + + assert exc.match('raise statement is not supported') + omnisci.reset() + + +def test_issue_235(omnisci): + + @omnisci('int32(Column, RowMultiplier, OutputColumn)') + def text_rbc_copy_rowmul(x, m, y): + for i in range(len(x)): + y[i] = x[i] + return len(x) + + @omnisci('int32(Cursor, RowMultiplier, OutputColumn, OutputColumn)') # noqa: E501 + def text_rbc_copy_rowmul(x, x2, m, y, y2): # noqa: F811 + for i in range(len(x)): + y[i] = x[i] + y2[i] = x2[i] + return len(x) + + query = (f'select * from table(text_rbc_copy_rowmul(' + f'cursor(select i8, f8 from {omnisci.table_name}), 1));') + _, result = omnisci.sql_execute(query) + assert list(result) == list(zip(np.arange(5), np.arange(5, dtype=np.float64))) diff --git a/rbc/tests/test_rbclib.py b/rbc/tests/test_rbclib.py new file mode 100644 index 000000000..a997e1ccd --- /dev/null +++ b/rbc/tests/test_rbclib.py @@ -0,0 +1,126 @@ +import pytest +from rbc.remotejit import RemoteJIT +from rbc import rbclib +from rbc.rbclib.tracing_allocator import (TracingAllocator, LeakDetector, + InvalidFreeError, MemoryLeakError) +from .test_numpy_rjit import rjit # noqa: F401 + + +@pytest.fixture +def djit(): + """ + Debug JIT: a RemoteJIT() which automatically uses tracing_allocator and + detects memory leaks + """ + return RemoteJIT(local=True, debug=True, use_tracing_allocator=True) + + +def test_add_ints_cffi(): + res = rbclib.lib._rbclib_add_ints(20, 22) + assert res == 42 + + +def test_add_ints_rjit(rjit): # noqa: F811 + @rjit('int64(int64, int64)') + def my_add(a, b): + return rbclib.add_ints(a, b) + assert my_add(20, 22) == 42 + + +class TestTracingAllocator: + + def test_record_allocate(self): + allocator = TracingAllocator() + allocator.record_allocate(0x123) + allocator.record_allocate(0x456) + assert allocator.seq == 2 + assert allocator.alive_memory == {0x123: 1, 0x456: 2} + + def test_record_free(self): + allocator = TracingAllocator() + allocator.record_allocate(0x123) + allocator.record_allocate(0x456) + allocator.record_free(0x123) + allocator.record_allocate(0x789) + assert allocator.seq == 3 + assert allocator.alive_memory == {0x456: 2, 0x789: 3} + + def test_invalid_free(self): + allocator = TracingAllocator() + # 1. raise in case we try to free an unknown pointer + with pytest.raises(InvalidFreeError): + allocator.record_free(0x123) + + # 2. raise in case of double free + allocator.record_allocate(0x456) + allocator.record_free(0x456) + assert allocator.alive_memory == {} + with pytest.raises(InvalidFreeError): + allocator.record_free(0x456) + + +class TestLeakDetector: + + def test_no_nested_activation(self): + allocator = TracingAllocator() + ld = LeakDetector(allocator) + with ld: + with pytest.raises(ValueError): + with ld: + pass + + def test_double_enter(self): + allocator = TracingAllocator() + ld = LeakDetector(allocator) + # check that we can activate the same LeakDetector twice, as long as + # it's not nested + with ld: + pass + with ld: + pass + + def test_no_leak(self): + allocator = TracingAllocator() + ld = LeakDetector(allocator) + with ld: + allocator.record_allocate(0x123) + allocator.record_allocate(0x456) + allocator.record_free(0x456) + allocator.record_free(0x123) + + def test_detect_leak(self): + allocator = TracingAllocator() + ld = LeakDetector(allocator) + with pytest.raises(MemoryLeakError) as exc: + with ld: + allocator.record_allocate(0x123) + allocator.record_allocate(0x456) + allocator.record_allocate(0x789) + allocator.record_free(0x123) + assert exc.value.leaks == [(0x456, 2), (0x789, 3)] + + +class Test_djit: + """ + These are the the most important rbclib tests: checks that we can actually + detect memory leaks inside @djit compiled functions. + """ + + def test_djit_target_info(self, djit): + targets = djit.targets + ti = targets['cpu'] + assert ti.name == 'host_cpu_tracing_allocator' + assert ti.use_tracing_allocator + assert ti.info['fn_allocate_varlen_buffer'] == 'rbclib_tracing_allocate_varlen_buffer' + + def test_djit_leak(self, djit): + from rbc.stdlib import array_api as xp + + @djit('int32(int32)') + def leak_some_memory(size): + # memory leak! + a = xp.Array(size, xp.float64) # noqa: F841 + return size + + with pytest.raises(MemoryLeakError): + leak_some_memory(10) diff --git a/rbc/tests/test_remotejit.py b/rbc/tests/test_remotejit.py index 35a8b3776..5fcad6d05 100644 --- a/rbc/tests/test_remotejit.py +++ b/rbc/tests/test_remotejit.py @@ -39,6 +39,21 @@ def test_func_(): return test_func_ +def test_devices_validation(ljit): + # normal cases + + _ = ljit('double(double, double)', devices=['cpu', 'gpu']) + _ = ljit('double(double, double)', devices=['cpu', 'cpu', 'gpu']) + + # failing cases + + with pytest.raises(ValueError, match="'devices' can only be a list"): + _ = ljit('double(double, double)', devices=['both']) + + with pytest.raises(ValueError, match="'devices' can only be a list"): + _ = ljit('double(double, double)', devices=['cpu', 'gpu', 'bob']) + + @with_localjit def test_construction(ljit): @@ -161,7 +176,7 @@ def add(a, b): with pytest.raises( TypeError, - match=r'found no matching function type to given argument types'): + match=r'found no matching function signature to given argument types'): add(1, 2.5) add.signature('d(d,d)') @@ -174,7 +189,7 @@ def add(a, b): with pytest.raises( TypeError, - match=r'found no matching function type to given argument types'): + match=r'found no matching function signature to given argument types'): add(1j, 2) add.signature('c128(c128,c128)') @@ -214,6 +229,7 @@ def bar(x: int) -> int: @with_localjit def test_templates(ljit): + ljit.reset() assert isinstance(ljit, RemoteJIT) @@ -322,6 +338,8 @@ class MyClass2(Type): @pytest.mark.parametrize("T", scalar_pointer_types) @pytest.mark.parametrize("V", scalar_pointer_types) def test_scalar_pointer_conversion(rjit, T, V): + rjit.reset() + with Type.alias(T=T, V=V, intp='int64'): # pointer-intp conversion @@ -463,6 +481,7 @@ def pp2r(a): @pytest.mark.parametrize("T", ['int64', 'int32', 'int16', 'int8', 'float32', 'float64']) def test_scalar_pointer_access_local(ljit, T): + ljit.reset() with Type.alias(T=T): arr = np.array([1, 2, 3, 4], dtype=T) @@ -503,6 +522,8 @@ def sitem(x, i, v): @pytest.mark.parametrize("T", ['int64', 'int32', 'int16', 'int8', 'float32', 'float64']) @pytest.mark.parametrize("memman", list(memory_managers)) def test_scalar_pointer_access_remote(rjit, memman, T): + rjit.reset() + calloc_prototype, free_prototype = memory_managers[memman] with Type.alias(T=T): @@ -548,6 +569,7 @@ def sitem(x, i, v): @pytest.mark.parametrize("T", ['int64', 'int32', 'int16', 'int8', 'float32', 'float64']) def test_struct_input(ljit, rjit, location, T): jit = rjit if location == 'remote' else ljit + jit.reset() S = '{T x, T y, T z}' @@ -695,6 +717,7 @@ def next_S(s): @pytest.mark.parametrize("T", ['int64', 'int32', 'int16', 'int8', 'float32', 'float64']) def test_struct_pointer_members(ljit, rjit, location, T): jit = rjit if location == 'remote' else ljit + jit.reset() index_t = 'int32' S = '{T* data, index_t size}' @@ -779,6 +802,7 @@ def range_S(s): @pytest.mark.parametrize("T", ['int64', 'int32', 'int16', 'int8', 'float32', 'float64']) def test_struct_double_pointer_members(ljit, rjit, location, T): jit = rjit if location == 'remote' else ljit + jit.reset() index_t = 'int32' S = '{T** data, index_t length, index_t size}' diff --git a/rbc/tests/test_targetinfo.py b/rbc/tests/test_targetinfo.py new file mode 100644 index 000000000..70b528027 --- /dev/null +++ b/rbc/tests/test_targetinfo.py @@ -0,0 +1,33 @@ +from rbc.targetinfo import TargetInfo + + +def test_basic(): + host = TargetInfo.host() + assert host.name == 'host_cpu' + with host: + ti = TargetInfo() + assert ti is host + + +def test_to_from_dict(): + host = TargetInfo.host() + d = host.todict() + host2 = TargetInfo.fromdict(d) + assert host.__dict__ == host2.__dict__ + + +def test_host_cache(): + host = TargetInfo.host() + host2 = TargetInfo.host() + assert host is host2 + + +def test_allocation_functions(): + host = TargetInfo.host() + dhost = TargetInfo.host(use_tracing_allocator=True) + assert host is not dhost # check that use_tracing_allocator is part of the cache key + assert host.info['fn_allocate_varlen_buffer'] == 'rbclib_allocate_varlen_buffer' + assert host.info['fn_free_buffer'] == 'rbclib_free_buffer' + # + assert dhost.info['fn_allocate_varlen_buffer'] == 'rbclib_tracing_allocate_varlen_buffer' + assert dhost.info['fn_free_buffer'] == 'rbclib_tracing_free_buffer' diff --git a/rbc/tests/test_typesystem.py b/rbc/tests/test_typesystem.py index 6a2403bf8..73b484dfb 100644 --- a/rbc/tests/test_typesystem.py +++ b/rbc/tests/test_typesystem.py @@ -622,3 +622,11 @@ def test_get_signature_ufunc(target_info): sig = get_signature(np.modf) assert len(sig.parameters) == 3 + + +def test_copy(target_info): + t = Type.fromstring('int foo| a = 1') + t2 = t.copy() + t.annotation(b=1) + assert str(t) == 'int32 foo | a=1 | b=1' + assert str(t2) == 'int32 foo | a=1' diff --git a/rbc/thrift/server.py b/rbc/thrift/server.py index 6850d1d15..fda0623ff 100644 --- a/rbc/thrift/server.py +++ b/rbc/thrift/server.py @@ -34,6 +34,26 @@ tblib.pickling_support.install() +class TServerSocket(thr.transport.TServerSocket): + + def close(self): + # Copied from https://github.com/Thriftpy/thriftpy2/pull/184 + # Remove when using pythrift2 > 0.4.14 + if not self.sock: + return + + try: + self.sock.shutdown(socket.SHUT_RDWR) + except OSError: + pass + + try: + self.sock.close() + except OSError: + pass + self.sock = None + + class Processor(thr.thrift.TProcessor): def __init__(self, server, service, handler): @@ -122,15 +142,16 @@ def run_bg(dispatcher, thrift_file, options, startup_time=5): args=(dispatcher, thrift_file, options)) p.start() start = time.time() + number_of_tries = 0 while time.time() < start + startup_time: + number_of_tries += 1 try: socket.create_connection( - (options['host'], options['port']), timeout=0.1) + (options['host'], options['port']), timeout=0.2) except ConnectionRefusedError: time.sleep(0.5) except Exception as msg: - print('Connection failed: `%s`, trying again in 0.5 secs..' - % (msg)) + warnings.warn(f'Connection failed: `{msg}`, trying again in 0.5 secs..') time.sleep(0.5) else: break @@ -141,8 +162,12 @@ def run_bg(dispatcher, thrift_file, options, startup_time=5): p.terminate() raise RuntimeError( 'failed to start up rpc_thrift server' - ' (was alive={}, startup_time={}s)' - .format(is_alive, startup_time)) + f' (was alive={is_alive}, startup time={startup_time}s,' + f' elapsed time={time.time() - start})') + if number_of_tries > 1: + warnings.warn( + f'More than one try ({number_of_tries}) in starting up rpc_thrift_server.' + f' Total elapsed time is {time.time() - start} seconds.') return p def _serve(self): @@ -161,7 +186,7 @@ def _serve(self): s_proc = Processor(self, service, self._dispatcher(self, debug=self.debug)) server = thr.server.TThreadedServer( s_proc, - thr.transport.TServerSocket(**self.options), + TServerSocket(**self.options), iprot_factory=thr.protocol.TBinaryProtocolFactory(), itrans_factory=thr.transport.TBufferedTransportFactory()) server.serve() diff --git a/rbc/typesystem.py b/rbc/typesystem.py index f296a9595..f855e7c52 100644 --- a/rbc/typesystem.py +++ b/rbc/typesystem.py @@ -5,6 +5,7 @@ import re +import copy import ctypes import _ctypes import inspect @@ -411,6 +412,13 @@ def __new__(cls, *args, **params): 'attempt to create an invalid Type object from `%s`' % (args,)) return obj.postprocess_type() + def copy(self, cls=None): + """Return a copy of type. + """ + if cls is None: + cls = type(self) + return cls(*self, **copy.deepcopy(self._params)) + @classmethod def preprocess_args(cls, args): """Preprocess the arguments of Type constructor. @@ -718,13 +726,23 @@ def __str__(self): return self.tostring() return tuple.__str__(self) - def tostring(self, use_typename=False, use_annotation=True): + def tostring(self, use_typename=False, use_annotation=True, use_name=True, + use_annotation_name=False, _skip_annotation=False): """Return string representation of a type. """ - if use_annotation: - s = self.tostring(use_typename=use_typename, use_annotation=False) - annotation = self.annotation() + options = dict(use_typename=use_typename, use_annotation=use_annotation, + use_name=use_name, + use_annotation_name=use_annotation_name) + annotation = self.annotation() + if use_annotation and not _skip_annotation: + s = self.tostring(_skip_annotation=True, **options) for name, value in annotation.items(): + if ( + use_annotation_name + and use_name + and name == 'name' + and self._params.get('name', value) == value): + continue if value: s = '%s | %s=%s' % (s, name, value) else: @@ -733,18 +751,21 @@ def tostring(self, use_typename=False, use_annotation=True): if self.is_void: return 'void' - name = self._params.get('name') + + name = self._params.get('name') if use_name else None + if use_annotation_name and use_name: + annot_name = annotation.get('name') + if annot_name is not None and name is None: + name = annot_name + if self.is_function: if use_typename: typename = self._params.get('typename') if typename is not None: return typename - if name: - name = ' ' + name - return (self[0].tostring(use_typename=use_typename) - + name + '(' + ', '.join( - a.tostring(use_typename=use_typename) - for a in self[1]) + ')') + name = ' ' + name if name else '' + return (self[0].tostring(**options) + + name + '(' + ', '.join(a.tostring(**options) for a in self[1]) + ')') if name is not None: suffix = ' ' + name @@ -757,15 +778,14 @@ def tostring(self, use_typename=False, use_annotation=True): if self.is_atomic: return self[0] + suffix if self.is_pointer: - return self[0].tostring(use_typename=use_typename) + '*' + suffix + return self[0].tostring(**options) + '*' + suffix if self.is_struct: clsname = self._params.get('clsname') if clsname is not None: return clsname + '<' + ', '.join( - [t.tostring(use_typename=use_typename) + [t.tostring(**options) for t in self]) + '>' + suffix - return '{' + ', '.join([t.tostring(use_typename=use_typename) - for t in self]) + '}' + suffix + return '{' + ', '.join([t.tostring(**options) for t in self]) + '}' + suffix if self.is_custom: params = self[0] @@ -774,10 +794,11 @@ def tostring(self, use_typename=False, use_annotation=True): params = params[1:] else: name = type(self).__name__ + name = self._params.get('shorttypename', name) new_params = [] for a in params: if isinstance(a, Type): - s = a.tostring(use_typename=use_typename) + s = a.tostring(**options) else: s = str(a) new_params.append(s) @@ -1001,7 +1022,9 @@ def _fromstring(cls, s): else: name = rtype._params.pop('name', '') return cls(rtype, atypes, name=name) - if '|' in s: + + i_bar, i_gt = s.find('|'), s.find('>') # TODO: will need a better parser + if '|' in s and (i_gt == -1 or i_bar > i_gt): s, a = s.rsplit('|', 1) t = cls._fromstring(s.rstrip()) if '=' in a: @@ -1388,6 +1411,16 @@ def match(self, other): return 0 if other.is_void: return (0 if self.is_void else None) + elif self.is_custom: + if type(self) is not type(other): + return + if self[0] == other[0]: + if self._params or other._params: + warnings.warn( + 'The default match implementation ignores _params content. Please' + f' implement match method for custom type {type(self).__name__}') + return 1 + return elif other.is_pointer: if not self.is_pointer: return @@ -1470,6 +1503,10 @@ def match(self, other): if self.bits == other.bits: return 1 return + elif ((self.is_string and not other.is_string) + or (not self.is_string and other.is_string)): + return + # TODO: lots of raise NotImplementedError(repr((self, other))) elif isinstance(other, tuple): @@ -1490,7 +1527,7 @@ def match(self, other): raise NotImplementedError(repr(type(other))) def __call__(self, *atypes, **params): - return Type(self, atypes, **params) + return Type(self, atypes or (Type(),), **params) def pointer(self): numba_ptr_type = self._params.get('NumbaPointerType') @@ -1509,9 +1546,12 @@ def apply_templates(self, templates): elif self.is_atomic: type_list = templates.get(self[0]) if type_list: + assert isinstance(type_list, list), type_list for i, t in enumerate(type_list): + # using copy so that template symbols will not be + # contaminated with self parameters t = Type.fromobject(t) - t._params.update(self._params) + t_ = t.copy() if t.is_concrete: # templates is changed in-situ! This ensures that # `T(T)` produces `i4(i4)`, `i8(i8)` for `T in @@ -1520,8 +1560,7 @@ def apply_templates(self, templates): # `T1(T2)` where `T1 in [i4, i8]` and `T2 in [i4, # i8]` templates[self[0]] = [t] - # assert not self._params, (t, self, self._params) - yield t + yield t_.params(None, **self._params) # restore templates templates[self[0]] = type_list else: @@ -1530,7 +1569,7 @@ def apply_templates(self, templates): templates[self[0]] = [] for ct in t.apply_templates(templates): templates[self[0]] = [ct] - yield ct + yield ct.params(None, **self._params) templates[self[0]] = [] templates[self[0]] = type_list else: diff --git a/rbc/utils.py b/rbc/utils.py index 93e80aa93..6fc11ed0c 100644 --- a/rbc/utils.py +++ b/rbc/utils.py @@ -235,3 +235,7 @@ def foo(): last_instr = instr return True + + +DEFAULT = object() +UNSPECIFIED = object() diff --git a/requirements.txt b/requirements.txt index 2fe4c31b6..260476d11 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,3 +4,4 @@ tblib thriftpy2 six netifaces +cffi diff --git a/setup.cfg b/setup.cfg index 5fe77de7b..9d3e0fd4c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -12,6 +12,12 @@ tag_prefix = v parentdir_prefix = [flake8] +per-file-ignores = + rbc/omnisci_backend/numpy_ufuncs.py: F822 # undefined name in __all__ + rbc/omnisci_backend/numpy_funcs.py: F822 + rbc/stdlib/creation_functions.py: F822 + rbc/stdlib/elementwise_functions.py: F822 + rbc/stdlib/statistical_functions.py: F822 exclude = versioneer.py .eggs diff --git a/setup.py b/setup.py index 691ba6fd3..560e349c3 100644 --- a/setup.py +++ b/setup.py @@ -1,13 +1,10 @@ import os import sys -import builtins import versioneer if sys.version_info[:2] < (3, 7): raise RuntimeError("Python version >= 3.7 required.") -builtins.__RBC_SETUP__ = True - if os.path.exists('MANIFEST'): os.remove('MANIFEST') @@ -40,6 +37,15 @@ def setup_package(): install_requires = [] setup_requires = [] tests_require = [] + # manually check that cffi is available, else _rbclib is silently + # ignored and result in an ImportError at runtime + try: + import cffi # noqa: F401 + except ImportError as e: + msg = (f'{e}\n' + f'cffi is a required build-time dependency, please do:\n' + f' conda install -c conda-forge cffi') + raise RuntimeError(msg) else: # Get requirements via PyPI. Use at your own risk as more than # once the numba and llvmlite have not matched. @@ -66,11 +72,13 @@ def setup_package(): 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', "Operating System :: OS Independent", "Topic :: Software Development", ], packages=find_packages(), - package_data={'': ['*.thrift']}, + package_data={'': ['*.thrift'], 'rbc.rbclib': ['*.c', '*.h']}, + cffi_modules=['rbc/rbclib//_rbclib_build.py:ffibuilder'], install_requires=install_requires, setup_requires=setup_requires, tests_require=tests_require, @@ -86,4 +94,3 @@ def setup_package(): if __name__ == '__main__': setup_package() - del builtins.__RBC_SETUP__ diff --git a/test_requirements.txt b/test_requirements.txt index 86af03782..5030405f3 100644 --- a/test_requirements.txt +++ b/test_requirements.txt @@ -1,7 +1,9 @@ +cffi numba>=0.52 llvmlite>=0.29 tblib thriftpy2 six netifaces -sphinx_autodoc_typehints \ No newline at end of file +sphinx_autodoc_typehints +pydata-sphinx-theme>=0.8.0 diff --git a/utils/client_ssh_tunnel.conf b/utils/client_ssh_tunnel.conf index ab32578ba..522243101 100644 --- a/utils/client_ssh_tunnel.conf +++ b/utils/client_ssh_tunnel.conf @@ -6,7 +6,7 @@ # 1. Run omnscidb server with ssh port forwarding:: # # ssh -L 6274:127.0.0.1:16274 -# bin/omnisci_server --enable-runtime-udf --enable-table-functions -p 16274 --http-port 16278 --calcite-port 16279 +# bin/omnisci_server --enable-dev-table-functions --enable-runtime-udf --enable-table-functions -p 16274 --http-port 16278 --calcite-port 16279 # # 2. Relate the omniscidb server to client: # diff --git a/utils/tag-version.sh b/utils/tag-version.sh index 2d3db76fd..3afb6b6e4 100755 --- a/utils/tag-version.sh +++ b/utils/tag-version.sh @@ -28,4 +28,4 @@ fi # tag a commit echo "Creating a new tag" git tag -a ${TAG_STR} -m "Bumping rbc to version ${TAG_STR}" -git push origin master --tags +git push origin ${TAG_STR}