Skip to content
szcompressorPublic

About

The GPU error-bounded lossy compressor achieving both extreme throughput and a high compression ratio simultaneously.

Topics

Resources

Contributing

Stars

8 stars

Watchers

0 watching

Forks

Repository files navigation

SZ-GPU (FSZ)

SZ-GPU (FSZ) is the production GPU library for the SZ compressor family. It is an extremely fast error-bounded lossy compressor. It stands at the family's Pareto frontier: achieving both extreme throughput and a high compression ratio simultaneously. It is the compressor introduced in the SC'26 paper FSZ: Breaking the Prediction-Throughput Trade-off in GPU Lossy Compression (arXiv:2607.15413), nominated for the Best Paper Award at SC'26.

You set an error bound, absolute or relative. SZ-GPU compresses at up to 1.4 TB/s and decompresses at up to 1.7 TB/s (measured on a B200 GPU with the tool in this repository), and every reconstructed value is guaranteed to stay within the bound. The data can be anything floating point: simulation fields, sensor and instrument captures, checkpoints, machine learning tensors.

What you get:

  • A guaranteed bound. Every reconstructed value stays within the absolute or relative error bound you set, on float32 and float64 alike, and the tool checks it on every run.
  • Nothing to tune. SZ-GPU adapts to the data on its own: no modes to select, no flags to sweep, and compression ratios hold up on smooth, sparse, and unstructured data alike.
  • Every interface. The szgpu binary plus C, C++, Python, and Fortran APIs. Python takes numpy arrays of any shape and hands them back with the shape restored; Fortran accepts real(4) and real(8) arrays up to rank four. .szgpu files are self-describing and decompress with no further arguments; a bare zero-overhead bitstream mode is also available.
  • BSD 3-Clause licensed.

News

  • 2026-11: The project is renamed SZ-GPU, the production GPU library for the SZ compressor family. SZ-GPU 1.0.1 is released.
  • 2026-08: FSZ 1.0.0 is released.
  • 2026-07: The FSZ paper is nominated for the Best Paper Award at SC'26.
  • 2026-07: Paper accepted at SC'26.

1. Requirements

  • NVIDIA GPU, compute capability >= 8.0 (Ampere or newer).
  • CUDA Toolkit 12.x or 13.x.
  • C++17 host compiler.
  • CMake >= 3.18 (only for the CMake build path).
  • Python >= 3.8 with NumPy (only for the Python API).
  • A Fortran 2008 compiler such as gfortran (only for the Fortran API).

2. Build and install

CMake

git clone https://github.com/szcompressor/SZ-GPU.git
cd SZ-GPU
cmake -S . -B build
cmake --build build -j
ctest --test-dir build --output-on-failure   # optional, needs a GPU
sudo cmake --install build                   # optional: libszgpu, headers, szgpu tool

The default build covers GPU generations from Ampere on: it embeds native code for sm_80 and sm_90 (plus sm_100 when the CUDA toolkit is 12.8 or newer) together with PTX, so compute-capability 8.6/8.9 devices run the sm_80 code directly and newer architectures load through the embedded PTX. Override with -DCMAKE_CUDA_ARCHITECTURES=90 (or 80;90;100, etc.) to build for specific generations only.

Toggles: -DSZGPU_BUILD_SHARED=OFF (skip libszgpu.so), -DSZGPU_BUILD_TOOLS=OFF, -DSZGPU_BUILD_EXAMPLES=OFF, -DSZGPU_BUILD_TESTS=OFF.

Installed projects can consume the library with CMake's find_package:

find_package(szgpu REQUIRED)
target_link_libraries(myapp PRIVATE szgpu::szgpu)

Makefile (nvcc only)

make ARCH=90        # ARCH auto-detected from nvidia-smi if omitted
./build/szgpu -h

3. Quick start

Compress any raw float32 array with a relative error bound of 1e-3:

./build/szgpu -i velocity.f32 -eb rel 1e-3

This runs an in-memory compress + decompress round trip and reports the compression ratio, throughput, and the measured maximum error against the bound. To actually write files:

./build/szgpu -z -i velocity.f32 -o velocity.szgpu -eb rel 1e-3 -d 512 512 512
./build/szgpu -x -i velocity.szgpu -o velocity.out.f32

The .szgpu file is self-describing: decompression needs no dimensions, sizes, or error bounds on the command line.

4. Command-line tool

szgpu -i data.f32 -eb rel 1e-3 [-d D1 [D2 [D3]]]        report mode: round trip + error check, writes nothing
szgpu -z -i data.f32 -o data.szgpu -eb rel 1e-3 [-d ...]  compress to a self-describing .szgpu file
szgpu -x -i data.szgpu -o data.out.f32                    decompress (no other arguments needed)
szgpu -t f64 -i data.d64 -eb rel 1e-3                   any mode on float64 data
Option Meaning
-z / -x force compress / decompress. Without either, files starting with the SZ-GPU magic are decompressed and raw inputs get the report mode.
-i, -o input / output path. Without -o, -z and -x run fully but write nothing.
-eb abs V absolute error bound V.
-eb rel V relative error bound: V * (max - min) of the input data.
-t f32|f64 element type of a raw input file (default f32). Decompression of .szgpu files reads the type from the header instead.
-d D1 [D2 [D3]] data dimensions in C order (D1 varies slowest, like a NumPy shape). Also accepts -d D1xD2xD3. Optional; the product must match the file's element count.
--bare with -z: write the raw bitstream without the 56-byte header. Decompressing a bare stream needs -n (or -d) and -eb abs.
-n N element count, for decompressing bare streams.
--csv additionally print a one-line machine-readable record.
--ssim additionally compute the windowed structural similarity of the reconstruction (slower; uses the -d shape). PSNR and NRMSE are always reported.

Exit codes: 0 success (error check passed), 1 bound violated, 2 usage or file errors.

5. C API

Device-pointer API (data already on the GPU; zero extra copies):

#include <szgpu/szgpu.h>

szgpu_workspace_t* ws = NULL;
szgpu_workspace_create(&ws, n_max);            /* reusable across calls */

szgpu_compress_result_t r;
szgpu_compress(d_in, d_cmp, n, eb_abs, ws, /*stream=*/0, &r);
/* r.cmp_size bytes of d_cmp now hold the bitstream */

szgpu_decompress(d_out, d_cmp, n, eb_abs, &r, ws, /*stream=*/0);

szgpu_workspace_destroy(ws);

Host-pointer API (one call, no CUDA boilerplate; the library manages device memory and transfers internally):

size_t cmp_size = 0;
unsigned char* cmp = malloc(szgpu_max_compressed_bytes(n));
szgpu_compress_hostptr(h_in, cmp, n, eb_abs, &cmp_size);

szgpu_decompress_hostptr(h_out, cmp, cmp_size, n, eb_abs);

Supporting calls:

size_t szgpu_max_compressed_bytes(size_t n);   /* safe d_cmp / cmp capacity  */
size_t szgpu_num_tiles(size_t n);
szgpu_compress_result_t szgpu_make_result(size_t n, size_t cmp_size);
                                             /* rebuild the result struct
                                                for a stored bare stream   */
const char* szgpu_version(void);
const char* szgpu_status_string(szgpu_status_t);

All szgpu_* calls return szgpu_status_t; SZGPU_STATUS_OK == 0.

Float64 data uses the _f64 variants of the same four entry points (szgpu_compress_f64, szgpu_decompress_f64, szgpu_compress_hostptr_f64, szgpu_decompress_hostptr_f64), which take double buffers and a double bound. Workspaces and the sizing helpers are shared between element types.

Buffer rules:

  • d_in / d_out: n * sizeof(float) device bytes.
  • d_cmp: szgpu_max_compressed_bytes(n) device bytes, 4-byte aligned (any cudaMalloc allocation qualifies).
  • Workspace: created once with a maximum capacity and reused for any n <= szgpu_workspace_capacity(ws). Allocate one workspace per concurrent stream; a workspace must not be shared by two in-flight calls. Passing NULL instead is also allowed: the call then creates and destroys a temporary workspace internally (one-shot mode; decompression is then synchronous). Reuse a workspace when compressing repeatedly.
  • szgpu_compress synchronizes the stream before returning (it must deliver cmp_size); szgpu_decompress is fully asynchronous on the given stream.

6. C++ API

#include <szgpu/szgpu.hpp>

szgpu::Workspace ws(n_max);                       // RAII
auto r = szgpu::compress(d_in, d_cmp, n, eb_abs, ws);
szgpu::decompress(d_out, d_cmp, n, eb_abs, r, ws);

// host-pointer one-shots
size_t cmp_size = szgpu::compress_hostptr(h_in, cmp, n, eb_abs);
szgpu::decompress_hostptr(h_out, cmp, cmp_size, n, eb_abs);

Errors are reported as szgpu::Error (derives from std::runtime_error). All of these functions also accept double* buffers through overloads.

7. Python API

pip install ./python

The install compiles and bundles the shared library, so nothing needs to be built first; it only needs a CUDA toolkit on the machine. Set SZGPU_CUDA_ARCHITECTURES (for example 80;90;100) to target specific GPU generations. If no toolkit is present the install still succeeds and the module falls back to SZGPU_LIB, a repository build directory, or the system search path, naming all of them if none works.

import numpy as np
import szgpu

arr = np.fromfile("velocity.f32", dtype=np.float32).reshape(512, 512, 512)

blob = szgpu.compress(arr, eb=1e-3, mode="rel")   # bytes (self-describing)
out  = szgpu.decompress(blob)                     # float32 ndarray, shape restored

print(arr.shape == out.shape, np.abs(arr - out).max())

Arrays of dtype float64 compress through the float64 path and decompress back as float64; the container records which type was written.

File helpers mirror the CLI: szgpu.compress_file(src, dst, eb, mode="rel", dims=None, dtype=np.float32) and szgpu.decompress_file(src, dst=None). The package is a thin ctypes wrapper over libszgpu.so: point it at a custom build with the SZGPU_LIB environment variable if the library is not installed system-wide.

8. Fortran API

The szgpu module wraps the host-pointer calls with generic interfaces for real(4) and real(8) data; arrays of rank one to four are passed directly:

use szgpu
real(4) :: field(512, 512, 512)
integer(c_int8_t), allocatable :: cmp(:)
integer(c_size_t) :: n, cmp_size
integer(c_int) :: ierr

n = int(size(field), c_size_t)
allocate(cmp(szgpu_max_compressed_bytes(n)))

call szgpu_compress(field, n, 1.0e-3, cmp, cmp_size, ierr)    ! absolute bound
call szgpu_decompress(field, cmp, cmp_size, n, 1.0e-3, ierr)

ierr is SZGPU_OK (0) on success and szgpu_status_message(ierr) describes a failure. CMake builds the module automatically when a Fortran compiler is present (the szgpu_fortran library and szgpu.mod); with the Makefile, run make fortran.

For data that is already on the GPU, pass device addresses as type(c_ptr) and keep a workspace across calls. This is what CUDA Fortran gives through c_devloc, and what OpenACC and OpenMP give inside host_data use_device and target data use_device_ptr:

type(c_ptr) :: ws
type(szgpu_result) :: res

call szgpu_workspace_create(ws, n, ierr)
!$acc host_data use_device(field, cmp_buffer)
call szgpu_compress_device(c_loc(field), c_loc(cmp_buffer), n, 1.0e-3, ws, res, ierr)
!$acc end host_data
call szgpu_workspace_destroy(ws)

res%cmp_size gives the stream length. The element type follows the kind of the error bound, so a real(8) bound selects the float64 path. The workspace may be c_null_ptr for a one-shot call, and an optional trailing stream argument places the work on a CUDA stream.

9. Performance

Compression ratios are deterministic and bit-reproducible across GPUs; the ratios below are the per-dataset averages over all fields of the SDRBench suites evaluated in the paper. Miranda is distributed in double precision and is evaluated as float64, measured with this repository; the other rows are the paper's float32 results.

Dataset CR @ rel 1e-2 CR @ rel 1e-3 CR @ rel 1e-4
CESM-ATM 54.25 27.18 16.09
EXAALT 6.07 3.72 2.70
HACC 24.83 8.75 4.68
Hurricane 43.40 24.99 15.82
Miranda (float64) 74.21 45.47 27.77
NYX 70.52 42.47 24.30
OpenSciVis-Truss 13.20 6.54 4.28
SCALE-LETKF 51.68 30.53 18.46

Throughput measured with this repository on an NVIDIA B200 (CUDA 12.8.1) at rel 1e-3, steady-state average of 30 runs, strictly sequential single-field calls:

Field Size Compress GB/s Decompress GB/s
OpenSciVis-Truss 6.9 GB 1250 1502
CESM-ATM/CLDICE 674 MB 1127 1323
HACC/xx 1.1 GB 1075 1430
NYX/temperature 537 MB 1036 1303
SCALE-LETKF/T 564 MB 972 1226

Float64 fields, measured with the szgpu tool on the same B200 at rel 1e-3 (average of 5 timed runs after 3 warmups):

Field Size CR Compress GB/s Decompress GB/s
S3D/CH4 (float64) 1.0 GB 30.29 1395 1713
Miranda/density (float64) 302 MB 40.57 774 1218

10. Citation

If you use SZ-GPU, please cite the FSZ paper:

@inproceedings{huang2026fsz,
  title     = {{FSZ}: Breaking the Prediction-Throughput Trade-off in {GPU} Lossy Compression},
  author    = {Huang, Jiajun},
  booktitle = {Proceedings of the International Conference for High Performance
               Computing, Networking, Storage and Analysis},
  year      = {2026}
}

11. License

BSD 3-Clause. See LICENSE.

About

The GPU error-bounded lossy compressor achieving both extreme throughput and a high compression ratio simultaneously.

Topics

Resources

Contributing

Stars

8 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages