-
Notifications
You must be signed in to change notification settings - Fork 4k
GH-43660: [C++][Compute] Avoid ZeroCopyCastExec when casting Binary offset -> Binary offset types #48171
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
GH-43660: [C++][Compute] Avoid ZeroCopyCastExec when casting Binary offset -> Binary offset types #48171
Changes from 4 commits
e5b0d43
dfec3b6
6966d4f
71ed279
49dfcb1
bbfd1e6
bb8c691
c8daf74
0b4c46b
8006925
4f613e4
e20f54b
6fa4898
48b0571
4929843
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -20,6 +20,7 @@ | |||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| #include "arrow/array/array_base.h" | ||||||||||||||||||||||||||||||||||||||||||
| #include "arrow/array/builder_binary.h" | ||||||||||||||||||||||||||||||||||||||||||
| #include "arrow/buffer.h" | ||||||||||||||||||||||||||||||||||||||||||
| #include "arrow/compute/kernels/base_arithmetic_internal.h" | ||||||||||||||||||||||||||||||||||||||||||
| #include "arrow/compute/kernels/codegen_internal.h" | ||||||||||||||||||||||||||||||||||||||||||
| #include "arrow/compute/kernels/common_internal.h" | ||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -304,8 +305,21 @@ BinaryToBinaryCastExec(KernelContext* ctx, const ExecSpan& batch, ExecResult* ou | |||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| // Start with a zero-copy cast, but change indices to expected size | ||||||||||||||||||||||||||||||||||||||||||
| RETURN_NOT_OK(ZeroCopyCastExec(ctx, batch, out)); | ||||||||||||||||||||||||||||||||||||||||||
| std::shared_ptr<ArrayData> input_arr = input.ToArrayData(); | ||||||||||||||||||||||||||||||||||||||||||
| ArrayData* output = out->array_data().get(); | ||||||||||||||||||||||||||||||||||||||||||
| output->length = input_arr->length; | ||||||||||||||||||||||||||||||||||||||||||
| output->SetNullCount(input_arr->null_count); | ||||||||||||||||||||||||||||||||||||||||||
| output->buffers = std::move(input_arr->buffers); | ||||||||||||||||||||||||||||||||||||||||||
| output->child_data = std::move(input_arr->child_data); | ||||||||||||||||||||||||||||||||||||||||||
scott-routledge2 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||
| if (output->buffers[0]) { | ||||||||||||||||||||||||||||||||||||||||||
| // If reusing the null bitmap, ensure offset into the first byte is the same as input. | ||||||||||||||||||||||||||||||||||||||||||
| output->offset = input_arr->offset % 8; | ||||||||||||||||||||||||||||||||||||||||||
| output->buffers[0] = SliceBuffer(output->buffers[0], input_arr->offset / 8); | ||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||
| output->offset = 0; | ||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
| if (output->buffers[0]) { | |
| // If reusing the null bitmap, ensure offset into the first byte is the same as input. | |
| output->offset = input_arr->offset % 8; | |
| output->buffers[0] = SliceBuffer(output->buffers[0], input_arr->offset / 8); | |
| } else { | |
| output->offset = 0; | |
| } | |
| // slice buffers to reduce allocation when casting the offsets buffer | |
| auto length = input_arr->length; | |
| int64_t buffer_offset = 0; | |
| if (output->null_count != 0 && output->buffers[0]) { | |
| // avoiding reallocation of the validity buffer by allowing some padding bits | |
| output->offset = input_arr->offset % 8; | |
| buffer_offset = input_arr->offset / 8; | |
| } else { | |
| output->offset = 0; | |
| buffer_offset = input_arr->offset; | |
| } | |
| output->buffers[0] = SliceBuffer(output->buffers[0], buffer_offset, length); | |
| output->buffers[1] = SliceBuffer(output->buffers[1], buffer_offset, length); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please review my suggestions and tell if something is weird. This stuff is hard.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the suggestions! I didn't slice the offset buffers originally because they are reallocated by CastBinaryToBinaryOffsets with the correct offset. Although, this would only be true for the case where the offset type changes, in the case where the offset stays the same then we would either have to slice here or call ZeroCopyCastExec like in the comment above?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But if you don't slice they get reallocated with the same length, no? Nevertheless, it becomes a creates a very weird relationship between this code and the function. Making it very non-obvious how it is correct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the late reply. What you are saying makes sense, however, I think I am still a little confused about specifics of the slicing here. Wouldn't we want to slice the offset buffer with a different value than the validity buffer?
For example, if we are casting a slice that has length 8 and offset 8, we would slice the
validity buffer with a value of 1, and be left with a buffer of length 1 representing the 8 null bits for the elements in our casted slice. We would also slice the offsets buffer by 1, which would mean the buffer will have length 17*offset_size - 1 and be out of alignment.
Similarly in the case where we have output->null_count == 0 (and buffer[0] != nullptr), we would slice the offset buffer by 8, leaving a buffer of size 17*offset_size - 8 and we would also slice the validity buffer by 8 , which would go out of bounds.
Wouldn't we want to slice the offsets buffer by input_arr->offset* sizeof(typename I::offset_type) and the validity buffer by input_arr->offset / 8
Edit: I think the "offset" in SliceBuffer is the byte-offset as opposed to the logical offset.
Uh oh!
There was an error while loading. Please reload this page.