G-Query Light is a CLI-based C++/CUDA data engine built to study host-device orchestration and PCIe bottlenecks.
Phase 1 focuses on a simple analytical workload:
- load a large NYC Taxi CSV dataset
- extract a small set of numeric columns
- apply a fixed filter predicate
- compute a count and a sum
- establish a CPU baseline before GPU offload
This phase is intentionally narrow. The goal is not query-language flexibility or advanced kernel optimization. The goal is disciplined measurement of data movement and execution time.
NYC Taxi CSV files
trip_distancefare_amount
trip_distance > 2.5f && fare_amount > 10.0f- count
- sum_fare_amount
Sum is accumulated in double for numerical stability.
Requirements:
- CMake 3.5 or newer
- A C++20 compiler
- Optional: an NVIDIA toolkit with
nvcconPATH. If CMake finds a CUDA compiler, the project definesGQUERY_USE_CUDAand links the GPU filter; otherwisegqueryis CPU-only.
Configure and build (out-of-tree build recommended):
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -jSmoke tests (no GPU required for the CPU paths):
./build/test_smokeGPU code must be compiled for the same virtual architecture as the GPU you run on. CMake passes this through CUDA_ARCHITECTURES via cache variable GQUERY_CUDA_ARCH.
- Default:
80(NVIDIA Ampere, e.g. A100, RTX 30xx in many setups). This keeps headless CI and machines without a visible GPU from failing at configure time (unlikenative, which needs device detection). - Your machine: set
GQUERY_CUDA_ARCHto the without-decimal form of your GPU’s compute capability (major×10 + minor). Examples:- Compute capability 7.5 (e.g. T4, RTX 20xx) →
75 - 8.0 →
80 - 8.6 →
86 - 8.9 (e.g. L4, RTX 40xx) →
89
- Compute capability 7.5 (e.g. T4, RTX 20xx) →
You can read compute capability from the driver, for example:
nvidia-smi --query-gpu=compute_cap --format=csv,noheaderThen configure once, for example:
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DGQUERY_CUDA_ARCH=75
cmake --build build -jIf the architecture does not match the GPU, runbin may fail at launch with an error similar to “no kernel image is available for execution on the device.” Reconfigure with the correct GQUERY_CUDA_ARCH and rebuild.
native: On a workstation where CMake can detect the installed GPU at configure time, you may use -DGQUERY_CUDA_ARCH=native so the build targets that GPU automatically. This is convenient locally but is a poor default for reproducible or CI builds when no GPU is present.
./build/gquery csv2bin <input.csv> <output.bin>Writes a small header (uint64_t row count) followed by raw float arrays: trip_distance[], then fare_amount[].
./build/gquery runbin <input.bin> [iterations]iterationsdefaults to1. It controls how many times the filter is run (useful for timing); aggregate count / sum_fare_amount are from the last run.
With CUDA enabled (GQUERY_USE_CUDA): each iteration allocates device buffers, copies columns host→device, runs a single simple kernel (one thread per row, atomics for count/sum), and copies results back. Output is GPU mode and does not print CPU-only fields like filter_ms (avg) unless the program explicitly measured CPU filtering in that same invocation. GPU mode prints h2d_ms, kernel_ms, d2h_ms, total_gpu_ms, effective_h2d_gb_per_s along with the common context fields (file_bytes, payload_bytes, rows, iterations, load_ms, total_ms, count, sum_fare_amount, load_gb_per_s) and a mode=gpu,... machine-readable line.
Without CUDA: the same predicate runs on the CPU; filter_ms (avg) is the per-iteration CPU filter time.
After a GPU runbin, the program also runs the CPU filter once on the same in-memory columns and prints a small comparison:
cpu_countvsgpu_count: must match exactlycpu_sum_fare_amountvsgpu_sum_fare_amount: may differ slightly due to floating-point atomic accumulation order on GPU; the output includessum_delta,abs_sum_delta, and the tolerance used.
./build/gquery <input.csv> [iterations]Parses CSV once, then repeats the CPU filter iterations times.
data/test_5_rows.csv is used by test_smoke for the CSV reader. After csv2bin, the filter on those five rows should yield count = 3 and sum_fare_amount = 120 (rows with trip_distance > 2.5 and fare_amount > 10; the row with trip_distance == 2.5 does not qualify).