├── .circleci └── config.yml ├── .clang-format ├── .dockerignore ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── release-drafter-config.yml └── workflows │ ├── deploy-docs.yaml │ ├── release-drafter.yml │ ├── trigger-build-and-test-gpu.yaml │ └── trigger-valgrind.yaml ├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE.txt ├── README.md ├── commands.json ├── docs ├── Doxyfile ├── clients.md ├── commands.md ├── configuration.md ├── contrib.md ├── developer-backends.md ├── developer.md ├── examples.md ├── generate_llapi_reference.py ├── gtm.js ├── images │ ├── RedisAI_data_structures_and_backends.png │ ├── cat_classified.jpg │ ├── favicon.png │ ├── flask_modelserver.png │ ├── graph.pb.png │ ├── logo.svg │ ├── logo_small.png │ ├── redisai_modelserver.png │ └── tfs_modelserver.png ├── index.md ├── intro.md ├── performance.md ├── quickstart.md ├── requirements-llapi.txt ├── requirements.txt └── snippets │ └── notebooks │ ├── data │ └── cat.jpg │ └── models │ └── tensorflow │ ├── imagenet │ └── resnet50.pb │ ├── mobilenet │ └── mobilenet_224.pb │ └── tinyyolo │ └── tinyyolo.pb ├── get_deps.sh ├── hooks └── post_checkout ├── license ├── RSALv2.txt └── SSPLv1.txt ├── mkdocs.yml ├── opt ├── Makefile ├── build │ ├── backends.rules │ ├── docker │ │ ├── Makefile │ │ ├── dockerfile-gpu-test.tmpl │ │ ├── dockerfile.tmpl │ │ └── templates │ │ │ └── gpu.yml │ ├── dockerparts │ │ ├── apt.yml │ │ └── cmake.yml │ └── onnxruntime │ │ ├── .gitignore │ │ ├── Makefile │ │ ├── dockerfile.tmpl │ │ └── pack.sh ├── clang-check-all.sh ├── clang-format-all.sh ├── getver ├── pack.sh ├── redis_valgrind.sup └── system-setup.py ├── ramp-light.yml ├── ramp-rce.yml ├── ramp.yml ├── src ├── CMakeLists.txt ├── backends │ ├── backends.c │ ├── backends.h │ ├── backends_api.h │ ├── libtflite_c │ │ ├── CMakeLists.txt │ │ ├── tflite_c.cpp │ │ └── tflite_c.h │ ├── libtorch_c │ │ ├── CMakeLists.txt │ │ ├── torch_c.cpp │ │ ├── torch_c.h │ │ └── torch_extensions │ │ │ ├── torch_redis.cpp │ │ │ └── torch_redis.h │ ├── onnx_allocator │ │ ├── CMakeLists.txt │ │ ├── onnx_allocator.cpp │ │ └── onnx_allocator.h │ ├── onnx_timeout.c │ ├── onnx_timeout.h │ ├── onnxruntime.c │ ├── onnxruntime.h │ ├── tensorflow.c │ ├── tensorflow.h │ ├── tflite.c │ ├── tflite.h │ ├── torch.c │ ├── torch.h │ ├── util.c │ └── util.h ├── config │ ├── config.c │ ├── config.h │ └── gdb_config.h ├── execution │ ├── DAG │ │ ├── dag.c │ │ ├── dag.h │ │ ├── dag_builder.c │ │ ├── dag_builder.h │ │ ├── dag_execute.c │ │ ├── dag_execute.h │ │ ├── dag_op.c │ │ └── dag_op.h │ ├── background_workers.c │ ├── background_workers.h │ ├── command_parser.c │ ├── command_parser.h │ ├── execution_contexts │ │ ├── execution_ctx.c │ │ ├── execution_ctx.h │ │ ├── modelRun_ctx.c │ │ ├── modelRun_ctx.h │ │ ├── scriptRun_ctx.c │ │ └── scriptRun_ctx.h │ ├── parsing │ │ ├── dag_parser.c │ │ ├── dag_parser.h │ │ ├── deprecated.c │ │ ├── deprecated.h │ │ ├── model_commands_parser.c │ │ ├── model_commands_parser.h │ │ ├── parse_utils.c │ │ ├── parse_utils.h │ │ ├── script_commands_parser.c │ │ ├── script_commands_parser.h │ │ ├── tensor_commands_parsing.c │ │ └── tensor_commands_parsing.h │ ├── run_info.c │ ├── run_info.h │ ├── run_queue_info.c │ ├── run_queue_info.h │ ├── utils.c │ └── utils.h ├── redis_ai_objects │ ├── err.c │ ├── err.h │ ├── model.c │ ├── model.h │ ├── model_struct.h │ ├── script.c │ ├── script.h │ ├── script_struct.h │ ├── stats.c │ ├── stats.h │ ├── tensor.c │ ├── tensor.h │ └── tensor_struct.h ├── redis_ai_types │ ├── model_type.c │ ├── model_type.h │ ├── script_type.c │ ├── script_type.h │ ├── tensor_type.c │ └── tensor_type.h ├── redisai.c ├── redisai.h ├── redismodule.h ├── rmutil │ ├── alloc.c │ ├── alloc.h │ ├── args.c │ ├── args.h │ ├── sds.c │ ├── sds.h │ └── sdsalloc.h ├── serialization │ ├── AOF │ │ ├── rai_aof_rewrite.c │ │ └── rai_aof_rewrite.h │ ├── RDB │ │ ├── decoder │ │ │ ├── current │ │ │ │ └── v4 │ │ │ │ │ ├── decode_v4.c │ │ │ │ │ └── decode_v4.h │ │ │ ├── decode_previous.c │ │ │ ├── decode_previous.h │ │ │ ├── previous │ │ │ │ ├── v0 │ │ │ │ │ ├── decode_v0.c │ │ │ │ │ └── decode_v0.h │ │ │ │ ├── v1 │ │ │ │ │ ├── decode_v1.c │ │ │ │ │ └── decode_v1.h │ │ │ │ ├── v2 │ │ │ │ │ ├── decode_v2.c │ │ │ │ │ └── decode_v2.h │ │ │ │ └── v3 │ │ │ │ │ ├── decode_v3.c │ │ │ │ │ └── decode_v3.h │ │ │ ├── rai_rdb_decoder.c │ │ │ └── rai_rdb_decoder.h │ │ └── encoder │ │ │ ├── rai_rdb_encode.c │ │ │ ├── rai_rdb_encode.h │ │ │ └── v4 │ │ │ ├── encode_v4.c │ │ │ └── encode_v4.h │ ├── ai_datatypes.c │ └── serialization_include.h ├── util │ ├── arr.h │ ├── dict.c │ ├── dict.h │ ├── dictionaries.c │ ├── dictionaries.h │ ├── queue.c │ ├── queue.h │ ├── redisai_memory.h │ ├── siphash.c.inc │ ├── string_utils.c │ └── string_utils.h └── version.h └── tests ├── __init__.py ├── flow ├── __init__.py ├── includes.py ├── onnx_benchmark.py ├── test_data_files.txt ├── test_serializations.py ├── test_torchscript_extensions.py ├── tests_commands.py ├── tests_common.py ├── tests_dag.py ├── tests_dag_basic.py ├── tests_dag_errors.py ├── tests_deprecated_commands.py ├── tests_gears_llapi.py ├── tests_llapi.py ├── tests_onnx.py ├── tests_pytorch.py ├── tests_sanitizer.py ├── tests_setup │ ├── Install_RedisGears.sh │ ├── test_requirements.txt │ ├── tests.sh │ └── valgrind.sh ├── tests_tensorflow.py └── tests_tflite.py ├── module ├── CMakeLists.txt ├── DAG_utils.c ├── DAG_utils.h └── LLAPI.c └── qa ├── RS_VERSIONS ├── RS_VERSIONS-lite ├── nightly.json ├── release.json └── run /.clang-format: -------------------------------------------------------------------------------- 1 | IndentWidth: 4 2 | ColumnLimit: 100 3 | SortIncludes: false 4 | AlignEscapedNewlinesLeft: false 5 | AlignConsecutiveMacros: true 6 | SpacesBeforeTrailingComments: 1 7 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | /bin/ 2 | /deps/ 3 | /docs/ 4 | /install* 5 | /build/ 6 | .venv/ 7 | venv*/ 8 | /[0-9]*/ 9 | *.zip 10 | *.tgz 11 | *.tar.gz 12 | /VARAINT 13 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.pb filter=lfs diff=lfs merge=lfs -text 2 | *.pt filter=lfs diff=lfs merge=lfs -text 3 | *.onnx filter=lfs diff=lfs merge=lfs -text 4 | *.tflite filter=lfs diff=lfs merge=lfs -text 5 | *.jpg filter=lfs diff=lfs merge=lfs -text 6 | *.raw filter=lfs diff=lfs merge=lfs -text 7 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve RedisAI 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. ... 16 | 2. .... 17 | 18 | **Expected behavior** 19 | A clear and concise description of what you expected to happen. 20 | 21 | **Screenshots** 22 | If applicable, add screenshots to help explain your problem. 23 | 24 | **Environment (please complete the following information):** 25 | - OS: [e.g. ubuntu 20.04] 26 | - Version [e.g. 1.2.2] 27 | - Platfrom [e.g. x86, Jetson, ARM] 28 | - Runtime [e.g. CPU, CUDA] 29 | 30 | **Additional context** 31 | Add any other context about the problem here. 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for pushing RedisAI further 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/release-drafter-config.yml: -------------------------------------------------------------------------------- 1 | name-template: '$NEXT_MAJOR_VERSION' 2 | tag-template: 'v$NEXT_MAJOR_VERSION' 3 | autolabeler: 4 | - label: 'maintenance' 5 | files: 6 | - '*.md' 7 | - '.github/*' 8 | - label: 'bug' 9 | branch: 10 | - '/bug-.+' 11 | - label: 'maintenance' 12 | branch: 13 | - '/maintenance-.+' 14 | - label: 'feature' 15 | branch: 16 | - '/feature-.+' 17 | categories: 18 | - title: 'Breaking Changes' 19 | labels: 20 | - 'breakingchange' 21 | 22 | - title: '🧪 Experimental Features' 23 | labels: 24 | - 'experimental' 25 | - title: '🚀 New Features' 26 | labels: 27 | - 'feature' 28 | - 'enhancement' 29 | - title: '🐛 Bug Fixes' 30 | labels: 31 | - 'fix' 32 | - 'bugfix' 33 | - 'bug' 34 | - 'BUG' 35 | - title: '🧰 Maintenance' 36 | label: 'maintenance' 37 | change-template: '- $TITLE (#$NUMBER)' 38 | exclude-labels: 39 | - 'skip-changelog' 40 | template: | 41 | ## Changes 42 | 43 | $CHANGES 44 | 45 | ## Contributors 46 | We'd like to thank all the contributors who worked on this release! 47 | 48 | $CONTRIBUTORS 49 | 50 | -------------------------------------------------------------------------------- /.github/workflows/deploy-docs.yaml: -------------------------------------------------------------------------------- 1 | name: Deploy docs to website 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - master 8 | - '[0-9]+.[0-9]+' 9 | paths: 10 | - 'mkdocs.yml' 11 | - 'docs/**' 12 | 13 | jobs: 14 | deploy: 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v2.1.1 19 | - name: Set up Python 3.x 20 | uses: actions/setup-python@v2 21 | with: 22 | python-version: '3.9' 23 | - name: Display Python version 24 | run: python -c "import sys; print(sys.version)" 25 | - name: Install docs dependencies 26 | run: pip install -r docs/requirements.txt 27 | - name: Get entire project 28 | run: git fetch -t 29 | - name: Build docs 30 | run: mkdocs build 31 | - uses: jakejarvis/s3-sync-action@v0.5.1 32 | with: 33 | args: --acl public-read --follow-symlinks 34 | env: 35 | AWS_S3_BUCKET: ${{ secrets.DOCS_AWS_S3_BUCKET }} 36 | AWS_ACCESS_KEY_ID: ${{ secrets.DOCS_AWS_ACCESS_KEY_ID }} 37 | AWS_SECRET_ACCESS_KEY: ${{ secrets.DOCS_AWS_SECRET_ACCESS_KEY }} 38 | DEST_DIR: ${{ secrets.DOCS_AWS_S3_DIR }} 39 | SOURCE_DIR: 'site' 40 | -------------------------------------------------------------------------------- /.github/workflows/release-drafter.yml: -------------------------------------------------------------------------------- 1 | name: Release Drafter 2 | 3 | on: 4 | push: 5 | # branches to consider in the event; optional, defaults to all 6 | branches: 7 | - master 8 | 9 | jobs: 10 | update_release_draft: 11 | runs-on: ubuntu-latest 12 | steps: 13 | # Drafts your next Release notes as Pull Requests are merged into "master" 14 | - uses: release-drafter/release-drafter@v5 15 | with: 16 | # (Optional) specify config name to use, relative to .github/. Default: release-drafter.yml 17 | config-name: release-drafter-config.yml 18 | env: 19 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 20 | -------------------------------------------------------------------------------- /.github/workflows/trigger-build-and-test-gpu.yaml: -------------------------------------------------------------------------------- 1 | # https://github.com/marketplace/actions/run-circle-ci-on-label 2 | name: build-and-test-gpu 3 | 4 | on: 5 | pull_request: 6 | types: 7 | - labeled 8 | - synchronize 9 | - assigned 10 | 11 | jobs: 12 | valgrind_general: 13 | if: github.event.label.name == 'ci-test' 14 | runs-on: ubuntu-latest 15 | name: Run build and test gpu 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: circle-ci job runner 20 | id: curl-circle-ci 21 | uses: Open-Source-Contrib/circle-ci-trigger-action@latest 22 | with: 23 | circle_ci_token: ${{ secrets.CIRCLE_CI_SECRET}} 24 | circle_ci_job: build-and-test-gpu 25 | circle_ci_project_url: ${{ github.event.pull_request.head.ref }} 26 | -------------------------------------------------------------------------------- /.github/workflows/trigger-valgrind.yaml: -------------------------------------------------------------------------------- 1 | # https://github.com/marketplace/actions/run-circle-ci-on-label 2 | name: valgrind-general-run 3 | 4 | on: 5 | pull_request: 6 | types: 7 | - labeled 8 | - synchronize 9 | - assigned 10 | 11 | jobs: 12 | valgrind_general: 13 | if: github.event.label.name == 'ci-test' 14 | runs-on: ubuntu-latest 15 | name: Run valgrind general 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - name: circle-ci job runner 20 | id: curl-circle-ci 21 | uses: Open-Source-Contrib/circle-ci-trigger-action@latest 22 | with: 23 | circle_ci_token: ${{ secrets.CIRCLE_CI_SECRET}} 24 | circle_ci_job: valgrind-general 25 | circle_ci_project_url: ${{ github.event.pull_request.head.ref }} 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /bin/ 2 | /deps/ 3 | /build/ 4 | /install* 5 | /tests/venv/ 6 | logs/ 7 | /tests/logs/ 8 | .env/ 9 | env*/ 10 | .venv/ 11 | venv*/ 12 | /install 13 | /[0-9]*/ 14 | *.zip 15 | *.tgz 16 | *.tar.gz 17 | /VARIANT 18 | 19 | # Docs API reference 20 | docs/api_reference.md 21 | 22 | ### Cmake auto tools 23 | cmake-build-debug 24 | 25 | # Misc 26 | .DS_Store 27 | *.swp 28 | 29 | # Python 30 | __pycache__ 31 | *.pyc 32 | 33 | # Eclipse (if that's your jam...) 34 | .project 35 | .cproject 36 | .settings/ 37 | 38 | # VSCode 39 | *.vscode 40 | 41 | # Prerequisites 42 | *.d 43 | 44 | # Object files 45 | *.o 46 | *.ko 47 | *.obj 48 | *.elf 49 | 50 | # Linker output 51 | *.ilk 52 | *.map 53 | *.exp 54 | 55 | # Precompiled Headers 56 | *.gch 57 | *.pch 58 | 59 | # Libraries 60 | *.lib 61 | *.a 62 | *.la 63 | *.lo 64 | 65 | # Shared objects (inc. Windows DLLs) 66 | *.dll 67 | *.so 68 | *.so.* 69 | *.dylib 70 | 71 | # Executables 72 | *.exe 73 | *.out 74 | *.app 75 | *.i*86 76 | *.x86_64 77 | *.hex 78 | 79 | # Debug files 80 | *.dSYM/ 81 | *.su 82 | *.idb 83 | *.pdb 84 | 85 | # Debug/Profile files 86 | # ignore perf html reports 87 | *.html 88 | 89 | # Kernel Module Compile Results 90 | *.mod* 91 | *.cmd 92 | .tmp_versions/ 93 | modules.order 94 | Module.symvers 95 | Mkfile.old 96 | dkms.conf 97 | 98 | ### from JetBrains template 99 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 100 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 101 | 102 | .idea 103 | .idea/ 104 | .idea/* 105 | 106 | # User-specific stuff: 107 | .idea/workspace.xml 108 | .idea/tasks.xml 109 | .idea/dictionaries 110 | .idea/vcs.xml 111 | .idea/jsLibraryMappings.xml 112 | 113 | # Sensitive or high-churn files: 114 | .idea/dataSources.ids 115 | .idea/dataSources.xml 116 | .idea/dataSources.local.xml 117 | .idea/sqlDataSources.xml 118 | .idea/dynamic.xml 119 | .idea/uiDesigner.xml 120 | 121 | # Gradle: 122 | .idea/gradle.xml 123 | .idea/libraries 124 | 125 | # Mongo Explorer plugin: 126 | .idea/mongoSettings.xml 127 | 128 | ## File-based project format: 129 | *.iws 130 | 131 | ## Plugin-specific files: 132 | 133 | # IntelliJ 134 | /out/ 135 | 136 | # mpeltonen/sbt-idea plugin 137 | .idea_modules/ 138 | 139 | # docs site 140 | site/ 141 | 142 | # test data 143 | tests/flow/test_data 144 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "opt/readies"] 2 | path = opt/readies 3 | url = https://github.com/RedisLabsModules/readies.git 4 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Except as otherwise specified in the source code headers for specific files, the source code in this repository is made available to you under your choice of 2 | (i) Redis Source Available License 2.0 (RSALv2) or (ii) the Server Side Public License v1 (SSPLv1) 3 | -------------------------------------------------------------------------------- /docs/clients.md: -------------------------------------------------------------------------------- 1 | # RedisAI Clients 2 | 3 | Some languages already have client libraries that provide support for RedisAI's commands. The following table lists the known ones: 4 | 5 | | Project | Language | License | Author | URL | 6 | | ------- | -------- | ------- | ------ | --- | 7 | | JRedisAI | Java | BSD-3 | [RedisLabs](https://redislabs.com/) | [Github](https://github.com/RedisAI/JRedisAI) | 8 | | redisai-py | Python | BSD-3 | [RedisLabs](https://redislabs.com/) | [Github](https://github.com/RedisAI/redisai-py) | 9 | | redisai-go | Go | BSD-3 | [RedisLabs](https://redislabs.com/) | [Github](https://github.com/RedisAI/redisai-go) | 10 | | redisai-js | Typescript/Javascript | BSD-3 | [RedisLabs](https://redislabs.com/) | [Github](https://github.com/RedisAI/redisai-js) | 11 | | redis-modules-sdk | TypeScript | BSD-3-Clause | [Dani Tseitlin](https://github.com/danitseitlin) | [Github](https://github.com/danitseitlin/redis-modules-sdk) | 12 | | redis-modules-java | Java | Apache-2.0 | [dengliming](https://github.com/dengliming) | [Github](https://github.com/dengliming/redis-modules-java) | 13 | | smartredis | C++ | BSD-2-Clause | [Cray Labs](https://github.com/CrayLabs) | [Github](https://github.com/CrayLabs/SmartRedis) | 14 | | smartredis | C | BSD-2-Clause | [Cray Labs](https://github.com/CrayLabs) | [Github](https://github.com/CrayLabs/SmartRedis) | 15 | | smartredis | Fortran | BSD-2-Clause | [Cray Labs](https://github.com/CrayLabs) | [Github](https://github.com/CrayLabs/SmartRedis) | 16 | | smartredis | Python | BSD-2-Clause | [Cray Labs](https://github.com/CrayLabs) | [Github](https://github.com/CrayLabs/SmartRedis) | 17 | 18 | 19 | 20 | The full documentation for RedisAI's API can be found at the [Commands page](commands.md). 21 | -------------------------------------------------------------------------------- /docs/contrib.md: -------------------------------------------------------------------------------- 1 | # Contributor Agreement 2 | Please refer to the following page for the agreement: [Redis Labs Software Grant and Contributor License Agreement](https://cla-assistant.io/RedisAI/RedisAI) 3 | -------------------------------------------------------------------------------- /docs/developer-backends.md: -------------------------------------------------------------------------------- 1 | # RedisAI Development Backends 2 | 3 | This document describes how ONNXRuntime backend can be built from this repository. 4 | We build the ONNXRuntime library with the DISABLE_EXTERNAL_INITIALIZERS=ON build flag. As a result, loading ONNX models that use external files to store the initial (usually very large) values of the model's operations, is invalid. Hence, initialization values must be part of the serialized model, which is also the standard use case. 5 | 6 | It is compiled in a docker, which is responsible for the configuration and installation of all tools required the build process. 7 | 8 | To follow these instructions, this repository must be cloned with all of its submodules (i.e *git clone --recursive https://github.com/redisai/redisai*) 9 | 10 | GNU Make is used as a runner for the dockerfile generator. Python is the language used for the generator script, and jinja is the templating library used to create the docker file from the template *dockerfile.tmpl*, located in the `/opt/build/onnxruntime` directory. 11 | 12 | ### Tools 13 | 14 | Building the backend requires installation of the following tools: 15 | 16 | 1. gnu make 17 | 1. python (3.0 or higher) 18 | 1. docker 19 | 1. jinja2 20 | 21 | On ubuntu bionic these can be installed by running the following steps, to install python3, create a virtual environment, and install the jinja templating dependency. Replace */path/to/venv* with your desired virtualenv location. 22 | 23 | ``` 24 | sudo apt install python3 python3-dev make docker 25 | python3 -m venv /path/to/venv 26 | source /path/to/venv/bin/activate 27 | pip install jinja2 28 | ``` 29 | 30 | ------- 31 | 32 | **Compilation target devices:** 33 | 34 | 1. x86\_64 bit linux systems 35 | 36 | 1. x86\_64 bit linux systems with a GPU 37 | 38 | **Directory:** opt/build/onnxruntime 39 | 40 | **Build options:** 41 | 42 | 1. To build run *make* 43 | 44 | 1. To build with GPU support on x86\_64 run *make GPU=1* 45 | -------------------------------------------------------------------------------- /docs/examples.md: -------------------------------------------------------------------------------- 1 | # RedisAI Examples 2 | The following sections consist of various sample projects and python notebook examples showing the uses for RedisAI. 3 | 4 | To contribute your example (and get the credit for it), click the "Edit this page" button at the top to submit a Pull Request. 5 | 6 | ## Sample projects 7 | This is a list of RedisAI sample projects that can be used as-is or as an inspiration source. 8 | 9 | | Example | Description | Author | License | URL | 10 | | --- | --- | --- | --- | --- | 11 | | RedisAI showcase | Demonstrates using RedisAI functionality, backends and clients | [RedisLabs](https://redislabs.com/) | MIT | [git](https://github.com/RedisAI/redisai-examples) | 12 | | ChatBotDemo | An example of using RedisAI and a Web App for Conversational AI (i.e. chatbot) | [RedisLabs](https://redislabs.com/) | Apache-2.0 | [git](https://github.com/RedisAI/ChatBotDemo) | 13 | | AnimalRecognitionDemo | An example of using Redis Streams, RedisGears and RedisAI for Realtime Video Analytics (i.e. filtering cats) | [RedisLabs](https://redislabs.com/) | BSD-3-Clause | [git](https://github.com/RedisGears/AnimalRecognitionDemo) | 14 | | EdgeRealtimeVideoAnalytics | An example of using Redis Streams, RedisGears, RedisAI and RedisTimeSeries for Realtime Video Analytics (i.e. counting people) | [RedisLabs](https://redislabs.com/) | Apache-2.0 | [git](https://github.com/RedisGears/EdgeRealtimeVideoAnalytics) | 15 | | demo-market-basket-analysis | An exmaple of prediciting shopping baskets on passed purchases | [RedisLabs](https://redislabs.com/) | | [git](https://github.com/RedisLabs-Field-Engineering/demo-market-basket-analysis) | 16 | -------------------------------------------------------------------------------- /docs/gtm.js: -------------------------------------------------------------------------------- 1 | (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': 2 | new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], 3 | j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= 4 | 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); 5 | })(window,document,'script','dataLayer','GTM-MDHLQC4'); 6 | -------------------------------------------------------------------------------- /docs/images/RedisAI_data_structures_and_backends.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedisAI/redis-inference-optimization/c458c5f83e93ee07963af7123e9ad17b52389bcd/docs/images/RedisAI_data_structures_and_backends.png -------------------------------------------------------------------------------- /docs/images/cat_classified.jpg: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:736790963619339be55eea9ae4986751e744d8e9670a14b3aaf5d95d41fcc056 3 | size 26775 4 | -------------------------------------------------------------------------------- /docs/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedisAI/redis-inference-optimization/c458c5f83e93ee07963af7123e9ad17b52389bcd/docs/images/favicon.png -------------------------------------------------------------------------------- /docs/images/flask_modelserver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedisAI/redis-inference-optimization/c458c5f83e93ee07963af7123e9ad17b52389bcd/docs/images/flask_modelserver.png -------------------------------------------------------------------------------- /docs/images/graph.pb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedisAI/redis-inference-optimization/c458c5f83e93ee07963af7123e9ad17b52389bcd/docs/images/graph.pb.png -------------------------------------------------------------------------------- /docs/images/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 9 | 14 | 15 | -------------------------------------------------------------------------------- /docs/images/logo_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedisAI/redis-inference-optimization/c458c5f83e93ee07963af7123e9ad17b52389bcd/docs/images/logo_small.png -------------------------------------------------------------------------------- /docs/images/redisai_modelserver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedisAI/redis-inference-optimization/c458c5f83e93ee07963af7123e9ad17b52389bcd/docs/images/redisai_modelserver.png -------------------------------------------------------------------------------- /docs/images/tfs_modelserver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedisAI/redis-inference-optimization/c458c5f83e93ee07963af7123e9ad17b52389bcd/docs/images/tfs_modelserver.png -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # logo RedisAI 2 | [![Forum](https://img.shields.io/badge/Forum-RedisAI-blue)](https://forum.redislabs.com/c/modules/redisai) 3 | [![Discord](https://img.shields.io/discord/697882427875393627?style=flat-square)](https://discord.gg/rTQm7UZ) 4 | 5 | RedisAI is a Redis module for executing Deep Learning/Machine Learning models and managing their data. Its purpose is being a "workhorse" for model serving, by providing out-of-the-box support for popular DL/ML frameworks and unparalleled performance. **RedisAI both maximizes computation throughput and reduces latency by adhering to the principle of data locality**, as well as simplifies the deployment and serving of graphs by leveraging on Redis' production-proven infrastructure. 6 | 7 | ## Where Next? 8 | * The [Introduction](intro.md) is the recommended starting point 9 | * The [Quickstart](quickstart.md) page provides information about building, installing and running RedisAI 10 | * The [Commands](commands.md) page is a reference of the RedisAI API 11 | * The [RedisGears integration](https://oss.redis.com/redisgears/master/redisai.html) page is a reference of the built-in integration of [RedisGears](https://oss.redis.com/redisgears/) with RedisAI via a Python plugin. 12 | * The [Clients](clients.md) page lists RedisAI clients by programming language 13 | * The [Configuration](configuration.md) page explains how to configure RedisAI 14 | * The [Performance](performance.md) page provides instructions for running benchmarks with RedisAI 15 | * The [Developer](developer.md) page has more information about the design and implementation of the RedisAI module 16 | 17 | ## Quick Links 18 | * [Source code repository](https://github.com/RedisAI/RedisAI) 19 | * [Releases](https://github.com/RedisAI/RedisAI/releases) 20 | * [Docker image](https://hub.docker.com/r/redislabs/redisai/) 21 | 22 | ## Contact Us 23 | If you have questions, want to provide feedback or perhaps report an issue or [contribute some code](contrib.md), here's where we're listening to you: 24 | 25 | * [Forum](https://forum.redis.com/c/modules/redisai) 26 | * [Repository](https://github.com/RedisAI/RedisAI/issues) 27 | 28 | ## License 29 | RedisAI is licensed under the [Redis Source Available License Agreement](https://github.com/RedisAI/RedisAI/blob/master/LICENSE). 30 | -------------------------------------------------------------------------------- /docs/quickstart.md: -------------------------------------------------------------------------------- 1 | # RedisAI Quickstart 2 | RedisAI is a Redis module. To run it you'll need a Redis server (v6.0.0 or greater), the module's shared library, and its dependencies. 3 | 4 | The following sections describe how to get started with RedisAI. 5 | 6 | ## Docker 7 | The quickest way to try RedisAI is by launching its official Docker container images. 8 | 9 | ### On a CPU only machine 10 | ``` 11 | docker run -p 6379:6379 redislabs/redisai:1.2.7-cpu-bionic 12 | ``` 13 | 14 | ### On a GPU machine 15 | For GPU support you will need a machine you'll need a machine that has Nvidia driver (CUDA 11.2 and cuDNN 8.1), nvidia-container-toolkit and Docker 19.03+ installed. For detailed information, checkout [nvidia-docker documentation](https://github.com/NVIDIA/nvidia-docker) 16 | ``` 17 | docker run -p 6379:6379 --gpus all -it --rm redislabs/redisai:1.2.7-gpu-bionic 18 | ``` 19 | 20 | 21 | ## Building 22 | You can compile and build the module from its source code. The [Developer](developer.md) page has more information about the design and implementation of the RedisAI module and how to contribute. 23 | 24 | ### Prerequisites 25 | * Packages: git, python3, make, wget, g++/clang, & unzip 26 | * CMake 3.0 or higher needs to be installed. 27 | * CUDA 11.2 and cuDNN 8.1 or higher needs to be installed if GPU support is required. 28 | * Redis v6.0.0 or greater. 29 | 30 | ### Get the Source Code 31 | You can obtain the module's source code by cloning the project's repository using git like so: 32 | 33 | ```sh 34 | git clone --recursive https://github.com/RedisAI/RedisAI 35 | ``` 36 | 37 | Switch to the project's directory with: 38 | 39 | ```sh 40 | cd RedisAI 41 | ``` 42 | 43 | ### Building the Dependencies 44 | Use the following script to download and build the libraries of the various RedisAI backends (TensorFlow, PyTorch, ONNXRuntime) for CPU only: 45 | 46 | ```sh 47 | bash get_deps.sh 48 | ``` 49 | 50 | Alternatively, you can run the following to fetch the backends with GPU support. 51 | 52 | ```sh 53 | bash get_deps.sh gpu 54 | ``` 55 | 56 | ### Building the Module 57 | Once the dependencies have been built, you can build the RedisAI module with: 58 | 59 | ```sh 60 | make -C opt clean ALL=1 61 | make -C opt 62 | ``` 63 | 64 | Alternatively, run the following to build RedisAI with GPU support: 65 | 66 | ```sh 67 | make -C opt clean ALL=1 68 | make -C opt GPU=1 69 | ``` 70 | 71 | ## Loading the Module 72 | To load the module upon starting the Redis server, simply use the `--loadmodule` command line switch, the `loadmodule` configuration directive or the [Redis `MODULE LOAD` command](https://redis.io/commands/module-load) with the path to module's library. 73 | 74 | For example, to load the module from the project's path with a server command line switch use the following: 75 | 76 | ```sh 77 | redis-server --loadmodule ./install-cpu/redisai.so 78 | ``` 79 | -------------------------------------------------------------------------------- /docs/requirements-llapi.txt: -------------------------------------------------------------------------------- 1 | -e git+https://github.com/matusnovak/doxybook.git#egg=doxybook 2 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | mkdocs==1.3.0 2 | mkdocs-material==6.2.2 3 | -e git+https://github.com/RedisLabs/mkdocs-versions-menu.git#egg=mkdocs-versions-menu 4 | -e git+https://github.com/RedisLabs/mkdocs-include.git#egg=mkdocs-include 5 | -e git+https://github.com/RedisLabs/mkdocs-modules-template.git#egg=mkdocs-modules-template 6 | # uncomment requirement to build LL API 7 | # -e git+https://github.com/matusnovak/doxybook.git#egg=doxybook 8 | -------------------------------------------------------------------------------- /docs/snippets/notebooks/data/cat.jpg: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:6705f3b1bada344ec2ab7bc33d626ba64eb7f50e1b6bab7e09240e493e91875d 3 | size 52647 4 | -------------------------------------------------------------------------------- /docs/snippets/notebooks/models/tensorflow/imagenet/resnet50.pb: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:7018654e139bbbc15518e204af9c08e84a520247f42e2d81fe547538ab865742 3 | size 102621616 4 | -------------------------------------------------------------------------------- /docs/snippets/notebooks/models/tensorflow/mobilenet/mobilenet_224.pb: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:111479258f3841c93d0a7a377c976c24e8281077818991931429d2277dd88590 3 | size 24508794 4 | -------------------------------------------------------------------------------- /docs/snippets/notebooks/models/tensorflow/tinyyolo/tinyyolo.pb: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:5a48ca053cf228a10023f11f92274efdaac7a0f991d7f15066add62523612137 3 | size 63481382 4 | -------------------------------------------------------------------------------- /hooks/post_checkout: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Docker hub does a recursive clone, then checks the branch out, 3 | # so when a PR adds a submodule (or updates it), it fails. 4 | git submodule update --init --recursive 5 | 6 | -------------------------------------------------------------------------------- /license/RSALv2.txt: -------------------------------------------------------------------------------- 1 | Redis Source Available License 2.0 dated November 15, 2022 2 | 3 | ## Acceptance 4 | 5 | By using the software, you agree to all of the terms and conditions below. 6 | 7 | ## Copyright License 8 | 9 | The licensor grants you a non-exclusive, royalty-free, worldwide, non-sublicensable, non-transferable license to use, copy, distribute, make available, and prepare derivative works of the software, in each case subject to the limitations and conditions below. 10 | 11 | ## Limitations 12 | 13 | You may not make the functionality of the software or a modified version available to third parties as a service, or distribute the software or a modified version in a manner that makes the functionality of the software available to third parties. 14 | Making the functionality of the software or modified version available to third parties includes, without limitation, enabling third parties to interact with the functionality of the software or modified version in distributed form or remotely through a computer network, offering a product or service the value of which entirely or primarily derives from the value of the software or modified version, or offering a product or service that accomplishes for users the primary purpose of the software or modified version. 15 | 16 | You may not alter, remove, or obscure any licensing, copyright, or other notices of the licensor in the software. Any use of the licensor’s trademarks is subject to applicable law. 17 | 18 | ## Patents 19 | 20 | The licensor grants you a license, under any patent claims the licensor can license, or becomes able to license, to make, have made, use, sell, offer for sale, import and have imported the software, in each case subject to the limitations and conditions in this license. This license does not cover any patent claims that you cause to be infringed by modifications or additions to the software. If you or your company make any written claim that the software infringes or contributes to infringement of any patent, your patent license for the software granted under these terms ends immediately. If your company makes such a claim, your patent license ends immediately for work on behalf of your company. 21 | 22 | ## Notices 23 | 24 | You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these terms. 25 | If you modify the software, you must include in any modified copies of the software prominent notices stating that you have modified the software. 26 | 27 | ## No Other Rights 28 | 29 | These terms do not imply any licenses other than those expressly granted in these terms. 30 | Termination 31 | 32 | If you use the software in violation of these terms, such use is not licensed, and your licenses will automatically terminate. If the licensor provides you with a notice of your violation, and you cease all violations of this license no later than 30 days after you receive that notice, your licenses will be reinstated retroactively. However, if you violate these terms after such reinstatement, any additional violation of these terms will cause your licenses to terminate automatically and permanently. 33 | 34 | ## No Liability 35 | 36 | As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim. 37 | 38 | ## Definitions 39 | 40 | The licensor is the entity offering these terms, and the software is the software the licensor makes available under these terms, including any portion of it. 41 | 42 | To modify a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission other than making an exact copy. The resulting work is called a modified version of the earlier work. 43 | 44 | you refers to the individual or entity agreeing to these terms. 45 | 46 | your company is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all organizations that have control over, are under the control of, or are under common control with that organization. control means ownership of substantially all the assets of an entity, or the power to direct its management and policies by vote, contract, or otherwise. Control can be direct or indirect. 47 | 48 | your licenses are all the licenses granted to you for the software under these terms. 49 | 50 | use means anything you do with the software requiring one of your licenses. 51 | 52 | trademark means trademarks, service marks, and similar rights. 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: RedisAI - A Server for Machine and Deep Learning Models 2 | site_url: http://redisai.io 3 | repo_url: https://github.com/RedisAI/RedisAI 4 | repo_name: RedisAI/RedisAI 5 | 6 | google_analytics: 7 | - 'UA-92003007-1' 8 | - 'auto' 9 | 10 | use_directory_urls: true 11 | 12 | theme: 13 | name: 'material' 14 | language: 'en' 15 | logo: 'images/logo_small.png' 16 | favicon: 'images/favicon.png' 17 | palette: 18 | primary: 'indigo' 19 | accent: 'red' 20 | font: 21 | text: 'Roboto' 22 | code: 'Roboto Mono' 23 | feature: 24 | tabs: false 25 | 26 | extra_javascript: 27 | - 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-MML-AM_CHTML' 28 | - gtm.js 29 | 30 | nav: 31 | - 'Home': index.md 32 | - 'Introduction': intro.md 33 | - 'Quickstart': quickstart.md 34 | - 'Commands': commands.md 35 | - 'Clients': clients.md 36 | - 'Configuration': configuration.md 37 | - 'Developer': developer.md 38 | - 'Performance': performance.md 39 | - 'Examples': examples.md 40 | - 'Contributing': contrib.md 41 | 42 | markdown_extensions: 43 | - admonition 44 | - pymdownx.arithmatex 45 | - pymdownx.details 46 | - pymdownx.superfences 47 | - codehilite: 48 | guess_lang: False 49 | - toc: 50 | permalink: True 51 | 52 | plugins: 53 | - search 54 | - include: 55 | src_path: docs/snippets 56 | - modules-template: 57 | try-for-free: false 58 | modules: 59 | - name: 'Search' 60 | link: '/redisearch' 61 | 62 | - name: 'Time Series' 63 | link: '/redistimeseries' 64 | 65 | - name: 'Bloom' 66 | link: '/redisbloom' 67 | 68 | - name: 'Graph' 69 | link: '/redisgraph' 70 | 71 | - name: 'JSON' 72 | link: '/redisjson' 73 | 74 | - name: 'Gears' 75 | link: '/redisgears' 76 | - versions-menu: 77 | -------------------------------------------------------------------------------- /opt/build/backends.rules: -------------------------------------------------------------------------------- 1 | # PRODUCT var is the backend name, without any other configuration (set in each backend's corresponding makefile) 2 | 3 | # default is x64 4 | ARCH=$(shell ${READIES}/bin/platform --arch) 5 | OS=$(shell ${READIES}/bin/platform --os) 6 | REDIS_CMAKE_ARCH=x86_64 7 | DOCKER_ORG=redislabs 8 | 9 | # jetson 10 | ifeq ($(shell test -e /usr/share/doc/nvidia-l4t-jetson-io && echo -n yes),yes) 11 | ARCH=jetson 12 | REDIS_CMAKE_ARCH=aarch64 13 | GPU=1 14 | endif 15 | export REDIS_CMAKE_ARCH 16 | 17 | # override if necessary in top-level make files 18 | DEFAULT_DOCKER_TAG=${DOCKER_ORG}/${PRODUCT}:build 19 | CIDFILE=${PRODUCT}.${ARCH}.cid 20 | 21 | ifeq ($(GPU),1) 22 | REDIS_GPU=1 23 | VARIANT=gpu 24 | CIDFILE=${PRODUCT}.${ARCH}.gpu.cid # this way we can build from the same tree across platforms 25 | export REDIS_GPU 26 | endif 27 | 28 | ifeq ($(VARIANT),) 29 | BACKEND_NAME=${PRODUCT}-${OS}-${ARCH}-${VERSION}.tgz 30 | else 31 | BACKEND_NAME=${PRODUCT}-${OS}-${ARCH}-${VARIANT}-${VERSION}.tgz 32 | endif 33 | 34 | S3_URL=redismodules/${PRODUCT} 35 | 36 | build: 37 | @rm -f ${BACKEND_NAME} *.cid 38 | REDIS_ARCH=${ARCH} \ 39 | REDIS_OSNICK=${OSNICK} \ 40 | ${READIES}/bin/dockerwrapper \ 41 | -d ${CURDIR}/Dockerfile${DOCKER_SUFFIX} \ 42 | -t ${DEFAULT_DOCKER_TAG} \ 43 | -S ../dockerparts \ 44 | -e REDIS \ 45 | -D "${DOCKER_OPTS}" \ 46 | ${DOCKER_ARGS} 47 | docker create --cidfile ${CIDFILE} ${DEFAULT_DOCKER_TAG} 48 | docker cp `cat ${CIDFILE}`:/build/${BACKEND_NAME} . 49 | 50 | publish: 51 | @aws s3 cp ${BACKEND_NAME} s3://$(S3_URL)/ --acl public-read 52 | 53 | # --------------------------------------------------------------------------------------------------- 54 | define HELP 55 | make build> # build the backend, tagging the docker image so that the files can be copied out of it 56 | OSNICK=<> # optional base operating system (xenial, bionic, etc) 57 | REDIS_CUDA_VERSION=<> # optional cuda version to override 58 | DOCKER_SUFFIX=<> # optional suffix for the generated dockerfile 59 | GPU=1 # if set, build the GPU 60 | make publish > # upload the generated artifacts to s3 same 61 | GPU=1 # if set, upload the GPU artifact (defaults to cpu) 62 | endef 63 | # --------------------------------------------------------------------------------------------------- 64 | include ${READIES}/mk/help.defs 65 | include ${READIES}/mk/help.rules 66 | -------------------------------------------------------------------------------- /opt/build/docker/Makefile: -------------------------------------------------------------------------------- 1 | # Feel free to change these 2 | PRODUCT=redisai 3 | DOCKER_ORG=redislabs 4 | REDIS_VERSION=6.2.7 5 | REDIS_CUDA_VERSION=11.3.1-cudnn8 6 | REDISAI_LITE=0 7 | 8 | PACK=1 # to fetch the artifacts 9 | 10 | DOCKER_OPTS= # set, to pass custom options to docker, but remember to quote them 11 | OSNICK ?= bionic 12 | 13 | # set to pass multiple directories as docker sources to include in templates 14 | DOCKER_SOURCES="" 15 | 16 | # set, to generate a file named Dockerfile, i.e useful when you want to run things in parallel 17 | DOCKER_SUFFIX= 18 | 19 | # Add space delimited docker tags, and they'll all be applied 20 | DOCKER_TAGS= 21 | 22 | DEFAULT_TAG=${DOCKER_ORG}/${PRODUCT}:${VERSION}-cpu-${OSNICK} 23 | 24 | # set gpu arguments 25 | ifeq ($(GPU),1) 26 | DOCKER_ARGS = gpu_build=1 27 | DOCKER_SUFFIX=gpu 28 | DEFAULT_TAG=${DOCKER_ORG}/${PRODUCT}:${VERSION}-gpu-${OSNICK} 29 | endif 30 | 31 | # remap ubuntu versions because of nvidia cuda 32 | ifeq ($(OSNICK),xenial) 33 | REDIS_CUDA_MAPVERSION=ubuntu16.04 34 | endif 35 | ifeq ($(OSNICK),bionic) 36 | REDIS_CUDA_MAPVERSION=ubuntu18.04 37 | endif 38 | ifeq ($(OSNICK),centos8) 39 | REDIS_CUDA_MAPVERSION=centos8 40 | endif 41 | 42 | DOCKERWRAPPER_EXTRA_VARS=\ 43 | REDISAI_LITE=${REDISAI_LITE} \ 44 | REDIS_CUDA_VERSION=${REDIS_CUDA_VERSION} \ 45 | REDIS_CUDA_MAPVERSION=${REDIS_CUDA_MAPVERSION} 46 | 47 | ### Defaults ### 48 | ROOT=../../.. 49 | READIES=${ROOT}/opt/readies 50 | 51 | #------------------------------------------------------------------------------ 52 | define HELP 53 | make build # build and optionally publish the docker, from a template file 54 | OSNICK=<> # base operating system 55 | REDISAI_LITE=1 # enable RedisAI lite builds 56 | DOCKER_SUFFIX=<> # optional suffix for the generated dockerfile 57 | DOCKER_ARGS=FOO=BAR # key-value pairs of variables to pass into the docker build 58 | PACK=1 # fetch generated artifacts 59 | DOCKER_TAGS=a,b,c # tags to append and push to dockerhub 60 | DEFAULT_TAG=redislabs/redisai # default docker tag to build, and push 61 | TEST=1 # run tests, if specified 62 | VERSION=x.y.z # set the docker version 63 | NOP=1 # set to echo files in docker generation, and not run 64 | DOCKER_SOURCES=/a/path # append paths to the template generator 65 | PUBLISH=1 # if set, push to dockerhub (requires docker login) 66 | DOCKER_OPTS=XXX # Options to pass to the docker build command 67 | GPU=1 # if set, build the GPU docker 68 | endef 69 | #------------------------------------------------------------------------------ 70 | 71 | # rules, for building 72 | include ${READIES}/mk/docker.rules 73 | -------------------------------------------------------------------------------- /opt/build/docker/dockerfile-gpu-test.tmpl: -------------------------------------------------------------------------------- 1 | # BUILD redisfab/redisai:{{VERSION}}-gpu-{{REDIS_ARCH}}-{{REDIS_OSNICK}}-test 2 | 3 | ARG PACK={{REDIS_PACK}} 4 | 5 | # OSNICK=bionic|centos7|centos6 6 | ARG OSNICK=bionic 7 | 8 | # ARCH=x64|arm64v8|arm32v7 9 | ARG ARCH=x64 10 | 11 | # OS=ubuntu18.04|ubuntu16.04|centos7 12 | ARG OS=ubuntu18.04 13 | 14 | #---------------------------------------------------------------------------------------------- 15 | FROM redisfab/redis:{{REDIS_VERSION}}-{{REDIS_ARCH}}-{{REDIS_OSNICK}} AS redis 16 | FROM nvidia/cuda:{{REDIS_CUDA_VERSION}}-devel-ubuntu18.04 AS builder 17 | 18 | ARG PACK 19 | 20 | SHELL ["/bin/bash", "-c"] 21 | 22 | {% include "templates/gpu.yml" %} 23 | 24 | ENV LANG=en_US.UTF-8 25 | RUN apt-get update 26 | RUN apt-get install -y locales && \ 27 | sed -i -e "s/# $LANG.*/$LANG UTF-8/" /etc/locale.gen && \ 28 | dpkg-reconfigure --frontend=noninteractive locales && \ 29 | update-locale LANG=$LANG 30 | 31 | WORKDIR /build 32 | ADD ./ /build 33 | COPY --from=redis /usr/local/ /usr/local/ 34 | COPY ./opt/ opt/ 35 | COPY ./tests/flow/tests_setup/test_requirements.txt tests/flow/tests_setup/ 36 | COPY ./tests/flow/tests_setup/Install_RedisGears.sh tests/flow/tests_setup/ 37 | COPY ./get_deps.sh . 38 | 39 | RUN apt-get -q install -y git 40 | 41 | RUN VENV=venv FORCE=1 ./opt/readies/bin/getpy3 42 | 43 | RUN set -e ;\ 44 | . venv/bin/activate ;\ 45 | ./opt/system-setup.py 46 | 47 | ARG DEPS_ARGS="" 48 | RUN set -e ;\ 49 | . venv/bin/activate ;\ 50 | if [[ -z $DEPS_ARGS ]]; then \ 51 | VERBOSE=1 ./get_deps.sh gpu ;\ 52 | else \ 53 | env $DEPS_ARGS ./get_deps.sh gpu ;\ 54 | fi 55 | 56 | ARG BUILD_ARGS="" 57 | RUN set -e ;\ 58 | . venv/bin/activate ;\ 59 | bash -l -c "make -C opt build GPU=1 $BUILD_ARGS SHOW=1" 60 | 61 | RUN set -e ;\ 62 | if [[ $PACK == 1 ]]; then \ 63 | . venv/bin/activate ;\ 64 | bash -l -c "make -C opt pack GPU=1 VERBOSE=1" ;\ 65 | fi 66 | 67 | RUN git remote set-url origin https://github.com/RedisAI/RedisAI 68 | 69 | CMD ["bash", "-c", ". ./venv/bin/activate; make -C opt test GPU=1 SHOW=1"] 70 | -------------------------------------------------------------------------------- /opt/build/docker/dockerfile.tmpl: -------------------------------------------------------------------------------- 1 | # BUILD redisfab/redisai:{{VERSION}}-cpu-{{REDIS_ARCH}}-{{REDIS_OSNICK}} 2 | 3 | 4 | ARG PACK={{REDIS_PACK}} 5 | ARG REDISAI_LITE={{REDISAI_LITE}} 6 | ARG TEST={{REDIS_TEST}} 7 | 8 | 9 | #---------------------------------------------------------------------------------------------- 10 | FROM redisfab/redis:{{REDIS_VERSION}}-{{REDIS_ARCH}}-{{REDIS_OSNICK}} AS redis 11 | {% if gpu_build is defined %} 12 | FROM nvidia/cuda:{{REDIS_CUDA_VERSION}}-devel-{{REDIS_CUDA_MAPVERSION}} AS builder 13 | {% else %} 14 | FROM {{REDIS_OS}} AS builder 15 | {% endif %} 16 | 17 | ARG REDISAI_LITE 18 | ARG PACK 19 | ARG TEST 20 | 21 | RUN echo "Building for {{REDIS_OSNICK}} ({{REDIS_OS}}) for {{REDIS_ARCH}} [with Redis {{REDIS_VERSION}}]" 22 | 23 | {% if gpu_build is defined %} 24 | {% include "templates/gpu.yml" %} 25 | {% endif %} 26 | 27 | # centos8 specific integration until a move to rocky or similar 28 | {% if REDIS_OSNICK == "centos8" %} 29 | RUN cd /etc/yum.repos.d/ 30 | RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-* 31 | RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-* 32 | {% endif %} 33 | 34 | WORKDIR /build 35 | COPY --from=redis /usr/local/ /usr/local/ 36 | 37 | COPY ./opt/ opt/ 38 | ADD ./tests/flow/ tests/flow/ 39 | 40 | RUN if [ ! -z $(command -v apt-get) ]; then apt-get -qq update; apt-get -q install -y git; fi 41 | RUN if [ ! -z $(command -v yum) ]; then yum install -y git; fi 42 | RUN FORCE=1 ./opt/readies/bin/getpy3 43 | RUN ./opt/system-setup.py 44 | 45 | ARG DEPS_ARGS="" 46 | COPY ./get_deps.sh . 47 | RUN if [ "$DEPS_ARGS" = "" ]; then ./get_deps.sh {% if gpu_build is defined %}gpu {% else %} cpu {% endif %}; else env $DEPS_ARGS ./get_deps.sh {% if gpu_build is defined %} gpu {% else %} cpu {% endif %}; fi 48 | 49 | ARG BUILD_ARGS="" 50 | ADD ./ /build 51 | RUN bash -l -c "make -C opt build {% if gpu_build is defined %} GPU=1 {% else %} REDISAI_LITE={{REDISAI_LITE}} {% endif %}$BUILD_ARGS SHOW=1" 52 | 53 | 54 | RUN mkdir -p bin/artifacts 55 | RUN set -e ;\ 56 | if [ "$PACK" = "1" ]; then bash -l -c "make -C opt pack {% if gpu_build is defined %} GPU=1 {% endif %} REDISAI_LITE={{REDISAI_LITE}}"; fi 57 | 58 | RUN set -e ;\ 59 | if [ "$TEST" = "1" ]; then \ 60 | bash -l -c "TEST= make -C opt test {% if gpu_build is defined %}GPU=1{% endif %} REDISAI_LITE={{REDISAI_LITE}} $BUILD_ARGS NO_LFS=1" ;\ 61 | if [[ -d test/logs ]]; then \ 62 | {% if gpu_build is defined %} 63 | tar -C test/logs -czf bin/artifacts/test-logs-gpu.tgz . ;\ 64 | {% else %} 65 | tar -C test/logs -czf bin/artifacts/test-logs-cpu.tgz . ;\ 66 | {% endif %} 67 | fi ;\ 68 | fi 69 | 70 | #---------------------------------------------------------------------------------------------- 71 | {% if gpu_build is defined %} 72 | FROM nvidia/cuda:{{REDIS_CUDA_VERSION}}-runtime-{{REDIS_CUDA_MAPVERSION}} 73 | {% else %} 74 | FROM redisfab/redis:{{REDIS_VERSION}}-{{REDIS_ARCH}}-{{REDIS_OSNICK}} 75 | {% endif %} 76 | 77 | ARG PACK 78 | # centos8 specific integration until a move to rocky or similar 79 | {% if REDIS_OSNICK == "centos8" %} 80 | RUN cd /etc/yum.repos.d/ 81 | RUN sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-* 82 | RUN sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-* 83 | {% endif %} 84 | 85 | RUN if [ ! -z $(command -v apt-get) ]; then apt-get -qq update; apt-get -q install -y libgomp1; fi 86 | RUN if [ ! -z $(command -v yum) ]; then yum install -y libgomp; fi 87 | 88 | ENV REDIS_MODULES /usr/lib/redis/modules 89 | ENV LD_LIBRARY_PATH $REDIS_MODULES 90 | 91 | RUN mkdir -p $REDIS_MODULES/ 92 | 93 | {% if gpu_build is defined %} 94 | COPY --from=builder /build/install-gpu/ $REDIS_MODULES/ 95 | {% else %} 96 | COPY --from=builder /build/install-cpu/ $REDIS_MODULES/ 97 | {% endif %} 98 | 99 | COPY --from=builder /build/bin/artifacts/ /var/opt/redislabs/artifacts 100 | {% if gpu_build is defined %} 101 | COPY --from=redis /usr/local/bin/redis* /usr/local/bin/ 102 | {% endif %} 103 | 104 | WORKDIR /data 105 | EXPOSE 6379 106 | CMD ["/usr/local/bin/redis-server", "--loadmodule", "/usr/lib/redis/modules/redisai.so"] 107 | -------------------------------------------------------------------------------- /opt/build/docker/templates/gpu.yml: -------------------------------------------------------------------------------- 1 | # given the cuda version, generate the paths so that we don't manually maintain them 2 | {% set cuda_list = REDIS_CUDA_VERSION.split("-") %} 3 | {% set cuda_parts = cuda_list[0].split(".") %} 4 | {% set cuda_version = cuda_parts[0] + "." + cuda_parts[1] %} 5 | ENV NVIDIA_VISIBLE_DEVICES all 6 | ENV NVIDIA_DRIVER_CAPABILITIES compute,utility 7 | RUN echo export LD_LIBRARY_PATH=/usr/local/cuda/lib64:/usr/local/cuda-{{cuda_version}}/lib64:/usr/local/cuda-{{cuda_version}}/compat/:$LD_LIBRARY_PATH > /etc/profile.d/cuda.sh 8 | 9 | -------------------------------------------------------------------------------- /opt/build/dockerparts/apt.yml: -------------------------------------------------------------------------------- 1 | RUN apt-get update -qq 2 | RUN DEBIAN_NONINTERACTIVE=y1 apt-get install -y software-properties-common 3 | 4 | {% if REDIS_OSNICK == 'xenial' %} 5 | RUN add-apt-repository ppa:deadsnakes/ppa 6 | RUN add-apt-repository ppa:ubuntu-toolchain-r/test 7 | {% endif %} 8 | 9 | RUN apt-get update -qq 10 | RUN DEBIAN_NONINTERACTIVE=1 apt-get install -y curl wget tar git patch \ 11 | build-essential libcurl4-openssl-dev libssl-dev libatlas-base-dev zlib1g-dev \ 12 | python3.7 python3-pip python3-dev \ 13 | gcc-7 g++-7 14 | 15 | RUN update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.7 60 16 | RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 60 --slave /usr/bin/g++ g++ /usr/bin/g++-7 17 | 18 | RUN python3 -m pip install --upgrade pip setuptools wheel 19 | 20 | ENV LANG=en_US.UTF-8 21 | RUN apt-get install -y locales && \ 22 | sed -i -e "s/# $LANG.*/$LANG UTF-8/" /etc/locale.gen && \ 23 | dpkg-reconfigure --frontend=noninteractive locales && \ 24 | update-locale LANG=$LANG 25 | 26 | 27 | -------------------------------------------------------------------------------- /opt/build/dockerparts/cmake.yml: -------------------------------------------------------------------------------- 1 | {% set cmake_version = "3.19.7" %} 2 | RUN wget -q https://github.com/Kitware/CMake/releases/download/v{{cmake_version}}/cmake-{{cmake_version}}-Linux-{{REDIS_CMAKE_ARCH}}.tar.gz -O /tmp/cmake.tgz 3 | 4 | WORKDIR /tmp 5 | RUN tar -zxpf /tmp/cmake.tgz 6 | RUN mv /tmp/cmake*/bin/* /usr/bin 7 | RUN mv /tmp/cmake-*/share/cmake* /usr/share/ 8 | 9 | 10 | -------------------------------------------------------------------------------- /opt/build/onnxruntime/.gitignore: -------------------------------------------------------------------------------- 1 | Dockerfile 2 | *.cid 3 | -------------------------------------------------------------------------------- /opt/build/onnxruntime/Makefile: -------------------------------------------------------------------------------- 1 | REDIS_ONNX_VERSION?=1.11.1 2 | REDIS_ONNX_REPO?=https://github.com/microsoft/onnxruntime 3 | 4 | PRODUCT=onnxruntime 5 | VERSION=${REDIS_ONNX_VERSION} 6 | REDIS_CUDA_VERSION=11.3.1-cudnn8 7 | 8 | # anything prefixed with REDIS, and exported is available in the docker build 9 | export REDIS_ONNX_VERSION 10 | export REDIS_ONNX_REPO 11 | export REDIS_CUDA_VERSION 12 | 13 | OSNICK=bionic 14 | 15 | ROOT=. 16 | READIES=${ROOT}/../../readies 17 | 18 | include ../backends.rules 19 | -------------------------------------------------------------------------------- /opt/build/onnxruntime/dockerfile.tmpl: -------------------------------------------------------------------------------- 1 | {% if REDIS_OSNICK == "bionic" %} 2 | {% set cuda_suffix_os = "ubuntu18.04" %} 3 | {% endif %} 4 | 5 | {% if REDIS_ARCH == 'jetson' %} 6 | FROM nvcr.io/nvidia/deepstream-l4t:5.1-21.02-base 7 | {% endif %} 8 | 9 | {% if REDIS_ARCH == 'x64' %} 10 | {% if REDIS_GPU is defined %} 11 | FROM nvidia/cuda:{{REDIS_CUDA_VERSION}}-devel-{{cuda_suffix_os}} 12 | {% else %} 13 | {% if REDIS_OSNICK == "bionic" %} 14 | FROM ubuntu:bionic 15 | {% endif %} 16 | {% endif %} 17 | {% endif %} 18 | 19 | ARG ONNXRUNTIME_REPO={{REDIS_ONNX_REPO}} 20 | ARG ONNXRUNTIME_VER={{REDIS_ONNX_VERSION}} 21 | 22 | {% include 'apt.yml' %} 23 | 24 | {% include 'cmake.yml' %} 25 | 26 | # build 27 | WORKDIR /build 28 | {% if REDIS_GPU is defined %} 29 | {% set BUILDTYPE="Release" %} 30 | {% set BUILDARGS="--use_cuda --cudnn_home /usr/local/cuda --cuda_home /usr/local/cuda --cmake_extra_defines onnxruntime_DISABLE_EXTERNAL_INITIALIZERS=ON"%} 31 | {% else %} 32 | {% set BUILDTYPE="Release" %} 33 | {% set BUILDARGS="--cmake_extra_defines onnxruntime_DISABLE_EXTERNAL_INITIALIZERS=ON" %} 34 | {% endif %} 35 | 36 | ARG BUILDARGS="--config {{BUILDTYPE}} --parallel" 37 | RUN git clone --single-branch --branch v{{REDIS_ONNX_VERSION}} {{REDIS_ONNX_REPO}} onnxruntime 38 | WORKDIR /build/onnxruntime 39 | RUN ./build.sh --config {{BUILDTYPE}} {{BUILDARGS}} --update --build --build_shared_lib --parallel 40 | 41 | # package 42 | ADD ./pack.sh /build 43 | WORKDIR /build 44 | RUN ./pack.sh {{REDIS_ONNX_VERSION}} {{REDIS_ARCH}} {{BUILDTYPE}} linux {% if REDIS_GPU is defined %} gpu {% endif %} 45 | -------------------------------------------------------------------------------- /opt/build/onnxruntime/pack.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | VER="$1" # 1.9.0 5 | PLATFORM="$2" # x64|jetson 6 | BUILDTYPE="$3" # Release 7 | BASEOS="$4" # linux (mac future?) 8 | VARIANT="$5" # if set (gpu) 9 | 10 | target=onnxruntime-${BASEOS}-${PLATFORM}-${VER} 11 | if [ ! -z "${VARIANT}" ]; then 12 | target=onnxruntime-${BASEOS}-${PLATFORM}-${VARIANT}-${VER} 13 | fi 14 | 15 | mkdir -p pack/include pack/lib 16 | cp onnxruntime/build/Linux/$BUILDTYPE/libonnxruntime.so.${VER} pack/lib/ 17 | cp onnxruntime/docs/C_API_Guidelines.md pack/ 18 | cp onnxruntime/LICENSE pack/ 19 | cp onnxruntime/README.md pack/ 20 | cp onnxruntime/ThirdPartyNotices.txt pack/ 21 | cp onnxruntime/VERSION_NUMBER pack/ 22 | cd onnxruntime/ 23 | git rev-parse HEAD > ../pack/GIT_COMMIT_ID 24 | cd .. 25 | cp onnxruntime/include/onnxruntime/core/session/onnxruntime_c_api.h pack/include/ 26 | cp onnxruntime/include/onnxruntime/core/session/onnxruntime_cxx_api.h pack/include/ 27 | cp onnxruntime/include/onnxruntime/core/session/onnxruntime_cxx_inline.h pack/include/ 28 | cp onnxruntime/include/onnxruntime/core/framework/provider_options.h pack/include/ 29 | cp onnxruntime/include/onnxruntime/core/providers/cpu/cpu_provider_factory.h pack/include/ 30 | cd pack/lib/ 31 | ln -s libonnxruntime.so.${VER} libonnxruntime.so 32 | cd ../.. 33 | mv pack ${target} 34 | tar czf ${target}.tgz ${target}/ 35 | -------------------------------------------------------------------------------- /opt/clang-check-all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # exit immediatly on error ( no need to keep checking ) 4 | set -e 5 | 6 | CLANG_FMT_SRCS=$(find ../src/ \( -name '*.c' -o -name '*.cc' -o -name '*.cpp' -o -name '*.h' -o -name '*.hh' -o -name '*.hpp' \)) 7 | CLANG_FMT_TESTS=$(find ../tests/ \( -name '*.c' -o -name '*.cc' -o -name '*.cpp' -o -name '*.h' -o -name '*.hh' -o -name '*.hpp' \)) 8 | 9 | for filename in $CLANG_FMT_SRCS; do 10 | echo "Checking $filename" 11 | clang-format -style=file -Werror --dry-run $filename 12 | done 13 | 14 | for filename in $CLANG_FMT_TESTS; do 15 | echo "Checking $filename" 16 | clang-format -style=file -Werror --dry-run $filename 17 | done 18 | -------------------------------------------------------------------------------- /opt/clang-format-all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # exit immediatly on error ( no need to keep checking ) 4 | set -e 5 | 6 | CLANG_FMT_SRCS=$(find ../src/ \( -name '*.c' -o -name '*.cc' -o -name '*.cpp' -o -name '*.h' -o -name '*.hh' -o -name '*.hpp' \)) 7 | CLANG_FMT_TESTS=$(find ../tests/ \( -name '*.c' -o -name '*.cc' -o -name '*.cpp' -o -name '*.h' -o -name '*.hh' -o -name '*.hpp' \)) 8 | 9 | for filename in $CLANG_FMT_SRCS; do 10 | clang-format --verbose -style=file -i $filename 11 | done 12 | 13 | for filename in $CLANG_FMT_TESTS; do 14 | clang-format --verbose -style=file -i $filename 15 | done 16 | -------------------------------------------------------------------------------- /opt/getver: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" 4 | ROOT=$(cd $HERE/..; pwd) 5 | 6 | getver_c=$(mktemp "${TMPDIR:-/tmp}/getver-XXXXXXX.c") 7 | if [[ $NUMERIC != 1 ]]; then 8 | cat <<- EOF > $getver_c 9 | #include 10 | 11 | #include "src/version.h" 12 | 13 | int main(int argc, char *argv[]) { 14 | printf("%d.%d.%d\n", REDISAI_VERSION_MAJOR, REDISAI_VERSION_MINOR, REDISAI_VERSION_PATCH); 15 | return 0; 16 | } 17 | EOF 18 | else 19 | cat <<- EOF > $getver_c 20 | #include 21 | 22 | #include "src/version.h" 23 | 24 | int main(int argc, char *argv[]) { 25 | printf("%d\n", REDISAI_MODULE_VERSION); 26 | return 0; 27 | } 28 | EOF 29 | fi 30 | prog=$(mktemp "${TMPDIR:-/tmp}/getver.XXXXXXX") 31 | gcc -I$ROOT -o $prog $getver_c 32 | ver=`$prog` 33 | rm -f $prog $getver_c 34 | echo $ver 35 | exit 0 36 | -------------------------------------------------------------------------------- /opt/redis_valgrind.sup: -------------------------------------------------------------------------------- 1 | { 2 | ignore_unversioned_libs 3 | Memcheck:Leak 4 | ... 5 | obj:*/libtensorflow.so.* 6 | } 7 | 8 | { 9 | ignore_unversioned_libs 10 | Memcheck:Leak 11 | ... 12 | obj:*/libtensorflow_framework.so.* 13 | } 14 | 15 | { 16 | ignore_unversioned_libs 17 | Memcheck:Leak 18 | ... 19 | obj:*/libtorch.so.* 20 | } 21 | 22 | { 23 | ignore_unversioned_libs 24 | Memcheck:Overlap 25 | ... 26 | obj:*/libtorch_cpu.so* 27 | } 28 | 29 | { 30 | ignore_unversioned_libs 31 | Memcheck:Overlap 32 | ... 33 | obj:*/libonnxruntime.so* 34 | } 35 | 36 | { 37 | ignore_unversioned_libs 38 | Memcheck:Leak 39 | ... 40 | obj:*/libtorch.so* 41 | } 42 | 43 | { 44 | 45 | Memcheck:Cond 46 | fun:lzf_compress 47 | } 48 | 49 | { 50 | 51 | Memcheck:Value4 52 | fun:lzf_compress 53 | } 54 | 55 | { 56 | 57 | Memcheck:Value8 58 | fun:lzf_compress 59 | } 60 | 61 | { 62 | 63 | Memcheck:Leak 64 | fun:malloc 65 | ... 66 | fun:dlopen@@GLIBC_2.2.5 67 | ... 68 | fun:RAI_LoadBackend 69 | } 70 | 71 | { 72 | 73 | Memcheck:Cond 74 | fun:lzf_compress 75 | } 76 | { 77 | 78 | Memcheck:Cond 79 | ... 80 | fun:Py_InitializeEx 81 | ... 82 | } 83 | { 84 | 85 | Memcheck:Cond 86 | ... 87 | fun:_PyEval_EvalFrameDefault 88 | ... 89 | } 90 | { 91 | 92 | Memcheck:Leak 93 | ... 94 | fun:_imp_exec_builtin 95 | ... 96 | } 97 | { 98 | 99 | Memcheck:Cond 100 | ... 101 | fun:PySys_SetArgvEx 102 | ... 103 | } 104 | { 105 | 106 | Memcheck:Cond 107 | ... 108 | fun:_PyMethodDef_RawFastCallKeywords 109 | ... 110 | } 111 | { 112 | 113 | Memcheck:Value8 114 | fun:lzf_compress 115 | } 116 | { 117 | 118 | Memcheck:Addr4 119 | obj:*libpython2.7* 120 | } 121 | { 122 | 123 | Memcheck:Addr8 124 | obj:*libpython2.7* 125 | } 126 | { 127 | 128 | Memcheck:Value8 129 | obj:*libpython2.7* 130 | } 131 | { 132 | 133 | Memcheck:Cond 134 | obj:*libpython2.7* 135 | } 136 | { 137 | 138 | Memcheck:Leak 139 | ... 140 | obj:*libpython2.7* 141 | ... 142 | } 143 | { 144 | 145 | Memcheck:Leak 146 | ... 147 | fun:redisLibeventAttach 148 | ... 149 | } 150 | { 151 | 152 | Memcheck:Leak 153 | ... 154 | fun:compiler_visit_expr 155 | ... 156 | } 157 | { 158 | 159 | Memcheck:Leak 160 | ... 161 | fun:redisConnectNonBlock 162 | ... 163 | } 164 | { 165 | 166 | Memcheck:Leak 167 | ... 168 | fun:_redisContextConnectTcp 169 | ... 170 | } 171 | { 172 | Libuv_epoll_ctl 173 | Memcheck:Param 174 | epoll_ctl(event) 175 | fun:epoll_ctl 176 | ... 177 | } 178 | 179 | 180 | { 181 | <_dl_catch_exception> 182 | Memcheck:Addr8 183 | fun:strncmp 184 | ... 185 | fun:_dl_catch_exception 186 | ... 187 | } 188 | 189 | { 190 | 191 | Memcheck:Cond 192 | ... 193 | obj:*/libtorch_cpu.so* 194 | } 195 | -------------------------------------------------------------------------------- /opt/system-setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys 4 | import os 5 | import argparse 6 | 7 | HERE = os.path.abspath(os.path.dirname(__file__)) 8 | ROOT = os.path.abspath(os.path.join(HERE, "..")) 9 | READIES = os.path.join(ROOT, "opt/readies") 10 | sys.path.insert(0, READIES) 11 | import paella 12 | 13 | #---------------------------------------------------------------------------------------------- 14 | 15 | class RedisAISetup(paella.Setup): 16 | def __init__(self, nop=False): 17 | paella.Setup.__init__(self, nop) 18 | 19 | def common_first(self): 20 | self.install_downloaders() 21 | self.pip_install("wheel") 22 | 23 | self.install("git unzip") 24 | if self.osnick != 'centos8': 25 | self.install("coreutils") # for realpath 26 | 27 | def debian_compat(self): 28 | self.run("%s/bin/enable-utf8" % READIES) 29 | self.run("%s/bin/getgcc" % READIES) 30 | self.install("gawk libssl-dev python3-regex python3-networkx libmpich-dev libopenblas-dev") 31 | if self.platform.is_arm(): 32 | self.install("python3-dev") # python3-skimage 33 | self.install_git_lfs_on_linux() 34 | 35 | def redhat_compat(self): 36 | self.run("%s/bin/enable-utf8" % READIES) 37 | self.install("epel-release") 38 | if self.osnick == "centos8": 39 | self.run("dnf install -qy dnf-plugins-core") 40 | self.run("dnf config-manager -qy --set-enabled powertools") 41 | self.install("redhat-lsb-core") 42 | 43 | self.run("%s/bin/getgcc --modern" % READIES) 44 | 45 | if self.arch == 'x64': 46 | self.install_linux_gnu_tar() 47 | 48 | if not self.dist == "amzn": 49 | self.install("epel-release") 50 | self.install("python3-devel libaec-devel") 51 | else: 52 | self.run("amazon-linux-extras install epel", output_on_error=True) 53 | self.install("python3-devel") 54 | 55 | self.install_git_lfs_on_linux() 56 | 57 | def fedora(self): 58 | self.run("%s/bin/getepel" % READIES) 59 | self.install("python3-networkx") 60 | self.install_git_lfs_on_linux() 61 | 62 | def linux_last(self): 63 | self.install("valgrind") 64 | 65 | def macos(self): 66 | self.install_gnu_utils() 67 | self.install("git-lfs") 68 | self.install("redis") 69 | 70 | def common_last(self): 71 | self.run("%s/bin/getclang --format" % READIES) 72 | if self.platform == "arm": 73 | self.run("%s/bin/getcmake --from-repo" % READIES) 74 | else: 75 | self.run("%s/bin/getcmake" % READIES) 76 | 77 | self.pip_install("--ignore-installed PyYAML -r %s/tests/flow/tests_setup/test_requirements.txt" % ROOT) 78 | 79 | self.pip_install("awscli") 80 | self.pip_install("mkdocs mkdocs-material mkdocs-extensions") 81 | 82 | #---------------------------------------------------------------------------------------------- 83 | 84 | parser = argparse.ArgumentParser(description='Set up system for build.') 85 | parser.add_argument('-n', '--nop', action="store_true", help='no operation') 86 | args = parser.parse_args() 87 | 88 | RedisAISetup(nop=args.nop).setup() 89 | -------------------------------------------------------------------------------- /ramp-light.yml: -------------------------------------------------------------------------------- 1 | display_name: RedisAI Light 2 | author: Tensorwerk and RedisLabs 3 | email: support@redislabs.com 4 | description: Serving tensors and executing deep learning graphs 5 | homepage: https://oss.redislabs.com/redisai/ 6 | license: Redis Source Available License 2.0 (RSALv2) or the Server Side Public License v1 (SSPLv1) 7 | command_line_args: "BACKENDSPATH /var/opt/redislabs/modules/ai-light/{{NUMVER}}/deps" 8 | # command_line_args: "BACKENDSPATH /var/opt/redislabs/modules/ai/{{NUMVER}}/deps/backends" 9 | min_redis_version: "6.0.0" 10 | min_redis_pack_version: "6.0.12" 11 | capabilities: 12 | - types 13 | - hash_policy 14 | - eviction_expiry 15 | - failover_migrate 16 | - persistence_rdb 17 | - persistence_aof 18 | - clustering 19 | - backup_restore 20 | - replica_of 21 | - flash 22 | - reshard_rebalance 23 | dependencies: 24 | {{NAME_tensorflow}}: 25 | url: http://redismodules.s3.amazonaws.com/redisai/{{PATH_tensorflow}} 26 | sha256: {{SHA256_tensorflow}} 27 | {{NAME_torch}}: 28 | url: http://redismodules.s3.amazonaws.com/redisai/{{PATH_torch}} 29 | sha256: {{SHA256_torch}} 30 | {{NAME_onnxruntime}}: 31 | url: http://redismodules.s3.amazonaws.com/redisai/{{PATH_onnxruntime}} 32 | sha256: {{SHA256_onnxruntime}} 33 | {{NAME_tflite}}: 34 | url: http://redismodules.s3.amazonaws.com/redisai/{{PATH_tflite}} 35 | sha256: {{SHA256_tflite}} 36 | # {{NAME_all}}: 37 | # url: http://redismodules.s3.amazonaws.com/redisai/{{PATH_all}} 38 | # sha256: {{SHA256_all}} 39 | -------------------------------------------------------------------------------- /ramp-rce.yml: -------------------------------------------------------------------------------- 1 | display_name: RedisAI-RCE 2 | author: Tensorwerk and RedisLabs 3 | email: support@redislabs.com 4 | description: Serving tensors and executing deep learning graphs 5 | homepage: https://oss.redislabs.com/redisai/ 6 | license: Redis Source Available License 2.0 (RSALv2) or the Server Side Public License v1 (SSPLv1) 7 | command_line_args: "BACKENDSPATH /var/opt/redislabs/modules/ai-light/{{NUMVER}}/deps" 8 | # command_line_args: "BACKENDSPATH /var/opt/redislabs/modules/ai/{{NUMVER}}/deps/backends" 9 | min_redis_version: "6.0.0" 10 | min_redis_pack_version: "6.0.12" 11 | capabilities: 12 | - types 13 | - hash_policy 14 | - eviction_expiry 15 | - failover_migrate 16 | - persistence_rdb 17 | - persistence_aof 18 | - clustering 19 | - backup_restore 20 | - replica_of 21 | - flash 22 | - resharding 23 | dependencies: 24 | {{NAME_onnxruntime}}: 25 | url: http://redismodules.s3.amazonaws.com/redisai/{{PATH_onnxruntime}} 26 | sha256: {{SHA256_onnxruntime}} 27 | 28 | -------------------------------------------------------------------------------- /ramp.yml: -------------------------------------------------------------------------------- 1 | display_name: RedisAI 2 | author: Tensorwerk and RedisLabs 3 | email: support@redislabs.com 4 | description: Serving tensors and executing deep learning graphs 5 | homepage: https://oss.redislabs.com/redisai/ 6 | license: Redis Source Available License 2.0 (RSALv2) or the Server Side Public License v1 (SSPLv1) 7 | command_line_args: "BACKENDSPATH /var/opt/redislabs/modules/ai/{{NUMVER}}/deps" 8 | # command_line_args: "BACKENDSPATH /var/opt/redislabs/modules/ai/{{NUMVER}}/deps/backends" 9 | min_redis_version: "6.0.0" 10 | min_redis_pack_version: "6.2.2" 11 | capabilities: 12 | - types 13 | - hash_policy 14 | - eviction_expiry 15 | - failover_migrate 16 | - persistence_rdb 17 | - persistence_aof 18 | - clustering 19 | - backup_restore 20 | - intershard_tls 21 | - intershard_tls_pass 22 | exclude_commands: 23 | - ai.modelstore 24 | - ai.modelset 25 | - ai.modeldel 26 | - ai.scriptstore 27 | - ai.scriptset 28 | - ai.scriptdel 29 | dependencies: 30 | {{NAME_tensorflow}}: 31 | url: http://redismodules.s3.amazonaws.com/redisai/{{PATH_tensorflow}} 32 | sha256: {{SHA256_tensorflow}} 33 | {{NAME_torch}}: 34 | url: http://redismodules.s3.amazonaws.com/redisai/{{PATH_torch}} 35 | sha256: {{SHA256_torch}} 36 | {{NAME_onnxruntime}}: 37 | url: http://redismodules.s3.amazonaws.com/redisai/{{PATH_onnxruntime}} 38 | sha256: {{SHA256_onnxruntime}} 39 | {{NAME_tflite}}: 40 | url: http://redismodules.s3.amazonaws.com/redisai/{{PATH_tflite}} 41 | sha256: {{SHA256_tflite}} 42 | # {{NAME_all}}: 43 | # url: http://redismodules.s3.amazonaws.com/redisai/{{PATH_all}} 44 | # sha256: {{SHA256_all}} 45 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if (CMAKE_BUILD_TYPE STREQUAL Debug) 2 | SET(DEBUG_SRC "${CMAKE_CURRENT_SOURCE_DIR}/../opt/readies/cetara/diag/gdb.c") 3 | endif() 4 | 5 | file (GLOB_RECURSE SERIALIZATION_SRC 6 | redis_ai_objects/tensor.c 7 | redis_ai_objects/model.c 8 | redis_ai_objects/script.c 9 | backends/backends.c 10 | stats.c 11 | config.c 12 | serialization/*.c) 13 | 14 | file (GLOB BACKEND_COMMON_SRC 15 | backends/util.c 16 | redis_ai_objects/err.c 17 | util/dict.c 18 | util/dictionaries.c 19 | redis_ai_objects/tensor.c 20 | redis_ai_objects/model.c 21 | redis_ai_objects/stats.c 22 | redis_ai_objects/script.c 23 | util/string_utils.c 24 | execution/utils.c 25 | execution/execution_contexts/execution_ctx.c 26 | serialization/ai_datatypes.c) 27 | 28 | ADD_LIBRARY(redisai_obj OBJECT 29 | util/dict.c 30 | util/dictionaries.c 31 | util/queue.c 32 | util/string_utils.c 33 | redisai.c 34 | execution/command_parser.c 35 | execution/parsing/deprecated.c 36 | execution/parsing/dag_parser.c 37 | execution/parsing/tensor_commands_parsing.c 38 | execution/parsing/model_commands_parser.c 39 | execution/parsing/script_commands_parser.c 40 | execution/parsing/parse_utils.c 41 | execution/run_info.c 42 | execution/background_workers.c 43 | execution/run_queue_info.c 44 | execution/utils.c 45 | config/config.c 46 | execution/DAG/dag.c 47 | execution/DAG/dag_builder.c 48 | execution/DAG/dag_execute.c 49 | execution/DAG/dag_op.c 50 | execution/execution_contexts/execution_ctx.c 51 | execution/execution_contexts/modelRun_ctx.c 52 | execution/execution_contexts/scriptRun_ctx.c 53 | backends/backends.c 54 | backends/util.c 55 | redis_ai_objects/model.c 56 | redis_ai_objects/err.c 57 | redis_ai_objects/script.c 58 | redis_ai_objects/stats.c 59 | redis_ai_objects/tensor.c 60 | rmutil/alloc.c 61 | rmutil/sds.c 62 | rmutil/args.c 63 | redis_ai_types/model_type.c 64 | redis_ai_types/tensor_type.c 65 | redis_ai_types/script_type.c 66 | ${SERIALIZATION_SRC} 67 | ${DEBUG_SRC}) 68 | 69 | IF(BUILD_TF) 70 | ADD_LIBRARY(redisai_tensorflow_obj OBJECT 71 | backends/tensorflow.c 72 | ${BACKEND_COMMON_SRC} 73 | ) 74 | ENDIF() 75 | 76 | IF(BUILD_TFLITE) 77 | ADD_LIBRARY(redisai_tflite_obj OBJECT 78 | backends/tflite.c 79 | ${BACKEND_COMMON_SRC} 80 | ) 81 | ENDIF() 82 | 83 | IF(BUILD_TORCH) 84 | ADD_LIBRARY(redisai_torch_obj OBJECT 85 | backends/torch.c 86 | ${BACKEND_COMMON_SRC} 87 | ) 88 | ENDIF() 89 | 90 | IF(BUILD_ORT) 91 | ADD_LIBRARY(redisai_onnxruntime_obj OBJECT 92 | backends/onnxruntime.c 93 | backends/onnx_timeout.c 94 | ${BACKEND_COMMON_SRC} 95 | ) 96 | ENDIF() 97 | 98 | INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) 99 | INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/rmutil) 100 | INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/util) 101 | -------------------------------------------------------------------------------- /src/backends/backends.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | /** 8 | * backends.h 9 | * 10 | * Contains the structure and method signatures required to register a new 11 | * backend to be loaded by the module. 12 | * 13 | */ 14 | 15 | #pragma once 16 | 17 | #include "config/config.h" 18 | #include "redis_ai_objects/err.h" 19 | #include "redis_ai_objects/tensor.h" 20 | #include "redis_ai_objects/model.h" 21 | #include "redis_ai_objects/script.h" 22 | #include "execution/execution_contexts/execution_ctx.h" 23 | 24 | /* 25 | * To register a new backend to be loaded by the module, the backend needs to 26 | * implement the following: 27 | * 28 | * * ** model_create_with_nodes **: A callback function pointer that creates a 29 | * model given the RAI_ModelOpts and input and output nodes. 30 | * 31 | * * ** model_create **: A callback function pointer that creates a model given 32 | * the RAI_ModelOpts. 33 | * 34 | * * ** model_run **: A callback function pointer that runs a model given the 35 | * RAI_Model pointer and an array of RAI_ExecutionCtx pointers. 36 | * 37 | * * ** model_serialize **: A callback function pointer that serializes a model 38 | * given the RAI_Model pointer. 39 | * 40 | * * ** script_create **: A callback function pointer that creates a script. 41 | * 42 | * * ** script_free **: A callback function pointer that frees a script given 43 | * the RAI_Script pointer. 44 | * 45 | * * ** script_run **: A callback function pointer that runs a model given the 46 | * RAI_Script pointer and . 47 | */ 48 | typedef struct RAI_LoadedBackend { 49 | // ** model_create_with_nodes **: A callback function pointer that creates a 50 | // model given the RAI_ModelOpts and input and output nodes 51 | RAI_Model *(*model_create_with_nodes)(RAI_Backend, const char *, RAI_ModelOpts, size_t, 52 | const char **, size_t, const char **, const char *, 53 | size_t, RAI_Error *); 54 | 55 | // ** model_create **: A callback function pointer that creates a model given 56 | // the RAI_ModelOpts 57 | RAI_Model *(*model_create)(RAI_Backend, const char *, RAI_ModelOpts, const char *, size_t, 58 | RAI_Error *); 59 | 60 | // ** model_free **: A callback function pointer that frees a model given the 61 | // RAI_Model pointer 62 | void (*model_free)(RAI_Model *, RAI_Error *); 63 | 64 | // ** model_run **: A callback function pointer that runs a model given the 65 | // RAI_Model pointer and an array of RAI_ExecutionCtx pointers 66 | int (*model_run)(RAI_Model *, RAI_ExecutionCtx **, RAI_Error *); 67 | 68 | // ** model_serialize **: A callback function pointer that serializes a model 69 | // given the RAI_Model pointer 70 | int (*model_serialize)(RAI_Model *, char **, size_t *, RAI_Error *); 71 | 72 | // ** script_create **: A callback function pointer that creates a script 73 | RAI_Script *(*script_create)(const char *, const char *, const char **, size_t, RAI_Error *); 74 | 75 | // ** script_free **: A callback function pointer that frees a script given 76 | // the RAI_Script pointer 77 | void (*script_free)(RAI_Script *, RAI_Error *); 78 | 79 | // ** script_run **: A callback function pointer that runs a model given the 80 | // RAI_ScriptRunCtx pointer 81 | int (*script_run)(RAI_Script *, const char *function, RAI_ExecutionCtx *, RAI_Error *); 82 | 83 | // Returns the backend version. 84 | const char *(*get_version)(void); 85 | 86 | // Returns the backend's memory usage for INFO report 87 | unsigned long long (*get_memory_info)(void); 88 | 89 | // Returns the number of times that Redis accessed backend allocator. 90 | unsigned long long (*get_memory_access_num)(void); 91 | 92 | // A callback for to use whenever a new device is introduced. 93 | int (*add_new_device_cb)(const char *); 94 | 95 | // Kill run session callback (for stopping long runs). 96 | void (*stop_long_running_sessions_cb)(RedisModuleCtx *, RedisModuleEvent, uint64_t, void *); 97 | 98 | // Get the number of maximum run sessions that can run. 99 | size_t (*get_max_run_sessions)(void); 100 | } RAI_LoadedBackend; 101 | 102 | typedef struct RAI_LoadedBackends { 103 | RAI_LoadedBackend tf; 104 | RAI_LoadedBackend tflite; 105 | RAI_LoadedBackend torch; 106 | RAI_LoadedBackend onnx; 107 | } RAI_LoadedBackends; 108 | 109 | RAI_LoadedBackends RAI_backends; 110 | 111 | int RAI_LoadBackend(RedisModuleCtx *ctx, int backend, const char *path); 112 | 113 | int RAI_LoadDefaultBackend(RedisModuleCtx *ctx, int backend); 114 | 115 | /** 116 | * @brief Returns the backend name as string. 117 | */ 118 | const char *RAI_GetBackendName(RAI_Backend backend); 119 | 120 | /** 121 | * @brief Set the default backends path (/backends) in backends_path place holder. 122 | */ 123 | void RAI_SetBackendsDefaultPath(char **backends_path); 124 | -------------------------------------------------------------------------------- /src/backends/backends_api.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include "redismodule.h" 11 | 12 | #ifdef BACKENDS_API_EXTERN 13 | #define BACKENDS_API extern 14 | #endif 15 | 16 | #ifndef BACKENDS_API 17 | #define BACKENDS_API 18 | #endif 19 | 20 | typedef struct RAI_Tensor RAI_Tensor; 21 | typedef struct RAI_Model RAI_Model; 22 | typedef struct RAI_ModelRunCtx RAI_ModelRunCtx; 23 | typedef struct RAI_Error RAI_Error; 24 | 25 | /** 26 | * @return The internal id of RedisAI current working thread. 27 | * id range is {0, ..., -1}. If this is called from a non 28 | * RedisAI BG thread, return -1. 29 | */ 30 | BACKENDS_API long (*RedisAI_GetThreadId)(void); 31 | 32 | /** 33 | * @return The number of working threads in RedisAI. This number should be 34 | * equal to the number of threads per queue (load time config) * number of devices 35 | * registered in RedisAI (a new device is registered if a model is set to run on 36 | * this device in AI.MODELSTORE command. 37 | */ 38 | BACKENDS_API uintptr_t (*RedisAI_GetThreadsCount)(void); 39 | 40 | /** 41 | * @return The number of working threads per device queue (load time config). 42 | */ 43 | BACKENDS_API long long (*RedisAI_GetNumThreadsPerQueue)(void); 44 | 45 | /** 46 | * @return The maximum number of milliseconds that a model run session should run 47 | * before it is terminated forcefully (load time config). 48 | * Currently supported only for onnxruntime backend. 49 | */ 50 | BACKENDS_API long long (*RedisAI_GetModelExecutionTimeout)(void); 51 | 52 | /** 53 | * @return The maximum number of memory (in MB) that a backend can consume 54 | * for creating and running inference sessions. When memory limit is exceeded, operation 55 | * is not permitted and an error is returned. 56 | * Currently supported only for onnxruntime backend. 57 | */ 58 | BACKENDS_API long long (*RedisAI_GetMemoryLimit)(void); 59 | 60 | /** 61 | * The following functions are part of RedisAI low level API (the full low level 62 | * API is defined in redisai.h). For every function below named "RedisAI_X", its 63 | * implementation can be found under the name "RAI_X" in RedisAI header files. 64 | */ 65 | 66 | BACKENDS_API int (*RedisAI_InitError)(RAI_Error **err); 67 | BACKENDS_API void (*RedisAI_FreeError)(RAI_Error *err); 68 | BACKENDS_API const char *(*RedisAI_GetError)(RAI_Error *err); 69 | 70 | BACKENDS_API RAI_Tensor *(*RedisAI_TensorCreateFromDLTensor)(DLManagedTensor *dl_tensor); 71 | BACKENDS_API DLTensor *(*RedisAI_TensorGetDLTensor)(RAI_Tensor *tensor); 72 | BACKENDS_API RAI_Tensor *(*RedisAI_TensorGetShallowCopy)(RAI_Tensor *t); 73 | BACKENDS_API void (*RedisAI_TensorFree)(RAI_Tensor *tensor); 74 | 75 | BACKENDS_API RAI_ModelRunCtx *(*RedisAI_ModelRunCtxCreate)(RAI_Model *model); 76 | BACKENDS_API int (*RedisAI_GetModelFromKeyspace)(RedisModuleCtx *ctx, RedisModuleString *keyName, 77 | RAI_Model **model, int mode, RAI_Error *err); 78 | BACKENDS_API int (*RedisAI_ModelRunCtxAddInput)(RAI_ModelRunCtx *mctx, const char *inputName, 79 | RAI_Tensor *inputTensor); 80 | BACKENDS_API int (*RedisAI_ModelRunCtxAddOutput)(RAI_ModelRunCtx *mctx, const char *outputName); 81 | BACKENDS_API size_t (*RedisAI_ModelRunCtxNumOutputs)(RAI_ModelRunCtx *mctx); 82 | BACKENDS_API RAI_Tensor *(*RedisAI_ModelRunCtxOutputTensor)(RAI_ModelRunCtx *mctx, size_t index); 83 | BACKENDS_API void (*RedisAI_ModelRunCtxFree)(RAI_ModelRunCtx *mctx); 84 | BACKENDS_API int (*RedisAI_ModelRun)(RAI_ModelRunCtx **mctx, long long n, RAI_Error *err); 85 | -------------------------------------------------------------------------------- /src/backends/libtflite_c/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(tflite_c STATIC tflite_c.cpp) 2 | message(${TFLITE_LIBRARIES}) 3 | target_link_libraries(tflite_c "${TFLITE_LIBRARIES}") 4 | set_property(TARGET tflite_c PROPERTY CXX_STANDARD 11) 5 | -------------------------------------------------------------------------------- /src/backends/libtflite_c/tflite_c.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "dlpack/dlpack.h" 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | // void tfliteBasicTest(); 16 | 17 | void *tfliteLoadModel(const char *model, size_t modellen, DLDeviceType device, int64_t device_id, 18 | char **error); 19 | 20 | void tfliteRunModel(void *ctx, long nInputs, DLManagedTensor **inputs, long nOutputs, 21 | DLManagedTensor **outputs, char **error); 22 | 23 | void tfliteSerializeModel(void *ctx, char **buffer, size_t *len, char **error); 24 | 25 | void tfliteDeallocContext(void *ctx); 26 | 27 | size_t tfliteModelNumInputs(void *ctx, char **error); 28 | 29 | const char *tfliteModelInputNameAtIndex(void *modelCtx, size_t index, char **error); 30 | 31 | size_t tfliteModelNumOutputs(void *ctx, char **error); 32 | 33 | const char *tfliteModelOutputNameAtIndex(void *modelCtx, size_t index, char **error); 34 | 35 | #ifdef __cplusplus 36 | } 37 | #endif 38 | -------------------------------------------------------------------------------- /src/backends/libtorch_c/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(torch_c STATIC torch_c.cpp torch_extensions/torch_redis.cpp) 2 | target_link_libraries(torch_c "${TORCH_LIBRARIES}") 3 | set_property(TARGET torch_c PROPERTY CXX_STANDARD 14) 4 | -------------------------------------------------------------------------------- /src/backends/libtorch_c/torch_extensions/torch_redis.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #include "torch/jit.h" 8 | #include "torch/script.h" 9 | #include "torch/csrc/jit/frontend/resolver.h" 10 | 11 | namespace torch { 12 | namespace jit { 13 | namespace script { 14 | struct RedisResolver : public Resolver { 15 | 16 | std::shared_ptr resolveValue(const std::string &name, GraphFunction &m, 17 | const SourceRange &loc) override { 18 | if (strcasecmp(name.c_str(), "torch") == 0) { 19 | return std::make_shared("aten"); 20 | } else if (strcasecmp(name.c_str(), "redis") == 0) { 21 | return std::make_shared("redis"); 22 | } else if (strcasecmp(name.c_str(), "redisAI") == 0) { 23 | return std::make_shared("redisAI"); 24 | } 25 | return nullptr; 26 | } 27 | 28 | TypePtr resolveType(const std::string &name, const SourceRange &loc) override { 29 | return nullptr; 30 | } 31 | }; 32 | inline std::shared_ptr redisResolver() { return std::make_shared(); } 33 | } // namespace script 34 | } // namespace jit 35 | } // namespace torch 36 | 37 | torch::IValue redisExecute(const std::string &fn_name, const std::vector &args); 38 | torch::List asList(const torch::IValue &v); 39 | std::vector modelExecute(const std::string &model_key, 40 | const std::vector &inputs, 41 | int64_t num_outputs); 42 | 43 | // Register Redis and RedisAI costume ops in torch 44 | void registerRedisOps(void); 45 | -------------------------------------------------------------------------------- /src/backends/onnx_allocator/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(onnx_allocator STATIC onnx_allocator.cpp) 2 | target_link_libraries(onnx_allocator "${ONNX_LIBRARIES}") 3 | set_property(TARGET onnx_allocator PROPERTY CXX_STANDARD 14) -------------------------------------------------------------------------------- /src/backends/onnx_allocator/onnx_allocator.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "onnxruntime_c_api.h" 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | OrtAllocator *CreateCustomAllocator(unsigned long long max_memory); 16 | 17 | unsigned long long RAI_GetMemoryInfoORT(); 18 | 19 | unsigned long long RAI_GetMemoryAccessORT(); 20 | 21 | #ifdef __cplusplus 22 | } 23 | #endif 24 | -------------------------------------------------------------------------------- /src/backends/onnx_timeout.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "backends/onnxruntime.h" 10 | #include "onnxruntime_c_api.h" 11 | 12 | /** 13 | * The possible states for every run session entry in the array (entry per BG thread): 14 | * Every is initialized as AVAILABLE, which means that it is ready to get a new run session. 15 | * BG thread can perform a transition from AVAILABLE to ACTIVE upon starting a new run session. 16 | * In the cron callback, Redis main thread can perform a transition from ACTIVE to 17 | * INVALID if a timeout has reached, set the run session as terminated, and then make 18 | * another transition to TERMINATED. 19 | * At the end of a run session, the state is ACTIVE/TERMINATED, and then the BG thread 20 | * reset the entry and make a transition back to AVAILABLE. 21 | * Transition are done atomically to ensure right synchronization (BG thread cannot reset 22 | * run session while main thread is setting it as terminated). 23 | */ 24 | typedef enum { 25 | RUN_SESSION_AVAILABLE, 26 | RUN_SESSION_ACTIVE, 27 | RUN_SESSION_TERMINATED, 28 | RUN_SESSION_INVALID 29 | } RunSessionState; 30 | 31 | typedef struct OnnxRunSessionCtx { 32 | long long queuingTime; 33 | OrtRunOptions *runOptions; 34 | RunSessionState *runState; 35 | } OnnxRunSessionCtx; 36 | 37 | // This is a global array of OnnxRunSessionCtx. Contains an entry for every thread 38 | // (on every device) that onnx models may run on. 39 | typedef struct OnnxGlobalRunSessions { 40 | OnnxRunSessionCtx **OnnxRunSessions; 41 | pthread_rwlock_t rwlock; 42 | } OnnxGlobalRunSessions; 43 | 44 | OnnxGlobalRunSessions *onnx_global_run_sessions; 45 | 46 | /** 47 | * @brief This is called whenever Onnx backend is loaded. It creates the global 48 | * OnnxGlobalRunSessions structure with entry-per-thread (for CPU threads at first), 49 | * so that every thread will have a designated entry to update with the onnx session 50 | * that it's going to run. 51 | */ 52 | int RAI_InitGlobalRunSessionsORT(void); 53 | 54 | /** 55 | * @return The length of the global array (should be the number of current working threads) 56 | */ 57 | size_t RAI_GetGlobalRunSessionsLenORT(void); 58 | 59 | /** 60 | * @brief This is called whenever RedisAI gets a request to store a model that run 61 | * on a new device, and creates some more working thread, as configured in 62 | * ThreadPerQueue. Thus, the global array of onnx sessions that has an 63 | * entry-per-thread is extended accordingly. 64 | */ 65 | int RAI_AddNewDeviceORT(const char *device_str); 66 | 67 | /** 68 | * @brief A callback that is registered to RedisCron event, that is, it is called 69 | * periodically and go over all the (possibly running) onnx sessions, and kill 70 | * those that exceeds the timeout. 71 | */ 72 | void RAI_EnforceTimeoutORT(RedisModuleCtx *ctx, RedisModuleEvent eid, uint64_t subevent, 73 | void *data); 74 | 75 | /** 76 | * @brief Set a new OrtRunOptions in the global structure, to allow us to 77 | * "terminate" the run session from the cron callback. 78 | * @param new_run_options - The newly created OrtRunOptions to store. 79 | * @param run_session_index - placeholder for the index of the running thread 80 | * in the global array, to have a quick access later to clean this entry. 81 | */ 82 | void RAI_ActivateRunSessionCtxORT(OrtRunOptions *new_run_options, long *run_session_index); 83 | 84 | /** 85 | * @brief Release the OrtRunOptions of a session that finished its run and 86 | * reset the corresponding entry in the global structure. 87 | * @param run_session_index - The entry index where OrtRunOptions was stored. 88 | */ 89 | void RAI_ResetRunSessionCtxORT(long run_session_index); 90 | -------------------------------------------------------------------------------- /src/backends/onnxruntime.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "config/config.h" 10 | #include "redis_ai_objects/err.h" 11 | #include "redis_ai_objects/model.h" 12 | #include "execution/execution_contexts/execution_ctx.h" 13 | 14 | int RAI_InitBackendORT(int (*get_api_fn)(const char *, void **)); 15 | 16 | RAI_Model *RAI_ModelCreateORT(RAI_Backend backend, const char *devicestr, RAI_ModelOpts opts, 17 | const char *modeldef, size_t modellen, RAI_Error *err); 18 | 19 | void RAI_ModelFreeORT(RAI_Model *model, RAI_Error *error); 20 | 21 | int RAI_ModelRunORT(RAI_Model *model, RAI_ExecutionCtx **ectxs, RAI_Error *error); 22 | 23 | int RAI_ModelSerializeORT(RAI_Model *model, char **buffer, size_t *len, RAI_Error *error); 24 | 25 | const char *RAI_GetBackendVersionORT(void); 26 | -------------------------------------------------------------------------------- /src/backends/tensorflow.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "config/config.h" 10 | #include "redis_ai_objects/err.h" 11 | #include "redis_ai_objects/model.h" 12 | #include "execution/execution_contexts/execution_ctx.h" 13 | 14 | int RAI_InitBackendTF(int (*get_api_fn)(const char *, void *)); 15 | 16 | RAI_Model *RAI_ModelCreateTF(RAI_Backend backend, const char *devicestr, RAI_ModelOpts opts, 17 | size_t ninputs, const char **inputs, size_t noutputs, 18 | const char **outputs, const char *modeldef, size_t modellen, 19 | RAI_Error *error); 20 | 21 | void RAI_ModelFreeTF(RAI_Model *model, RAI_Error *error); 22 | 23 | int RAI_ModelRunTF(RAI_Model *model, RAI_ExecutionCtx **ectxs, RAI_Error *error); 24 | 25 | int RAI_ModelSerializeTF(RAI_Model *model, char **buffer, size_t *len, RAI_Error *error); 26 | 27 | const char *RAI_GetBackendVersionTF(void); 28 | -------------------------------------------------------------------------------- /src/backends/tflite.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "config/config.h" 10 | #include "redis_ai_objects/err.h" 11 | #include "redis_ai_objects/model.h" 12 | #include "execution/execution_contexts/execution_ctx.h" 13 | 14 | int RAI_InitBackendTFLite(int (*get_api_fn)(const char *, void *)); 15 | 16 | RAI_Model *RAI_ModelCreateTFLite(RAI_Backend backend, const char *devicestr, RAI_ModelOpts opts, 17 | const char *modeldef, size_t modellen, RAI_Error *err); 18 | 19 | void RAI_ModelFreeTFLite(RAI_Model *model, RAI_Error *error); 20 | 21 | int RAI_ModelRunTFLite(RAI_Model *model, RAI_ExecutionCtx **ectxs, RAI_Error *error); 22 | 23 | int RAI_ModelSerializeTFLite(RAI_Model *model, char **buffer, size_t *len, RAI_Error *error); 24 | 25 | const char *RAI_GetBackendVersionTFLite(void); 26 | -------------------------------------------------------------------------------- /src/backends/torch.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "config/config.h" 10 | #include "redis_ai_objects/err.h" 11 | #include "redis_ai_objects/model.h" 12 | #include "redis_ai_objects/script.h" 13 | #include "execution/execution_contexts/execution_ctx.h" 14 | 15 | int RAI_InitBackendTorch(int (*get_api_fn)(const char *, void *)); 16 | 17 | RAI_Model *RAI_ModelCreateTorch(RAI_Backend backend, const char *devicestr, RAI_ModelOpts opts, 18 | const char *modeldef, size_t modellen, RAI_Error *err); 19 | 20 | void RAI_ModelFreeTorch(RAI_Model *model, RAI_Error *error); 21 | 22 | int RAI_ModelRunTorch(RAI_Model *model, RAI_ExecutionCtx **ectxs, RAI_Error *error); 23 | 24 | int RAI_ModelSerializeTorch(RAI_Model *model, char **buffer, size_t *len, RAI_Error *error); 25 | 26 | RAI_Script *RAI_ScriptCreateTorch(const char *devicestr, const char *scriptdef, 27 | const char **entry_points, size_t n_entry_points, 28 | RAI_Error *error); 29 | 30 | void RAI_ScriptFreeTorch(RAI_Script *script, RAI_Error *error); 31 | 32 | int RAI_ScriptRunTorch(RAI_Script *script, const char *function, RAI_ExecutionCtx *ectx, 33 | RAI_Error *error); 34 | 35 | const char *RAI_GetBackendVersionTorch(void); 36 | -------------------------------------------------------------------------------- /src/backends/util.c: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #include 8 | #include 9 | #include "backends/util.h" 10 | 11 | int parseDeviceStr(const char *device_str, RAI_Device *device, int64_t *device_id) { 12 | if (strncasecmp(device_str, "CPU", 3) == 0) { 13 | *device = RAI_DEVICE_CPU; 14 | *device_id = -1; 15 | } else if (strcasecmp(device_str, "GPU") == 0) { 16 | *device = RAI_DEVICE_GPU; 17 | *device_id = -1; 18 | } else if (strncasecmp(device_str, "GPU:", 4) == 0) { 19 | *device = RAI_DEVICE_GPU; 20 | // Convert the id string into a number, returns zero if no valid conversion could be 21 | // preformed, and sets errno in case of overflow. 22 | long long id = strtoll(device_str + 4, NULL, 0); 23 | if (errno == ERANGE) 24 | return 0; 25 | *device_id = id; 26 | } else { 27 | return 0; 28 | } 29 | return 1; 30 | } 31 | -------------------------------------------------------------------------------- /src/backends/util.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include "config/config.h" 14 | 15 | int parseDeviceStr(const char *device_str, RAI_Device *device, int64_t *device_id); 16 | -------------------------------------------------------------------------------- /src/config/gdb_config.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | *Copyright Redis Ltd. 2018 - present 4 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 5 | *the Server Side Public License v1 (SSPLv1). 6 | */ 7 | 8 | #if defined(DEBUG) || defined(_DEBUG) 9 | #include "readies/cetara/diag/gdb.h" 10 | #endif 11 | -------------------------------------------------------------------------------- /src/execution/DAG/dag_builder.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "redisai.h" 10 | 11 | /** 12 | * @brief Create a new empty DAG runInfo object. 13 | */ 14 | RAI_DAGRunCtx *RAI_DAGRunCtxCreate(void); 15 | 16 | /** 17 | * @brief Create a new MODELRUN op for a DAG. 18 | * @param model The model to run. 19 | */ 20 | RAI_DAGRunOp *RAI_DAGCreateModelRunOp(RAI_Model *model); 21 | 22 | /** 23 | * @brief Create a new SCRIPTRUN op for a DAG. 24 | * @param script The script to run. 25 | * @param func_name The specific function to run in the given script. 26 | */ 27 | RAI_DAGRunOp *RAI_DAGCreateScriptRunOp(RAI_Script *script, const char *func_name); 28 | 29 | /** 30 | * @brief Add an input key to a DAG run op (before inserting it to the DAG). 31 | * @param DAGop The DAG run op (MODELRUN / SCRIPTRUN). 32 | * @param input The tensor input name (this name should appear in a previous op of the DAG). 33 | */ 34 | int RAI_DAGRunOpAddInput(RAI_DAGRunOp *DAGOp, const char *input); 35 | 36 | /** 37 | * @brief Add an output key to a DAG run op (before inserting it to the DAG). 38 | * @param DAGop The DAG run op (MODELRUN / SCRIPTRUN). 39 | * @param output The tensor output name (this name may appear in one of the following ops of the 40 | * DAG). 41 | */ 42 | int RAI_DAGRunOpAddOutput(RAI_DAGRunOp *DAGOp, const char *output); 43 | 44 | /** 45 | * @brief Add a run op (MODELRUN/SCRIPTRUN) to a DAG. 46 | * @param runInfo The DAG to insert the op to. 47 | * @param DAGop The DAG run op (MODELRUN / SCRIPTRUN). 48 | * @param err Error is returned in case of a MODELRUN op if the number of inputs and outputs 49 | * given to the op does not match to the number of inputs and outputs in the model definition. 50 | */ 51 | int RAI_DAGAddRunOp(RAI_DAGRunCtx *run_info, RAI_DAGRunOp *DAGop, RAI_Error *err); 52 | 53 | /** 54 | * @brief Load a given tensor to the DAG local context. 55 | * @param runInfo The DAG to load the tensor into. 56 | * @param tname The tensor key. 57 | * @param tensor The tensor to load to the DAG (we load a shallow copy). 58 | */ 59 | int RAI_DAGLoadTensor(RAI_DAGRunCtx *run_info, const char *t_name, RAI_Tensor *tensor); 60 | 61 | /** 62 | * @brief Append a TENSORSET op to a DAG (can use to load an intermediate tensors) 63 | * @param runInfo The DAG to append this op into. 64 | * @param tensor The tensor to set. 65 | */ 66 | int RAI_DAGAddTensorSet(RAI_DAGRunCtx *run_info, const char *t_name, RAI_Tensor *tensor); 67 | 68 | /** 69 | * @brief Append a TENSORGET op to a DAG (can use to output intermediate and final tensors) 70 | * @param runInfo The DAG to append this op into. 71 | * @param tensor The tensor to set. 72 | */ 73 | int RAI_DAGAddTensorGet(RAI_DAGRunCtx *run_info, const char *t_name); 74 | 75 | /** 76 | * @brief Add ops to a DAG from string (according to the command syntax). In case of a valid 77 | * string, the ops are added to the DAG run info, and otherwise all the ops are discarded. 78 | * @param runInfo The DAG to insert the ops into. 79 | * @param dag The string representing the DAG ops to add. 80 | * @param err Error is returned in case of a MODELRUN op if the number of inputs and outputs 81 | * given to the op does not match to the number of inputs and outputs in the model definition. 82 | */ 83 | int RAI_DAGAddOpsFromString(RAI_DAGRunCtx *run_info, const char *dag, RAI_Error *err); 84 | 85 | /** 86 | * @brief Returns the number of ops in a DAG. 87 | */ 88 | size_t RAI_DAGNumOps(RAI_DAGRunCtx *run_info); 89 | 90 | /** 91 | * @brief Free DAG's runInfo and all its internal ops. 92 | */ 93 | void RAI_DAGFree(RAI_DAGRunCtx *run_info); 94 | 95 | /** 96 | * @brief Free a specific DAG run op (MODELRUN/SCRIPTRUN). 97 | */ 98 | void RAI_DAGRunOpFree(RAI_DAGRunOp *dagOp); 99 | -------------------------------------------------------------------------------- /src/execution/DAG/dag_execute.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "redismodule.h" 10 | #include "execution/run_info.h" 11 | 12 | /** 13 | @brief We are given a DAG runInfo of a sequence of operations, each with its own 14 | input and output keys. The names of the keys will be used to look whether the 15 | inputs to a DAG operation have all been realized by previous operations (or if 16 | they are available as part of LOADed keys from keyspace). 17 | This strategy is fine if keys are not aliased, that is, if a command's output 18 | overwrites the key of a previous command. This would trick DAG operations into 19 | thinking that their input is ready when it's not. 20 | To overcome this, we map the input and output tensors for every operation to indices, 21 | in the following way. For every input of an operation having the key "x", we map the index 22 | for which "x" was last mapped to when, it was an output of a previous operation. 23 | For every output of an operation "y", we map the next available index in the array. 24 | Every entry in the DAG array contains NULL (except for tensors that where loaded 25 | before the DAG run starts). 26 | @param rinfo The DAG runInfo. 27 | @param tensorsNamesToInd A dict mapping every key name of a tensor that appeared 28 | in DAG operation, to the maximal index of the DAG shared array for which they were mapped to. 29 | @returns REDISMODULE_ERR if there exists an operation for which one of the input 30 | tensors didn't appear as an output of a previous operation, REDISMODULE_OK otherwise 31 | */ 32 | int MapTensorsKeysToIndices(RedisAI_RunInfo *rinfo, AI_dict *tensorsNamesToInd); 33 | 34 | /** 35 | * @brief Validates that tensors key names to persist appeared in the DAG operations. 36 | * @param rinfo The DAG runInfo. 37 | * @param tensorsNamesToInd A dict mapping every key name of a tensor that appeared 38 | * in DAG operation, to the maximal index of the DAG shared array for which they were mapped to. 39 | * @param persistTensorsNames A hash table the contains the names of the tensors 40 | * to persist when the DAG run is finished. 41 | * @return REDISMODULE_ERR if there exists a tensor key to persist that didn't 42 | * appear in DAG operation, REDISMODULE_OK otherwise 43 | */ 44 | int ValidatePersistKeys(RedisAI_RunInfo *rinfo, AI_dict *tensorsNamesToInd, 45 | AI_dict *persistTensorsNames); 46 | 47 | /** 48 | * @brief Run asynchronously a DAG. This will validate that the sequence of DAG ops 49 | * is valid and generate a unique key to the tensor that flow in the DAG (mangleTensorsNames) 50 | * Then, DAG is sent to the devices' run queues and will be execute by a workung thread. 51 | * @param DAGAsyncFinish This is a callback that will be called after the whole DAG finish its run. 52 | * @param private_data This is an input to the DAGAsyncFinish callback. Can be used to save the 53 | * results and errors 54 | * @param err Error is returned in case that the validation failed, and the DAG wasn't inserted to 55 | * the queues. 56 | */ 57 | int RAI_DAGRun(RAI_DAGRunCtx *run_info, RAI_OnFinishCB DAGAsyncFinish, void *private_data, 58 | RAI_Error *err); 59 | 60 | /** 61 | * @brief This can be called in the finish CB, returns the number of outputs (TENSORGET ops). 62 | * @param finish_ctx This represents the DAG runInfo at the end of the run. 63 | */ 64 | size_t RAI_DAGNumOutputs(RAI_OnFinishCtx *finish_ctx); 65 | 66 | /** 67 | * @brief This can be called in the finish CB, returns a specific output tensor (result of a 68 | * TENSORGET op). 69 | * @param finish_ctx This represents the DAG runInfo at the end of the run. 70 | * @param index The index of the TENSORGET op in the DAG. 71 | * @retval returns the tensor that the i'th TENSORGET op outputs. 72 | */ 73 | const RAI_Tensor *RAI_DAGOutputTensor(RAI_OnFinishCtx *finish_ctx, size_t index); 74 | 75 | /** 76 | * @brief Returns true if (at least) one of the DAG ops encountered an error. 77 | */ 78 | bool RAI_DAGRunError(RAI_OnFinishCtx *finish_ctx); 79 | 80 | /** 81 | * @brief This can be called in the finish CB, to get DAG error details. 82 | * @param finish_ctx This represents the DAG runInfo at the end of the run. 83 | * @retval returns an object that represents the DAG status, from which a user can 84 | * obtain the error code (error code is "OK" if no error has occurred) and error details. 85 | */ 86 | const RAI_Error *RAI_DAGGetError(RAI_OnFinishCtx *finish_ctx); 87 | -------------------------------------------------------------------------------- /src/execution/DAG/dag_op.c: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #include "dag_op.h" 8 | #include "util/arr.h" 9 | #include "execution/execution_contexts/modelRun_ctx.h" 10 | #include "execution/execution_contexts/scriptRun_ctx.h" 11 | /** 12 | * Allocate the memory and initialise the RAI_DagOp. 13 | * @param result Output parameter to capture allocated RAI_DagOp. 14 | * @return REDISMODULE_OK on success, or REDISMODULE_ERR if the allocation 15 | * failed. 16 | */ 17 | int RAI_InitDagOp(RAI_DagOp **result) { 18 | RAI_DagOp *dagOp; 19 | dagOp = (RAI_DagOp *)RedisModule_Calloc(1, sizeof(RAI_DagOp)); 20 | 21 | dagOp->commandType = REDISAI_DAG_CMD_NONE; 22 | dagOp->inkeys = (RedisModuleString **)array_new(RedisModuleString *, 1); 23 | dagOp->outkeys = (RedisModuleString **)array_new(RedisModuleString *, 1); 24 | dagOp->inkeys_indices = array_new(size_t, 1); 25 | dagOp->outkeys_indices = array_new(size_t, 1); 26 | dagOp->outTensor = NULL; 27 | dagOp->ectx = NULL; 28 | dagOp->devicestr = NULL; 29 | dagOp->duration_us = 0; 30 | dagOp->result = -1; 31 | RAI_InitError(&dagOp->err); 32 | dagOp->argv = NULL; 33 | dagOp->argc = 0; 34 | 35 | *result = dagOp; 36 | return REDISMODULE_OK; 37 | } 38 | 39 | void RAI_FreeDagOp(RAI_DagOp *dagOp) { 40 | 41 | RAI_FreeError(dagOp->err); 42 | 43 | if (dagOp->outTensor) 44 | RAI_TensorFree(dagOp->outTensor); 45 | 46 | if (dagOp->ectx) { 47 | dagOp->ectx->freeFn(dagOp->ectx); 48 | } 49 | 50 | if (dagOp->inkeys) { 51 | for (size_t i = 0; i < array_len(dagOp->inkeys); i++) { 52 | RedisModule_FreeString(NULL, dagOp->inkeys[i]); 53 | } 54 | array_free(dagOp->inkeys); 55 | } 56 | array_free(dagOp->inkeys_indices); 57 | 58 | if (dagOp->outkeys) { 59 | for (size_t i = 0; i < array_len(dagOp->outkeys); i++) { 60 | RedisModule_FreeString(NULL, dagOp->outkeys[i]); 61 | } 62 | array_free(dagOp->outkeys); 63 | } 64 | array_free(dagOp->outkeys_indices); 65 | RedisModule_Free(dagOp); 66 | } 67 | -------------------------------------------------------------------------------- /src/execution/DAG/dag_op.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | #include "redismodule.h" 9 | #include "redis_ai_objects/err.h" 10 | #include "redis_ai_objects/script.h" 11 | #include "redis_ai_objects/model_struct.h" 12 | #include "execution/execution_contexts/execution_ctx.h" 13 | 14 | typedef enum DAGCommand { 15 | REDISAI_DAG_CMD_NONE = 0, 16 | REDISAI_DAG_CMD_TENSORSET, 17 | REDISAI_DAG_CMD_TENSORGET, 18 | REDISAI_DAG_CMD_MODELRUN, 19 | REDISAI_DAG_CMD_SCRIPTRUN 20 | } DAGCommand; 21 | 22 | #define VALIDATE_DAG_COMMAND(cmd) \ 23 | RedisModule_Assert(cmd >= REDISAI_DAG_CMD_TENSORSET && cmd <= REDISAI_DAG_CMD_SCRIPTRUN); 24 | 25 | typedef struct RAI_DagOp { 26 | DAGCommand commandType; 27 | RedisModuleString **inkeys; 28 | RedisModuleString **outkeys; 29 | size_t *inkeys_indices; 30 | size_t *outkeys_indices; 31 | RAI_Tensor *outTensor; // The tensor to upload in TENSORSET op. 32 | RAI_ExecutionCtx *ectx; 33 | uint fmt; // This is relevant for TENSORGET op. 34 | char *devicestr; 35 | int result; // REDISMODULE_OK or REDISMODULE_ERR 36 | long long duration_us; 37 | RAI_Error *err; 38 | RedisModuleString **argv; 39 | int argc; 40 | } RAI_DagOp; 41 | 42 | /** 43 | * Allocate the memory and initialise the RAI_DagOp. 44 | * @param result Output parameter to capture allocated RAI_DagOp. 45 | * @return REDISMODULE_OK on success, or REDISMODULE_ERR if the allocation 46 | * failed. 47 | */ 48 | int RAI_InitDagOp(RAI_DagOp **result); 49 | 50 | /** 51 | * Frees the memory allocated of RAI_DagOp 52 | * @param ctx Context in which Redis modules operate 53 | * @param RAI_DagOp context in which RedisAI command operates. 54 | */ 55 | void RAI_FreeDagOp(RAI_DagOp *dagOp); 56 | -------------------------------------------------------------------------------- /src/execution/background_workers.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | /** 8 | * background_workers.h 9 | * 10 | * Contains the structure and method signatures required to manage the 11 | * per-device queues, used for decoupling the work from the main thread to the 12 | * background worker threads. For each of the incoming ModelRun, ScriptRun, and 13 | * DagRun commands, the request is queued and evaded asynchronously to one the 14 | * device queues. 15 | * 16 | */ 17 | 18 | #pragma once 19 | 20 | #if defined(__linux__) && !defined(_GNU_SOURCE) 21 | #define _GNU_SOURCE 22 | #endif 23 | 24 | #include 25 | 26 | #include "config/config.h" 27 | #include "DAG/dag.h" 28 | #include "redis_ai_objects/model.h" 29 | #include "redisai.h" 30 | #include "rmutil/alloc.h" 31 | #include "rmutil/args.h" 32 | #include "redis_ai_objects/script.h" 33 | #include "redis_ai_objects/stats.h" 34 | #include "redis_ai_objects/tensor.h" 35 | #include "util/arr.h" 36 | #include "util/queue.h" 37 | 38 | /** 39 | * @brief RedisAI main loop for every background working thread 40 | * @param arg - This is the run queue info of the device on which this thread is 41 | * running the AI model/script 42 | */ 43 | void *BGWorker_ThreadMain(void *arg); 44 | 45 | /** 46 | * @brief Returns the thread id (among RedisAI working threads). If this is called 47 | * form a non RedisAI working thread, return -1 48 | */ 49 | long BGWorker_GetThreadId(void); 50 | 51 | /** 52 | * @brief Returns the total number of RedisAI working threads (for all devices). 53 | */ 54 | uintptr_t BGWorker_GetThreadsCount(void); -------------------------------------------------------------------------------- /src/execution/command_parser.c: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #include "command_parser.h" 8 | #include "redismodule.h" 9 | #include "execution/utils.h" 10 | #include "execution/run_info.h" 11 | #include "execution/DAG/dag.h" 12 | #include "execution/parsing/dag_parser.h" 13 | #include "execution/parsing/deprecated.h" 14 | #include "execution/parsing/model_commands_parser.h" 15 | #include "execution/parsing/script_commands_parser.h" 16 | 17 | int RedisAI_ExecuteCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, 18 | RunCommand command, bool ro_dag) { 19 | 20 | int flags = RedisModule_GetContextFlags(ctx); 21 | bool blocking_not_allowed = (flags & (REDISMODULE_CTX_FLAGS_MULTI | REDISMODULE_CTX_FLAGS_LUA)); 22 | if (blocking_not_allowed) 23 | return RedisModule_ReplyWithError( 24 | ctx, "ERR Cannot run RedisAI command within a transaction or a LUA script"); 25 | 26 | RedisAI_RunInfo *rinfo; 27 | RAI_InitRunInfo(&rinfo); 28 | int status = REDISMODULE_ERR; 29 | 30 | switch (command) { 31 | case CMD_MODELRUN: 32 | rinfo->single_op_dag = 1; 33 | RAI_DagOp *modelRunOp; 34 | RAI_InitDagOp(&modelRunOp); 35 | rinfo->dagOps = array_append(rinfo->dagOps, modelRunOp); 36 | status = ParseModelRunCommand(rinfo, modelRunOp, argv, argc); 37 | break; 38 | case CMD_SCRIPTRUN: 39 | rinfo->single_op_dag = 1; 40 | RAI_DagOp *scriptRunOp; 41 | RAI_InitDagOp(&scriptRunOp); 42 | rinfo->dagOps = array_append(rinfo->dagOps, scriptRunOp); 43 | status = ParseScriptRunCommand(rinfo, scriptRunOp, argv, argc); 44 | break; 45 | case CMD_DAGRUN: 46 | status = ParseDAGRunCommand(rinfo, ctx, argv, argc, ro_dag); 47 | break; 48 | case CMD_MODELEXECUTE: 49 | rinfo->single_op_dag = 1; 50 | RAI_DagOp *modelExecuteOp; 51 | RAI_InitDagOp(&modelExecuteOp); 52 | rinfo->dagOps = array_append(rinfo->dagOps, modelExecuteOp); 53 | status = ParseModelExecuteCommand(rinfo, modelExecuteOp, argv, argc); 54 | break; 55 | case CMD_SCRIPTEXECUTE: 56 | rinfo->single_op_dag = 1; 57 | RAI_DagOp *scriptExecOp; 58 | RAI_InitDagOp(&scriptExecOp); 59 | rinfo->dagOps = array_append(rinfo->dagOps, scriptExecOp); 60 | status = ParseScriptExecuteCommand(rinfo, scriptExecOp, argv, argc); 61 | break; 62 | case CMD_DAGEXECUTE: 63 | status = ParseDAGExecuteCommand(rinfo, ctx, argv, argc, ro_dag); 64 | break; 65 | default: 66 | break; 67 | } 68 | if (status == REDISMODULE_ERR) { 69 | RedisModule_ReplyWithError(ctx, RAI_GetErrorOneLine(rinfo->err)); 70 | RAI_FreeRunInfo(rinfo); 71 | return REDISMODULE_OK; 72 | } 73 | rinfo->dagOpCount = array_len(rinfo->dagOps); 74 | 75 | rinfo->OnFinish = DAG_ReplyAndUnblock; 76 | rinfo->client = RedisModule_BlockClient(ctx, RedisAI_DagRun_Reply, NULL, RunInfo_FreeData, 0); 77 | if (DAG_InsertDAGToQueue(rinfo) != REDISMODULE_OK) { 78 | RedisModule_UnblockClient(rinfo->client, rinfo); 79 | return REDISMODULE_ERR; 80 | } 81 | int major, minor, patch; 82 | RedisAI_GetRedisVersion(&major, &minor, &patch); 83 | // The following command is supported only from redis 6.2 84 | if (major > 6 || (major == 6 && minor >= 2)) { 85 | RedisModule_BlockedClientMeasureTimeStart(rinfo->client); 86 | } 87 | return REDISMODULE_OK; 88 | } 89 | -------------------------------------------------------------------------------- /src/execution/command_parser.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "redismodule.h" 10 | #include "run_info.h" 11 | 12 | typedef enum RunCommand { 13 | CMD_MODELRUN = 0, 14 | CMD_SCRIPTRUN, 15 | CMD_DAGRUN, 16 | CMD_MODELEXECUTE, 17 | CMD_SCRIPTEXECUTE, 18 | CMD_DAGEXECUTE 19 | } RunCommand; 20 | 21 | /** 22 | * @brief Parse and execute RedisAI run command. After parsing and validation, the resulted 23 | * runInfo (DAG) is queued and the client is blocked until the execution is complete (async 24 | * execution). 25 | * @return Returns REDISMODULE_OK if the command is valid, REDISMODULE_ERR otherwise. 26 | */ 27 | int RedisAI_ExecuteCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, 28 | RunCommand command, bool ro_dag); 29 | -------------------------------------------------------------------------------- /src/execution/execution_contexts/execution_ctx.c: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #include "execution_ctx.h" 8 | #include "redismodule.h" 9 | #include "util/arr.h" 10 | 11 | void RAI_ExecutionCtx_Init(RAI_ExecutionCtx *ctx, RAI_RunStats *run_stats, 12 | RAI_ExecutionCtx_Free_fn freeFn) { 13 | ctx->inputs = array_new(RAI_Tensor *, 10); 14 | ctx->outputs = array_new(RAI_Tensor *, 10); 15 | ctx->runStats = run_stats; 16 | ctx->freeFn = freeFn; 17 | } 18 | void RAI_ExecutionCtx_Free(RAI_ExecutionCtx *ctx) { 19 | size_t inputsLen = array_len(ctx->inputs); 20 | for (size_t i = 0; i < inputsLen; i++) { 21 | RAI_TensorFree(ctx->inputs[i]); 22 | } 23 | size_t outputsLen = array_len(ctx->outputs); 24 | for (size_t i = 0; i < outputsLen; i++) { 25 | RAI_TensorFree(ctx->outputs[i]); 26 | } 27 | array_free(ctx->inputs); 28 | array_free(ctx->outputs); 29 | } 30 | 31 | inline size_t RAI_ExecutionCtx_NumInputs(RAI_ExecutionCtx *ctx) { return array_len(ctx->inputs); } 32 | 33 | inline void RAI_ExecutionCtx_AddInput(RAI_ExecutionCtx *ctx, RAI_Tensor *t) { 34 | if (t != NULL) { 35 | t = RAI_TensorGetShallowCopy(t); 36 | } 37 | ctx->inputs = array_append(ctx->inputs, t); 38 | } 39 | 40 | inline RAI_Tensor *RAI_ExecutionCtx_GetInput(RAI_ExecutionCtx *ctx, size_t index) { 41 | RedisModule_Assert(index < array_len(ctx->inputs)); 42 | return ctx->inputs[index]; 43 | } 44 | 45 | inline size_t RAI_ExecutionCtx_NumOutputs(RAI_ExecutionCtx *ctx) { return array_len(ctx->outputs); } 46 | 47 | inline void RAI_ExecutionCtx_AddOutputPlaceholder(RAI_ExecutionCtx *ctx) { 48 | ctx->outputs = array_append(ctx->outputs, NULL); 49 | } 50 | 51 | void RAI_ExecutionCtx_SetOutput(RAI_ExecutionCtx *ctx, RAI_Tensor *t, size_t index) { 52 | RedisModule_Assert(index < array_len(ctx->outputs)); 53 | ctx->outputs[index] = t; 54 | } 55 | 56 | inline RAI_Tensor *RAI_ExecutionCtx_GetOutput(RAI_ExecutionCtx *ctx, size_t index) { 57 | RedisModule_Assert(index < array_len(ctx->outputs)); 58 | return ctx->outputs[index]; 59 | } 60 | 61 | inline RAI_RunStats *RAI_ExecutionCtx_GetStats(RAI_ExecutionCtx *ctx) { return ctx->runStats; } 62 | -------------------------------------------------------------------------------- /src/execution/execution_contexts/execution_ctx.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include "redis_ai_objects/tensor.h" 11 | 12 | // Pre decleration 13 | typedef struct RAI_ExecutionCtx RAI_ExecutionCtx; 14 | 15 | typedef void (*RAI_ExecutionCtx_Free_fn)(RAI_ExecutionCtx *ctx); 16 | 17 | /** 18 | * @brief Generic struct to hold execution contexts for DAG ops. This struct holds the input and 19 | * output tensors of the op, as well as inheriting classes specific functionality. 20 | * 21 | */ 22 | typedef struct RAI_ExecutionCtx { 23 | RAI_Tensor **inputs; // DAG op input tensors. 24 | RAI_Tensor **outputs; // DAG op output tensors. 25 | RAI_RunStats *runStats; // The underline op's (Model/Script) stats entry. 26 | RAI_ExecutionCtx_Free_fn freeFn; // Inheriting execution context free function. 27 | } RAI_ExecutionCtx; 28 | 29 | /** 30 | * @brief Initializes an allocated RAI_ExecutionCtx. 31 | * 32 | * @param ctx - Execution context to initialize. 33 | * @param freeFn - Specific free function for inheriting execution contexts (script or model) 34 | */ 35 | void RAI_ExecutionCtx_Init(RAI_ExecutionCtx *ctx, RAI_RunStats *run_stats, 36 | RAI_ExecutionCtx_Free_fn freeFn); 37 | 38 | /** 39 | * @brief Frees the execution context internal structures. To be used from an inhereting execution 40 | * contxt. 41 | * 42 | * @param ctx - Execution context to Free. 43 | */ 44 | void RAI_ExecutionCtx_Free(RAI_ExecutionCtx *ctx); 45 | 46 | /** 47 | * @brief Returns the number of input tensors of the execution context. 48 | * 49 | * @param ctx - Execution context. 50 | * @return size_t - Number of input tensors. 51 | */ 52 | size_t RAI_ExecutionCtx_NumInputs(RAI_ExecutionCtx *ctx); 53 | 54 | /** 55 | * @brief Adds an input tensor to the execution context. 56 | * 57 | * @param ctx - Execution context. 58 | * @param t - Input tensor. 59 | */ 60 | void RAI_ExecutionCtx_AddInput(RAI_ExecutionCtx *ctx, RAI_Tensor *t); 61 | 62 | /** 63 | * @brief Returns an input tensor from the execution context, for a given index. 64 | * 65 | * @param ctx - Execution context. 66 | * @param index 67 | * @return RAI_Tensor* - Input tensor. 68 | */ 69 | RAI_Tensor *RAI_ExecutionCtx_GetInput(RAI_ExecutionCtx *ctx, size_t index); 70 | 71 | /** 72 | * @brief Returns the number of output tensors/placeholders of the execution context. 73 | * 74 | * @param ctx - Execution context. 75 | * @return size_t - Number of output tensors/placeholders. 76 | */ 77 | size_t RAI_ExecutionCtx_NumOutputs(RAI_ExecutionCtx *ctx); 78 | 79 | /** 80 | * @brief Sets (appends) an output tensor placeholder to the execution context. 81 | * 82 | * @param ctx - Execution context. 83 | */ 84 | void RAI_ExecutionCtx_AddOutputPlaceholder(RAI_ExecutionCtx *ctx); 85 | 86 | /** 87 | * @brief Sets an output tensor in a specfic index, populated before by a placeholder. 88 | * 89 | * @param ctx - Execution context. 90 | * @param t - Output tensor. 91 | * @param index 92 | */ 93 | void RAI_ExecutionCtx_SetOutput(RAI_ExecutionCtx *ctx, RAI_Tensor *t, size_t index); 94 | 95 | /** 96 | * @brief Returns an output tensor from the execution context, for a given index. 97 | * 98 | * @param ctx - Execution context. 99 | * @param index 100 | * @return RAI_Tensor* - Output tensor. 101 | */ 102 | RAI_Tensor *RAI_ExecutionCtx_GetOutput(RAI_ExecutionCtx *ctx, size_t index); 103 | 104 | /** 105 | * @brief Returns the RunStats object for underline object. 106 | * @param ctx - Execution context. 107 | * @return RAI_RunStats 108 | */ 109 | RAI_RunStats *RAI_ExecutionCtx_GetStats(RAI_ExecutionCtx *ctx); 110 | -------------------------------------------------------------------------------- /src/execution/parsing/dag_parser.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "execution/run_info.h" 10 | 11 | /** 12 | * @brief Parse and validate DAGEXECUTE command (Populate the rinfo object): 13 | * - parse KEYS, LOAD, PERSIST, and TIMEOUT args. Persist is not allowed if the DAG is READ-ONLY 14 | * (dag_to is true). 15 | * - parse and validate every DAGop individually. SCRIPTEXECUTE is not allowed if the DAG is 16 | * READ-ONLY. 17 | * - Generate a unique key for every tensor name that appear in the DAG's ops. 18 | * (thus ensure that the operations will be done by the desired order). 19 | * @return Returns REDISMODULE_OK if the command is valid, REDISMODULE_ERR otherwise. 20 | */ 21 | int ParseDAGExecuteCommand(RedisAI_RunInfo *rinfo, RedisModuleCtx *ctx, RedisModuleString **argv, 22 | int argc, bool dag_ro); 23 | 24 | /** 25 | * @brief Parse the arguments of the given ops in the DAGRUN command and build every op accordingly. 26 | * @param rinfo The DAG run info that will be populated with the ops if they are valid. 27 | * with its op, 28 | * @param ops A local array of ops, where every op has an argv field that points to an 29 | * array of RedisModule strings arguments, and an argc field which is the number of 30 | * args. 31 | * @return Returns REDISMODULE_OK if the command is valid, REDISMODULE_ERR otherwise. 32 | */ 33 | int ParseDAGExecuteOps(RedisAI_RunInfo *rinfo, RAI_DagOp **ops, bool ro); 34 | 35 | int DAGInitialParsing(RedisAI_RunInfo *rinfo, RedisModuleCtx *ctx, RedisModuleString **argv, 36 | int argc, bool dag_ro, RAI_DagOp ***dag_ops); 37 | -------------------------------------------------------------------------------- /src/execution/parsing/deprecated.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "redismodule.h" 10 | #include "execution/run_info.h" 11 | 12 | /** 13 | * @brief Parse and validate MODELRUN command: create a modelRunCtx based on the model obtained 14 | * from the key space and save it in the op. The keys of the input and output tensors are stored in 15 | * the op's inkeys and outkeys arrays, and the given timeout 16 | * is saved as well (if given, otherwise it is zero). 17 | * @return Returns REDISMODULE_OK if the command is valid, REDISMODULE_ERR otherwise. 18 | */ 19 | int ParseModelRunCommand(RedisAI_RunInfo *rinfo, RAI_DagOp *currentOp, RedisModuleString **argv, 20 | int argc); 21 | 22 | int ParseScriptRunCommand(RedisAI_RunInfo *rinfo, RAI_DagOp *currentOp, RedisModuleString **argv, 23 | int argc); 24 | 25 | int ModelSetCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc); 26 | 27 | int ScriptSetCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc); 28 | 29 | /** 30 | * @brief Parse the arguments of the given ops in the DAGRUN command and build every op accordingly. 31 | * @param rinfo The DAG run info that will be populated with the ops if they are valid. 32 | * with its op, 33 | * @param ops A local array of ops, where every op has an argv field that points to an 34 | * array of RedisModule strings arguments, and an argc field which is the number of 35 | * args. 36 | * @return Returns REDISMODULE_OK if the command is valid, REDISMODULE_ERR otherwise. 37 | */ 38 | int ParseDAGRunOps(RedisAI_RunInfo *rinfo, RAI_DagOp **ops); 39 | 40 | /** 41 | * @brief Parse and validate DAGRUN command (Populate the rinfo object): 42 | * - parse LOAD, PERSIST, and TIMEOUT args. Persist is not allowed if the DAG is READ-ONLY (dag_to 43 | * is true). 44 | * - parse and validate every DAGop individually. 45 | * - Generate a unique key for every tensor name that appear in the DAG's ops. 46 | * (thus ensure that the operations will be done by the desired order). 47 | * @return Returns REDISMODULE_OK if the command is valid, REDISMODULE_ERR otherwise. 48 | */ 49 | int ParseDAGRunCommand(RedisAI_RunInfo *rinfo, RedisModuleCtx *ctx, RedisModuleString **argv, 50 | int argc, bool dag_ro); 51 | -------------------------------------------------------------------------------- /src/execution/parsing/model_commands_parser.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | #include "redismodule.h" 9 | #include "execution/run_info.h" 10 | 11 | /** 12 | * @brief Parse and validate MODELEXECUTE command: create a modelRunCtx based on the model obtained 13 | * from the key space and save it in the op. The keys of the input and output tensors are stored in 14 | * the op's inkeys and outkeys arrays, and the given timeout 15 | * is saved as well (if given, otherwise it is zero). 16 | * @return Returns REDISMODULE_OK if the command is valid, REDISMODULE_ERR otherwise. 17 | */ 18 | int ParseModelExecuteCommand(RedisAI_RunInfo *rinfo, RAI_DagOp *currentOp, RedisModuleString **argv, 19 | int argc); 20 | -------------------------------------------------------------------------------- /src/execution/parsing/parse_utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #include 8 | #include "parse_utils.h" 9 | #include "string.h" 10 | 11 | int ParseTimeout(RedisModuleString *timeout_arg, RAI_Error *error, long long *timeout) { 12 | 13 | const int retval = RedisModule_StringToLongLong(timeout_arg, timeout); 14 | if (retval != REDISMODULE_OK || *timeout <= 0) { 15 | RAI_SetError(error, RAI_EMODELRUN, "ERR Invalid value for TIMEOUT"); 16 | return REDISMODULE_ERR; 17 | } 18 | return REDISMODULE_OK; 19 | } 20 | 21 | const char *ScriptCommand_GetFunctionName(RedisModuleString *functionName) { 22 | const char *functionName_cstr = RedisModule_StringPtrLen(functionName, NULL); 23 | return functionName_cstr; 24 | } 25 | 26 | int ValidateKeysArgs(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, RAI_Error *err) { 27 | if (argc < 3) { 28 | RAI_SetError(err, RAI_EDAGBUILDER, "ERR Missing arguments after KEYS keyword"); 29 | return -1; 30 | } 31 | 32 | long long n_keys; 33 | const int retval = RedisModule_StringToLongLong(argv[1], &n_keys); 34 | if (retval != REDISMODULE_OK || n_keys <= 0) { 35 | RAI_SetError(err, RAI_EDAGBUILDER, "ERR Invalid or negative value found in number of KEYS"); 36 | return -1; 37 | } 38 | 39 | size_t argpos = 2; 40 | if (argpos + n_keys > argc) { 41 | RAI_SetError( 42 | err, RAI_EDAGBUILDER, 43 | "ERR Number of pre declared KEYS to be used in the command does not match the number " 44 | "of given arguments"); 45 | return -1; 46 | } 47 | 48 | // Go over the given args and verify that these keys are located in the local shard. 49 | while (argpos < n_keys + 2) { 50 | if (!VerifyKeyInThisShard(ctx, argv[argpos++])) { 51 | RAI_SetError(err, RAI_EDAGBUILDER, 52 | "ERR Some of the KEYS specified in the command hash to slots which aren't " 53 | "belong to the current shard"); 54 | return -1; 55 | } 56 | } 57 | return argpos; 58 | } 59 | -------------------------------------------------------------------------------- /src/execution/parsing/parse_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | #include "redismodule.h" 9 | #include "redis_ai_objects/err.h" 10 | 11 | /** 12 | * @brief Parse and validate TIMEOUT argument. If it is valid, store it in timeout. 13 | * Otherwise set an error. 14 | * @return Returns REDISMODULE_OK if the command is valid, REDISMODULE_ERR otherwise. 15 | */ 16 | int ParseTimeout(RedisModuleString *timeout_arg, RAI_Error *error, long long *timeout); 17 | 18 | /** 19 | * @brief 20 | * 21 | * @param functionName 22 | * @return const char* 23 | */ 24 | const char *ScriptCommand_GetFunctionName(RedisModuleString *functionName); 25 | 26 | /** 27 | * Parse KEYS section in command [* KEYS key1 key2... ] 28 | * 29 | * @param ctx Context in which Redis modules operate 30 | * @param argv Redis command arguments, as an array of strings 31 | * @param argc Redis command number of arguments 32 | * @param err An error object to store an error message if needed. 33 | * @return processed number of arguments on success, or -1 if the parsing failed 34 | */ 35 | 36 | int ValidateKeysArgs(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, RAI_Error *err); 37 | -------------------------------------------------------------------------------- /src/execution/parsing/script_commands_parser.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | #include "redismodule.h" 9 | #include "execution/run_info.h" 10 | 11 | /** 12 | * @brief Parse and validate SCRIPTEXECUTE command: create a scriptRunCtx based on the script 13 | * obtained from the key space and the function name given, and save it in the op. The keys of the 14 | * input and output tensors are stored in the op's inkeys and outkeys arrays, 15 | * and the given timeout is saved as well (if given, otherwise it is zero). 16 | * @return Returns REDISMODULE_OK if the command is valid, REDISMODULE_ERR otherwise. 17 | */ 18 | int ParseScriptExecuteCommand(RedisAI_RunInfo *rinfo, RAI_DagOp *currentOp, 19 | RedisModuleString **argv, int argc); 20 | -------------------------------------------------------------------------------- /src/execution/parsing/tensor_commands_parsing.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "redismodule.h" 10 | #include "redis_ai_objects/err.h" 11 | #include "redis_ai_objects/tensor.h" 12 | 13 | /** 14 | * Helper method to parse AI.TENSORGET arguments 15 | * 16 | * @param argv Redis command arguments, as an array of strings 17 | * @param argc Redis command number of arguments 18 | * @param t Destination tensor to store the parsed data 19 | * @param error error data structure to store error message in the case of 20 | * parsing failures 21 | * @return REDISMODULE_OK on success, or REDISMODULE_ERR if the parsing failed 22 | */ 23 | int ParseTensorSetArgs(RedisModuleString **argv, int argc, RAI_Tensor **t, RAI_Error *error); 24 | 25 | /** 26 | * Helper method to parse AI.TENSORGET arguments 27 | * 28 | * @param error error data structure to store error message in the case of 29 | * parsing failures 30 | * @param argv Redis command arguments, as an array of strings 31 | * @param argc Redis command number of arguments 32 | * @return The format in which tensor is returned. 33 | */ 34 | 35 | uint ParseTensorGetFormat(RAI_Error *error, RedisModuleString **argv, int argc); 36 | -------------------------------------------------------------------------------- /src/execution/run_queue_info.c: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #include "string_utils.h" 8 | #include "run_queue_info.h" 9 | #include "backends/backends.h" 10 | #include "background_workers.h" 11 | 12 | extern unsigned int BGWorkersCount; 13 | 14 | RunQueueInfo *RunQueue_Create(const char *device_str) { 15 | 16 | size_t device_str_len = strlen(device_str); 17 | char upper_device_str[device_str_len + 1]; 18 | RAI_StringToUpper(device_str, upper_device_str, device_str_len + 1); 19 | 20 | // Create new run queue and initialize its inner fields. 21 | RunQueueInfo *run_queue_info = RedisModule_Alloc(sizeof(RunQueueInfo)); 22 | run_queue_info->run_queue = queueCreate(); 23 | run_queue_info->device_str = RedisModule_Strdup(upper_device_str); 24 | pthread_cond_init(&(run_queue_info->queue_condition_var), NULL); 25 | pthread_mutex_init(&(run_queue_info->run_queue_mutex), NULL); 26 | run_queue_info->threads = array_new(pthread_t, Config_GetNumThreadsPerQueue()); 27 | // Save device with its associate run queue info in the dictionary. 28 | if (AI_dictAdd(RunQueues, upper_device_str, run_queue_info) != DICT_OK) { 29 | RunQueue_Free(run_queue_info); 30 | return NULL; 31 | } 32 | 33 | // Create worker threads, update the global counter. 34 | for (int i = 0; i < Config_GetNumThreadsPerQueue(); i++) { 35 | pthread_t thread; 36 | if (pthread_create(&thread, NULL, BGWorker_ThreadMain, run_queue_info) != 0) { 37 | AI_dictDelete(RunQueues, upper_device_str); 38 | RunQueue_Free(run_queue_info); 39 | return NULL; 40 | } 41 | run_queue_info->threads = array_append(run_queue_info->threads, thread); 42 | } 43 | BGWorkersCount += Config_GetNumThreadsPerQueue(); 44 | 45 | // Add the new device worker threads to onnx run sessions tracking. 46 | if (RAI_backends.onnx.add_new_device_cb) { 47 | RAI_backends.onnx.add_new_device_cb(device_str); 48 | } 49 | return run_queue_info; 50 | } 51 | 52 | RunQueueInfo *RunQueue_GetInfo(const char *device_str) { 53 | size_t device_str_len = strlen(device_str); 54 | char upper_device_str[device_str_len + 1]; 55 | RAI_StringToUpper(device_str, upper_device_str, device_str_len + 1); 56 | AI_dictEntry *entry = AI_dictFind(RunQueues, upper_device_str); 57 | RedisModule_Assert(entry != NULL); 58 | return AI_dictGetVal(entry); 59 | } 60 | 61 | bool RunQueue_IsExists(const char *device_str) { 62 | size_t device_str_len = strlen(device_str); 63 | char upper_device_str[device_str_len + 1]; 64 | RAI_StringToUpper(device_str, upper_device_str, device_str_len + 1); 65 | return AI_dictFind(RunQueues, upper_device_str) != NULL; 66 | } 67 | 68 | void RunQueue_Free(RunQueueInfo *run_queue_info) { 69 | RedisModule_Assert(queueLength(run_queue_info->run_queue) == 0); 70 | RedisModule_Free(run_queue_info->run_queue); 71 | RedisModule_Free(run_queue_info->device_str); 72 | 73 | // Wait for workers to exit and free the pool. 74 | for (int i = 0; i < array_len(run_queue_info->threads); i++) { 75 | RedisModule_Assert(pthread_join(run_queue_info->threads[i], NULL) == 0); 76 | RedisModule_Free(run_queue_info->threads); 77 | } 78 | pthread_mutex_destroy(&(run_queue_info->run_queue_mutex)); 79 | pthread_cond_destroy(&(run_queue_info->queue_condition_var)); 80 | RedisModule_Free(run_queue_info); 81 | } 82 | -------------------------------------------------------------------------------- /src/execution/run_queue_info.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | 9 | /** 10 | * Contains the structure to manage the per-device queues, used for decoupling 11 | * the work from the main thread to the background worker threads. For each of 12 | * the incoming ModelRun, ScriptRun, and DagRun commands, the request is queued 13 | * and evaded asynchronously to one the device queues. 14 | */ 15 | 16 | #include "utils.h" 17 | #include "queue.h" 18 | #include "dictionaries.h" 19 | 20 | AI_dict *RunQueues; 21 | 22 | typedef struct RunQueueInfo { 23 | pthread_mutex_t run_queue_mutex; 24 | pthread_cond_t queue_condition_var; 25 | queue *run_queue; 26 | pthread_t *threads; 27 | char *device_str; 28 | } RunQueueInfo; 29 | 30 | /** 31 | * @brief Create a new run queue for a device. 32 | */ 33 | RunQueueInfo *RunQueue_Create(const char *device_str); 34 | 35 | /** 36 | * @brief Return true if a ru queue exists for this particular device. 37 | */ 38 | bool RunQueue_IsExists(const char *device_str); 39 | 40 | /** 41 | * @brief Return the RunQueueInfo saved in the global RunQueues dict for a certain 42 | * device name, after asserting that it exists. 43 | */ 44 | RunQueueInfo *RunQueue_GetInfo(const char *device_str); 45 | 46 | /** 47 | * @brief Terminate all working threads and free the run queue with its inner fields. 48 | */ 49 | void RunQueue_Free(RunQueueInfo *info); 50 | -------------------------------------------------------------------------------- /src/execution/utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #include "utils.h" 8 | #include "redis_ai_objects/model.h" 9 | 10 | int redisMajorVersion; 11 | int redisMinorVersion; 12 | int redisPatchVersion; 13 | 14 | int rlecMajorVersion; 15 | int rlecMinorVersion; 16 | int rlecPatchVersion; 17 | int rlecBuild; 18 | 19 | void RedisAI_SetRedisVersion() { 20 | RedisModuleCtx *ctx = RedisModule_GetThreadSafeContext(NULL); 21 | RedisModuleCallReply *reply = RedisModule_Call(ctx, "info", "c", "server"); 22 | assert(RedisModule_CallReplyType(reply) == REDISMODULE_REPLY_STRING); 23 | size_t len; 24 | const char *replyStr = RedisModule_CallReplyStringPtr(reply, &len); 25 | 26 | int n = sscanf(replyStr, "# Server\nredis_version:%d.%d.%d", &redisMajorVersion, 27 | &redisMinorVersion, &redisPatchVersion); 28 | 29 | assert(n == 3); 30 | 31 | rlecMajorVersion = -1; 32 | rlecMinorVersion = -1; 33 | rlecPatchVersion = -1; 34 | rlecBuild = -1; 35 | char *enterpriseStr = strstr(replyStr, "rlec_version:"); 36 | if (enterpriseStr) { 37 | n = sscanf(enterpriseStr, "rlec_version:%d.%d.%d-%d", &rlecMajorVersion, &rlecMinorVersion, 38 | &rlecPatchVersion, &rlecBuild); 39 | if (n != 4) { 40 | RedisModule_Log(NULL, "warning", "Could not extract enterprise version"); 41 | } 42 | } 43 | 44 | RedisModule_FreeCallReply(reply); 45 | RedisModule_FreeThreadSafeContext(ctx); 46 | } 47 | 48 | void RedisAI_GetRedisVersion(int *major, int *minor, int *patch) { 49 | *major = redisMajorVersion; 50 | *minor = redisMinorVersion; 51 | *patch = redisPatchVersion; 52 | } 53 | 54 | bool IsEnterprise() { return rlecMajorVersion != -1; } 55 | 56 | bool VerifyKeyInThisShard(RedisModuleCtx *ctx, RedisModuleString *key_str) { 57 | if (IsEnterprise()) { 58 | int first_slot, last_slot; 59 | RedisModule_ShardingGetSlotRange(&first_slot, &last_slot); 60 | int key_slot = RedisModule_ShardingGetKeySlot(key_str); 61 | 62 | // If first_slot=last_slot=-1, then sharding is not enabled in enterprise, 63 | // so we definitely don't have a cross shard violation. 64 | if (first_slot != -1 && last_slot != -1 && 65 | (key_slot < first_slot || key_slot > last_slot)) { 66 | RedisModule_Log(ctx, "warning", 67 | "could not load %s from keyspace," 68 | " this key's hash slot belongs to a different shard", 69 | RedisModule_StringPtrLen(key_str, NULL)); 70 | return false; 71 | } 72 | } 73 | return true; 74 | } 75 | -------------------------------------------------------------------------------- /src/execution/utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include "redismodule.h" 11 | 12 | /** Use this to check if a command is given a key whose hash slot is not on the current 13 | * shard, when using enterprise cluster. 14 | **/ 15 | bool VerifyKeyInThisShard(RedisModuleCtx *ctx, RedisModuleString *key_str); 16 | 17 | /** 18 | * Use this function when loading the model. Stores the version in global variables. 19 | */ 20 | void RedisAI_SetRedisVersion(); 21 | 22 | /** 23 | * Returns redis version in the major, minor, and patch placeholders. 24 | */ 25 | void RedisAI_GetRedisVersion(int *major, int *minor, int *patch); 26 | 27 | /** 28 | * Returns true if Redis is running in enterprise mode. 29 | */ 30 | bool IsEnterprise(); 31 | -------------------------------------------------------------------------------- /src/redis_ai_objects/err.c: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | /** 8 | * err.c 9 | * 10 | * Contains a formal API to create, initialize, get, reset, and free errors 11 | * among different backends. 12 | */ 13 | 14 | #include "err.h" 15 | 16 | #include "redismodule.h" 17 | #include "stdlib.h" 18 | #include "string.h" 19 | 20 | char *RAI_Chomp(const char *src) { 21 | char *str = RedisModule_Strdup(src); 22 | size_t len = strlen(src); 23 | for (size_t i = 0; i < len; i++) { 24 | if (str[i] == '\n' || str[i] == '\r') { 25 | str[i] = ' '; 26 | } 27 | } 28 | return str; 29 | } 30 | 31 | const char *RAI_GetError(RAI_Error *err) { return err->detail; } 32 | 33 | const char *RAI_GetErrorOneLine(RAI_Error *err) { return err->detail_oneline; } 34 | 35 | RAI_ErrorCode RAI_GetErrorCode(RAI_Error *err) { return err->code; } 36 | 37 | void RAI_CloneError(RAI_Error *dest, const RAI_Error *src) { 38 | dest->code = src->code; 39 | RedisModule_Assert(!dest->detail); 40 | dest->detail = RedisModule_Strdup(src->detail); 41 | dest->detail_oneline = RAI_Chomp(dest->detail); 42 | } 43 | 44 | void RAI_SetError(RAI_Error *err, RAI_ErrorCode code, const char *detail) { 45 | if (!err) { 46 | return; 47 | } 48 | if (err->code != RAI_OK) { 49 | return; 50 | } 51 | RedisModule_Assert(!err->detail); 52 | err->code = code; 53 | 54 | if (detail) { 55 | err->detail = RedisModule_Strdup(detail); 56 | } else { 57 | err->detail = RedisModule_Strdup("ERR Generic error"); 58 | } 59 | err->detail_oneline = RAI_Chomp(err->detail); 60 | } 61 | 62 | /** 63 | * Allocate the memory and initialise the RAI_Error. 64 | * @param result Output parameter to capture allocated RAI_Error. 65 | * @return 0 on success, or 1 if the allocation 66 | * failed. 67 | */ 68 | int RAI_InitError(RAI_Error **result) { 69 | RAI_Error *err; 70 | err = (RAI_Error *)RedisModule_Calloc(1, sizeof(RAI_Error)); 71 | *result = err; 72 | return REDISMODULE_OK; 73 | } 74 | 75 | void RAI_ClearError(RAI_Error *err) { 76 | if (err) { 77 | if (err->detail) { 78 | RedisModule_Free(err->detail); 79 | err->detail = NULL; 80 | } 81 | if (err->detail_oneline) { 82 | RedisModule_Free(err->detail_oneline); 83 | err->detail_oneline = NULL; 84 | } 85 | err->code = RAI_OK; 86 | } 87 | } 88 | 89 | void RAI_FreeError(RAI_Error *err) { 90 | if (err) { 91 | RAI_ClearError(err); 92 | RedisModule_Free(err); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/redis_ai_objects/err.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | /** 8 | * err.h 9 | * 10 | * Contains the structure and headers for a formal API to create, initialize, 11 | * get, reset, and free errors among different backends. 12 | */ 13 | 14 | #pragma once 15 | 16 | typedef enum { 17 | RAI_OK = 0, 18 | RAI_EMODELIMPORT, 19 | RAI_EMODELCONFIGURE, 20 | RAI_EMODELCREATE, 21 | RAI_EMODELRUN, 22 | RAI_EMODELSERIALIZE, 23 | RAI_EMODELFREE, 24 | RAI_ESCRIPTIMPORT, 25 | RAI_ESCRIPTCONFIGURE, 26 | RAI_ESCRIPTCREATE, 27 | RAI_ESCRIPTRUN, 28 | RAI_EUNSUPPORTEDBACKEND, 29 | RAI_EBACKENDNOTLOADED, 30 | RAI_ESCRIPTFREE, 31 | RAI_ETENSORSET, 32 | RAI_ETENSORGET, 33 | RAI_EDAGBUILDER, 34 | RAI_EDAGRUN, 35 | RAI_EFINISHCTX, 36 | RAI_EKEYEMPTY 37 | } RAI_ErrorCode; 38 | 39 | typedef struct RAI_Error { 40 | RAI_ErrorCode code; 41 | char *detail; 42 | char *detail_oneline; 43 | } RAI_Error; 44 | 45 | /** 46 | * Allocate the memory and initialise the RAI_Error. 47 | * 48 | * @param result Output parameter to capture allocated RAI_Error. 49 | * @return 0 on success, or 1 if the allocation 50 | * failed. 51 | */ 52 | int RAI_InitError(RAI_Error **err); 53 | 54 | /** 55 | * Populates the RAI_Error data structure with the error details 56 | * 57 | * @param err 58 | * @param code 59 | * @param detail 60 | */ 61 | void RAI_SetError(RAI_Error *err, RAI_ErrorCode code, const char *detail); 62 | 63 | /** 64 | * Return the error description 65 | * 66 | * @param err 67 | * @return error description 68 | * @param err 69 | */ 70 | const char *RAI_GetError(RAI_Error *err); 71 | 72 | /** 73 | * Return the error description as one line 74 | * 75 | * @param err 76 | * @return error description as one line 77 | * @param err 78 | */ 79 | const char *RAI_GetErrorOneLine(RAI_Error *err); 80 | 81 | /** 82 | * Return the error code 83 | * 84 | * @param err 85 | * @return error code 86 | * @param err 87 | */ 88 | RAI_ErrorCode RAI_GetErrorCode(RAI_Error *err); 89 | 90 | /** 91 | * Make dest a clone of src 92 | * 93 | * @param dest An allocated error 94 | * @param src The error to copy 95 | */ 96 | void RAI_CloneError(RAI_Error *dest, const RAI_Error *src); 97 | 98 | /** 99 | * Resets an previously used/allocated RAI_Error 100 | * 101 | * @param err 102 | */ 103 | void RAI_ClearError(RAI_Error *err); 104 | 105 | /** 106 | * Frees the memory of the RAI_Error 107 | * 108 | * @param err 109 | */ 110 | void RAI_FreeError(RAI_Error *err); 111 | -------------------------------------------------------------------------------- /src/redis_ai_objects/model_struct.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "config/config.h" 10 | #include "tensor_struct.h" 11 | #include "redis_ai_objects/stats.h" 12 | 13 | typedef struct RAI_ModelOpts { 14 | size_t batchsize; 15 | size_t minbatchsize; 16 | size_t minbatchtimeout; 17 | long long backends_intra_op_parallelism; // number of threads used within an 18 | // individual op for parallelism. 19 | long long backends_inter_op_parallelism; // number of threads used for parallelism 20 | // between independent operations. 21 | } RAI_ModelOpts; 22 | 23 | typedef struct RAI_Model { 24 | void *model; 25 | // TODO: use session pool? The ideal would be to use one session per client. 26 | // If a client disconnects, we dispose the session or reuse it for 27 | // another client. 28 | void *session; 29 | RAI_Backend backend; 30 | char *devicestr; 31 | RedisModuleString *tag; 32 | RAI_ModelOpts opts; 33 | char **inputs; 34 | size_t ninputs; 35 | char **outputs; 36 | size_t noutputs; 37 | long long refCount; 38 | char *data; 39 | long long datalen; 40 | RAI_RunStats *info; 41 | } RAI_Model; 42 | -------------------------------------------------------------------------------- /src/redis_ai_objects/script_struct.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "config/config.h" 10 | #include "tensor_struct.h" 11 | #include "redis_ai_objects/stats.h" 12 | #include "util/dict.h" 13 | 14 | typedef enum { 15 | UNKOWN, 16 | TENSOR, 17 | INT, 18 | FLOAT, 19 | STRING, 20 | TENSOR_LIST, 21 | INT_LIST, 22 | FLOAT_LIST, 23 | STRING_LIST 24 | } TorchScriptFunctionArgumentType; 25 | 26 | typedef struct RAI_Script { 27 | void *script; 28 | char *scriptdef; 29 | // TODO: scripts do not have placement in PyTorch 30 | // Placement depends on the inputs, as do outputs 31 | // We keep it here at the moment, until we have a 32 | // CUDA allocator for dlpack 33 | char *devicestr; 34 | RedisModuleString *tag; 35 | long long refCount; 36 | RAI_RunStats *info; 37 | char **entryPoints; 38 | } RAI_Script; 39 | -------------------------------------------------------------------------------- /src/redis_ai_objects/stats.c: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | /** 8 | * stats.c 9 | * 10 | * Contains the helper methods to create, 11 | * initialize, get, reset, and free run-time statistics, like call count, error 12 | * count, and aggregate durations of ModelRun and ScriptRun sessions. 13 | * 14 | */ 15 | 16 | #include 17 | #include 18 | #include "stats.h" 19 | #include "util/string_utils.h" 20 | 21 | // Global dictionary that stores run statistics for all models and scripts in the shard. 22 | AI_dict *RunStats; 23 | 24 | long long ustime(void) { 25 | struct timeval tv; 26 | long long ust; 27 | 28 | gettimeofday(&tv, NULL); 29 | ust = ((long long)tv.tv_sec) * 1000000; 30 | ust += tv.tv_usec; 31 | return ust; 32 | } 33 | 34 | mstime_t mstime(void) { return ustime() / 1000; } 35 | 36 | RAI_RunStats *RAI_StatsCreate(RedisModuleString *key, RAI_RunType type, RAI_Backend backend, 37 | const char *device_str, RedisModuleString *tag) { 38 | RAI_RunStats *r_stats = RedisModule_Calloc(1, sizeof(RAI_RunStats)); 39 | r_stats->key = RedisModule_CreateStringFromString(NULL, key); 40 | r_stats->type = type; 41 | r_stats->backend = backend; 42 | r_stats->device_str = RedisModule_Strdup(device_str); 43 | r_stats->tag = RAI_HoldString(tag); 44 | return r_stats; 45 | } 46 | 47 | void RAI_StatsReset(RAI_RunStats *r_stats) { 48 | RedisModule_Assert(r_stats); 49 | __atomic_store_n(&r_stats->duration_us, 0, __ATOMIC_RELAXED); 50 | __atomic_store_n(&r_stats->samples, 0, __ATOMIC_RELAXED); 51 | __atomic_store_n(&r_stats->calls, 0, __ATOMIC_RELAXED); 52 | __atomic_store_n(&r_stats->n_errors, 0, __ATOMIC_RELAXED); 53 | } 54 | 55 | void RAI_StatsAddDataPoint(RAI_RunStats *r_stats, unsigned long duration, unsigned long calls, 56 | unsigned long errors, unsigned long samples) { 57 | RedisModule_Assert(r_stats); 58 | __atomic_add_fetch(&r_stats->duration_us, duration, __ATOMIC_RELAXED); 59 | __atomic_add_fetch(&r_stats->calls, calls, __ATOMIC_RELAXED); 60 | __atomic_add_fetch(&r_stats->n_errors, errors, __ATOMIC_RELAXED); 61 | __atomic_add_fetch(&r_stats->samples, samples, __ATOMIC_RELAXED); 62 | } 63 | 64 | void RAI_StatsFree(RAI_RunStats *r_stats) { 65 | if (r_stats) { 66 | if (r_stats->device_str) { 67 | RedisModule_Free(r_stats->device_str); 68 | } 69 | if (r_stats->tag) { 70 | RedisModule_FreeString(NULL, r_stats->tag); 71 | } 72 | if (r_stats->key) { 73 | RedisModule_FreeString(NULL, r_stats->key); 74 | } 75 | RedisModule_Free(r_stats); 76 | } 77 | } 78 | 79 | /************************************* Global RunStats dict API *********************************/ 80 | 81 | void RAI_StatsStoreEntry(RedisModuleString *key, RAI_RunStats *new_stats_entry) { 82 | AI_dictReplace(RunStats, (void *)key, (void *)new_stats_entry); 83 | } 84 | 85 | void RAI_StatsGetAllEntries(RAI_RunType type, long long *nkeys, RedisModuleString ***keys, 86 | RedisModuleString ***tags) { 87 | AI_dictIterator *stats_iter = AI_dictGetSafeIterator(RunStats); 88 | long long stats_size = AI_dictSize(RunStats); 89 | 90 | *keys = RedisModule_Calloc(stats_size, sizeof(RedisModuleString *)); 91 | *tags = RedisModule_Calloc(stats_size, sizeof(RedisModuleString *)); 92 | *nkeys = 0; 93 | 94 | AI_dictEntry *stats_entry = AI_dictNext(stats_iter); 95 | RAI_RunStats *r_stats = NULL; 96 | 97 | while (stats_entry) { 98 | r_stats = AI_dictGetVal(stats_entry); 99 | if (r_stats->type == type) { 100 | (*keys)[*nkeys] = r_stats->key; 101 | (*tags)[*nkeys] = r_stats->tag; 102 | *nkeys += 1; 103 | } 104 | stats_entry = AI_dictNext(stats_iter); 105 | } 106 | AI_dictReleaseIterator(stats_iter); 107 | } 108 | 109 | void RAI_StatsRemoveEntry(RedisModuleString *info_key) { 110 | AI_dictEntry *stats_entry = AI_dictFind(RunStats, info_key); 111 | 112 | if (stats_entry) { 113 | AI_dictDelete(RunStats, info_key); 114 | } 115 | } 116 | 117 | RAI_RunStats *RAI_StatsGetEntry(RedisModuleString *runkey) { 118 | RedisModule_Assert(RunStats); 119 | AI_dictEntry *entry = AI_dictFind(RunStats, runkey); 120 | if (!entry) { 121 | return NULL; 122 | } 123 | return AI_dictGetVal(entry); 124 | } 125 | -------------------------------------------------------------------------------- /src/redis_ai_objects/stats.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | /** 8 | * stats.h 9 | * 10 | * Contains the structure and headers for the helper methods to create, 11 | * initialize, get, reset, and free run-time statics, like call count, error 12 | * count, and aggregate durations of ModelRun and ScriptRun sessions. 13 | * 14 | */ 15 | 16 | #pragma once 17 | 18 | #include "config/config.h" 19 | #include "redismodule.h" 20 | #include "util/dict.h" 21 | 22 | typedef struct RAI_RunStats { 23 | RedisModuleString *key; 24 | RAI_RunType type; 25 | RAI_Backend backend; 26 | char *device_str; 27 | RedisModuleString *tag; 28 | unsigned long duration_us; 29 | unsigned long samples; 30 | unsigned long calls; 31 | unsigned long n_errors; 32 | unsigned long ref_count; 33 | } RAI_RunStats; 34 | 35 | long long ustime(void); 36 | mstime_t mstime(void); 37 | 38 | /** 39 | * Adds an entry to the ephemeral run-time statistic. The statistics are not 40 | * saved to the keyspace, and on maximum live for the duration of the DB uptime. 41 | * 42 | * @param key key name to use as unique stats identifier 43 | * @param type type of stats identifier ( one of RAI_MODEL or RAI_SCRIPT ) 44 | * @param backend backend identifier (one of RAI_BACKEND_TENSORFLOW, 45 | * RAI_BACKEND_TFLITE, RAI_BACKEND_TORCH, RAI_BACKEND_ONNXRUNTIME,) 46 | * @param device_str device to execute the model on (CPU, GPU, ...) 47 | * @param tag optional tag of Model/Script 48 | * @return A newly heap allocated RedisAI_RunStats object with the given fields. 49 | */ 50 | RAI_RunStats *RAI_StatsCreate(RedisModuleString *key, RAI_RunType type, RAI_Backend backend, 51 | const char *device_str, RedisModuleString *tag); 52 | 53 | /** 54 | * @brief Reset atomically counters for a given run_stats of some model/script. 55 | * @param run_stats entry to reset. 56 | */ 57 | void RAI_StatsReset(RAI_RunStats *run_stats); 58 | 59 | /** 60 | * Update atomically stats counters after execution. 61 | * @param r_stats runStats entry that matches some model/script. 62 | * @param duration execution runtime in us 63 | * @param calls number of calls to the underline model/script operation. 64 | * @param errors number of errors that had occurred. 65 | * @param samples number of samples that the model execute (batch size) 66 | */ 67 | void RAI_StatsAddDataPoint(RAI_RunStats *r_stats, unsigned long duration, unsigned long calls, 68 | unsigned long errors, unsigned long samples); 69 | 70 | /** 71 | * @brief Release RunStats struct. 72 | * @param run_stats entry to remove. 73 | */ 74 | void RAI_StatsFree(RAI_RunStats *r_stats); 75 | 76 | /************************************* Global RunStats dict API *********************************/ 77 | /** 78 | * Adds an entry to the ephemeral run-time statistic. The statistics are not 79 | * saved to the keyspace, and on maximum live for the duration of the DB uptime. 80 | * If a run stats object already exists for this key, it will override it. 81 | * 82 | * @param keyName key name to use as unique stats identifier. 83 | * @param run_stats_entry RunStats entry pointer to store. 84 | */ 85 | void RAI_StatsStoreEntry(RedisModuleString *key, RAI_RunStats *run_stats_entry); 86 | 87 | /** 88 | * @brief: Removes the statistical entry with the provided unique stats identifier 89 | * @param info_key 90 | */ 91 | void RAI_StatsRemoveEntry(RedisModuleString *info_key); 92 | 93 | /** 94 | * Returns a list of all statistical entries that match a specific RAI_RunType ( 95 | * model or script). 96 | * @param type type of stats identifier to provide the list for (one of 97 | * RAI_MODEL or RAI_SCRIPT). 98 | * @param nkeys output variable containing the number of returned stats. 99 | * @param keys output variable containing the list of returned keys. 100 | * @param tags output variable containing the list of returned tags. 101 | */ 102 | void RAI_StatsGetAllEntries(RAI_RunType type, long long *nkeys, RedisModuleString ***keys, 103 | RedisModuleString ***tags); 104 | 105 | /** 106 | * @brief Retrieve the run stats info of run_key from the global RunStat dictionary and set it in 107 | * r_stats. 108 | * @param run_key module/script key name 109 | * @return The RAI_RunStats object that is associated with the key, or NULL if it doesn't exist. 110 | */ 111 | RAI_RunStats *RAI_StatsGetEntry(RedisModuleString *run_key); 112 | -------------------------------------------------------------------------------- /src/redis_ai_objects/tensor_struct.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "limits.h" 10 | #include "config/config.h" 11 | #include "dlpack/dlpack.h" 12 | 13 | #define LEN_UNKNOWN ULONG_MAX 14 | typedef struct RAI_Tensor { 15 | DLManagedTensor tensor; 16 | size_t len; 17 | long long refCount; 18 | size_t blobSize; 19 | } RAI_Tensor; 20 | -------------------------------------------------------------------------------- /src/redis_ai_types/model_type.c: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #include "model_type.h" 8 | #include "redis_ai_objects/model.h" 9 | #include "serialization/AOF/rai_aof_rewrite.h" 10 | #include "serialization/RDB/encoder/rai_rdb_encode.h" 11 | #include "serialization/RDB/decoder/rai_rdb_decoder.h" 12 | #include "serialization/RDB/decoder/decode_previous.h" 13 | 14 | extern RedisModuleType *RedisAI_ModelType; 15 | 16 | static void *RAI_Model_RdbLoad(struct RedisModuleIO *io, int encver) { 17 | if (encver > REDISAI_ENC_VER) { 18 | RedisModule_LogIOError( 19 | io, "error", "Failed loading model, RedisAI version (%d) is not forward compatible.\n", 20 | REDISAI_MODULE_VERSION); 21 | return NULL; 22 | } else if (encver < REDISAI_ENC_VER) { 23 | return Decode_PreviousModel(io, encver); 24 | } else { 25 | return RAI_RDBLoadModel(io); 26 | } 27 | } 28 | 29 | static void RAI_Model_RdbSave(RedisModuleIO *io, void *value) { RAI_RDBSaveModel(io, value); } 30 | 31 | static void RAI_Model_AofRewrite(RedisModuleIO *aof, RedisModuleString *key, void *value) { 32 | RAI_AOFRewriteModel(aof, key, value); 33 | } 34 | 35 | static void RAI_Model_DTFree(void *value) { 36 | RAI_Error err = {0}; 37 | RAI_ModelFree(value, &err); 38 | if (err.code != RAI_OK) { 39 | printf("ERR: %s\n", err.detail); 40 | RAI_ClearError(&err); 41 | } 42 | } 43 | 44 | int ModelType_Register(RedisModuleCtx *ctx) { 45 | RedisModuleTypeMethods tmModel = {.version = REDISMODULE_TYPE_METHOD_VERSION, 46 | .rdb_load = RAI_Model_RdbLoad, 47 | .rdb_save = RAI_Model_RdbSave, 48 | .aof_rewrite = RAI_Model_AofRewrite, 49 | .mem_usage = NULL, 50 | .free = RAI_Model_DTFree, 51 | .digest = NULL}; 52 | 53 | RedisAI_ModelType = RedisModule_CreateDataType(ctx, "AI__MODEL", REDISAI_ENC_VER, &tmModel); 54 | return RedisAI_ModelType != NULL; 55 | } 56 | -------------------------------------------------------------------------------- /src/redis_ai_types/model_type.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "redismodule.h" 10 | 11 | int ModelType_Register(RedisModuleCtx *ctx); 12 | -------------------------------------------------------------------------------- /src/redis_ai_types/script_type.c: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #include "script_type.h" 8 | #include "redis_ai_objects/script.h" 9 | #include "serialization/AOF/rai_aof_rewrite.h" 10 | #include "serialization/RDB/encoder/rai_rdb_encode.h" 11 | #include "serialization/RDB/decoder/rai_rdb_decoder.h" 12 | #include "serialization/RDB/decoder/decode_previous.h" 13 | 14 | extern RedisModuleType *RedisAI_ScriptType; 15 | 16 | static void *RAI_Script_RdbLoad(struct RedisModuleIO *io, int encver) { 17 | if (encver > REDISAI_ENC_VER) { 18 | RedisModule_LogIOError( 19 | io, "error", "Failed loading script, RedisAI version (%d) is not forward compatible.\n", 20 | REDISAI_MODULE_VERSION); 21 | return NULL; 22 | } else if (encver < REDISAI_ENC_VER) { 23 | return Decode_PreviousScript(io, encver); 24 | } else { 25 | return RAI_RDBLoadScript(io); 26 | } 27 | } 28 | 29 | static void RAI_Script_RdbSave(RedisModuleIO *io, void *value) { RAI_RDBSaveScript(io, value); } 30 | 31 | static void RAI_Script_AofRewrite(RedisModuleIO *aof, RedisModuleString *key, void *value) { 32 | RAI_AOFRewriteScript(aof, key, value); 33 | } 34 | 35 | static void RAI_Script_DTFree(void *value) { 36 | RAI_Error err = {0}; 37 | RAI_ScriptFree(value, &err); 38 | if (err.code != RAI_OK) { 39 | printf("ERR: %s\n", err.detail); 40 | RAI_ClearError(&err); 41 | } 42 | } 43 | 44 | int ScriptType_Register(RedisModuleCtx *ctx) { 45 | RedisModuleTypeMethods tmScript = {.version = REDISMODULE_TYPE_METHOD_VERSION, 46 | .rdb_load = RAI_Script_RdbLoad, 47 | .rdb_save = RAI_Script_RdbSave, 48 | .aof_rewrite = RAI_Script_AofRewrite, 49 | .mem_usage = NULL, 50 | .free = RAI_Script_DTFree, 51 | .digest = NULL}; 52 | 53 | RedisAI_ScriptType = RedisModule_CreateDataType(ctx, "AI_SCRIPT", REDISAI_ENC_VER, &tmScript); 54 | return RedisAI_ScriptType != NULL; 55 | } 56 | -------------------------------------------------------------------------------- /src/redis_ai_types/script_type.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "redismodule.h" 10 | 11 | int ScriptType_Register(RedisModuleCtx *ctx); 12 | -------------------------------------------------------------------------------- /src/redis_ai_types/tensor_type.c: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #include "tensor_type.h" 8 | #include "redis_ai_objects/tensor.h" 9 | #include "serialization/AOF/rai_aof_rewrite.h" 10 | #include "serialization/RDB/encoder/rai_rdb_encode.h" 11 | #include "serialization/RDB/decoder/rai_rdb_decoder.h" 12 | #include "serialization/RDB/decoder/decode_previous.h" 13 | 14 | extern RedisModuleType *RedisAI_TensorType; 15 | 16 | static void RAI_Tensor_RdbSave(RedisModuleIO *io, void *value) { RAI_RDBSaveTensor(io, value); } 17 | 18 | static void *RAI_Tensor_RdbLoad(struct RedisModuleIO *io, int encver) { 19 | if (encver > REDISAI_ENC_VER) { 20 | RedisModule_LogIOError( 21 | io, "error", "Failed loading tensor, RedisAI version (%d) is not forward compatible.\n", 22 | REDISAI_MODULE_VERSION); 23 | return NULL; 24 | } else if (encver < REDISAI_ENC_VER) { 25 | return Decode_PreviousTensor(io, encver); 26 | } else { 27 | return RAI_RDBLoadTensor(io); 28 | } 29 | } 30 | 31 | static void RAI_Tensor_AofRewrite(RedisModuleIO *aof, RedisModuleString *key, void *value) { 32 | RAI_AOFRewriteTensor(aof, key, value); 33 | } 34 | 35 | static void RAI_Tensor_DTFree(void *value) { RAI_TensorFree(value); } 36 | 37 | int TensorType_Register(RedisModuleCtx *ctx) { 38 | RedisModuleTypeMethods tmTensor = { 39 | .version = REDISMODULE_TYPE_METHOD_VERSION, 40 | .rdb_load = RAI_Tensor_RdbLoad, 41 | .rdb_save = RAI_Tensor_RdbSave, 42 | .aof_rewrite = RAI_Tensor_AofRewrite, 43 | .mem_usage = NULL, 44 | .free = RAI_Tensor_DTFree, 45 | .digest = NULL, 46 | }; 47 | RedisAI_TensorType = RedisModule_CreateDataType(ctx, "AI_TENSOR", REDISAI_ENC_VER, &tmTensor); 48 | return RedisAI_TensorType != NULL; 49 | } 50 | -------------------------------------------------------------------------------- /src/redis_ai_types/tensor_type.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "redismodule.h" 10 | 11 | int TensorType_Register(RedisModuleCtx *ctx); 12 | -------------------------------------------------------------------------------- /src/rmutil/alloc.c: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include "alloc.h" 11 | 12 | /* A patched implementation of strdup that will use our patched calloc */ 13 | char *rmalloc_strndup(const char *s, size_t n) { 14 | char *ret = calloc(n + 1, sizeof(char)); 15 | if (ret) 16 | memcpy(ret, s, n); 17 | return ret; 18 | } 19 | 20 | /* 21 | * Re-patching RedisModule_Alloc and friends to the original malloc functions 22 | * 23 | * This function shold be called if you are working with malloc-patched code 24 | * ouside of redis, usually for unit tests. Call it once when entering your unit 25 | * tests' main(). 26 | * 27 | * Since including "alloc.h" while defining REDIS_MODULE_TARGET 28 | * replaces all malloc functions in redis with the RM_Alloc family of functions, 29 | * when running that code outside of redis, your app will crash. This function 30 | * patches the RM_Alloc functions back to the original mallocs. */ 31 | void RMUTil_InitAlloc() { 32 | 33 | RedisModule_Alloc = malloc; 34 | RedisModule_Realloc = realloc; 35 | RedisModule_Calloc = calloc; 36 | RedisModule_Free = free; 37 | RedisModule_Strdup = strdup; 38 | } 39 | -------------------------------------------------------------------------------- /src/rmutil/alloc.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | 9 | /* Automatic Redis Module Allocation functions monkey-patching. 10 | * 11 | * Including this file while REDIS_MODULE_TARGET is defined, will explicitly 12 | * override malloc, calloc, realloc & free with RedisModule_Alloc, 13 | * RedisModule_Callc, etc implementations, that allow Redis better control and 14 | * reporting over allocations per module. 15 | * 16 | * You should include this file in all c files AS THE LAST INCLUDED FILE 17 | * 18 | * This only has effect when when compiling with the macro REDIS_MODULE_TARGET 19 | * defined. The idea is that for unit tests it will not be defined, but for the 20 | * module build target it will be. 21 | * 22 | */ 23 | 24 | #include 25 | #include "redismodule.h" 26 | 27 | char *rmalloc_strndup(const char *s, size_t n); 28 | 29 | #ifdef REDIS_MODULE_TARGET /* Set this when compiling your code as a module */ 30 | 31 | #define malloc(size) RedisModule_Alloc(size) 32 | #define calloc(count, size) RedisModule_Calloc(count, size) 33 | #define realloc(ptr, size) RedisModule_Realloc(ptr, size) 34 | #define free(ptr) RedisModule_Free(ptr) 35 | 36 | #ifdef strdup 37 | #undef strdup 38 | #endif 39 | #define strdup(ptr) RedisModule_Strdup(ptr) 40 | 41 | /* More overriding */ 42 | // needed to avoid calling strndup->malloc 43 | #ifdef strndup 44 | #undef strndup 45 | #endif 46 | #define strndup(s, n) rmalloc_strndup(s, n) 47 | 48 | #else 49 | 50 | #endif /* REDIS_MODULE_TARGET */ 51 | /* This function shold be called if you are working with malloc-patched code 52 | * ouside of redis, usually for unit tests. Call it once when entering your unit 53 | * tests' main() */ 54 | void RMUTil_InitAlloc(); 55 | -------------------------------------------------------------------------------- /src/rmutil/sdsalloc.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | /* SDS allocator selection. 8 | * 9 | * This file is used in order to change the SDS allocator at compile time. 10 | * Just define the following defines to what you want to use. Also add 11 | * the include of your alternate allocator if needed (not needed in order 12 | * to use the default libc allocator). */ 13 | 14 | #if defined(__MACH__) || defined(__FreeBSD__) 15 | #include 16 | #else 17 | #include 18 | #endif 19 | //#include "zmalloc.h" 20 | #define s_malloc malloc 21 | #define s_realloc realloc 22 | #define s_free free 23 | -------------------------------------------------------------------------------- /src/serialization/AOF/rai_aof_rewrite.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | #include "../serialization_include.h" 9 | 10 | void RAI_AOFRewriteTensor(RedisModuleIO *aof, RedisModuleString *key, void *value); 11 | 12 | void RAI_AOFRewriteModel(RedisModuleIO *aof, RedisModuleString *key, void *value); 13 | 14 | void RAI_AOFRewriteScript(RedisModuleIO *aof, RedisModuleString *key, void *value); 15 | -------------------------------------------------------------------------------- /src/serialization/RDB/decoder/current/v4/decode_v4.c: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #include "decode_v4.h" 8 | #include "../../previous/v3/decode_v3.h" 9 | #include "assert.h" 10 | 11 | /** 12 | * In case of IO errors, the default return values are: 13 | * numbers - 0 14 | * strings - null 15 | * So only when it is necessary check for IO errors. 16 | */ 17 | 18 | void *RAI_RDBLoadTensor_v4(RedisModuleIO *io) { 19 | DLDataTypeCode code = RedisModule_LoadUnsigned(io); 20 | uint8_t bits = RedisModule_LoadUnsigned(io); 21 | DLDataType data_type = (DLDataType){.code = code, .bits = bits, .lanes = 1}; 22 | 23 | int ndims = (int)RedisModule_LoadSigned(io); 24 | size_t shape[ndims]; 25 | for (size_t i = 0; i < ndims; ++i) { 26 | shape[i] = RedisModule_LoadSigned(io); 27 | } 28 | 29 | RAI_Tensor *tensor = RAI_TensorNew(data_type, shape, ndims); 30 | 31 | size_t blob_len; 32 | char *data = RedisModule_LoadStringBuffer(io, &blob_len); 33 | if (RedisModule_IsIOError(io)) 34 | goto error; 35 | 36 | tensor->blobSize = blob_len; 37 | tensor->tensor.dl_tensor.data = data; 38 | 39 | if (data_type.code == kDLString) { 40 | for (size_t i = 0; i < RAI_TensorLength(tensor); i++) { 41 | tensor->tensor.dl_tensor.elements_length[i] = RedisModule_LoadUnsigned(io); 42 | } 43 | } 44 | if (RedisModule_IsIOError(io)) 45 | goto error; 46 | return tensor; 47 | 48 | error: 49 | RedisModule_LogIOError(io, "error", "Experienced a short read while reading a tensor from RDB"); 50 | RAI_TensorFree(tensor); 51 | if (data) { 52 | RedisModule_Free(data); 53 | } 54 | return NULL; 55 | } 56 | 57 | void *RAI_RDBLoadModel_v4(RedisModuleIO *io) { return RAI_RDBLoadModel_v3(io); } 58 | 59 | void *RAI_RDBLoadScript_v4(RedisModuleIO *io) { return RAI_RDBLoadScript_v3(io); } 60 | -------------------------------------------------------------------------------- /src/serialization/RDB/decoder/current/v4/decode_v4.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | #include "serialization/serialization_include.h" 9 | 10 | void *RAI_RDBLoadTensor_v4(RedisModuleIO *io); 11 | 12 | void *RAI_RDBLoadModel_v4(RedisModuleIO *io); 13 | 14 | void *RAI_RDBLoadScript_v4(RedisModuleIO *io); 15 | -------------------------------------------------------------------------------- /src/serialization/RDB/decoder/decode_previous.c: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #include "decode_previous.h" 8 | #include "previous/v0/decode_v0.h" 9 | #include "previous/v1/decode_v1.h" 10 | #include "previous/v2/decode_v2.h" 11 | #include "previous/v3/decode_v3.h" 12 | 13 | void *Decode_PreviousTensor(RedisModuleIO *rdb, int encver) { 14 | switch (encver) { 15 | case 0: 16 | return RAI_RDBLoadTensor_v0(rdb); 17 | case 1: 18 | return RAI_RDBLoadTensor_v1(rdb); 19 | case 2: 20 | return RAI_RDBLoadTensor_v2(rdb); 21 | case 3: 22 | return RAI_RDBLoadTensor_v3(rdb); 23 | default: 24 | assert(false && "Invalid encoding version"); 25 | } 26 | return NULL; 27 | } 28 | 29 | void *Decode_PreviousModel(RedisModuleIO *rdb, int encver) { 30 | switch (encver) { 31 | case 0: 32 | return RAI_RDBLoadModel_v0(rdb); 33 | case 1: 34 | return RAI_RDBLoadModel_v1(rdb); 35 | case 2: 36 | return RAI_RDBLoadModel_v2(rdb); 37 | case 3: 38 | return RAI_RDBLoadModel_v3(rdb); 39 | default: 40 | assert(false && "Invalid encoding version"); 41 | } 42 | return NULL; 43 | } 44 | 45 | void *Decode_PreviousScript(RedisModuleIO *rdb, int encver) { 46 | switch (encver) { 47 | case 0: 48 | return RAI_RDBLoadScript_v0(rdb); 49 | case 1: 50 | return RAI_RDBLoadScript_v1(rdb); 51 | case 2: 52 | return RAI_RDBLoadScript_v2(rdb); 53 | case 3: 54 | return RAI_RDBLoadScript_v3(rdb); 55 | default: 56 | assert(false && "Invalid encoding version"); 57 | } 58 | return NULL; 59 | } -------------------------------------------------------------------------------- /src/serialization/RDB/decoder/decode_previous.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | #include "../../serialization_include.h" 9 | 10 | void *Decode_PreviousTensor(RedisModuleIO *rdb, int encver); 11 | 12 | void *Decode_PreviousModel(RedisModuleIO *rdb, int encver); 13 | 14 | void *Decode_PreviousScript(RedisModuleIO *rdb, int encver); -------------------------------------------------------------------------------- /src/serialization/RDB/decoder/previous/v0/decode_v0.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | #include "../../../../serialization_include.h" 9 | 10 | void *RAI_RDBLoadTensor_v0(RedisModuleIO *io); 11 | 12 | void *RAI_RDBLoadModel_v0(RedisModuleIO *io); 13 | 14 | void *RAI_RDBLoadScript_v0(RedisModuleIO *io); -------------------------------------------------------------------------------- /src/serialization/RDB/decoder/previous/v1/decode_v1.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | #include "serialization/serialization_include.h" 9 | 10 | void *RAI_RDBLoadTensor_v1(RedisModuleIO *io); 11 | 12 | void *RAI_RDBLoadModel_v1(RedisModuleIO *io); 13 | 14 | void *RAI_RDBLoadScript_v1(RedisModuleIO *io); -------------------------------------------------------------------------------- /src/serialization/RDB/decoder/previous/v2/decode_v2.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | #include "serialization/serialization_include.h" 9 | 10 | void *RAI_RDBLoadTensor_v2(RedisModuleIO *io); 11 | 12 | void *RAI_RDBLoadModel_v2(RedisModuleIO *io); 13 | 14 | void *RAI_RDBLoadScript_v2(RedisModuleIO *io); 15 | -------------------------------------------------------------------------------- /src/serialization/RDB/decoder/previous/v3/decode_v3.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | #include "serialization/serialization_include.h" 9 | 10 | void *RAI_RDBLoadTensor_v3(RedisModuleIO *io); 11 | 12 | void *RAI_RDBLoadModel_v3(RedisModuleIO *io); 13 | 14 | void *RAI_RDBLoadScript_v3(RedisModuleIO *io); 15 | -------------------------------------------------------------------------------- /src/serialization/RDB/decoder/rai_rdb_decoder.c: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #include "rai_rdb_decoder.h" 8 | #include "current/v4/decode_v4.h" 9 | 10 | void *RAI_RDBLoadTensor(RedisModuleIO *io) { return RAI_RDBLoadTensor_v4(io); } 11 | 12 | void *RAI_RDBLoadModel(RedisModuleIO *io) { return RAI_RDBLoadModel_v4(io); } 13 | 14 | void *RAI_RDBLoadScript(RedisModuleIO *io) { return RAI_RDBLoadScript_v4(io); } 15 | -------------------------------------------------------------------------------- /src/serialization/RDB/decoder/rai_rdb_decoder.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "../../serialization_include.h" 10 | 11 | void *RAI_RDBLoadTensor(RedisModuleIO *io); 12 | 13 | void *RAI_RDBLoadModel(RedisModuleIO *io); 14 | 15 | void *RAI_RDBLoadScript(RedisModuleIO *io); -------------------------------------------------------------------------------- /src/serialization/RDB/encoder/rai_rdb_encode.c: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #include "rai_rdb_encode.h" 8 | #include "v4/encode_v4.h" 9 | 10 | void RAI_RDBSaveTensor(RedisModuleIO *io, void *value) { RAI_RDBSaveTensor_v4(io, value); } 11 | 12 | void RAI_RDBSaveModel(RedisModuleIO *io, void *value) { RAI_RDBSaveModel_v4(io, value); } 13 | 14 | void RAI_RDBSaveScript(RedisModuleIO *io, void *value) { RAI_RDBSaveScript_v4(io, value); } 15 | -------------------------------------------------------------------------------- /src/serialization/RDB/encoder/rai_rdb_encode.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "../../serialization_include.h" 10 | 11 | void RAI_RDBSaveTensor(RedisModuleIO *io, void *value); 12 | 13 | void RAI_RDBSaveModel(RedisModuleIO *io, void *value); 14 | 15 | void RAI_RDBSaveScript(RedisModuleIO *io, void *value); 16 | -------------------------------------------------------------------------------- /src/serialization/RDB/encoder/v4/encode_v4.c: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #include "encode_v4.h" 8 | 9 | void RAI_RDBSaveTensor_v4(RedisModuleIO *io, void *value) { 10 | RAI_Tensor *tensor = (RAI_Tensor *)value; 11 | 12 | RedisModule_SaveUnsigned(io, tensor->tensor.dl_tensor.dtype.code); 13 | RedisModule_SaveUnsigned(io, tensor->tensor.dl_tensor.dtype.bits); 14 | 15 | size_t ndim = tensor->tensor.dl_tensor.ndim; 16 | RedisModule_SaveSigned(io, ndim); 17 | for (size_t i = 0; i < ndim; i++) { 18 | RedisModule_SaveSigned(io, tensor->tensor.dl_tensor.shape[i]); 19 | } 20 | 21 | size_t size = RAI_TensorByteSize(tensor); 22 | RedisModule_SaveStringBuffer(io, tensor->tensor.dl_tensor.data, size); 23 | 24 | if (tensor->tensor.dl_tensor.dtype.code == kDLString) { 25 | for (size_t i = 0; i < RAI_TensorLength(tensor); i++) { 26 | RedisModule_SaveUnsigned(io, tensor->tensor.dl_tensor.elements_length[i]); 27 | } 28 | } 29 | } 30 | 31 | void RAI_RDBSaveModel_v4(RedisModuleIO *io, void *value) { 32 | RAI_Model *model = (RAI_Model *)value; 33 | char *buffer = NULL; 34 | size_t len = 0; 35 | RAI_Error err = {0}; 36 | 37 | int ret = RAI_ModelSerialize(model, &buffer, &len, &err); 38 | 39 | if (err.code != RAI_OK) { 40 | RedisModuleCtx *stats_ctx = RedisModule_GetContextFromIO(io); 41 | printf("ERR: %s\n", err.detail); 42 | RAI_ClearError(&err); 43 | if (buffer) { 44 | RedisModule_Free(buffer); 45 | } 46 | return; 47 | } 48 | 49 | RedisModule_SaveUnsigned(io, model->backend); 50 | RedisModule_SaveStringBuffer(io, model->devicestr, strlen(model->devicestr) + 1); 51 | RedisModule_SaveString(io, model->tag); 52 | RedisModule_SaveUnsigned(io, model->opts.batchsize); 53 | RedisModule_SaveUnsigned(io, model->opts.minbatchsize); 54 | RedisModule_SaveUnsigned(io, model->opts.minbatchtimeout); 55 | RedisModule_SaveUnsigned(io, model->ninputs); 56 | for (size_t i = 0; i < model->ninputs; i++) { 57 | RedisModule_SaveStringBuffer(io, model->inputs[i], strlen(model->inputs[i]) + 1); 58 | } 59 | RedisModule_SaveUnsigned(io, model->noutputs); 60 | for (size_t i = 0; i < model->noutputs; i++) { 61 | RedisModule_SaveStringBuffer(io, model->outputs[i], strlen(model->outputs[i]) + 1); 62 | } 63 | long long chunk_size = Config_GetModelChunkSize(); 64 | const size_t n_chunks = len / chunk_size + 1; 65 | RedisModule_SaveUnsigned(io, len); 66 | RedisModule_SaveUnsigned(io, n_chunks); 67 | for (size_t i = 0; i < n_chunks; i++) { 68 | size_t chunk_len = i < n_chunks - 1 ? chunk_size : len % chunk_size; 69 | RedisModule_SaveStringBuffer(io, buffer + i * chunk_size, chunk_len); 70 | } 71 | 72 | if (buffer) { 73 | RedisModule_Free(buffer); 74 | } 75 | } 76 | 77 | void RAI_RDBSaveScript_v4(RedisModuleIO *io, void *value) { 78 | RAI_Script *script = (RAI_Script *)value; 79 | 80 | RedisModule_SaveStringBuffer(io, script->devicestr, strlen(script->devicestr) + 1); 81 | RedisModule_SaveString(io, script->tag); 82 | RedisModule_SaveStringBuffer(io, script->scriptdef, strlen(script->scriptdef) + 1); 83 | size_t nEntryPoints = array_len(script->entryPoints); 84 | 85 | RedisModule_SaveUnsigned(io, nEntryPoints); 86 | for (size_t i = 0; i < nEntryPoints; i++) { 87 | RedisModule_SaveStringBuffer(io, script->entryPoints[i], 88 | strlen(script->entryPoints[i]) + 1); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/serialization/RDB/encoder/v4/encode_v4.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | #include "../../../serialization_include.h" 9 | 10 | void RAI_RDBSaveTensor_v4(RedisModuleIO *io, void *value); 11 | 12 | void RAI_RDBSaveModel_v4(RedisModuleIO *io, void *value); 13 | 14 | void RAI_RDBSaveScript_v4(RedisModuleIO *io, void *value); 15 | -------------------------------------------------------------------------------- /src/serialization/ai_datatypes.c: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #include "serialization_include.h" 8 | 9 | RedisModuleType *RedisAI_TensorType = NULL; 10 | RedisModuleType *RedisAI_ModelType = NULL; 11 | RedisModuleType *RedisAI_ScriptType = NULL; 12 | -------------------------------------------------------------------------------- /src/serialization/serialization_include.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "redismodule.h" 10 | #include "redis_ai_objects/stats.h" 11 | #include "redis_ai_objects/model.h" 12 | #include "redis_ai_objects/tensor.h" 13 | #include "redis_ai_objects/script.h" 14 | #include "backends/backends.h" 15 | #include "version.h" 16 | #include "util/string_utils.h" 17 | -------------------------------------------------------------------------------- /src/util/dictionaries.c: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #include "dictionaries.h" 8 | #include "string_utils.h" 9 | #include "arr.h" 10 | 11 | static array_t dict_arr_clone_fn(void *privdata, const void *arr) { 12 | array_t dest; 13 | array_clone(dest, (array_t)arr); 14 | return dest; 15 | } 16 | 17 | static void dict_arr_free_fn(void *privdata, void *arr) { array_free(arr); } 18 | 19 | AI_dictType AI_dictTypeHeapStrings = { 20 | .hashFunction = RAI_StringsHashFunction, 21 | .keyDup = RAI_StringsKeyDup, 22 | .valDup = NULL, 23 | .keyCompare = RAI_StringsKeyCompare, 24 | .keyDestructor = RAI_StringsKeyDestructor, 25 | .valDestructor = NULL, 26 | }; 27 | 28 | AI_dictType AI_dictTypeHeapRStrings = { 29 | .hashFunction = RAI_RStringsHashFunction, 30 | .keyDup = RAI_RStringsKeyDup, 31 | .valDup = NULL, 32 | .keyCompare = RAI_RStringsKeyCompare, 33 | .keyDestructor = RAI_RStringsKeyDestructor, 34 | .valDestructor = NULL, 35 | }; 36 | 37 | AI_dictType AI_dictType_String_ArrSimple = { 38 | .hashFunction = RAI_StringsHashFunction, 39 | .keyDup = RAI_StringsKeyDup, 40 | .valDup = dict_arr_clone_fn, 41 | .keyCompare = RAI_StringsKeyCompare, 42 | .keyDestructor = RAI_StringsKeyDestructor, 43 | .valDestructor = dict_arr_free_fn, 44 | }; 45 | -------------------------------------------------------------------------------- /src/util/dictionaries.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | #include "dict.h" 9 | 10 | /** 11 | * @brief Dictionary key type: const char*. value type: void*. 12 | * 13 | */ 14 | extern AI_dictType AI_dictTypeHeapStrings; 15 | 16 | /** 17 | * @brief Dictionary key type: RedisModuleString*. value type: void*. 18 | * 19 | */ 20 | extern AI_dictType AI_dictTypeHeapRStrings; 21 | 22 | /** 23 | * @brief Dictionary key type: const char*. value type: arr. 24 | * 25 | */ 26 | extern AI_dictType AI_dictType_String_ArrSimple; 27 | -------------------------------------------------------------------------------- /src/util/queue.c: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "queue.h" 12 | #include "util/redisai_memory.h" 13 | #include "redismodule.h" 14 | 15 | queue *queueCreate(void) { 16 | 17 | queue *queue = RedisModule_Calloc(1, sizeof(*queue)); 18 | 19 | queue->front = queue->back = NULL; 20 | queue->len = 0; 21 | queue->free = NULL; 22 | return queue; 23 | } 24 | 25 | void queuePush(queue *queue, void *value) { 26 | 27 | queueItem *item = RedisModule_Calloc(1, sizeof(*item)); 28 | item->value = value; 29 | item->next = NULL; 30 | item->prev = NULL; 31 | 32 | if (queue->len == 0) { 33 | queue->front = queue->back = item; 34 | } else { 35 | queue->back->next = item; 36 | item->prev = queue->back; 37 | queue->back = item; 38 | } 39 | queue->len++; 40 | } 41 | 42 | void queuePushFront(queue *queue, void *value) { 43 | 44 | queueItem *item = RedisModule_Calloc(1, sizeof(*item)); 45 | 46 | item->value = value; 47 | item->next = NULL; 48 | item->prev = NULL; 49 | 50 | if (queue->len == 0) { 51 | queue->front = queue->back = item; 52 | } else { 53 | queue->front->prev = item; 54 | item->next = queue->front; 55 | queue->front = item; 56 | } 57 | queue->len++; 58 | } 59 | 60 | queueItem *queuePop(queue *queue) { 61 | queueItem *item = queue->front; 62 | if (item == NULL) { 63 | return NULL; 64 | } 65 | queue->front = item->next; 66 | if (queue->front != NULL) { 67 | queue->front->prev = NULL; 68 | } 69 | if (item == queue->back) { 70 | queue->back = NULL; 71 | } 72 | item->next = NULL; 73 | item->prev = NULL; 74 | queue->len--; 75 | return item; 76 | } 77 | 78 | queueItem *queueFront(queue *queue) { return queue->front; } 79 | 80 | queueItem *queueNext(queueItem *item) { return item->next; } 81 | 82 | queueItem *queueEvict(queue *queue, queueItem *item) { 83 | if (item == queue->front) { 84 | return queuePop(queue); 85 | } else if (item == queue->back) { 86 | queue->back = item->prev; 87 | queue->back->next = NULL; 88 | } else { 89 | item->prev->next = item->next; 90 | item->next->prev = item->prev; 91 | } 92 | 93 | item->next = NULL; 94 | item->prev = NULL; 95 | queue->len--; 96 | return item; 97 | } 98 | 99 | unsigned long queueLength(queue *queue) { return queue->len; } 100 | 101 | void queueRelease(queue *queue) { 102 | unsigned long len; 103 | queueItem *current; 104 | 105 | len = queue->len; 106 | while (len--) { 107 | current = queuePop(queue); 108 | if (current && queue->free) 109 | queue->free(current->value); 110 | RedisModule_Free(current); 111 | } 112 | queue->front = queue->back = NULL; 113 | queue->len = 0; 114 | } 115 | -------------------------------------------------------------------------------- /src/util/queue.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include "util/redisai_memory.h" 14 | #include "redismodule.h" 15 | 16 | typedef struct queueItem { 17 | struct queueItem *next; 18 | struct queueItem *prev; 19 | void *value; 20 | } queueItem; 21 | 22 | typedef struct queue { 23 | queueItem *front; 24 | queueItem *back; 25 | void (*free)(void *ptr); 26 | unsigned long len; 27 | } queue; 28 | 29 | queue *queueCreate(void); 30 | void queuePush(queue *queue, void *value); 31 | void queuePushFront(queue *queue, void *value); 32 | queueItem *queuePop(queue *queue); 33 | queueItem *queueFront(queue *queue); 34 | queueItem *queueNext(queueItem *item); 35 | queueItem *queueEvict(queue *queue, queueItem *item); 36 | unsigned long queueLength(queue *queue); 37 | void queueRelease(queue *queue); 38 | -------------------------------------------------------------------------------- /src/util/redisai_memory.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #ifndef SRC_REDISAI_MEMORY_H_ 8 | #define SRC_REDISAI_MEMORY_H_ 9 | 10 | #include "redismodule.h" 11 | #include "stdlib.h" 12 | #include 13 | 14 | #ifdef VALGRIND 15 | #define RA_ALLOC malloc 16 | #define RA_CALLOC calloc 17 | #define RA_REALLOC realloc 18 | #define RA_FREE free 19 | #define RA_STRDUP strdup 20 | #else 21 | #define RA_ALLOC RedisModule_Alloc 22 | #define RA_CALLOC RedisModule_Calloc 23 | #define RA_REALLOC RedisModule_Realloc 24 | #define RA_FREE RedisModule_Free 25 | #define RA_STRDUP RedisModule_Strdup 26 | #endif 27 | 28 | #endif /* SRC_REDISAI_MEMORY_H_ */ 29 | -------------------------------------------------------------------------------- /src/util/string_utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #include "string_utils.h" 8 | #include "dict.h" 9 | #include 10 | #include 11 | #include "util/redisai_memory.h" 12 | 13 | RedisModuleString *RAI_HoldString(RedisModuleString *str) { 14 | if (str == NULL) { 15 | return NULL; 16 | } 17 | RedisModuleString *out; 18 | if (RMAPI_FUNC_SUPPORTED(RedisModule_HoldString)) { 19 | out = RedisModule_HoldString(NULL, str); 20 | } else { 21 | RedisModule_RetainString(NULL, str); 22 | out = str; 23 | } 24 | return out; 25 | } 26 | 27 | uint64_t RAI_StringsHashFunction(const void *key) { 28 | return AI_dictGenHashFunction(key, strlen((char *)key)); 29 | } 30 | 31 | int RAI_StringsKeyCompare(void *privdata, const void *key1, const void *key2) { 32 | const char *strKey1 = key1; 33 | const char *strKey2 = key2; 34 | 35 | return strcmp(strKey1, strKey2) == 0; 36 | } 37 | 38 | void RAI_StringsKeyDestructor(void *privdata, void *key) { RA_FREE(key); } 39 | 40 | void *RAI_StringsKeyDup(void *privdata, const void *key) { return RA_STRDUP((char *)key); } 41 | 42 | uint64_t RAI_RStringsHashFunction(const void *key) { 43 | size_t len; 44 | const char *buffer = RedisModule_StringPtrLen((RedisModuleString *)key, &len); 45 | return AI_dictGenHashFunction(buffer, len); 46 | } 47 | 48 | int RAI_RStringsKeyCompare(void *privdata, const void *key1, const void *key2) { 49 | RedisModuleString *strKey1 = (RedisModuleString *)key1; 50 | RedisModuleString *strKey2 = (RedisModuleString *)key2; 51 | 52 | return RedisModule_StringCompare(strKey1, strKey2) == 0; 53 | } 54 | 55 | void RAI_RStringsKeyDestructor(void *privdata, void *key) { 56 | RedisModule_FreeString(NULL, (RedisModuleString *)key); 57 | } 58 | 59 | void *RAI_RStringsKeyDup(void *privdata, const void *key) { 60 | return RedisModule_CreateStringFromString(NULL, (RedisModuleString *)key); 61 | } 62 | 63 | void RAI_StringToUpper(const char *str, char *upper, size_t str_len) { 64 | // Assumption: upper buffer size is at least str_len. This can be used for 65 | // every binary string, we do not assume that the string is null-terminated. 66 | for (size_t i = 0; i < str_len; i++) { 67 | upper[i] = (char)toupper(str[i]); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/util/string_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #include "redismodule.h" 8 | #include "dict.h" 9 | 10 | RedisModuleString *RAI_HoldString(RedisModuleString *str); 11 | void RAI_StringToUpper(const char *str, char *upper, size_t str_len); 12 | 13 | uint64_t RAI_StringsHashFunction(const void *key); 14 | int RAI_StringsKeyCompare(void *privdata, const void *key1, const void *key2); 15 | void RAI_StringsKeyDestructor(void *privdata, void *key); 16 | void *RAI_StringsKeyDup(void *privdata, const void *key); 17 | 18 | uint64_t RAI_RStringsHashFunction(const void *key); 19 | int RAI_RStringsKeyCompare(void *privdata, const void *key1, const void *key2); 20 | void RAI_RStringsKeyDestructor(void *privdata, void *key); 21 | void *RAI_RStringsKeyDup(void *privdata, const void *key); 22 | -------------------------------------------------------------------------------- /src/version.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | 9 | #define REDISAI_VERSION_MAJOR 99 10 | #define REDISAI_VERSION_MINOR 99 11 | #define REDISAI_VERSION_PATCH 99 12 | 13 | #define REDISAI_MODULE_VERSION \ 14 | (REDISAI_VERSION_MAJOR * 10000 + REDISAI_VERSION_MINOR * 100 + REDISAI_VERSION_PATCH) 15 | 16 | /* API versions. */ 17 | #define REDISAI_LLAPI_VERSION 1 18 | 19 | static const long long REDISAI_ENC_VER = 4; 20 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedisAI/redis-inference-optimization/c458c5f83e93ee07963af7123e9ad17b52389bcd/tests/__init__.py -------------------------------------------------------------------------------- /tests/flow/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RedisAI/redis-inference-optimization/c458c5f83e93ee07963af7123e9ad17b52389bcd/tests/flow/__init__.py -------------------------------------------------------------------------------- /tests/flow/test_data_files.txt: -------------------------------------------------------------------------------- 1 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/__init__.py 2 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/Pads.bin 3 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/batchdim_mismatch.onnx 4 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/batchdim_mismatch.pt 5 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/creditcardfraud.pb 6 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/graph.pb 7 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/identity_string.pb 8 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/identity_string.onnx 9 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/imagenet/__init__.py 10 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/imagenet/data_processing_script.txt 11 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/imagenet/cat.jpg 12 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/frozen_bad_model.pb 13 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/imagenet/dog.jpg 14 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/imagenet/data_processing_script_old.txt 15 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/imagenet/model_checker.py 16 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/graph_v2.pb 17 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/imagenet/model_saver.py 18 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/creditcard_10K.csv 19 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/imagenet/imagenet_class_index.json 20 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/imagenet_class_index.json 21 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/linear_iris.onnx 22 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/logreg_iris.onnx 23 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/lite-model_imagenet_mobilenet_v3_small_100_224_classification_5_default_1.tflite 24 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/mnist_batched.onnx 25 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/mnist.onnx 26 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/mnist_model_quant.tflite 27 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/mobilenet/__init__.py 28 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/inception-v2-9.onnx 29 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/mobilenet/mobilenet_v1_100_224_cpu_NxHxWxC.pb 30 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/mobilenet/mobilenet_v1_100_224_gpu_NxHxWxC.pb 31 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/mobilenet/model_saver.py 32 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/imagenet/resnet50.pb 33 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/mobilenet/mobilenet_v2_1.4_224_frozen.pb 34 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/model_with_infinite_loop.onnx 35 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/model_with_external_initializers.onnx 36 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/mul_1.onnx 37 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/one.raw 38 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/onnx_batch.py 39 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/onnx_batchdim_mismatch.py 40 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/onnx_string_identity.py 41 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/panda-224x224.jpg 42 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/panda.jpg 43 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/pt-minimal-bb.pt 44 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/pt_minimal.py 45 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/pt_minimal_bb.py 46 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/pt-minimal.pt 47 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/redis_scripts.py 48 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/rdb_test_prep_script.py 49 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/script_bad.txt 50 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/tf-minimal.py 51 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/tf2-minimal.py 52 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/tf_string_identity.py 53 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/mobilenet_v2_1.4_224_frozen.pb 54 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/old_script.txt 55 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/mobilenet/mobilenet_v1_100_224_gpu_NxHxWxC_fp16_trt.pb 56 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/one.png 57 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/script.txt 58 | http://dev.cto.redis.s3.amazonaws.com/RedisAI/test_data/bert-base-cased.onnx 59 | -------------------------------------------------------------------------------- /tests/flow/tests_sanitizer.py: -------------------------------------------------------------------------------- 1 | # Copyright Redis Ltd. 2018 - present 2 | # Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 3 | # the Server Side Public License v1 (SSPLv1). 4 | 5 | import redis 6 | from functools import wraps 7 | import multiprocessing as mp 8 | from includes import * 9 | 10 | ''' 11 | python -m RLTest --test tests_sanitizer.py --module path/to/redisai.so 12 | ''' 13 | 14 | 15 | def test_sanitizer_dagrun_mobilenet_v1(env): 16 | if (not TEST_TF or not TEST_PT): 17 | return 18 | con = get_connection(env, '{s}') 19 | mem_allocator = con.info()['mem_allocator'] 20 | if 'jemalloc' in mem_allocator: 21 | print("exiting sanitizer tests given we're not using stdlib allocator") 22 | return 23 | 24 | model_name = 'mobilenet_v1{s}' 25 | model_pb, input_var, output_var, labels, img = load_mobilenet_v1_test_data() 26 | 27 | ret = con.execute_command('AI.MODELSTORE', model_name, 'TF', DEVICE, 28 | 'INPUTS', 1, input_var, 29 | 'OUTPUTS', 1, output_var, 30 | 'BLOB', model_pb) 31 | env.assertEqual(ret, b'OK') 32 | 33 | for opnumber in range(1, MAX_ITERATIONS): 34 | image_key = 'image{{s}}{}'.format(opnumber) 35 | class_key = 'output{s}' 36 | 37 | ret = con.execute_command( 38 | 'AI.DAGEXECUTE', 'ROUTING', '{s}', '|>', 39 | 'AI.TENSORSET', image_key, 'FLOAT', 1, 224, 224, 3, 'BLOB', img.tobytes(), 40 | '|>', 41 | 'AI.MODELEXECUTE', model_name, 'INPUTS', 1, image_key, 'OUTPUTS', 1, class_key, 42 | '|>', 'AI.TENSORGET', class_key, 'blob') 43 | env.assertEqual([b'OK', b'OK'], ret[:2]) 44 | env.assertEqual(1001.0, len(ret[2])/4) 45 | 46 | 47 | def test_sanitizer_modelrun_mobilenet_v1(env): 48 | if (not TEST_TF or not TEST_PT): 49 | return 50 | con = get_connection(env, '{s}') 51 | mem_allocator = con.info()['mem_allocator'] 52 | if 'jemalloc' in mem_allocator: 53 | print("exiting sanitizer tests given we're not using stdlib allocator") 54 | return 55 | 56 | model_name = 'mobilenet_v1{s}' 57 | model_pb, input_var, output_var, labels, img = load_mobilenet_v1_test_data() 58 | 59 | ret = con.execute_command('AI.MODELSTORE', model_name, 'TF', DEVICE, 60 | 'INPUTS', 1, input_var, 61 | 'OUTPUTS', 1, output_var, 62 | 'BLOB', model_pb) 63 | env.assertEqual(ret, b'OK') 64 | 65 | for opnumber in range(1, MAX_ITERATIONS): 66 | image_key = 'image{s}' 67 | temp_key1 = 'temp_key1{s}' 68 | temp_key2 = 'temp_key2{s}' 69 | class_key = 'output{s}' 70 | ret = con.execute_command( 71 | 'AI.TENSORSET', image_key, 'FLOAT', 1, 224, 224, 3, 'BLOB', img.tobytes() 72 | ) 73 | env.assertEqual(b'OK', ret) 74 | 75 | ret = con.execute_command( 76 | 'AI.MODELEXECUTE', model_name, 77 | 'INPUTS', 1, image_key, 78 | 'OUTPUTS', 1, class_key 79 | ) 80 | 81 | env.assertEqual(b'OK', ret) 82 | 83 | ret = con.execute_command('AI.TENSORGET', class_key, 'blob') 84 | 85 | env.assertEqual(1001.0, len(ret)/4) 86 | -------------------------------------------------------------------------------- /tests/flow/tests_setup/Install_RedisGears.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" 6 | ROOT=$(cd $HERE/../../.. && pwd) 7 | READIES=$ROOT/opt/readies 8 | . $READIES/shibumi/defs 9 | 10 | if [[ "$1" == "--help" || "$1" == "help" || "$HELP" == "1" ]]; then 11 | cat <<-END 12 | Obtain RedisGears module binaries 13 | 14 | Install_RedisGears.sh [--help|help] 15 | 16 | Argument variables: 17 | GEARS_OSNICK=nick Get binaries for give osnick 18 | GEARS_PATH=dir Get binaries from given Gears repo 19 | NOP=1 No operation 20 | HELP=1 Show help 21 | 22 | END 23 | exit 0 24 | fi 25 | 26 | OP="" 27 | [[ "$NOP" == "1" ]] && OP=echo 28 | 29 | os="$($READIES/bin/platform --os)" 30 | arch="$($READIES/bin/platform --arch)" 31 | 32 | if [[ ! -z "$GEARS_PATH" ]]; then 33 | platform="$($READIES/bin/platform -t)" 34 | else 35 | if [[ "$os" != "linux" || "$arch" != "x64" ]]; then 36 | eprint "Cannot match binary artifacts - build RedisGears and set GEARS_PATH" 37 | exit 1 38 | fi 39 | 40 | dist="$($READIES/bin/platform --dist)" 41 | nick="$($READIES/bin/platform --osnick)" 42 | 43 | if [[ $dist == "ubuntu" ]]; then 44 | if [[ $nick != "bionic" && $nick != "xenial" && $nick != "trusty" ]]; then 45 | nick="bionic" 46 | fi 47 | elif [[ $dist == debian ]]; then 48 | nick=bionic 49 | elif [[ $dist == centos || $dist == redhat || $dist == fedora ]]; then 50 | nick=centos7 51 | elif [[ ! -z "$GEARS_OSNICK" ]]; then 52 | nick=$GEARS_OSNICK 53 | else 54 | eprint "Cannot match binary artifacts - build RedisGears and set GEARS_PATH" 55 | exit 1 56 | fi 57 | platform="${os}-${nick}-${arch}" 58 | fi 59 | 60 | GEARS_S3_URL="http://redismodules.s3.amazonaws.com/redisgears/snapshots" 61 | GEARS_MOD="redisgears.${platform}.master.zip" 62 | GEARS_DEPS="redisgears-python.${platform}.master.tgz" 63 | 64 | FINAL_WORK_DIR="$ROOT/bin/$($READIES/bin/platform -t)/RedisGears" 65 | 66 | if [[ -d $FINAL_WORK_DIR && -f $FINAL_WORK_DIR/redisgears.so ]]; then 67 | echo "RedisGears is in ${FINAL_WORK_DIR}" 68 | exit 0 69 | fi 70 | 71 | $OP mkdir -p $(dirname $FINAL_WORK_DIR) 72 | $OP rm -rf ${FINAL_WORK_DIR}.* 73 | WORK_DIR=$(mktemp -d ${FINAL_WORK_DIR}.XXXXXX) 74 | $OP mkdir -p $WORK_DIR 75 | 76 | if [[ -z $GEARS_PATH ]]; then 77 | F_GEARS_MOD="$WORK_DIR/$GEARS_MOD" 78 | if [[ ! -f $F_GEARS_MOD ]]; then 79 | echo "Download RedisGears ..." 80 | $OP wget -q -P $WORK_DIR $GEARS_S3_URL/$GEARS_MOD 81 | fi 82 | 83 | F_GEARS_DEPS="$WORK_DIR/$GEARS_DEPS" 84 | if [[ ! -f $F_GEARS_DEPS ]]; then 85 | echo "Download RedisGears deps ..." 86 | $OP wget -q -P $WORK_DIR $GEARS_S3_URL/$GEARS_DEPS 87 | fi 88 | else 89 | F_GEARS_MOD="${GEARS_PATH}/artifacts/snapshot/${GEARS_MOD}" 90 | F_GEARS_DEPS="${GEARS_PATH}/artifacts/snapshot/${GEARS_DEPS}" 91 | [[ ! -f $F_GEARS_MOD ]] && { eprint "$F_GEARS_MOD is missing"; exit 1; } 92 | [[ ! -f $F_GEARS_DEPS ]] && { eprint "$F_GEARS_DEPS is missing"; exit 1; } 93 | fi 94 | 95 | $OP unzip -q $F_GEARS_MOD -d $WORK_DIR 96 | $OP tar --no-same-owner -C $WORK_DIR -xzf $F_GEARS_DEPS 97 | $OP mv $WORK_DIR $FINAL_WORK_DIR 98 | -------------------------------------------------------------------------------- /tests/flow/tests_setup/test_requirements.txt: -------------------------------------------------------------------------------- 1 | numpy>=1.19 2 | scikit-image 3 | redisai 4 | redis~=4.1.4 5 | rltest~=0.5.0 6 | ramp-packer~=2.3.0 7 | -------------------------------------------------------------------------------- /tests/flow/tests_setup/tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | [[ $VERBOSE == 1 ]] && set -x 4 | [[ $IGNERR == 1 ]] || set -e 5 | 6 | error() { 7 | echo "There are errors:" 8 | gawk 'NR>L-4 && NR>> ":""),$0 }' L=$1 $0 9 | exit 1 10 | } 11 | 12 | [[ -z $_Dbg_DEBUGGER_LEVEL ]] && trap 'error $LINENO' ERR 13 | 14 | HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" 15 | export ROOT=$(cd $HERE/../../..; pwd) 16 | . $ROOT/opt/readies/shibumi/functions 17 | 18 | cd $HERE 19 | 20 | #---------------------------------------------------------------------------------------------- 21 | 22 | help() { 23 | cat <<-END 24 | Run Python tests. 25 | 26 | [ARGVARS...] tests.sh [--help|help] [] 27 | 28 | Argument variables: 29 | VERBOSE=1 Print commands 30 | IGNERR=1 Do not abort on error 31 | 32 | MODULE=path Path to redisai.so 33 | TESTMOD=path Path to LLAPI module 34 | 35 | DEVICE=cpu|gpu Device for testing 36 | GEN=0|1 General tests 37 | SLAVES=0|1 Tests with --test-slaves 38 | 39 | TEST=test Run specific test (e.g. test.py:test_name) 40 | LOG=0|1 Write to log 41 | VALGRIND|VGD=1 Run with Valgrind 42 | CALLGRIND|CGD=1 Run with Callgrind 43 | 44 | END 45 | } 46 | 47 | #---------------------------------------------------------------------------------------------- 48 | 49 | check_redis_server() { 50 | if ! command -v redis-server > /dev/null; then 51 | echo "Cannot find redis-server. Aborting." 52 | exit 1 53 | fi 54 | } 55 | 56 | #---------------------------------------------------------------------------------------------- 57 | 58 | valgrind_config() { 59 | export VG_OPTIONS=" 60 | -q \ 61 | --leak-check=full \ 62 | --show-reachable=no \ 63 | --show-possibly-lost=no" 64 | 65 | VALGRIND_SUPRESSIONS=$ROOT/opt/redis_valgrind.sup 66 | 67 | RLTEST_ARGS+="\ 68 | --use-valgrind \ 69 | --vg-suppressions $VALGRIND_SUPRESSIONS 70 | --cluster_node_timeout 60000" 71 | } 72 | 73 | valgrind_summary() { 74 | # Collect name of each flow log that contains leaks 75 | FILES_WITH_LEAKS=$(grep -l "definitely lost" logs/*.valgrind.log) 76 | if [[ ! -z $FILES_WITH_LEAKS ]]; then 77 | echo "Memory leaks introduced in flow tests." 78 | echo $FILES_WITH_LEAKS 79 | # Print the full Valgrind output for each leaking file 80 | echo $FILES_WITH_LEAKS | xargs cat 81 | exit 1 82 | else 83 | echo Valgrind test ok 84 | fi 85 | } 86 | 87 | #---------------------------------------------------------------------------------------------- 88 | 89 | get_tests_data() { 90 | local TEST_DATA_PATH=$ROOT/tests/flow/test_data 91 | if [ ! -d ${TEST_DATA_PATH} ]; then 92 | echo "Downloading tests data from s3..." 93 | wget -q -x -nH --cut-dirs=2 -i $ROOT/tests/flow/test_data_files.txt -P $ROOT/tests/flow/test_data 94 | echo "Done" 95 | fi 96 | } 97 | 98 | #---------------------------------------------------------------------------------------------- 99 | 100 | run_tests() { 101 | local title="$1" 102 | [[ ! -z $title ]] && { $ROOT/opt/readies/bin/sep -0; printf "Tests with $title:\n\n"; } 103 | cd $ROOT/tests/flow 104 | $OP python3 -m RLTest --clear-logs --module $MODULE $RLTEST_ARGS 105 | } 106 | 107 | #---------------------------------------------------------------------------------------------- 108 | 109 | [[ $1 == --help || $1 == help ]] && { help; exit 0; } 110 | 111 | DEVICE=${DEVICE:-cpu} 112 | 113 | GEN=${GEN:-1} 114 | SLAVES=${SLAVES:-0} 115 | 116 | GDB=${GDB:-0} 117 | 118 | OP="" 119 | [[ $NOP == 1 ]] && OP="echo" 120 | 121 | MODULE=${MODULE:-$1} 122 | [[ -z $MODULE || ! -f $MODULE ]] && { echo "Module not found at ${MODULE}. Aborting."; exit 1; } 123 | TESTMOD=${TESTMOD} 124 | echo "Test module path is ${TESTMOD}" 125 | 126 | [[ $VALGRIND == 1 || $VGD == 1 ]] && valgrind_config 127 | 128 | if [[ ! -z $TEST ]]; then 129 | RLTEST_ARGS+=" --test $TEST" 130 | if [[ $LOG != 1 ]]; then 131 | RLTEST_ARGS+=" -s" 132 | export PYDEBUG=${PYDEBUG:-1} 133 | fi 134 | fi 135 | 136 | [[ $VERBOSE == 1 ]] && RLTEST_ARGS+=" -v" 137 | [[ $GDB == 1 ]] && RLTEST_ARGS+=" -i --verbose" 138 | 139 | #---------------------------------------------------------------------------------------------- 140 | 141 | cd $ROOT/tests/flow/tests_setup 142 | 143 | check_redis_server 144 | ./Install_RedisGears.sh 145 | get_tests_data 146 | 147 | [[ ! -z $REDIS ]] && RL_TEST_ARGS+=" --env exiting-env --existing-env-addr $REDIS" run_tests "redis-server: $REDIS" 148 | [[ $GEN == 1 ]] && run_tests 149 | [[ $CLUSTER == 1 ]] && RLTEST_ARGS+=" --env oss-cluster --shards-count 3" run_tests "--env oss-cluster" 150 | [[ $VALGRIND != 1 && $SLAVES == 1 ]] && RLTEST_ARGS+=" --use-slaves" run_tests "--use-slaves" 151 | # [[ $VALGRIND == 1 ]] && valgrind_summary 152 | exit 0 153 | -------------------------------------------------------------------------------- /tests/flow/tests_setup/valgrind.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | [[ $VERBOSE == 1 ]] && set -x 4 | [[ $IGNERR == 1 ]] || set -e 5 | 6 | error() { 7 | echo "There are errors." 8 | exit 1 9 | } 10 | 11 | # trap error ERR 12 | 13 | HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" 14 | export ROOT=$(cd $HERE/../..; pwd) 15 | . $ROOT/opt/readies/shibumi/functions 16 | 17 | cd $HERE 18 | 19 | #---------------------------------------------------------------------------------------------- 20 | 21 | help() { 22 | cat <<-END 23 | Run Valgrind/Callgrind on RedisAI. 24 | 25 | [ARGVARS...] valgrind.sh [--help|help] [] 26 | 27 | Argument variables: 28 | VERBOSE=1 Print commands 29 | IGNERR=1 Do not abort on error 30 | 31 | CALLGRIND|CGD=1 Run with Callgrind 32 | 33 | END 34 | } 35 | 36 | #---------------------------------------------------------------------------------------------- 37 | 38 | check_redis_server() { 39 | if ! command -v redis-server > /dev/null; then 40 | echo "Cannot find redis-server. Aborting." 41 | exit 1 42 | fi 43 | } 44 | 45 | #---------------------------------------------------------------------------------------------- 46 | 47 | valgrind_config() { 48 | VALGRIND_SUPRESSIONS=$ROOT/opt/redis_valgrind.sup 49 | 50 | if [[ $CALLGRIND == 1 ]]; then 51 | 52 | VALGRIND_OPTIONS+="\ 53 | --tool=callgrind \ 54 | --dump-instr=yes \ 55 | --simulate-cache=no \ 56 | --collect-jumps=no \ 57 | --collect-atstart=yes \ 58 | --instr-atstart=yes \ 59 | --callgrind-out-file=$MODULE.call" 60 | else 61 | VALGRIND_OPTIONS+="\ 62 | -q \ 63 | --suppressions=$VALGRIND_SUPRESSIONS \ 64 | --leak-check=full \ 65 | --show-reachable=no \ 66 | --show-possibly-lost=no \ 67 | --show-leak-kinds=all" 68 | fi 69 | 70 | VALGRIND_OPTIONS+=" -v" 71 | } 72 | 73 | #---------------------------------------------------------------------------------------------- 74 | 75 | [[ $1 == --help || $1 == help ]] && { help; exit 0; } 76 | 77 | OP="" 78 | [[ $NOP == 1 ]] && OP="echo" 79 | 80 | MODULE=${MODULE:-$1} 81 | [[ -z $MODULE || ! -f $MODULE ]] && { echo "Module not found. Aborting."; exit 1; } 82 | 83 | VALGRIND_OPTIONS="" 84 | valgrind_config 85 | 86 | #---------------------------------------------------------------------------------------------- 87 | 88 | check_redis_server 89 | $OP valgrind $(echo "$VALGRIND_OPTIONS") redis-server --protected-mode no --save '' --appendonly no --loadmodule $MODULE 90 | -------------------------------------------------------------------------------- /tests/module/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ADD_LIBRARY(testmod SHARED LLAPI.c DAG_utils.c) 2 | 3 | INCLUDE_DIRECTORIES(../../src) 4 | SET_TARGET_PROPERTIES(testmod PROPERTIES PREFIX "") 5 | SET_TARGET_PROPERTIES(testmod PROPERTIES SUFFIX ".so") 6 | -------------------------------------------------------------------------------- /tests/module/DAG_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | *Copyright Redis Ltd. 2018 - present 3 | *Licensed under your choice of the Redis Source Available License 2.0 (RSALv2) or 4 | *the Server Side Public License v1 (SSPLv1). 5 | */ 6 | 7 | #pragma once 8 | #include "redisai.h" 9 | #include 10 | #include 11 | 12 | #define LLAPIMODULE_OK 0 13 | #define LLAPIMODULE_ERR 1 14 | 15 | typedef struct RAI_RunCtx { 16 | RAI_Tensor **outputs; 17 | RAI_Error *error; 18 | pthread_mutex_t lock; 19 | pthread_cond_t cond; 20 | } RAI_RunCtx; 21 | 22 | int testLoadTensor(RedisModuleCtx *ctx); 23 | 24 | int testModelRunOpError(RedisModuleCtx *ctx); 25 | 26 | int testEmptyDAGError(RedisModuleCtx *ctx); 27 | 28 | int testKeysMismatchError(RedisModuleCtx *ctx); 29 | 30 | int testBuildDAGFromString(RedisModuleCtx *ctx); 31 | 32 | int testSimpleDAGRun(RedisModuleCtx *ctx); 33 | 34 | int testSimpleDAGRun2(RedisModuleCtx *ctx); 35 | 36 | int testSimpleDAGRun2Error(RedisModuleCtx *ctx); 37 | 38 | int testDAGResnet(RedisModuleCtx *ctx); 39 | -------------------------------------------------------------------------------- /tests/qa/RS_VERSIONS: -------------------------------------------------------------------------------- 1 | 6.2.4-54 2 | 6.2.8-53 3 | 6.2.10-129 4 | 6.2.12-82 5 | 6.2.18-49 6 | 6.4.0-48 7 | 6.4.2-8 8 | 100.0.0-2988 9 | -------------------------------------------------------------------------------- /tests/qa/RS_VERSIONS-lite: -------------------------------------------------------------------------------- 1 | 6.0.12-58 2 | 6.0.20-101 3 | 6.2.4-54 4 | 6.2.8-53 5 | 6.2.10-129 6 | 6.2.12-82 7 | 6.2.18-49 8 | 6.4.0-48 9 | 6.4.2-8 10 | 100.0.0-2988 11 | -------------------------------------------------------------------------------- /tests/qa/nightly.json: -------------------------------------------------------------------------------- 1 | { 2 | "service_id": "single_module_test_cycle", 3 | "name": "redisai{{VARIANT}} automation-testing", 4 | "properties": { 5 | "sut_version": "master", 6 | "email_recipients": "redisaidev-aaaacob2o7eeecrhkqwua77kku@redislabs.slack.com", 7 | "sut_environments": [], 8 | "tools_environment": {}, 9 | "modules_version": "master", 10 | "test_names_modules": [ 11 | "{{RS_MODULE}}" 12 | ], 13 | "cycle_environments_setup": [ 14 | { 15 | "teardown": true, 16 | "name": "bionic-amd64-aws", 17 | "concurrency": 1, 18 | "module_url": "http://redismodules.s3.amazonaws.com/{{RS_MODULE_FILE_PREFIX}}/snapshots/{{RS_MODULE_FILE_PREFIX}}-cpu.linux-bionic-x64.master{{VARIANT}}.zip" 19 | } 20 | ] 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tests/qa/release.json: -------------------------------------------------------------------------------- 1 | { 2 | "service_id": "single_module_test_cycle", 3 | "name": "redisai{{VARIANT}} automation-testing", 4 | "properties": { 5 | "sut_version": "{{RS_VERSION}}", 6 | "email_recipients": "redisaidev-aaaacob2o7eeecrhkqwua77kku@redislabs.slack.com", 7 | "sut_environments": [], 8 | "tools_environment": {}, 9 | "modules_version": "{{MODULE_VERSION}}", 10 | "test_names_modules": [ 11 | "{{RS_MODULE}}" 12 | ], 13 | "cycle_environments_setup": [ 14 | { 15 | "teardown": true, 16 | "name": "bionic-amd64-aws", 17 | "concurrency": 1, 18 | "module_url": "http://redismodules.s3.amazonaws.com/{{RS_MODULE_LC}}/{{RS_MODULE_FILE_PREFIX}}.linux-bionic-x64.{{MODULE_VERSION}}{{VARIANT}}.zip" 19 | }, 20 | { 21 | "teardown": true, 22 | "name": "rhel8.5-x86_64-aws", 23 | "concurrency": 1, 24 | "module_url": "http://redismodules.s3.amazonaws.com/{{RS_MODULE_FILE_PREFIX}}/{{RS_MODULE_FILE_PREFIX}}.Linux-rhel8-x86_64.{{MODULE_VERSION}}.zip" 25 | }, 26 | { 27 | "teardown": true, 28 | "name": "focal-amd64-aws", 29 | "concurrency": 1, 30 | "module_url": "http://redismodules.s3.amazonaws.com/{{RS_MODULE_LC}}/{{RS_MODULE_FILE_PREFIX}}.Linux-focal-x64.{{MODULE_VERSION}}{{VARIANT}}.zip" 31 | } 32 | ] 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tests/qa/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" 4 | ROOT=$(cd $HERE/../.. && pwd) 5 | READIES=$ROOT/opt/readies 6 | 7 | (( VERBOSE > 1 )) && { set -x; PS4='$LINENO: '; } 8 | 9 | if [[ $1 == --help || $1 == help ]]; then 10 | cat <<-END 11 | Invoke QA Automation tests 12 | 13 | [ARGVARS...] run [--help|help] 14 | 15 | Argument variables: 16 | QA_AUTOMATION_TOKEN=token QA automation (Opereto) token 17 | TEST=name Name of .json parameters file 18 | MODULE_VERSION=ver Module version to test. Default: master 19 | NOP=1 Do not execute automation command 20 | VERBOSE=N Set verbosity level (N=1,2) 21 | QUICK=1 Only test one RS version 22 | 23 | Other configuration: 24 | RS_VERSIONS file includes Redis Enterprive versions for release tests. 25 | 26 | END 27 | exit 0 28 | fi 29 | 30 | export RS_MODULE=RedisAI 31 | export RS_MODULE_LC=${RS_MODULE,,} 32 | export RS_MODULE_FILE_PREFIX=redisai-cpu 33 | export VARIANT=${VARIANT} # for variants such as RedisAILite. We append -lite (see circleci for an example) 34 | 35 | if [[ -z $QA_AUTOMATION_TOKEN && $NOP != 1 ]]; then 36 | echo "Variable QA_AUTOMATION_TOKEN is undefined." >&2 37 | exit 1 38 | fi 39 | 40 | export TEST=${TEST:-release} 41 | if [[ ! -f $HERE/$TEST.json ]]; then 42 | echo "Invalid TEST name: $TEST" >&2 43 | exit 1 44 | fi 45 | 46 | run_test() { 47 | set -x 48 | export RS_VERSION=$1 49 | 50 | if [[ -z $MODULE_VERSION ]]; then 51 | export MODULE_VERSION=master 52 | else 53 | export MODULE_VERSION=$(echo "$MODULE_VERSION" | sed 's/^v\(.*\)/\1/') 54 | fi 55 | 56 | results() { 57 | echo "$JSON" | jq "$1" | cut -d\" -f2 58 | } 59 | 60 | cd $HERE 61 | 62 | json_in=$(mktemp /tmp/$TEST.json.XXXX) 63 | $READIES/bin/xtx -e VARIANT -e RS_MODULE -e RS_MODULE_LC -e RS_MODULE_FILE_PREFIX -e MODULE_VERSION -e RS_VERSION $TEST.json > $json_in 64 | (( VERBOSE >= 1 )) && cat $json_in 65 | 66 | if [[ $NOP == 1 ]]; then 67 | echo "Testing RS $RS_VERSION" 68 | return 0 69 | fi 70 | 71 | OPERETO3_URL="opereto.qa.redislabs.com" 72 | JSON=$(curl -sk \ 73 | -X POST -H "Content-Type: application/json" \ 74 | -H "Authorization: Bearer $QA_AUTOMATION_TOKEN" \ 75 | -d @$json_in \ 76 | https://$OPERETO3_URL/processes 2>&1) 77 | rc=$? 78 | rm $json_in 79 | status=$(results .status) 80 | if [[ $rc == 0 && $status == success ]]; then 81 | id=$(results .data[0]) 82 | echo "Tests running on $MODULE_VERSION for RS $RS_VERSION" 83 | echo "Results: https://$OPERETO3_URL/ui#dashboard/flow/$id" 84 | return 0 85 | else 86 | err=$(results .message) 87 | echo "Failed to run tests on $MODULE_VERSION for RS $RS_VERSION: $err" 88 | return 1 89 | fi 90 | } 91 | 92 | rc=0 93 | # By default we use RS_VERSIONS, but with variants they may need to specify their own redis verisons, hence this file 94 | VERSIONFILE=${HERE}/RS_VERSIONS${VARIANT} 95 | if [[ $QUICK == 1 ]]; then 96 | RS_VERSIONS=$(cat $VERSIONFILE | head -1) 97 | else 98 | RS_VERSIONS=$(cat $VERSIONFILE) 99 | fi 100 | for RS_VERSION in $RS_VERSIONS; do 101 | run_test $RS_VERSION 102 | [[ $? != 0 && $rc == 0 ]] && rc=$? 103 | done 104 | exit $rc 105 | --------------------------------------------------------------------------------