Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 48 additions & 56 deletions extensions/gpudb/description.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
extension:
name: gpudb
description: GPU-accelerated analytical operators for DuckDB on NVIDIA CUDA and Apple Silicon Metal. First SQL execution engine that targets Apple Silicon GPUs.
version: 0.1.3
version: 0.3.0
language: C++
build: cmake
license: Apache-2.0
Expand All @@ -12,12 +12,12 @@ extension:

repo:
github: singhpratech/duckdbgpumetaldbram
ref: 018d8a306ac2903f64c3391d42c59038b4fc2c28
ref: 2f416b1037a5d22662bd67b7fda26f0b96b82858

docs:
hello_world: |
LOAD gpudb;
-- GPU-accelerated SUM (CUDA on NVIDIA, Metal on Apple Silicon, CPU fallback otherwise)
-- Drop-in aggregates (BIGINT and DOUBLE overloads)
SELECT gpu_sum(value::BIGINT) FROM range(1000000) AS t(value);

-- Verify against native sum
Expand All @@ -26,53 +26,45 @@ docs:
sum(value::BIGINT) AS native
FROM range(1000000) AS t(value);
extended_description: |
`gpudb` adds GPU-accelerated aggregate operators that DuckDB transparently
dispatches to:
`gpudb` adds drop-in aggregate functions:

* `gpu_sum(BIGINT)` — GPU SUM
* `gpu_min(BIGINT)` — GPU MIN
* `gpu_max(BIGINT)` — GPU MAX
* `gpu_sum(BIGINT | DOUBLE)`
* `gpu_min(BIGINT | DOUBLE)`
* `gpu_max(BIGINT | DOUBLE)`

On NVIDIA hardware (CUDA backend, sm_70+) these run on the device with
PCIe-amortized transfer. On Apple Silicon (Metal backend, M1+) they use
the unified memory architecture so transfer cost is zero.
Smaller integer types (`INTEGER`, `SMALLINT`, `TINYINT`) widen implicitly
to the `BIGINT` overload. All three work in plain aggregation, `GROUP BY`,
and window frames (`OVER ()`, `OVER (ORDER BY ...)`,
`OVER (PARTITION BY ... ORDER BY ...)`), and match native DuckDB
semantics: empty input and all-NULL groups return SQL `NULL` (v0.2.0),
and the `DOUBLE` min/max overloads use the same NaN-aware total order as
native DuckDB — NaN sorts greatest (v0.3.0).

**v0.1.3** ships a hybrid Metal GROUP BY that auto-dispatches between two
paths per query: a 32K-partition slot-lock hash aggregate (sweet spot at
1024 ≤ unique ≤ 16M) and an optimized multi-pass radix sort (very low or
very high cardinality). This flipped TPC-H SF10 GROUP BY l_orderkey from
CPU 1.78× faster (v0.1.2) to Metal 1.30× faster.
**v0.3.0** replaces the buffered v0.1.x aggregate path with streaming
accumulator states. End-to-end queries through the SQL aggregates now run
at parity with native DuckDB (1.00–1.20× on rewritten TPC-H queries),
where v0.1.x could be substantially slower on the same queries. DuckDB
feeds aggregates pre-grouped 2048-row chunks, so the SQL aggregate path
deliberately streams running accumulators instead of round-tripping
chunks through the GPU.

A hybrid CPU/GPU planner picks the backend that wins for each cardinality
regime — this addresses the open problem from Rosenfeld/Breß CSUR 2022
and Cao SIGMOD 2024.
The GPU backends (CUDA on NVIDIA sm_70+, Metal on Apple Silicon M1+)
power the operator-level engine and benchmark tooling that ship in the
source tree, where whole columns are resident on the device. Headline
operator-level results, all traceable to rows in the project's
append-only BENCHMARK.md with reproduction steps:

Apple Silicon (M4 Max) vs DuckDB CPU 16-thread (the actual CLI default,
not single-thread). All cells trace to BENCHMARK.md rows:
* TPC-H SF10 multi-agg fusion l_quantity: Metal 25.5×
* TPC-H SF10 multi-agg fusion l_extendedprice: Metal 22.0×
* TPC-H SF10 multi-agg fusion l_orderkey: Metal 9.7×
* 1B int64 SUM HOT (resident column): Metal 2.6×
* 500M × 1M GROUP BY synthetic: Metal 3.4×
* 1B × 1M GROUP BY synthetic: Metal 3.2×
* TPC-H SF10 GROUP BY l_extendedprice (1.35M unique): Metal 3.9×
* TPC-H SF10 GROUP BY l_orderkey (15M unique): Metal 1.30×
* TPC-H SF1 GROUP BY l_orderkey (1.5M unique): Metal 1.40×
* Honest loss documented: TPC-H SF10 GROUP BY l_quantity (50 unique):
CPU 14× faster (structural — L1-resident hash table on CPU)
* Apple M4 Max vs DuckDB CPU 16-thread: multi-aggregate fusion over
TPC-H SF10 columns 9.7×–25.5×; SF10 GROUP BY at 1.35M unique keys
3.9×; honest loss documented at 50 unique keys (CPU 14× faster,
structural).
* NVIDIA RTX 4090: resident-column SUM ~17.9×; GROUP BY 50M rows ×
10M unique groups 13.7× (vs single-thread CPU baseline).

NVIDIA RTX 4090 (CUDA, vs single-thread CPU baseline):
* Peak SUM ratio: ~22.8× (size-dependent, resident column)
* GROUP BY 50M rows × 10M unique groups: 21.8×
* TPC-H SF1 GROUP BY (6M × 1.5M unique): 3.56× (re-bench post-launch)

The extension auto-selects the best backend at load time. If no GPU is
available it falls back cleanly to the CPU implementation — same SQL
surface either way. Community-extension binaries are built without the
CUDA toolchain for now (CPU fallback on Linux; full Metal on Apple
Silicon); build from source for the CUDA backend. Honest benchmark
notes (where GPU loses to CPU) are documented in the project's
BENCHMARK.md (append-only log).
Community-extension binaries are built without the CUDA toolchain for
now (full Metal path on Apple Silicon; clean CPU fallback on Linux);
build from source for the CUDA backend. If no GPU is available the
extension falls back cleanly — same SQL surface either way.

Source: https://github.com/singhpratech/duckdbgpumetaldbram

Expand All @@ -83,15 +75,15 @@ docs:
Falls back to CPU otherwise.

known_limitations: |
* Float64 SUM on Apple Silicon falls back to host loop (Apple GPUs
do not implement IEEE-754 doubles in MSL); same correctness, no
GPU speedup for that one type.
* GROUP BY currently supports BIGINT keys + BIGINT SUM; broader
type coverage planned in v0.2.
* Window functions: SUM OVER (), SUM OVER (ORDER BY), and
SUM OVER (PARTITION BY ... ORDER BY ...) all supported and
verified against native sum() in the SQL test suite.
* GROUP BY at very low cardinality (≤ 1K unique): CPU dominates
structurally (L1-resident hash). Auto-dispatch routes these to the
radix-opt path; for the bottom of the curve CPU still wins (e.g.,
TPC-H SF10 l_quantity at 50 unique groups: CPU 14× faster).
* `gpu_sum(BIGINT)` wraps on int64 overflow where native `sum()`
promotes to `HUGEINT`.
* `HUGEINT`, `DECIMAL`, and `FLOAT` arguments implicitly cast to the
`DOUBLE` overload — values beyond 2^53 lose precision where native
aggregates are exact, and the result type is `DOUBLE`. `VARCHAR`
arguments are a binder error (native `min`/`max` compare
lexicographically). Use native aggregates where those types matter.
* Apple GPUs do not implement IEEE-754 doubles in MSL; operator-level
f64 work on Metal runs on host. This does not affect the SQL
aggregate path.
* `GPUDB_FORCE_BACKEND` no longer affects the SQL aggregate path as of
v0.3.0 (operator-level tools still honor backend selection).
Loading