[
https://issues.apache.org/jira/browse/ARROW-764?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16321211#comment-16321211
]
ASF GitHub Bot commented on ARROW-764:
--------------------------------------
wesm closed pull request #1422: ARROW-764: [C++] Improves performance of
CopyBitmap and adds benchmarks
URL: https://github.com/apache/arrow/pull/1422
This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:
As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):
diff --git a/cpp/src/arrow/util/CMakeLists.txt
b/cpp/src/arrow/util/CMakeLists.txt
index a36dffb52..8b61a3acf 100644
--- a/cpp/src/arrow/util/CMakeLists.txt
+++ b/cpp/src/arrow/util/CMakeLists.txt
@@ -63,10 +63,10 @@ if (ARROW_BUILD_BENCHMARKS)
Shlwapi.lib
)
else()
- target_link_libraries(arrow_benchmark_main
+ target_link_libraries(arrow_benchmark_main
benchmark
pthread
- )
+ )
endif()
# TODO(wesm): Some benchmarks include gtest.h
@@ -80,4 +80,6 @@ ADD_ARROW_TEST(key-value-metadata-test)
ADD_ARROW_TEST(rle-encoding-test)
ADD_ARROW_TEST(stl-util-test)
+ADD_ARROW_BENCHMARK(bit-util-benchmark)
+
add_subdirectory(variant)
diff --git a/cpp/src/arrow/util/bit-util-benchmark.cc
b/cpp/src/arrow/util/bit-util-benchmark.cc
new file mode 100644
index 000000000..8969dd80b
--- /dev/null
+++ b/cpp/src/arrow/util/bit-util-benchmark.cc
@@ -0,0 +1,58 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "benchmark/benchmark.h"
+
+#include <vector>
+
+#include "arrow/buffer.h"
+#include "arrow/builder.h"
+#include "arrow/memory_pool.h"
+#include "arrow/test-util.h"
+#include "arrow/util/bit-util.h"
+
+namespace arrow {
+namespace BitUtil {
+
+static void BM_CopyBitmap(benchmark::State& state) { // NOLINT non-const
reference
+ const int kBufferSize = state.range(0);
+
+ std::shared_ptr<Buffer> buffer;
+ ASSERT_OK(AllocateBuffer(default_memory_pool(), kBufferSize, &buffer));
+ memset(buffer->mutable_data(), 0, kBufferSize);
+ test::random_bytes(kBufferSize, 0, buffer->mutable_data());
+
+ const int num_bits = kBufferSize * 8;
+ const uint8_t* src = buffer->data();
+
+ std::shared_ptr<Buffer> copy;
+ while (state.KeepRunning()) {
+ ABORT_NOT_OK(CopyBitmap(default_memory_pool(), src, state.range(1),
num_bits, ©));
+ }
+ state.SetBytesProcessed(state.iterations() * kBufferSize * sizeof(int8_t));
+}
+
+BENCHMARK(BM_CopyBitmap)
+ ->Args({100000, 0})
+ ->Args({1000000, 0})
+ ->Args({100000, 4})
+ ->Args({1000000, 4})
+ ->MinTime(1.0)
+ ->Unit(benchmark::kMicrosecond);
+
+} // namespace BitUtil
+} // namespace arrow
diff --git a/cpp/src/arrow/util/bit-util-test.cc
b/cpp/src/arrow/util/bit-util-test.cc
index 92bdcb5fc..4c64dea37 100644
--- a/cpp/src/arrow/util/bit-util-test.cc
+++ b/cpp/src/arrow/util/bit-util-test.cc
@@ -165,19 +165,20 @@ TEST(BitUtilTests, TestCopyBitmap) {
memset(buffer->mutable_data(), 0, kBufferSize);
test::random_bytes(kBufferSize, 0, buffer->mutable_data());
- const int num_bits = kBufferSize * 8;
-
const uint8_t* src = buffer->data();
+ std::vector<int64_t> lengths = {kBufferSize * 8 - 4, kBufferSize * 8};
std::vector<int64_t> offsets = {0, 12, 16, 32, 37, 63, 64, 128};
- for (int64_t offset : offsets) {
- const int64_t copy_length = num_bits - offset;
+ for (int64_t num_bits : lengths) {
+ for (int64_t offset : offsets) {
+ const int64_t copy_length = num_bits - offset;
- std::shared_ptr<Buffer> copy;
- ASSERT_OK(CopyBitmap(default_memory_pool(), src, offset, copy_length,
©));
+ std::shared_ptr<Buffer> copy;
+ ASSERT_OK(CopyBitmap(default_memory_pool(), src, offset, copy_length,
©));
- for (int64_t i = 0; i < copy_length; ++i) {
- ASSERT_EQ(BitUtil::GetBit(src, i + offset),
BitUtil::GetBit(copy->data(), i));
+ for (int64_t i = 0; i < copy_length; ++i) {
+ ASSERT_EQ(BitUtil::GetBit(src, i + offset),
BitUtil::GetBit(copy->data(), i));
+ }
}
}
}
diff --git a/cpp/src/arrow/util/bit-util.cc b/cpp/src/arrow/util/bit-util.cc
index 4dd91e99a..c77f0d008 100644
--- a/cpp/src/arrow/util/bit-util.cc
+++ b/cpp/src/arrow/util/bit-util.cc
@@ -109,9 +109,37 @@ Status CopyBitmap(MemoryPool* pool, const uint8_t* data,
int64_t offset, int64_t
std::shared_ptr<Buffer> buffer;
RETURN_NOT_OK(GetEmptyBitmap(pool, length, &buffer));
uint8_t* dest = buffer->mutable_data();
- for (int64_t i = 0; i < length; ++i) {
- BitUtil::SetBitTo(dest, i, BitUtil::GetBit(data, i + offset));
+
+ int64_t byte_offset = offset / 8;
+ int64_t bit_offset = offset % 8;
+ int64_t num_bytes = BitUtil::BytesForBits(length);
+ int64_t bits_to_zero = num_bytes * 8 - length;
+
+ if (bit_offset > 0) {
+ uint32_t carry_mask = BitUtil::kBitmask[bit_offset] - 1U;
+ uint32_t carry_shift = 8U - static_cast<uint32_t>(bit_offset);
+
+ uint32_t carry = 0U;
+ if (BitUtil::BytesForBits(length + bit_offset) > num_bytes) {
+ carry = (data[byte_offset + num_bytes] & carry_mask) << carry_shift;
+ }
+
+ int64_t i = num_bytes - 1;
+ while (i + 1 > 0) {
+ uint8_t cur_byte = data[byte_offset + i];
+ dest[i] = static_cast<uint8_t>((cur_byte >> bit_offset) | carry);
+ carry = (cur_byte & carry_mask) << carry_shift;
+ --i;
+ }
+ } else {
+ std::memcpy(dest, data + byte_offset, static_cast<size_t>(num_bytes));
+ }
+
+ for (int64_t i = length; i < length + bits_to_zero; ++i) {
+ // Both branches may copy extra bits - unsetting to match specification.
+ BitUtil::SetBitTo(dest, i, false);
}
+
*out = buffer;
return Status::OK();
}
diff --git a/cpp/src/arrow/util/bit-util.h b/cpp/src/arrow/util/bit-util.h
index cab3c9ee7..86c17d168 100644
--- a/cpp/src/arrow/util/bit-util.h
+++ b/cpp/src/arrow/util/bit-util.h
@@ -139,13 +139,10 @@ static inline void SetArrayBit(uint8_t* bits, int i, bool
is_set) {
}
static inline void SetBitTo(uint8_t* bits, int64_t i, bool bit_is_set) {
- // TODO: speed up. See https://graphics.stanford.edu/~seander/bithacks.html
+ // https://graphics.stanford.edu/~seander/bithacks.html
// "Conditionally set or clear bits without branching"
- if (bit_is_set) {
- SetBit(bits, i);
- } else {
- ClearBit(bits, i);
- }
+ bits[i / 8] ^= static_cast<uint8_t>(-static_cast<uint8_t>(bit_is_set) ^
bits[i / 8]) &
+ kBitmask[i % 8];
}
// Returns the minimum number of bits needed to represent the value of 'x'
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]
> [C++] Improve performance of CopyBitmap, add benchmarks
> -------------------------------------------------------
>
> Key: ARROW-764
> URL: https://issues.apache.org/jira/browse/ARROW-764
> Project: Apache Arrow
> Issue Type: Improvement
> Components: C++
> Reporter: Wes McKinney
> Assignee: Adam Seibert
> Labels: pull-request-available
> Fix For: 0.9.0
>
>
> This is follow up work after a discussion in the patch for ARROW-657
--
This message was sent by Atlassian JIRA
(v6.4.14#64029)