From eebf507c6a9390ebaa74aefc8bb5332c67346a7a Mon Sep 17 00:00:00 2001 From: Bill Date: Fri, 23 Dec 2022 15:04:39 +0800 Subject: [PATCH] WIP: group by optimizations --- README.md | 65 +++++++++++++++++----------------------- server/aggregations.h | 15 ++++++++++ server/hasher.h | 4 +++ server/monetdb_conn.cpp | 7 ++++- server/server.cpp | 27 ++++++++++++----- server/table.h | 1 + server/unordered_dense.h | 12 ++++++++ 7 files changed, 86 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index ef96a71..3624a73 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,20 @@ - # AQuery++ Database - -### Please try the latest code in dev branch if you encounter any problem. Use `git checkout dev` to switch branches. - ## Introduction AQuery++ Database is a cross-platform, In-Memory Column-Store Database that incorporates compiled query execution. (**Note**: If you encounter any problems, feel free to contact me via ys3540@nyu.edu) +# Architecture +![Architecture](./docs/arch-hybrid.svg) -## Docker (Recommended): - - See installation instructions from [docker.com](https://www.docker.com). Run **docker desktop** to start docker engine. - - In AQuery root directory, type `make docker` to build the docker image from scratch. - - For Arm-based Mac users, you would have to build and run the **x86_64** docker image because MonetDB doesn't offer official binaries for arm64 Linux. (Run `docker buildx build --platform=linux/amd64 -t aquery .` instead of `make docker`) - - Finally run the image in **interactive** mode (`docker run --name aquery -it aquery`) - - When you need to access the container again run `docker start -ai aquery` - - If there is a need to access the system shell within AQuery, type `dbg` to activate python interpreter and type `os.system('sh')` to launch a shell. - - Docker image is available on [Docker Hub](https://hub.docker.com/repository/docker/sunyinqi0508/aquery) but building image yourself is highly recommended (see [#2](../../issues/2)) -## CIMS Computer Lab (Only for NYU affiliates who have access) - 1. Clone this git repo in CIMS. - 2. Download the [patch](https://drive.google.com/file/d/1YkykhM6u0acZ-btQb4EUn4jAEXPT81cN/view?usp=sharing) - 3. Decompress the patch to any directory and execute script inside by typing (`source ./cims.sh`). Please use the source command or `. ./cims.sh` (dot space) to execute the script because it contains configurations for environment variables. Also note that this script can only work with bash and compatible shells (e.g. dash, zsh. but not csh) - 4. Execute `python3 ./prompt.py` +## AQuery Compiler +- The query is first processed by the AQuery Compiler which is composed of a frontend that parses the query into AST and a backend that generates target code that delivers the query. +- Front end of AQuery++ Compiler is built on top of [mo-sql-parsing](https://github.com/klahnakoski/mo-sql-parsing) with modifications to handle AQuery dialect and extension. +- Backend of AQuery++ Compiler generates target code dependent on the Execution Engine. It can either be the C++ code for AQuery Execution Engine or sql and C++ post-processor for Hybrid Engine or k9 for the k9 Engine. +## Execution Engines +- AQuery++ supports different execution engines thanks to the decoupled compiler structure. +- Hybrid Execution Engine: decouples the query into two parts. The sql-compliant part is executed by an Embedded version of Monetdb and everything else is executed by a post-process module which is generated by AQuery++ Compiler in C++ and then compiled and executed. +- AQuery Library: A set of header based libraries that provide column arithmetic and operations inspired by array programming languages like kdb. This library is used by C++ post-processor code which can significantly reduce the complexity of generated code, reducing compile time while maintaining the best performance. The set of libraries can also be used by UDFs as well as User modules which makes it easier for users to write simple, efficient yet powerful extensions. -## Singularity Container - 1. build container `singularity build aquery.sif aquery.def` - 2. execute container `singularity exec aquery.sif sh` - 3. run AQuery `python3 ./prompt.py` -# Native Installation: +# Installation: ## Requirements 1. Recent version of Linux, Windows or MacOS, with recent C++ compiler that has C++17 (1z) support. (however c++20 is recommended if available for heterogeneous lookup on unordered containers) - GCC: 9.0 or above (g++ 7.x, 8.x fail to handle fold-expressions due to a compiler bug) @@ -38,10 +27,6 @@ AQuery++ Database is a cross-platform, In-Memory Column-Store Database that inco - On MacOS, Monetdb can be easily installed in homebrew `brew install monetdb`. 3. Python 3.6 or above and install required packages in requirements.txt by `python3 -m pip install -r requirements.txt` - -## Installation -AQuery is tested on mainstream operating systems such as Windows, macOS and Linux - ### Windows There're multiple options to run AQuery on Windows. But for better consistency I recommend using a simulated Linux environment such as **Windows Subsystem for Linux** (1 or 2), **Docker** or **Linux Virtual Machines**. You can also use the native toolchain from Microsoft Visual Studio or gcc from Winlabs/Cygwin/MinGW. @@ -97,7 +82,24 @@ There're multiple options to run AQuery on Windows. But for better consistency I In this case, upgrade anaconda or your compiler or use the python from your OS or package manager instead. Or (**NOT recommended**) copy/link the library from your system (e.g. /usr/lib/x86_64-linux-gnu/libstdc++.so.6) to anaconda's library directory (e.g. ~/Anaconda3/lib/). +## Docker (Recommended): + - See installation instructions from [docker.com](https://www.docker.com). Run **docker desktop** to start docker engine. + - In AQuery root directory, type `make docker` to build the docker image from scratch. + - For Arm-based Mac users, you would have to build and run the **x86_64** docker image because MonetDB doesn't offer official binaries for arm64 Linux. (Run `docker buildx build --platform=linux/amd64 -t aquery .` instead of `make docker`) + - Finally run the image in **interactive** mode (`docker run --name aquery -it aquery`) + - When you need to access the container again run `docker start -ai aquery` + - If there is a need to access the system shell within AQuery, type `dbg` to activate python interpreter and type `os.system('sh')` to launch a shell. + - Docker image is available on [Docker Hub](https://hub.docker.com/repository/docker/sunyinqi0508/aquery) but building image yourself is highly recommended (see [#2](../../issues/2)) +## CIMS Computer Lab (Only for NYU affiliates who have access) + 1. Clone this git repo in CIMS. + 2. Download the [patch](https://drive.google.com/file/d/1YkykhM6u0acZ-btQb4EUn4jAEXPT81cN/view?usp=sharing) + 3. Decompress the patch to any directory and execute script inside by typing (`source ./cims.sh`). Please use the source command or `. ./cims.sh` (dot space) to execute the script because it contains configurations for environment variables. Also note that this script can only work with bash and compatible shells (e.g. dash, zsh. but not csh) + 4. Execute `python3 ./prompt.py` +## Singularity Container + 1. build container `singularity build aquery.sif aquery.def` + 2. execute container `singularity exec aquery.sif sh` + 3. run AQuery `python3 ./prompt.py` # Usage `python3 prompt.py` will launch the interactive command prompt. The server binary will be automatically rebuilt and started. ### Commands: @@ -268,17 +270,6 @@ SELECT * FROM my_table WHERE c1 > 10 - `sqrt(x), trunc(x), and other builtin math functions`: value-wise math operations. `sqrt(x)[i] = sqrt(x[i])` - `pack(cols, ...)`: pack multiple columns with exact same type into a single column. -# Architecture -![Architecture](./docs/arch-hybrid.svg) - -## AQuery Compiler -- The query is first processed by the AQuery Compiler which is composed of a frontend that parses the query into AST and a backend that generates target code that delivers the query. -- Front end of AQuery++ Compiler is built on top of [mo-sql-parsing](https://github.com/klahnakoski/mo-sql-parsing) with modifications to handle AQuery dialect and extension. -- Backend of AQuery++ Compiler generates target code dependent on the Execution Engine. It can either be the C++ code for AQuery Execution Engine or sql and C++ post-processor for Hybrid Engine or k9 for the k9 Engine. -## Execution Engines -- AQuery++ supports different execution engines thanks to the decoupled compiler structure. -- Hybrid Execution Engine: decouples the query into two parts. The sql-compliant part is executed by an Embedded version of Monetdb and everything else is executed by a post-process module which is generated by AQuery++ Compiler in C++ and then compiled and executed. -- AQuery Library: A set of header based libraries that provide column arithmetic and operations inspired by array programming languages like kdb. This library is used by C++ post-processor code which can significantly reduce the complexity of generated code, reducing compile time while maintaining the best performance. The set of libraries can also be used by UDFs as well as User modules which makes it easier for users to write simple but powerful extensions. # Roadmap - [x] SQL Parser -> AQuery Parser (Front End) diff --git a/server/aggregations.h b/server/aggregations.h index 0f1d8f8..bb8ca0e 100644 --- a/server/aggregations.h +++ b/server/aggregations.h @@ -186,6 +186,21 @@ decayed_t> sumw(uint32_t w, const VT& arr) { return ret; } +template class VT> +void avgw(uint32_t w, const VT& arr, + decayed_t>>& ret) { + typedef types::GetFPType> FPType; + const uint32_t& len = arr.size; + uint32_t i = 0; + types::GetLongType s{}; + w = w > len ? len : w; + if (len) s = ret[i++] = arr[0]; + for (; i < w; ++i) + ret[i] = (s += arr[i]) / (FPType)(i + 1); + for (; i < len; ++i) + ret[i] = ret[i - 1] + (arr[i] - arr[i - w]) / (FPType)w; +} + template class VT> decayed_t>> avgw(uint32_t w, const VT& arr) { typedef types::GetFPType> FPType; diff --git a/server/hasher.h b/server/hasher.h index 22a98e2..0675f96 100644 --- a/server/hasher.h +++ b/server/hasher.h @@ -132,3 +132,7 @@ namespace ankerl::unordered_dense{ struct hash> : public hasher{ }; } +struct aq_hashtable_value_t{ + uint32_t id; + uint32_t cnt; +}; \ No newline at end of file diff --git a/server/monetdb_conn.cpp b/server/monetdb_conn.cpp index a7827ae..c577c8b 100644 --- a/server/monetdb_conn.cpp +++ b/server/monetdb_conn.cpp @@ -6,6 +6,8 @@ #include "monetdb_conn.h" #include "monetdbe.h" #include "table.h" +#include + #undef ERROR #undef static_assert @@ -86,7 +88,10 @@ void Server::connect(Context *cxt){ } server = (monetdbe_database*)malloc(sizeof(monetdbe_database)); - auto ret = monetdbe_open(server, nullptr, nullptr); + monetdbe_options ops; + AQ_ZeroMemory(ops); + ops.nr_threads = std::thread::hardware_concurrency(); + auto ret = monetdbe_open(server, nullptr, &ops); if (ret == 0){ status = true; this->server = server; diff --git a/server/server.cpp b/server/server.cpp index f2e8c77..0176e5b 100644 --- a/server/server.cpp +++ b/server/server.cpp @@ -191,6 +191,21 @@ constexpr prt_fn_t monetdbe_prtfns[] = { aq_to_chars }; +#ifndef __AQ_USE_THREADEDGC__ +void aq_init_gc(void *handle, Context* cxt) +{ + typedef void (*aq_gc_init_t) (Context*); + if (handle && cxt){ + auto sym = dlsym(handle, "__AQ_Init_GC__"); + if(sym){ + ((aq_gc_init_t)sym)(cxt); + } + } +} +#else //__AQ_USE_THREADEDGC__ +#define aq_init_gc(h, c) +#endif //__AQ_USE_THREADEDGC__ + #include "monetdbe.h" #undef max #undef min @@ -363,12 +378,7 @@ start: recorded_queries.emplace_back(copy_lpstr("N")); } handle = dlopen(proc_name, RTLD_NOW); -#ifndef __AQ_USE_THREADEDGC__ - { - typedef void (*aq_gc_init_t) (Context*); - ((aq_gc_init_t)dlsym(handle, "__AQ_Init_GC__"))(cxt); - } -#endif + aq_init_gc(handle, cxt); if (procedure_recording) { recorded_libraries.emplace_back(handle); } @@ -474,11 +484,13 @@ start: p.__rt_loaded_modules = static_cast( malloc(sizeof(void*) * p.postproc_modules)); for(uint32_t j = 0; j < p.postproc_modules; ++j){ - auto pj = dlopen(p.name, RTLD_NOW); + auto pj = dlopen((procedure_root + p.name + std::to_string(j) + ".so").c_str(), RTLD_NOW); if (pj == nullptr){ printf("Error: failed to load module %s\n", p.name); return true; } + aq_init_gc(pj, cxt); + p.__rt_loaded_modules[j] = pj; } } @@ -528,6 +540,7 @@ start: puts(p.queries[j-1]); } fclose(fp); + p.__rt_loaded_modules = 0; return load_modules(p); }; switch(n_recvd[i][1]){ diff --git a/server/table.h b/server/table.h index 3a33136..9de4487 100644 --- a/server/table.h +++ b/server/table.h @@ -289,6 +289,7 @@ public: uint32_t len = end - start; return ColView<_Ty>(orig, idxs.subvec(start, end)); } + ColRef<_Ty> subvec_deep(uint32_t start, uint32_t end) const { uint32_t len = end - start; ColRef<_Ty> subvec(len); diff --git a/server/unordered_dense.h b/server/unordered_dense.h index 737d12b..d81a134 100644 --- a/server/unordered_dense.h +++ b/server/unordered_dense.h @@ -1059,6 +1059,18 @@ public: return do_insert_or_assign(std::move(key), std::forward(mapped)).first; } + template + auto hashtable_push(K&& key, M& mapped) { + ++ mapped.id; + ++ mapped.cnt; + auto it_isinserted = try_emplace(std::forward(key), std::forward(mapped)); + if (!it_isinserted.second) { + --mapped.cnt; + return it_isinserted.first->second.id; + } + return mapped.id; + } + template