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

Intentionally leak thread_local CUDA resources to avoid crash (part 1) #16787

Conversation

kingcrimsontianyu
Copy link
Contributor

@kingcrimsontianyu kingcrimsontianyu commented Sep 10, 2024

Description

The NVbench application PARQUET_READER_NVBENCH in libcudf currently crashes with the segmentation fault. To reproduce:

./PARQUET_READER_NVBENCH -d 0 -b 1 --run-once -a io_type=FILEPATH -a compression_type=SNAPPY -a cardinality=0 -a run_length=1

The root cause is that some (1) thread_local objects on the main thread in libcudf and (2) static objects in kvikio are destroyed after cudaDeviceReset() in NVbench and upon program termination. These objects should simply be leaked, since their destructors making CUDA calls upon program termination constitutes UB in CUDA.

This simple PR is the cuDF side of the fix. The other part is done here rapidsai/kvikio#462.

closes #13229

Checklist

  • I am familiar with the Contributing Guidelines.
  • New or existing tests cover these changes.
  • The documentation is up to date with these changes.

@github-actions github-actions bot added the libcudf Affects libcudf (C++/CUDA) code. label Sep 10, 2024
@kingcrimsontianyu kingcrimsontianyu changed the title Intentionally leak thread_local CUDA resources to avoid crash Intentionally leak thread_local CUDA resources to avoid crash (part 1) Sep 11, 2024
@kingcrimsontianyu kingcrimsontianyu marked this pull request as ready for review September 11, 2024 03:12
@kingcrimsontianyu kingcrimsontianyu requested a review from a team as a code owner September 11, 2024 03:12
@kingcrimsontianyu kingcrimsontianyu added bug Something isn't working non-breaking Non-breaking change labels Sep 11, 2024
@@ -130,7 +130,6 @@ rmm::cuda_device_id get_current_cuda_device()
*/
struct cuda_event {
cuda_event() { CUDF_CUDA_TRY(cudaEventCreateWithFlags(&e_, cudaEventDisableTiming)); }
virtual ~cuda_event() { CUDF_ASSERT_CUDA_SUCCESS(cudaEventDestroy(e_)); }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (maybe): This means that every usage of cuda_event in the code base will leak the underlying event. Is this really what we want? Perhaps we only want to leak the thread_local ones below.

That is, should we change event_for_thread to do (approximately):

thread_local std::vector<cuda_event *> thread_events(get_num_cuda_devices());
...
thread_events[device_id.value()] = new cuda_event();

?

Alternately, if the only usage of cuda_event is in event_for_thread, we could just delete this class completely and implement event_for_thread as:

thread_local std::vector<cudaEvent_t> thread_events(...);
if (!thread_events[device_id.value()]) {
    CUDF_CUDA_TRY(cudaEventCreateWithFlags(&thread_events[device_id.value()], ...);
}
return thread_events[device_id.value()];

WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cuda_event is only used as the RAII wrapper by event_for_thread, so deleting the user-defined destructor and allocating cuda_event on the heap happen to be equivalent. I agree that the leak makes the cuda_event wrapper entirely superfluous, so I will use the alternative approach you suggested to make the code cleaner. Thank you @wence- !

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Completed

@@ -147,12 +136,13 @@ struct cuda_event {
*/
cudaEvent_t event_for_thread()
{
thread_local std::vector<std::unique_ptr<cuda_event>> thread_events(get_num_cuda_devices());
thread_local std::vector<cudaEvent_t> thread_events(get_num_cuda_devices());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO we should keep cuda_event and only change thread_events to std::vector<cuda_event*>. cuda_event is a useful class and there are other places in libcudf where we can utilize it. I'd rather just disable RAII in this specific place.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. Should cuda_event be moved to the header file include/cudf/detail/utilities/stream_pool.hpp? It's currently defined in .cpp.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, we should move it at some point.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On a second thought, this event RAII wrapper should be moved to a separate header file if found useful. I have some doubt on its necessity after a brief search in the cudf repo. Anway, for this PR, I'm keeping its location unchanged, and have applied the change you suggested. @vuule

@kingcrimsontianyu kingcrimsontianyu force-pushed the tianyu.liu/leak-intentionally branch from 00b0549 to 442db74 Compare September 12, 2024 04:07
Copy link

copy-pr-bot bot commented Sep 12, 2024

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@kingcrimsontianyu
Copy link
Contributor Author

/ok to test

rapids-bot bot pushed a commit to rapidsai/kvikio that referenced this pull request Sep 12, 2024
The NVbench application `PARQUET_READER_NVBENCH` in libcudf currently crashes with the segmentation fault. To reproduce:

```
./PARQUET_READER_NVBENCH -d 0 -b 1 --run-once -a io_type=FILEPATH -a compression_type=SNAPPY -a cardinality=0 -a run_length=1
```
 
The root cause is that some (1) `thread_local`  objects on the main thread in `libcudf` and (2) `static` objects in `kvikio` are destroyed after `cudaDeviceReset()` in NVbench and upon program termination. These objects should simply be leaked, since their destructors making CUDA calls upon program termination constitutes UB in CUDA.

This simple PR is the kvikIO side of the fix. The other part is done here rapidsai/cudf#16787.

Authors:
  - Tianyu Liu (https://github.com/kingcrimsontianyu)

Approvers:
  - Mads R. B. Kristensen (https://github.com/madsbk)

URL: #462
@kingcrimsontianyu
Copy link
Contributor Author

/ok to test

@kingcrimsontianyu kingcrimsontianyu force-pushed the tianyu.liu/leak-intentionally branch from 442db74 to eb8bcdf Compare September 17, 2024 14:43
@kingcrimsontianyu kingcrimsontianyu force-pushed the tianyu.liu/leak-intentionally branch from 1a1731b to 5c28023 Compare September 18, 2024 15:27
@vuule vuule requested a review from lamarrr September 18, 2024 17:17
@ttnghia
Copy link
Contributor

ttnghia commented Sep 18, 2024

/ok to test

@vuule vuule added the 5 - Ready to Merge Testing and reviews complete, ready to merge label Sep 18, 2024
@vuule
Copy link
Contributor

vuule commented Sep 19, 2024

/ok to test

@vuule
Copy link
Contributor

vuule commented Sep 19, 2024

/merge

@rapids-bot rapids-bot bot merged commit 8e1345f into rapidsai:branch-24.10 Sep 19, 2024
97 checks passed
@kingcrimsontianyu kingcrimsontianyu self-assigned this Sep 20, 2024
rjzamora pushed a commit to rjzamora/cudf that referenced this pull request Sep 24, 2024
rapidsai#16787)

The NVbench application `PARQUET_READER_NVBENCH` in libcudf currently crashes with the segmentation fault. To reproduce:

```
./PARQUET_READER_NVBENCH -d 0 -b 1 --run-once -a io_type=FILEPATH -a compression_type=SNAPPY -a cardinality=0 -a run_length=1
```
 
The root cause is that some (1) `thread_local`  objects on the main thread in `libcudf` and (2) `static` objects in `kvikio` are destroyed after `cudaDeviceReset()` in NVbench and upon program termination. These objects should simply be leaked, since their destructors making CUDA calls upon program termination constitutes UB in CUDA.

This simple PR is the cuDF side of the fix. The other part is done here rapidsai/kvikio#462.

closes rapidsai#13229

Authors:
  - Tianyu Liu (https://github.com/kingcrimsontianyu)
  - Vukasin Milovanovic (https://github.com/vuule)

Approvers:
  - Vukasin Milovanovic (https://github.com/vuule)
  - Nghia Truong (https://github.com/ttnghia)

URL: rapidsai#16787
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
5 - Ready to Merge Testing and reviews complete, ready to merge bug Something isn't working libcudf Affects libcudf (C++/CUDA) code. non-breaking Non-breaking change
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[BUG] Crash running parquet reader benchmarks.
5 participants