Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] OOM in has_next and read_chunk of chunked parquet reader #15812

Closed
galipremsagar opened this issue May 22, 2024 · 9 comments
Closed

[BUG] OOM in has_next and read_chunk of chunked parquet reader #15812

galipremsagar opened this issue May 22, 2024 · 9 comments
Labels
bug Something isn't working cuIO cuIO issue

Comments

@galipremsagar
Copy link
Contributor

Describe the bug
While reading a dataframe of size ~8GB on T4(16GB), there seems to be an OOM exception when has_next is called.

Steps/Code to reproduce bug

# The dataframe can be fit into memory easily:

In [1]: import pyarrow as pa

In [2]: import pandas as pd

In [3]: import cudf

In [4]: table = pa.Table.from_pandas(pd.read_parquet("lineitem.parquet"))

In [5]: gdf = cudf.DataFrame.from_arrow(table)

In [6]: gdf
Out[6]: 
          l_orderkey  l_partkey  ...  l_shipmode                                  comments
0                  1    1551894  ...       TRUCK                   egular courts above the
1                  1     673091  ...        MAIL        ly final dependencies: slyly bold 
2                  1     636998  ...     REG AIR             riously. regular, express dep
3                  1      21315  ...         AIR                   lites. fluffily even de
4                  1     240267  ...         FOB                   pending foxes. slyly re
...              ...        ...  ...         ...                                       ...
59986047    60000000     698651  ...       TRUCK                                ons. accou
59986048    60000000     224200  ...     REG AIR                     the final requests. f
59986049    60000000     118838  ...        SHIP  odolites grow quickly. slyly even waters
59986050    60000000    1294851  ...        MAIL                    ests wake blithely fur
59986051    60000000     558286  ...     REG AIR           round the regular, special theo

[59986052 rows x 16 columns]

nvidia-smi:

Every 0.5s: nvidia-smi                                       dt07: Wed May 22 00:19:27 2024

Wed May 22 00:19:27 2024
+---------------------------------------------------------------------------------------+
| NVIDIA-SMI 535.161.08             Driver Version: 535.161.08   CUDA Version: 12.2     |
|-----------------------------------------+----------------------+----------------------+
| GPU  Name                 Persistence-M | Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp   Perf          Pwr:Usage/Cap |         Memory-Usage | GPU-Util  Compute M. |
|                                         |                      |               MIG M. |
|=========================================+======================+======================|
|   0  Tesla T4                       On  | 00000000:3B:00.0 Off |                    0 |
| N/A   44C    P0              27W /  70W |   8865MiB / 15360MiB |      0%      Default |
|                                         |                      |                  N/A |
+-----------------------------------------+----------------------+----------------------+
|   1  Tesla T4                       On  | 00000000:5E:00.0 Off |                    0 |
| N/A   37C    P8               9W /  70W |      5MiB / 15360MiB |      0%      Default |
|                                         |                      |                  N/A |
+-----------------------------------------+----------------------+----------------------+
|   2  Tesla T4                       On  | 00000000:AF:00.0 Off |                    0 |
| N/A   32C    P8               9W /  70W |      5MiB / 15360MiB |      0%      Default |
|                                         |                      |                  N/A |
+-----------------------------------------+----------------------+----------------------+
|   3  Tesla T4                       On  | 00000000:D8:00.0 Off |                    0 |
| N/A   30C    P8               9W /  70W |      5MiB / 15360MiB |      0%      Default |
|                                         |                      |                  N/A |
+-----------------------------------------+----------------------+----------------------+

+---------------------------------------------------------------------------------------+
| Processes:                                                                            |
|  GPU   GI   CI        PID   Type   Process name                            GPU Memory |
|        ID   ID                                                             Usage      |
|=======================================================================================|
|    0   N/A  N/A   1816858      C   ...0/pgali/envs/cudfdev/bin/python3.11     8860MiB |
+---------------------------------------------------------------------------------------+

Bug:

In [1]: import cudf

In [2]: from cudf._lib.parquet import ParquetReader

In [3]: reader = ParquetReader(["lineitem.parquet"], chunk_rea
   ...: d_limit=24000000)

In [4]: reader._has_next()
---------------------------------------------------------------------------
MemoryError                               Traceback (most recent call last)
Cell In[4], line 1
----> 1 reader._has_next()

File parquet.pyx:844, in cudf._lib.parquet.ParquetReader._has_next()

MemoryError: std::bad_alloc: out_of_memory: CUDA error at: /nvme/0/pgali/envs/cudfdev/include/rmm/mr/device/cuda_memory_resource.hpp:60: cudaErrorMemoryAllocation out of memory

Expected behavior
We should be able to read using chunked parquet reader.

Environment overview (please complete the following information)

  • Environment location: [Bare-metal]
  • Method of cuDF install: [from source]

This issue will need changes from : #15728

@galipremsagar galipremsagar added bug Something isn't working cuIO cuIO issue labels May 22, 2024
@galipremsagar galipremsagar changed the title [BUG] OOM in has_next of chunked parquet reader [BUG] OOM in has_next and read_chunk of chunked parquet reader May 22, 2024
@mhaseeb123
Copy link
Member

Looked into this but unable to reproduce the issue on my machine. The reader seems to be working fine as seen in the screenshot below.

image

@mhaseeb123
Copy link
Member

mhaseeb123 commented May 22, 2024

Here is my test code. I did notice in nvidia-smi that we see a transient GPU memory spike of 21.4GiB and it quickly goes down and saturates at around 10GiB. I am assuming that this 21.4GiB transient might be the culprit behind the OOM. It doesn't fail on my machine as my GPUs are free otherwise and can handle the transient.

def test_parquet_chunked_reader_oom():
    reader = ParquetReader(["/home/coder/datasets/lineitem.parquet"], chunk_read_limit=24000000)
    while (reader._has_next()):
        chunk = reader._read_chunk()

@galipremsagar
Copy link
Contributor Author

I did notice in nvidia-smi that we see a transient GPU memory spike of 21.4GiB and it quickly goes down and saturates at around 10GiB. I am assuming that this 21.4GiB transient might be the culprit behind the OOM.

Exactly, I did notice this too on T4 and since T4's can't handle that much amount of memory we end up with an OOM there too.

@GregoryKimball
Copy link
Contributor

GregoryKimball commented May 22, 2024

Thank you @mhaseeb123 and @galipremsagar for testing this. I don't believe the C++ API encounters this memory spike in the _has_next() function. @mhaseeb123 would you please check? @nvdbaranec would you please share your thoughts?

@nvdbaranec
Copy link
Contributor

First question, the code I'm seeing is just read_parquet(), not the chunked reader

In [4]: table = pa.Table.from_pandas(pd.read_parquet("lineitem.parquet"))

The regular reader is implemented in terms of the chunked reader, but with no limits set. Ie, infinite sizes. So if you're just using that, OOMs are absolutely possible.

If this code is somehow using the chunked reader, note that there are two parameters:

  • the output chunk limit, which limits the total size in bytes of the output file, but does nothing to control the memory usage of the decode process.
  • the input chunk limit, which limits how much (temporary) memory will be used during the decoding process.

They can be set independently, but only the input chunk limit will work to keep OOMs down.

@GregoryKimball
Copy link
Contributor

Thank you @nvdbaranec, yes we are trying to use the chunked reader here in python. It looks like we might not be setting the "input chunk limit"

@nvdbaranec
Copy link
Contributor

nvdbaranec commented May 22, 2024

Sorry, I misread. I thought the first block of code was where the bug was. It is odd that the one that uses the chunked reader directly would fail. There should be no difference between the two in overall memory usage, but maybe that small chunk value specfied (24 MB) is throwing something for a loop.

In this case, I would not expect the input limit to make a difference since it clearly loads in the non-chunked case.

@mhaseeb123
Copy link
Member

The following test code and patch for #15728 makes things smooth again

def test_parquet_chunked_reader_oom():
    reader = ParquetReader(["/home/coder/datasets/lineitem.parquet"], chunk_read_limit=24000000, pass_read_limit=16384000000) # setting pass_read_limit to 16GB but smaller values also work
    table = []
    while (reader._has_next()):
        chunk = reader._read_chunk()
        # table = table + chunk # concatenate not needed for testing
diff --git a/python/cudf/cudf/_lib/parquet.pyx b/python/cudf/cudf/_lib/parquet.pyx
index aa18002fe1..14c1d00c06 100644
--- a/python/cudf/cudf/_lib/parquet.pyx
+++ b/python/cudf/cudf/_lib/parquet.pyx
@@ -763,6 +763,7 @@ cdef class ParquetWriter:
 cdef class ParquetReader:
     cdef bool initialized
     cdef unique_ptr[cpp_chunked_parquet_reader] reader
+    cdef size_t pass_read_limit
     cdef size_t chunk_read_limit
     cdef size_t row_group_size_bytes
     cdef table_metadata result_meta
@@ -781,7 +782,7 @@ cdef class ParquetReader:
 
     def __cinit__(self, filepaths_or_buffers, columns=None, row_groups=None,
                   use_pandas_metadata=True,
-                  Expression filters=None, int chunk_read_limit=1024000000):
+                  Expression filters=None, size_t chunk_read_limit=1024000000, size_t pass_read_limit=0):
 
         # Convert NativeFile buffers to NativeFileDatasource,
         # but save original buffers in case we need to use
@@ -831,9 +832,10 @@ cdef class ParquetReader:
         self.allow_range_index &= filters is None
 
         self.chunk_read_limit = chunk_read_limit
+        self.pass_read_limit = pass_read_limit
 
         with nogil:
-            self.reader.reset(new cpp_chunked_parquet_reader(chunk_read_limit, args))
+            self.reader.reset(new cpp_chunked_parquet_reader(chunk_read_limit, pass_read_limit, args))
         self.initialized = False
         self.row_groups = row_groups
         self.filepaths_or_buffers = filepaths_or_buffers

@galipremsagar
Copy link
Contributor Author

The issue has been resolved by using pass_read_limit, Thanks @mhaseeb123 & @nvdbaranec !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working cuIO cuIO issue
Projects
None yet
Development

No branches or pull requests

4 participants