Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
9f25099
feat(cuda): add projected dictionary-free file scans
0ax1 Sep 17, 2026
11c9af9
refactor(cuda): simplify scan setup and export tests
0ax1 Sep 17, 2026
2b3d8df
perf(cuda): reuse decoded stream schemas across batches
0ax1 Sep 17, 2026
1f9a40b
perf(cuda): derive decoded stream schemas without polling
0ax1 Sep 17, 2026
ee8eaa1
perf(cuda): use a set for duplicate projection names
0ax1 Sep 17, 2026
55fbac6
refactor(cuda): simplify schema cleanup and test helpers
0ax1 Sep 17, 2026
ea9d2be
refactor(cuda): reduce stream and test scaffolding
0ax1 Sep 17, 2026
78f6eb6
docs(cuda): clarify dictionary export modes with an example
0ax1 Sep 17, 2026
744abf1
Fix CUDA test lints and edition policy expectations
0ax1 Sep 18, 2026
b5da45b
test(cuda): clarify projected scan fixtures and verify device values
0ax1 Sep 22, 2026
8a36a1c
fix(cuda): publish formatted headers only on change and enforce drift…
0ax1 Sep 22, 2026
8ad7a20
fix(cuda): register layouts once without replacing edition policy
0ax1 Sep 22, 2026
984759b
refactor(cuda): reuse decoded stream schema initialization
0ax1 Sep 22, 2026
8ca1a99
test(cuda): share exported device buffer readback helper
0ax1 Sep 22, 2026
7e7db60
refactor(cuda): expose and reuse the empty device array constructor
0ax1 Sep 22, 2026
03fad7d
docs(cuda): explain safety of FFI pointer operations
0ax1 Sep 22, 2026
4bcf470
test(cuda): use the required test function prefix
0ax1 Sep 22, 2026
f886357
test(cuda): release projected streams on assertion and error paths
0ax1 Sep 22, 2026
4d0ccf2
refactor(cuda): let projection planning validate struct fields
0ax1 Sep 22, 2026
41a9604
fix(cuda): preserve layout boundaries when batch rows is zero
0ax1 Sep 22, 2026
a12ab0a
fix(cuda): restore exact nonzero scan batch row counts
0ax1 Sep 22, 2026
b65236e
refactor(cuda): share the CUDA file writer strategy with the CLI
0ax1 Sep 22, 2026
8b227f9
fix(cuda): retain integer dictionaries with explicit writer blocks
0ax1 Sep 22, 2026
d018878
fix(cuda): reject unknown scan option flag bits
0ax1 Sep 22, 2026
d67340c
docs(cuda): avoid Rustdoc link brackets in the generated C header
0ax1 Sep 22, 2026
a0861d1
build(cuda): leave generated FFI headers in cbindgen format
0ax1 Sep 22, 2026
362d3ef
docs(cuda): trim repeated export and batching explanations
0ax1 Sep 22, 2026
de89ec4
test(cuda): focus layout and dictionary regression coverage
0ax1 Sep 22, 2026
556b223
test(cuda): consolidate focused FFI tests into the inline module
0ax1 Sep 22, 2026
9085f45
docs
0ax1 Sep 22, 2026
c70e408
docs(cuda): shorten scan and export API documentation
0ax1 Sep 22, 2026
9c800c0
fix(cuda): initialize layout registration guard explicitly
0ax1 Sep 22, 2026
9eb4475
fix(cuda): remove redundant FFI error free qualification
0ax1 Sep 22, 2026
aaa140b
docs(ffi): document error message safety requirements
0ax1 Sep 22, 2026
39ddfa5
fix(ffi): regenerate header after error safety docs
0ax1 Sep 22, 2026
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
4 changes: 4 additions & 0 deletions .github/workflows/cuda.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ jobs:
- "vortex-test/**"
- "pyproject.toml"
- "uv.lock"
- "Cargo.toml"
- "Cargo.lock"
- ".github/workflows/**"

cuda-build-lint:
Expand All @@ -71,6 +73,8 @@ jobs:
cargo build --profile ci --locked --all-features --all-targets
-p vortex-cuda -p vortex-cuda-ffi -p vortex-cub -p vortex-nvcomp
-p gpu-scan-cli -p vortex-test-e2e-cuda -p vortex-python-cuda
- name: Verify generated CUDA FFI header is up to date
run: git --no-pager diff --exit-code -- vortex-cuda/ffi/cinclude/vortex_cuda.h
- name: Clippy CUDA crates
run: |
cargo clippy --profile ci --locked --all-features --all-targets \
Expand Down
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions vortex-cuda/ffi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,13 @@ vortex-cuda = { path = ".." }
vortex-ffi = { path = "../../vortex-ffi" }

[dev-dependencies]
cudarc = { workspace = true }
tempfile = { workspace = true }
vortex-cuda-macros = { workspace = true }

[build-dependencies]
cbindgen = { workspace = true }

[lib]
name = "vortex_cuda_ffi"
crate-type = ["rlib", "staticlib", "cdylib"]
Expand Down
5 changes: 5 additions & 0 deletions vortex-cuda/ffi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,8 @@ pool and CUDA state are reused as well.
On Linux, use `vx_cuda_scan_path_arrow_device_stream_with_options` with
`vx_cuda_scan_options.flags = VX_CUDA_SCAN_FLAG_DIRECT_IO` to bypass the operating system page
cache for pooled data-plane reads. Footer and zone-map reads remain buffered on the host.

## Generated header

`build.rs` generates `cinclude/vortex_cuda.h` with cbindgen. Edit `src/lib.rs` or `cbindgen.toml`
and commit the regenerated header. It skips clang-format; CUDA CI checks for header drift.
60 changes: 60 additions & 0 deletions vortex-cuda/ffi/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: Copyright the Vortex contributors

use std::error::Error;
use std::fs;
use std::fs::OpenOptions;
use std::io;
use std::io::Write;
use std::process;

fn main() -> Result<(), Box<dyn Error>> {
println!("cargo:rerun-if-changed=src");
println!("cargo:rerun-if-changed=cbindgen.toml");
println!("cargo:rerun-if-changed=build.rs");

let header = "cinclude/vortex_cuda.h";
let mut generated = Vec::new();
// Parse only the FFI source to avoid macro expansion and recursive CUDA builds.
cbindgen::Builder::new()
.with_src("src/lib.rs")
.with_config(cbindgen::Config::from_file("cbindgen.toml")?)
.generate()?
.write(&mut generated);
match fs::read(header) {
Ok(existing) if existing == generated => return Ok(()),
Ok(_) => {}
Err(error) if error.kind() == io::ErrorKind::NotFound => {}
Err(error) => return Err(format!("failed to read {header}: {error}").into()),
}
publish_header(header, &generated)
.map_err(|error| format!("failed to publish {header}: {error}"))?;
Ok(())
}

fn publish_header(header: &str, generated: &[u8]) -> io::Result<()> {
let mut attempt = 0_u64;
let (temporary, mut file) = loop {
let temporary = format!("{header}.{}.{attempt}.tmp", process::id());
match OpenOptions::new()
.write(true)
.create_new(true)
.open(&temporary)
{
Ok(file) => break (temporary, file),
Err(error) if error.kind() == io::ErrorKind::AlreadyExists => attempt += 1,
Err(error) => return Err(error),
}
};

// Publish atomically so concurrent builds never see a truncated header.
let written = file.write_all(generated);
drop(file);
let result = written.and_then(|()| fs::rename(&temporary, header));
if result.is_err()
&& let Err(error) = fs::remove_file(&temporary)
{
eprintln!("failed to remove temporary header {temporary}: {error}");
}
result
}
77 changes: 77 additions & 0 deletions vortex-cuda/ffi/cbindgen.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright the Vortex contributors

language = "C"
braces = "SameLine"
cpp_compat = true
usize_is_size_t = true
style = "both"
no_includes = true

header = """
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: Copyright the Vortex contributors

// clang-format off

#pragma once

// THIS FILE IS AUTO-GENERATED, DO NOT MAKE EDITS DIRECTLY

#include <stddef.h>
#include <stdint.h>

#include "vortex.h"

/* Link against the CUDA-enabled FFI library that provides both the base Vortex FFI and these CUDA
* entry points. Do not pass Vortex handles between independently linked Rust FFI libraries. */

/* Definitions from the Arrow C Device data interface. Define USE_OWN_ARROW_DEVICE to skip them.
* https://arrow.apache.org/docs/format/CDeviceDataInterface.html */
#if !defined(ARROW_C_DEVICE_DATA_INTERFACE) && !defined(USE_OWN_ARROW_DEVICE)
#define ARROW_C_DEVICE_DATA_INTERFACE

typedef int32_t ArrowDeviceType;
#define ARROW_DEVICE_CPU 1
#define ARROW_DEVICE_CUDA 2
#define ARROW_DEVICE_CUDA_HOST 3
#define ARROW_DEVICE_OPENCL 4
#define ARROW_DEVICE_VULKAN 7
#define ARROW_DEVICE_METAL 8
#define ARROW_DEVICE_VPI 9
#define ARROW_DEVICE_ROCM 10
#define ARROW_DEVICE_ROCM_HOST 11
#define ARROW_DEVICE_EXT_DEV 12
#define ARROW_DEVICE_CUDA_MANAGED 13
#define ARROW_DEVICE_ONEAPI 14
#define ARROW_DEVICE_WEBGPU 15
#define ARROW_DEVICE_HEXAGON 16

struct ArrowDeviceArray {
struct ArrowArray array;
int64_t device_id;
ArrowDeviceType device_type;
void *sync_event;
int64_t reserved[3];
};
#endif

#if !defined(ARROW_C_DEVICE_STREAM_INTERFACE) && !defined(USE_OWN_ARROW_DEVICE)
#define ARROW_C_DEVICE_STREAM_INTERFACE
struct ArrowDeviceArrayStream {
ArrowDeviceType device_type;
int (*get_schema)(struct ArrowDeviceArrayStream *, struct ArrowSchema *out);
int (*get_next)(struct ArrowDeviceArrayStream *, struct ArrowDeviceArray *out);
const char *(*get_last_error)(struct ArrowDeviceArrayStream *);
void (*release)(struct ArrowDeviceArrayStream *);
void *private_data;
};
#endif
"""

trailer = "// clang-format on"

# These externally defined Arrow ABI types use struct tags, not typedef names.
[export.rename]
"ArrowDeviceArray" = "struct ArrowDeviceArray"
"ArrowDeviceArrayStream" = "struct ArrowDeviceArrayStream"
Loading
Loading