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

Fix two potential OOM issues in GPU aggregate. #11908

Open
wants to merge 5 commits into
base: branch-25.02
Choose a base branch
from

Conversation

firestarman
Copy link
Collaborator

close #11903

The first one is by taking the nested literals into account when calculating the output size for pre-split. See the linked issue above for more details.

The second one is by using the correct size for buffer size comparison when collecting the next bundle of batches in aggregate. The size return from the batchesByBucket.last.size() is not the actual buffer size in bytes,
but the element number of an array. It can not be used for the buffer size comparison.

I verified this PR locally by the toy query and it works well.

The first one is by taking the nested literals into account when calculating the output
size for pre-split.

The second one is by using the correct size for buffer size comparison when collecting the
next bundle of batches in aggregate.

Signed-off-by: Firestarman <[email protected]>
@firestarman firestarman changed the title Fix two potential OOM issues in agg. Fix two potential OOM issues in GPU aggregate. Jan 2, 2025
currentSize += bucket.map(_.sizeInBytes).sum
toAggregateBuckets += bucket
var keepGoing = true
while (batchesByBucket.nonEmpty && keepGoing) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

may need use a separate PR for this as it is irrelevant to the description in #11903

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thx for review. @binmahone Could you help file an issue for this? Then I will follow your suggestion.

Copy link
Collaborator

Choose a reason for hiding this comment

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

you can also consider modifying the description in 11903 :-)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Updated

case ArrayType(elemType, hasNullElem) =>
val numElems = pickRowNum(litVal.asInstanceOf[ArrayData].numElements())
// A GPU array literal requires only one column as the child
estimateLitAdditionSize(hasNullElem, hasOffset(elemType), numElems)
Copy link
Collaborator

Choose a reason for hiding this comment

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

is there a risk of over estimation here?

Copy link
Collaborator

Choose a reason for hiding this comment

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

My concern is more about accuracy. For fixed width types we were able to estimate the size almost exactly. For items with offsets we could not and we estimated values more on the small end of things. We were being conservative. For literal values we should be able to get a value that is almost exactly the right size. We can test this for many different literal values and see how close we end up getting.

My concern is for highly nested types. We recurse for the calcLitValueSize, but not for estimateLitAdditionSize. So if we have literal values that are highly nested (like array of array), then the estimate is going to be wrong.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I have done the refactor to calculate the size more exactly.
I follow the type definitions from https://github.com/rapidsai/cudf/blob/a0487be669326175982c8bfcdab4d61184c88e27/cpp/doxygen/developer_guide/DEVELOPER_GUIDE.md#list-columns

@firestarman
Copy link
Collaborator Author

build

Copy link
Collaborator

@revans2 revans2 left a comment

Choose a reason for hiding this comment

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

This needs a lot of testing in different cases to be sure that it works properly. Especially for nested types.

val pickRowNum: Int => Int = rowNum => if (litVal == null) 0 else rowNum
litType match {
case ArrayType(elemType, hasNullElem) =>
val numElems = pickRowNum(litVal.asInstanceOf[ArrayData].numElements())
Copy link
Collaborator

Choose a reason for hiding this comment

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

We need a null check here for a null array literal value.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Updated by the refactor.

estimateLitAdditionSize(f.nullable, hasOffset(f.dataType), childrenNumRows)
).sum
case MapType(keyType, valType, hasNullValue) =>
val mapRowsNum = pickRowNum(litVal.asInstanceOf[MapData].numElements())
Copy link
Collaborator

Choose a reason for hiding this comment

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

This too needs a check for litVal being null before this runs.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Updated by the refactor.

case StringType => lit.asInstanceOf[UTF8String].numBytes()
case BinaryType => lit.asInstanceOf[Array[Byte]].length
case ArrayType(elemType, _) =>
lit.asInstanceOf[ArrayData].array.map(calcLitValueSize(_, elemType)).sum
Copy link
Collaborator

Choose a reason for hiding this comment

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

This appears to only work on UnsafeArrayData. If I test with the following it fails. (I opened up the API to be public so I could test things manually)

scala> PreProjectSplitIterator.calcMemorySizeForLiteral(ArrayData.toArrayData(Array(1L)), ArrayType(LongType), 100)
java.lang.UnsupportedOperationException: Not supported on UnsafeArrayData.
  at org.apache.spark.sql.catalyst.expressions.UnsafeArrayData.array(UnsafeArrayData.java:103)
  at com.nvidia.spark.rapids.PreProjectSplitIterator$.calcLitValueSize(basicPhysicalOperators.scala:381)
  at com.nvidia.spark.rapids.PreProjectSplitIterator$.calcMemorySizeForLiteral(basicPhysicalOperators.scala:328)
  ... 51 elided

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Nice catch, thx a lot, updated.

@firestarman
Copy link
Collaborator Author

Thx for review, I am doing a small refactor for the meta size calculation part... Will update it once done.

Signed-off-by: Firestarman <[email protected]>
@firestarman
Copy link
Collaborator Author

Update for early review, I will run some tests next.

@firestarman
Copy link
Collaborator Author

This needs a lot of testing in different cases to be sure that it works properly. Especially for nested types.

Will work on this next.

Signed-off-by: Firestarman <[email protected]>
Signed-off-by: Firestarman <[email protected]>
Copy link
Collaborator

@revans2 revans2 left a comment

Choose a reason for hiding this comment

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

Looks good to me. I still would like to see some tests (at least some simple unit tests) to validate that it is doing the right thing and that we are covering corner cases like nulls, and arrays of arrays.

@firestarman
Copy link
Collaborator Author

Looks good to me. I still would like to see some tests (at least some simple unit tests) to validate that it is doing the right thing and that we are covering corner cases like nulls, and arrays of arrays.

Sure, working on the tests now...

Signed-off-by: Firestarman <[email protected]>
@firestarman
Copy link
Collaborator Author

Added some tests, also found some bugs and fixed them.

@firestarman
Copy link
Collaborator Author

build

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[BUG] Unexpected large output batches due to implementation defects
3 participants