NVIDIA / NVIDIA/cudf

[FEA] Improve Parquet decoding throughput in libcudf

Open
#18,350 11 comments 0 reactions 0 assignees View on GitHub
cuIO feature request libcudf strings
Dominant language
C++
Stars
9.8k
Forks
1.1k
Avg merge
3d 6m
Merged PRs (30d)
278

Description

**Is your feature request related to a problem? Please describe.**

We use specialized kernels to process uncompressed, encoded parquet data pages into arrow-formatted cuDF columns. The throughput achieved by the decoding kernels is a function of data type, and many data types show <50 GB/s of throughput on H100.

* generic decode kernel containing decode device functions, includes struct, list, string, fixed width, dictionary device functions
* delta byte array kernel for strings
* delta length byte array kernel for strings

![Image](https://github.com/user-attachments/assets/90ac3e8e-976d-4995-ad0e-ed2ba945cf29)

You can generate this data using this command:
```
./PARQUET_READER_NVBENCH -b 0 -a cardinality=0 -a run_length=1 --timeout 0.2
```

# Nsight Systems Profiles

Let's look at nsys profiles for each data type.

## INTEGER
![Image](https://github.com/user-attachments/assets/86b1be77-72f6-4d90-9147-07511199e948)
Shows three kernels (total 4 ms) of `gpuDecodePageDataGeneric`. Peak warp occupancy is ~50%, with drops at the end.

## FLOAT
![Image](https://github.com/user-attachments/assets/221de6ff-2bb3-430a-90a2-59b238b2753b)
Shows one 1.7 ms kernel of `gpuDecodePageDataGeneric`. Peak warp occupancy is ~50%, with drops at the end.

## BOOL8
![Image](https://github.com/user-attachments/assets/e78ef575-5133-4288-a397-e12c62377e43)
Shows one 8 ms kernel of `gpuDecodePageDataGeneric`. Peak warp occupancy is ~50%, with drops at the end.

## DECIMAL
![Image](https://github.com/user-attachments/assets/72f99612-10d9-4469-ae29-3b0570d948ef)
Shows 8.3 ms of unsnap (we should remove this, see #18349). Shows 1.3 ms of `gpuDecodePageDataGeneric`

## TIMESTAMP
![Image](https://github.com/user-attachments/assets/076b0df0-214d-4455-b1e0-d1fdaa12f904)
Shows 8.3 ms of unsnap (we should remove this, see #18349). Shows 1.7 ms over two calls of `gpuDecodePageDataGeneric`

## DURATION
![Image](https://github.com/user-attachments/assets/a5f19430-08af-42f6-8313-c3e3a9e51b9c)
Shows 1.6 ms of unsnap (we should remove this, see #18349). Shows 1.7 ms over two calls of `gpuDecodePageDataGeneric`

## STRING
![Image](https://github.com/user-attachments/assets/dd2bb8ff-0c53-40b5-8fcb-7a57c0574d53)
Shows 10 ms of unsnap (we should remove this, see #18349). Shows 0.7 ms in `gpuComputeStringPageBounds` and 9.6 ms in `gpuDecodePageDataGeneric`.

## LIST
![Image](https://github.com/user-attachments/assets/43a0fc22-4055-42f2-8ba5-6aef87235aef)
Shows 3.1 ms of unsnap, 6.2 ms of `gpuComputePageSizes` and 8.4 ms of `gpuDecodePageDataGeneric`. Plus 9.5 ms of `cub::reduce`, something like 120 calls. Is this a per-page reduction? (Needs attribution)

## STRUCT
![Image](https://github.com/user-attachments/assets/cb2b40ac-8035-4fa0-b0e9-b856b9c0d03c)
Shows 9.3 ms in unsnap, 6 ms in `gpuDecodePageDataGeneric` over two calls, and 29 ms in recursive calls to `superimpose_nulls_no_sanitize`.

**Describe the solution you'd like**
I believe we should target at least 100 GB/s throughput in the decode stage. We may need new approaches such as state machines based on the libcudf FST, intra-warp coordination, better usage of shared memory and L2 cache, and more ideas.

Opportunities:
* For strings, can we precompute more pieces similar to `gpuComputeStringPageBounds` so that the decode can run faster than 9.6 ms?
* For lists, can we fuse any of the `cub::DeviceReduce::Reduce` calls?
* For structs, can we find a more efficient approach to ensure nulls sanitization? 29 ms is a very long time

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.