Skip to content

Conversation

@davies
Copy link
Contributor

@davies davies commented May 26, 2016

What changes were proposed in this pull request?

Currently, the memory for temporary buffer used by TimSort is always allocated as on-heap without bookkeeping, it could cause OOM both in on-heap and off-heap mode.

This PR will try to manage that by preallocate it together with the pointer array, same with RadixSort. It both works for on-heap and off-heap mode.

This PR also change the loadFactor of BytesToBytesMap to 0.5 (it was 0.70), it enables use to radix sort also makes sure that we have enough memory for timsort.

How was this patch tested?

Existing tests.

@davies
Copy link
Contributor Author

davies commented May 26, 2016

cc @ericl

@rxin
Copy link
Contributor

rxin commented May 26, 2016

Can we add a unit test for this behavior?

@rxin
Copy link
Contributor

rxin commented May 26, 2016

FYI "This PR also change the loadFactor of BytesToBytesMap to 0.5 (it was 0.75)" this is a pretty low load factor.

@davies
Copy link
Contributor Author

davies commented May 26, 2016

It was 0.70 (corrected), it's 30% lower after this patch. For the simplest aggregate (one integer key and one integer value), the key-value pair need 40 bytes, the pointer array need 22+ bytes, becomes 32 bytes after the patch, it will need 15% more memory. Before this patch, TimSort still allocate some memory from heap (could OOM), so the difference will be even smaller.

newArray.getBaseObject(),
newArray.getBaseOffset(),
array.size() * (8 / memoryAllocationFactor)
pos * 8
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should keep the memoryAllocationFactor variable, to make it more clear we are overallocating on purpose.

Choose a reason for hiding this comment

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

+1 on that.
Is there any particular reason for removing the memoryAllocationFactor? Without this we might highly underutilize memory for TimSort.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In theory, memoryAllocationFactor should be 2 for radix sort and 1.5 for tim sort. For simplicity, I'd like to trade a little bit memory efficiency for simplicity. memoryAllocationFactor is only used in hasSpaceForAnotherRecord(), if you feel strong on this tradeoff, I could update hasSpaceForAnotherRecord() to use 1.5 for timsort.

For here, we don't need memoryAllocationFactor actually.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Should we also use 1/1.5 in BytesToBytesMap as load factor when radix sort could not be used? I feel that's too complicated.

Choose a reason for hiding this comment

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

IMO, it will be better to use the memoryAllocationFactor. Because otherwise, we might see unnecessary spilling due to memory under utilization. If we change the memory allocation factor from 2 to 1.5 for TimSort, that is a significant amount of memory considering the size of the pointer array can be in the order of GBs for large workload.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated.

@SparkQA
Copy link

SparkQA commented May 26, 2016

Test build #59350 has finished for PR 13318 at commit 6d074f6.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

@sitalkedia
Copy link

Thank you for making this fix 👍

@SparkQA
Copy link

SparkQA commented May 26, 2016

Test build #59405 has finished for PR 13318 at commit f651956.

  • This patch fails Spark unit tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

@SparkQA
Copy link

SparkQA commented May 26, 2016

Test build #59418 has finished for PR 13318 at commit c72cdea.

  • This patch fails MiMa tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

@SparkQA
Copy link

SparkQA commented May 26, 2016

Test build #3021 has finished for PR 13318 at commit c72cdea.

  • This patch fails MiMa tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

@SparkQA
Copy link

SparkQA commented May 26, 2016

Test build #3022 has finished for PR 13318 at commit c72cdea.

  • This patch fails Spark unit tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

@SparkQA
Copy link

SparkQA commented May 27, 2016

Test build #59432 has finished for PR 13318 at commit 2ad469d.

  • This patch fails Spark unit tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

* How many records could be inserted, because part of the array should be left for sorting.
*/
private int pos = 0;
private int capacity = 0;
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: usableCapacity?

@SparkQA
Copy link

SparkQA commented May 27, 2016

Test build #59465 has finished for PR 13318 at commit 8b4e033.

  • This patch fails Spark unit tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

@SparkQA
Copy link

SparkQA commented May 31, 2016

Test build #59670 has finished for PR 13318 at commit 2ad8eb8.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

@davies
Copy link
Contributor Author

davies commented May 31, 2016

@ericl Comments addressed, could you take another look?


private int calcCapacity() {
// Radix sort requires same amount of used memory as buffer, Tim sort requires
// half of the used memory as buffer.
Copy link
Member

Choose a reason for hiding this comment

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

can we also update the comments above while instantiating array to better indicate the contents of the array (and talk about the additional buffer that's needed for sorting)

Copy link
Member

Choose a reason for hiding this comment

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

by the way, out of curiosity, what's the worst case scenario in TimSort that requires 0.5x more buffer space?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@sameeragarwal I think you already had a test case for the worst case (there are two ordered part in the array, the shortest part will be copied into a temporary buffer, os it need 0.5 buffer space), it's doced in TimSort.

@sameeragarwal
Copy link
Member

Looks great overall, just few questions and a couple of minor comments.

@sameeragarwal
Copy link
Member

LGTM

@SparkQA
Copy link

SparkQA commented Jun 3, 2016

Test build #59949 has finished for PR 13318 at commit a929a06.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

asfgit pushed a commit that referenced this pull request Jun 3, 2016
## What changes were proposed in this pull request?

Currently, the memory for temporary buffer used by TimSort is always allocated as on-heap without bookkeeping, it could cause OOM both in on-heap and off-heap mode.

This PR will try to manage that by preallocate it together with the pointer array, same with RadixSort. It both works for on-heap and off-heap mode.

This PR also change the loadFactor of BytesToBytesMap to 0.5 (it was 0.70), it enables use to radix sort also makes sure that we have enough memory for timsort.

## How was this patch tested?

Existing tests.

Author: Davies Liu <[email protected]>

Closes #13318 from davies/fix_timsort.

(cherry picked from commit 3074f57)
Signed-off-by: Davies Liu <[email protected]>
@asfgit asfgit closed this in 3074f57 Jun 3, 2016
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.

6 participants