Skip to content

Repository files navigation

Copyright (c) 2026 Anubhab Banerjee (AnubhabBanerjee/WarpGroup-backend) All rights reserved. No part of this repository may be used, redistributed, or modified in any form or by any means without the prior written permission of the author.


πŸš€ WarpGroup-Backend: VRAM-Aware Asynchronous Sequence Packing & Zero-Copy Inference

WarpGroup-backend overview

Zero-padding, asynchronous First-Fit Decreasing (FFD) bin packing for extreme-context LLM workloads (e.g., AI patent evaluation). Bypasses the GIL and CPU memory bottlenecks by streaming tokenized sequences into a C++ backend, packing them dynamically based on empirical VRAM hardware limits, and passing them to FlashAttention-2 via zero-copy pinned memory (cudaHostAlloc).

This repo is a high-performance inference infrastructure slice: Python handles dynamic VRAM discovery and generic stream tokenization, while a compiled C++ backend (exposed via PyBind11) manages thread-safe sequence queuing, 16-token Tensor Core alignment, and exact hardware-bounded bin packing without ever duplicating data in host RAM.

For a complete explanation and tutorial on this repository, please read this article: https://towardsdatascience.com/i-built-a-c-backend-so-my-gpu-would-stop-eating-air/

🎯 Why VRAM-aware packing matters

In extreme-context LLM inference, variable-length documents cause massive padding waste or fatal Out-Of-Memory (OOM) errors with standard item-count batching. Kubernetes or native PyTorch schedulers do not protect against dynamic attention workspace bloat.

This repository implements a systems-level paradigm shift: it transitions from "Batch Size" batching to "VRAM Capacity" packing. By micro-padding to hardware boundaries and dynamically grouping independent sequences into a strictly enforced, hardware-defined byte limit, it guarantees zero OOMs and ensures every forward pass utilizes maximum GPU silicon.

πŸ“ˆ Performance benchmarks

WarpGroup was evaluated across entry-level and production hardware on highly variable text corpora. It seamlessly integrates with flash_attn_varlen_func to saturate Tensor Cores without the drag of padded tokens.

1. Extreme variance stress test (the "real world" distribution)

Hardware: NVIDIA H100 (80 GB) | Model: Qwen2.5-7B-Instruct Stack: WarpGroup tuned stack + SDPA (Standard PyTorch attention) Dataset: 400 PDFs (high-variance skew: 45–130-word documents interleaved with 1820–2000-word documents)

Standard batching collapses when faced with high-variance document lengths. In this stress test, the baseline Hugging Face pipeline was forced to pad over 818,000 tokens just to maintain rectangular tensor shapes, inflating its dynamic memory usage and cutting throughput in half.

WarpGroup effortlessly absorbed the variance, using 1D continuous tensors to achieve a 2.08Γ— throughput multiplier and a ~62% reduction in dynamic memory overhead.

Metric Baseline (HF) WarpGroup Improvement
Padding overhead 48.41% 0.55% 47.9 pp absolute reduction
Throughput 14,713 tok/s 30,672 tok/s 2.08Γ— higher
Peak VRAM 19.88 GB 16.50 GB 17% lower (3.38 GB saved)
Dynamic VRAM (est.)* ~5.38 GB ~2.00 GB ~62% lower dynamic memory
Wall clock 28.69 s 13.76 s 2.08Γ— faster

*Architecture note on dynamic VRAM: A 7B-parameter model in bf16/fp16 requires ~14.5–15 GB of static VRAM for weights. The dynamic memory (activations / KV cache) is where the padding penalty occurs. WarpGroup processed the exact same sequence of real tokens while shedding over 3 GB of wasted dynamic allocation.

2. Production scaling (uniform variable-length)

Dataset: 300 PDFs (uniform distribution: 50–1900 words)

Even on a less adversarial, uniformly distributed dataset, WarpGroup fully saturates the Hopper Tensor Cores without the drag of padded tokens, yielding a 70% increase in useful-token throughput over the baseline.

Metric Baseline (HF) WarpGroup Improvement
Padding overhead 36.20% 0.67% 35.5 pp absolute reduction
Throughput 18,047 tok/s 30,700 tok/s 1.70Γ— higher
Wall clock 17.86 s 10.50 s 1.70Γ— faster

3. Entry-level hardware (the padding annihilation)

Hardware: NVIDIA GeForce GTX 1080 (8 GB) | Model: SmolLM2-360M-Instruct

By packing continuous 1D tensors, WarpGroup drastically rescues throughput on older or memory-constrained hardware where standard batching wastes extreme amounts of compute.

Metric Baseline (HF) WarpGroup Improvement
Padding overhead 41.13% 0.00% Baseline padding eliminated
Throughput 405 tok/s 2,387 tok/s 5.89Γ— higher
Peak VRAM 2.85 GB 1.86 GB 35% lower

4. OOM prevention (unbounded lengths)

When MAX_LEN constraints are removed, standard batching attempts to allocate memory for the theoretical maximum grid (batch_size Γ— longest_sequence), rapidly causing CUDA Out-Of-Memory errors on variable text.

  • Baseline: Crashed (torch.OutOfMemoryError: Tried to allocate 30.00 GiB).
  • WarpGroup: Completed successfully (Peak VRAM: 3.60 GB). The Phase-0 autotune probes the GPU at startup and locks a strict hardware-aligned token budget; the bin packer rejects any forward pass that would exceed that budget.

Reproducing the benchmarks

python example_runs/run_vram_contrast_benchmark.py \
  --model example_models/Qwen2.5-7B-Instruct \
  --baseline-batch-size 8

python example_runs/random_pdf_generator.py --count 300 \
  --tokens-min 50 --tokens-max 1900 --seed 42
python example_runs/baseline_run.py  --pdf-dir example_runs/data/ \
  --model example_models/Qwen2.5-7B-Instruct --batch-size 4
python example_runs/optimized_run.py --pdf-dir example_runs/data/ \
  --model example_models/Qwen2.5-7B-Instruct

Raw JSON for every run is written under example_runs/results/ (and copied into example_runs/plots/<run_id>/ for archival). The Β§1 manifest is example_runs/results/vram_contrast_manifest.json.

🧠 System architecture

The pipeline is a decoupled autotune β†’ ingest β†’ pack β†’ execute graphβ€”I/O is isolated in Python, while compute and memory mapping run concurrently in C++:

  1. Phase 0: Hardware Autotuning β€” determine_vram_capacity empirically probes the GPU with synthetic sequences to find the physical VRAM limit for your specific model's attention workspace.
  2. Phase 1: Generic Ingestion β€” Python generators yield strings (e.g., from JSONL), tokenize them to flat integers, and stream them via submit_sequence across the PyBind11 boundary.
  3. Phase 2: Async C++ Dispatch & Alignment β€” async_dispatcher.cpp catches tokens in a std::deque outside the Python GIL. Sequences are micro-padded to 16-token intervals to prevent Tensor Core stalling.
  4. Phase 3: FFD Bin Packing β€” A background thread sorts the queue and packs sequences into a pinned memory pool (cudaHostAlloc) using a First-Fit Decreasing algorithm up to the empirical VRAM limit.
  5. Phase 4: Zero-Copy Wrapping β€” torch::from_blob wraps the C++ memory in a PyTorch metadata shell. The GPU's DMA controller pulls the unpadded sequences directly across the PCIe bus for FlashAttention-2 execution.

πŸ› οΈ Stack & core backend

Layer Role
C++17 / PyBind11 Thread-safe queueing, memory pooling, and GIL-free background execution.
CUDA Runtime API Explicit page-locked host memory allocation (cudaHostAlloc).
PyTorch 2.5+ Tensor metadata wrapping, model weights, and graph execution.
FlashAttention-2 Variable-length, padding-free exact attention (flash_attn_varlen_func).
Hugging Face Transformers Base model loading and tokenizer definitions.

Reference environment (pinned)

Item Value
OS Ubuntu 24.04
GPU NVIDIA H100 (80GB) or equivalent
NVIDIA driver 535+ (CUDA 12.2+)
Python 3.12+
Compiler GCC 9.0+ / CMake 3.18+
PyTorch v2.5+ (cu121)

βœ… Prerequisites

  • Linux host for compiling the C++ backend and running the PyTorch loops.
  • CUDA Toolkit installed and accessible in $PATH for compiling the C++ extensions.
  • Python 3.12+ with a virtual environment.
  • A target LLM supported by Hugging Face and configured for flash_attention_2.

βš™οΈ Installation

From the repository root, set up your Python environment and compile the C++ backend:

python3.12 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install -r requirements.txt
pip install -e .

# Compile the PyBind11 C++ backend
mkdir build && cd build
cmake ..
make -j4
cp warpgroup_backend*.so ..
cd ..

πŸš€ Execution

End-to-end VRAM autotuning, ingestion, and background packing:

python3 main_working_file.py

🎬 Example run

Default pipeline locations

Artifact Path
Python Entry Point main_working_file.py
PyTorch DataLoader Logic streaming_dataloader.py
C++ Engine Bindings csrc/bindings.cpp
C++ Async Queue csrc/core/async_dispatcher.h, csrc/core/async_dispatcher.cpp
Built Extension warpgroup_backend.cpython-312-x86_64-linux-gnu.so

πŸ“ Project layout

β”œβ”€β”€ README.md                                # Project overview + benchmarks
β”œβ”€β”€ README_vram_contrast_dataset.md          # β†’ see example_runs/  (note: this file is under example_runs/)
β”œβ”€β”€ CMakeLists.txt                           # PyBind11 + CUDA build directives
β”œβ”€β”€ setup.py                                 # `pip install -e .` entry point
β”œβ”€β”€ requirements.txt                         # torch, transformers, flash-attn, pymupdf, ...
β”œβ”€β”€ .gitignore
β”œβ”€β”€ overview_image.png                       # README hero image
β”‚
β”œβ”€β”€ main_working_file.py                     # End-to-end driver
β”œβ”€β”€ streaming_dataloader.py                  # Phase-0 hardware autotuner + VarlenModelWrapper
β”œβ”€β”€ reader_and_tokennizer.py                 # PDF reader + tokenizer helpers
β”‚
β”œβ”€β”€ warpgroup/                               # Importable Python package
β”‚   β”œβ”€β”€ __init__.py
β”‚   β”œβ”€β”€ dataloader.py
β”‚   └── reader.py
β”‚
β”œβ”€β”€ csrc/                                    # C++17 / PyBind11 backend
β”‚   β”œβ”€β”€ bindings.cpp                         # PyBind11 Python ↔ C++ boundary
β”‚   β”œβ”€β”€ core/
β”‚   β”‚   β”œβ”€β”€ async_dispatcher.cpp             # GIL-free background worker
β”‚   β”‚   β”œβ”€β”€ bin_packer.cpp                   # First-Fit Decreasing packing + 16-token TC alignment
β”‚   β”‚   └── memory_pool.cpp                  # cudaHostAlloc pinned memory + torch::from_blob handoff
β”‚   └── include/
β”‚       β”œβ”€β”€ async_dispatcher.h
β”‚       β”œβ”€β”€ bin_packer.h
β”‚       └── memory_pool.h
β”‚
└── example_runs/                            # Reproducible benchmark harness
    β”œβ”€β”€ README_example.md
    β”œβ”€β”€ README_vram_contrast_dataset.md      # Notes for the interleaved long/short corpus
    β”œβ”€β”€ run_e2e.sh                           # CMake build + setup + baseline + optimized + report
    β”œβ”€β”€ setup_experiment.py                  # Builds + copies warpgroup_backend.so into place
    β”œβ”€β”€ random_pdf_generator.py              # Uniform variable-length synthetic PDF corpus
    β”œβ”€β”€ baseline_run.py                      # Standard Hugging Face padded-batch baseline
    β”œβ”€β”€ optimized_run.py                     # WarpGroup tuned stack (FFD + zero-copy + FA2/SDPA)
    β”œβ”€β”€ generate_report.py                   # Builds bar charts into plots/<run_id>/
    β”œβ”€β”€ build_results_docx.py                # Compiles every run into RESULTS.docx
    β”œβ”€β”€ RESULTS.docx                         # Word-format results dossier
    └── plots/                               # PNG bar charts per run (PNGs only, no JSONs in zip)
        β”œβ”€β”€ e2e_smollm_300pdf/
        β”‚   β”œβ”€β”€ padding_overhead.png
        β”‚   β”œβ”€β”€ throughput_tokens.png
        β”‚   β”œβ”€β”€ time_comparison.png
        β”‚   └── vram_comparison.png
        β”œβ”€β”€ run_A_maxlen2048_dense/{padding_overhead,throughput_tokens,time_comparison,vram_comparison}.png
        β”œβ”€β”€ run_C_maxlen2048_variable/{padding_overhead,throughput_tokens,time_comparison,vram_comparison}.png
        β”œβ”€β”€ run_D_varlen_qwen_tuned/{padding_overhead,throughput_tokens,time_comparison,vram_comparison}.png
        β”œβ”€β”€ run_vram_contrast_corpus/{padding_overhead,throughput_tokens,time_comparison,vram_comparison}.png
        └── run_vram_contrast_appendix/{padding_overhead,throughput_tokens,time_comparison,vram_comparison}.png

πŸ›£οΈ Roadmap

Active and planned hardening for the engine:

  • Multi-GPU Sharding β€” Extend the dispatcher to manage multiple C++ queues, distributing dynamically sized bins across local GPU interconnects.

πŸ™ Acknowledgments

Built with PyBind11, PyTorch, and the NVIDIA CUDA Toolkit to optimize single-node LLM throughput by respecting silicon-level boundaries. Architecture inspired by the constraints of high-volume, asynchronous document evaluation pipelines.

About

A high-performance C++ backend for extreme-context LLM inference. It replaces item-count batching with dynamic, VRAM-aware First-Fit Decreasing (FFD) bin packing. By using PyBind11 for async queueing, 16-token alignment, and `cudaHostAlloc` for zero-copy FlashAttention-2 transfers, it mathematically eliminates OOMs and maximizes GPU throughput.

Topics

Resources

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages