You are viewing a plain text version of this content. The canonical link for it is here.
Posted to github@arrow.apache.org by "felipecrv (via GitHub)" <gi...@apache.org> on 2024/09/04 15:04:31 UTC

[PR] [C++] [arrow]

felipecrv opened a new pull request, #43954:
URL: https://github.com/apache/arrow/pull/43954

   ### Rationale for this change
   
   Improve tests and add benchmarks. I wrote the tests and benchmarks while trying to improve the performance of `ResolveMany` and failing at it.
   
   ### What changes are included in this PR?
   
   Tests, benchmarks, and changes that don't really affect performance but might unlock more optimization opportunities in the future.
   
   ### Are these changes tested?
   
   Yes.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] GH-43953: [C++] Add tests based on random data and benchmarks to ChunkResolver::ResolveMany [arrow]

Posted by "felipecrv (via GitHub)" <gi...@apache.org>.
felipecrv commented on PR #43954:
URL: https://github.com/apache/arrow/pull/43954#issuecomment-2329612449

   > There are a number of CI failures that need fixing.
   
   TIL `uniform_int_distribution` can't take `(u)int8_t` as type parameter on MSVC builds.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] GH-43953: [C++] Add tests based on random data and benchmarks to ChunkResolver::ResolveMany [arrow]

Posted by "pitrou (via GitHub)" <gi...@apache.org>.
pitrou commented on PR #43954:
URL: https://github.com/apache/arrow/pull/43954#issuecomment-2371262208

   Just a question: do you mean to keep the 64-bit to 32-bit chunk index change?


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] GH-43953: [C++] Add tests based on random data and benchmarks to ChunkResolver::ResolveMany [arrow]

Posted by "github-actions[bot] (via GitHub)" <gi...@apache.org>.
github-actions[bot] commented on PR #43954:
URL: https://github.com/apache/arrow/pull/43954#issuecomment-2329317109

   :warning: GitHub issue #43953 **has been automatically assigned in GitHub** to PR creator.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] GH-43953: [C++] Add tests based on random data and benchmarks to ChunkResolver::ResolveMany [arrow]

Posted by "felipecrv (via GitHub)" <gi...@apache.org>.
felipecrv commented on code in PR #43954:
URL: https://github.com/apache/arrow/pull/43954#discussion_r1744106248


##########
cpp/src/arrow/chunked_array_test.cc:
##########
@@ -373,10 +374,27 @@ TEST(TestChunkResolver, Resolve) {
   ASSERT_EQ(resolver.Resolve(10).chunk_index, 3);
 }
 
+template <class RNG>
+std::vector<int64_t> GenChunkedArrayOffsets(RNG& rng, int32_t num_chunks,
+                                            int64_t chunked_array_len) {
+  std::uniform_int_distribution<int64_t> offset_gen(1, chunked_array_len - 1);
+  std::vector<int64_t> offsets;
+  offsets.reserve(num_chunks + 1);
+  offsets.push_back(0);
+  while (offsets.size() < static_cast<size_t>(num_chunks)) {
+    offsets.push_back(offset_gen(rng));
+  }
+  offsets.push_back(chunked_array_len);
+  std::sort(offsets.begin() + 1, offsets.end());
+  return offsets;
+}
+
 template <typename T>
 class TestChunkResolverMany : public ::testing::Test {
  public:
   using IndexType = T;
+  static constexpr int32_t kMaxInt32 = std::numeric_limits<int32_t>::max();
+  static constexpr size_t kMaxValidIndex = std::numeric_limits<IndexType>::max();

Review Comment:
   True. Let me fix this.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] GH-43953: [C++] Add tests based on random data and benchmarks to ChunkResolver::ResolveMany [arrow]

Posted by "pitrou (via GitHub)" <gi...@apache.org>.
pitrou merged PR #43954:
URL: https://github.com/apache/arrow/pull/43954


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] GH-43953: [C++] Add tests based on random data and benchmarks to ChunkResolver::ResolveMany [arrow]

Posted by "felipecrv (via GitHub)" <gi...@apache.org>.
felipecrv commented on PR #43954:
URL: https://github.com/apache/arrow/pull/43954#issuecomment-2369722907

   @pitrou now it's all green. The only failure is unrelated.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] GH-43953: [C++] Add tests based on random data and benchmarks to ChunkResolver::ResolveMany [arrow]

Posted by "pitrou (via GitHub)" <gi...@apache.org>.
pitrou commented on PR #43954:
URL: https://github.com/apache/arrow/pull/43954#issuecomment-2329388308

   Ironically, uint32 seems slightly slower than both uint16 and uint64. Not sure that's due to the compiler or to the CPU.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] GH-43953: [C++] Add tests based on random data and benchmarks to ChunkResolver::ResolveMany [arrow]

Posted by "pitrou (via GitHub)" <gi...@apache.org>.
pitrou commented on PR #43954:
URL: https://github.com/apache/arrow/pull/43954#issuecomment-2346281570

   > The `chunk_hint` stuff really works. I forgot to plot it, but without it the throughput gains don't exist when indices are sorted.
   
   Yes, it's also quite dramatic for the actual Sort implementation :-)


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] GH-43953: [C++] Add tests based on random data and benchmarks to ChunkResolver::ResolveMany [arrow]

Posted by "felipecrv (via GitHub)" <gi...@apache.org>.
felipecrv commented on PR #43954:
URL: https://github.com/apache/arrow/pull/43954#issuecomment-2371844257

   > Just a question: do you mean to keep the 64-bit to 32-bit chunk index change?
   
   Yes I do.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] GH-43953: [C++] Add tests based on random data and benchmarks to ChunkResolver::ResolveMany [arrow]

Posted by "conbench-apache-arrow[bot] (via GitHub)" <gi...@apache.org>.
conbench-apache-arrow[bot] commented on PR #43954:
URL: https://github.com/apache/arrow/pull/43954#issuecomment-2372491212

   After merging your PR, Conbench analyzed the 3 benchmarking runs that have been run so far on merge-commit 83f35de2ebe4672d0d57290840d0153ac8a016e8.
   
   There were no benchmark performance regressions. 🎉
   
   The [full Conbench report](https://github.com/apache/arrow/runs/30612872044) has more details. It also includes information about 16 possible false positives for unstable benchmarks that are known to sometimes produce them.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] GH-43953: [C++] Add tests based on random data and benchmarks to ChunkResolver::ResolveMany [arrow]

Posted by "felipecrv (via GitHub)" <gi...@apache.org>.
felipecrv commented on PR #43954:
URL: https://github.com/apache/arrow/pull/43954#issuecomment-2329562976

   > Ironically, uint32 seems slightly slower than both uint16 and uint64. Not sure that's due to the compiler or to the CPU.
   
   Same on `12th Gen Intel(R) Core(TM) i7-12800H`. This is the reason I changed `lo` and `hi` to `uint32_t` and nothing changed in the benchmarks.
   
   Things are saner on the Apple M1 Pro with 32-bit being the fastest.
   
   ```
   Run on (8 X 24 MHz CPU s)
   CPU Caches:
     L1 Data 64 KiB
     L1 Instruction 128 KiB
     L2 Unified 4096 KiB (x8)
   Load Average: 14.23, 6.75, 4.28
   ------------------------------------------------------------------------------------------------
   Benchmark                                      Time             CPU   Iterations UserCounters...
   ------------------------------------------------------------------------------------------------
   ResolveManyUInt16Random/65535/100/508       2769 ns         2747 ns       252543 items_per_second=184.959M/s logical_len=65.535k num_chunks=100
   ResolveManyUInt32Random/65535/100/508       2715 ns         2689 ns       257431 items_per_second=188.93M/s logical_len=65.535k num_chunks=100
   ResolveManyUInt64Random/65535/100/508       2928 ns         2757 ns       252188 items_per_second=184.281M/s logical_len=65.535k num_chunks=100
   ResolveManyUInt16Sorted/65535/100/508       1023 ns         1012 ns       693694 items_per_second=501.751M/s logical_len=65.535k num_chunks=100
   ResolveManyUInt32Sorted/65535/100/508        929 ns          920 ns       761052 items_per_second=551.881M/s logical_len=65.535k num_chunks=100
   ResolveManyUInt64Sorted/65535/100/508        933 ns          926 ns       759878 items_per_second=548.86M/s logical_len=65.535k num_chunks=100
   ```


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] GH-43953: [C++] Add tests based on random data and benchmarks to ChunkResolver::ResolveMany [arrow]

Posted by "felipecrv (via GitHub)" <gi...@apache.org>.
felipecrv commented on code in PR #43954:
URL: https://github.com/apache/arrow/pull/43954#discussion_r1744110158


##########
cpp/src/arrow/chunk_resolver_benchmark.cc:
##########
@@ -0,0 +1,166 @@
+// 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 <algorithm>
+#include <cstdint>
+#include <random>
+#include <vector>
+
+#include "arrow/chunk_resolver.h"
+#include "arrow/util/benchmark_util.h"
+#include "arrow/util/pcg_random.h"
+
+namespace arrow {
+
+using internal::ChunkResolver;
+using internal::TypedChunkLocation;
+
+namespace {
+
+int64_t constexpr kChunkedArrayLength = std::numeric_limits<uint16_t>::max();
+
+struct ResolveManyBenchmark {
+  benchmark::State& state;
+  random::pcg64 rng;
+  // Values from the state.range(i)
+  int64_t chunked_array_length;
+  int32_t num_chunks;
+  int64_t num_logical_indices;
+
+  explicit ResolveManyBenchmark(benchmark::State& state)
+      : state(state),
+        rng(42),
+        chunked_array_length(state.range(0)),
+        num_chunks(static_cast<int32_t>(state.range(1))),
+        num_logical_indices(state.range(2)) {}
+
+  std::vector<int64_t> GenChunkedArrayOffsets() {
+    std::uniform_int_distribution<int64_t> offset_gen(1, chunked_array_length);
+    std::vector<int64_t> offsets;
+    offsets.reserve(num_chunks + 1);
+    offsets.push_back(0);
+    while (offsets.size() < static_cast<size_t>(num_chunks)) {
+      offsets.push_back(offset_gen(rng));
+    }
+    offsets.push_back(chunked_array_length);
+    std::sort(offsets.begin() + 1, offsets.end());
+    return offsets;
+  }
+
+  template <typename IndexType>
+  std::vector<IndexType> GenRandomIndices(IndexType max_index, bool sorted) {
+    std::uniform_int_distribution<IndexType> index_gen(0, max_index);
+    std::vector<IndexType> indices;
+    indices.reserve(num_logical_indices);
+    while (indices.size() < static_cast<size_t>(num_logical_indices)) {
+      indices.push_back(index_gen(rng));
+    }
+    if (sorted) {
+      std::sort(indices.begin(), indices.end());
+    }
+    return indices;
+  }
+
+  template <typename IndexType>
+  void Bench(bool sorted) {
+    if constexpr (sizeof(IndexType) < 8) {
+      constexpr uint64_t kLimitIndex = std::numeric_limits<IndexType>::max();
+      ARROW_CHECK_LE(static_cast<uint64_t>(chunked_array_length), kLimitIndex);
+    }
+    const auto max_random_index = static_cast<IndexType>(chunked_array_length);
+    auto offsets = GenChunkedArrayOffsets();
+    auto logical_indices = GenRandomIndices<IndexType>(max_random_index, sorted);
+    ChunkResolver resolver(std::move(offsets));
+    std::vector<TypedChunkLocation<IndexType>> chunk_location_vec(num_logical_indices);
+    BENCHMARK_UNUSED bool all_succeeded = true;
+    for (auto _ : state) {
+      const bool success = resolver.ResolveMany<IndexType>(
+          num_logical_indices, logical_indices.data(), chunk_location_vec.data());
+      all_succeeded &= success;
+    }
+    ARROW_CHECK(all_succeeded);
+    state.counters["logical_len"] = static_cast<double>(chunked_array_length);
+    state.counters["num_chunks"] = static_cast<double>(num_chunks);
+    state.SetItemsProcessed(state.iterations() * num_logical_indices);
+  }
+};
+
+template <typename IndexType>
+void ResolveManySetArgs(benchmark::internal::Benchmark* bench) {
+  constexpr int32_t kNonAligned = 3;
+  const int64_t kNumIndicesFew = (kChunkedArrayLength >> 7) - kNonAligned;
+  const int64_t kNumIndicesMany = (kChunkedArrayLength >> 1) - kNonAligned;
+
+  switch (sizeof(IndexType)) {
+    case 1:
+      // Unexpected. See comments below.
+    case 2:
+    case 4:
+    case 8:
+      bench->Args({kChunkedArrayLength, /*num_chunks*/ 10000, kNumIndicesFew});

Review Comment:
   The huge number is necessary (even though it's a bit unrealistic) to measure how effective the binary search is at reducing the search space (proportional to the number of chunks).



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] GH-43953: [C++] Add tests based on random data and benchmarks to ChunkResolver::ResolveMany [arrow]

Posted by "felipecrv (via GitHub)" <gi...@apache.org>.
felipecrv commented on code in PR #43954:
URL: https://github.com/apache/arrow/pull/43954#discussion_r1744101619


##########
cpp/src/arrow/chunked_array.cc:
##########
@@ -55,7 +55,7 @@ ChunkedArray::ChunkedArray(ArrayVector chunks, std::shared_ptr<DataType> type)
         << "cannot construct ChunkedArray from empty vector and omitted type";
     type_ = chunks_[0]->type();
   }
-
+  ARROW_CHECK_LE(chunks.size(), std::numeric_limits<int>::max());

Review Comment:
   This is useful in ensuring we are not generating more chunks than can be addressed by the index type.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [C++] [arrow]

Posted by "github-actions[bot] (via GitHub)" <gi...@apache.org>.
github-actions[bot] commented on PR #43954:
URL: https://github.com/apache/arrow/pull/43954#issuecomment-2329314781

   <!--
     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.
   -->
   
   Thanks for opening a pull request!
   
   If this is not a [minor PR](https://github.com/apache/arrow/blob/main/CONTRIBUTING.md#Minor-Fixes). Could you open an issue for this pull request on GitHub? https://github.com/apache/arrow/issues/new/choose
   
   Opening GitHub issues ahead of time contributes to the [Openness](http://theapacheway.com/open/#:~:text=Openness%20allows%20new%20users%20the,must%20happen%20in%20the%20open.) of the Apache Arrow project.
   
   Then could you also rename the pull request title in the following format?
   
       GH-${GITHUB_ISSUE_ID}: [${COMPONENT}] ${SUMMARY}
   
   or
   
       MINOR: [${COMPONENT}] ${SUMMARY}
   
   In the case of PARQUET issues on JIRA the title also supports:
   
       PARQUET-${JIRA_ISSUE_ID}: [${COMPONENT}] ${SUMMARY}
   
   See also:
   
     * [Other pull requests](https://github.com/apache/arrow/pulls/)
     * [Contribution Guidelines - Contributing Overview](https://arrow.apache.org/docs/developers/overview.html)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] GH-43953: [C++] Add tests based on random data and benchmarks to ChunkResolver::ResolveMany [arrow]

Posted by "felipecrv (via GitHub)" <gi...@apache.org>.
felipecrv commented on code in PR #43954:
URL: https://github.com/apache/arrow/pull/43954#discussion_r1744100466


##########
cpp/src/arrow/chunk_resolver_benchmark.cc:
##########
@@ -0,0 +1,166 @@
+// 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 <algorithm>
+#include <cstdint>
+#include <random>
+#include <vector>
+
+#include "arrow/chunk_resolver.h"
+#include "arrow/util/benchmark_util.h"
+#include "arrow/util/pcg_random.h"
+
+namespace arrow {
+
+using internal::ChunkResolver;
+using internal::TypedChunkLocation;
+
+namespace {
+
+int64_t constexpr kChunkedArrayLength = std::numeric_limits<uint16_t>::max();
+
+struct ResolveManyBenchmark {
+  benchmark::State& state;
+  random::pcg64 rng;
+  // Values from the state.range(i)
+  int64_t chunked_array_length;
+  int32_t num_chunks;
+  int64_t num_logical_indices;
+
+  explicit ResolveManyBenchmark(benchmark::State& state)
+      : state(state),
+        rng(42),
+        chunked_array_length(state.range(0)),
+        num_chunks(static_cast<int32_t>(state.range(1))),
+        num_logical_indices(state.range(2)) {}
+
+  std::vector<int64_t> GenChunkedArrayOffsets() {
+    std::uniform_int_distribution<int64_t> offset_gen(1, chunked_array_length);
+    std::vector<int64_t> offsets;
+    offsets.reserve(num_chunks + 1);
+    offsets.push_back(0);
+    while (offsets.size() < static_cast<size_t>(num_chunks)) {
+      offsets.push_back(offset_gen(rng));
+    }
+    offsets.push_back(chunked_array_length);
+    std::sort(offsets.begin() + 1, offsets.end());
+    return offsets;
+  }
+
+  template <typename IndexType>
+  std::vector<IndexType> GenRandomIndices(IndexType max_index, bool sorted) {
+    std::uniform_int_distribution<IndexType> index_gen(0, max_index);
+    std::vector<IndexType> indices;
+    indices.reserve(num_logical_indices);
+    while (indices.size() < static_cast<size_t>(num_logical_indices)) {
+      indices.push_back(index_gen(rng));
+    }
+    if (sorted) {
+      std::sort(indices.begin(), indices.end());
+    }
+    return indices;
+  }
+
+  template <typename IndexType>
+  void Bench(bool sorted) {
+    if constexpr (sizeof(IndexType) < 8) {
+      constexpr uint64_t kLimitIndex = std::numeric_limits<IndexType>::max();
+      ARROW_CHECK_LE(static_cast<uint64_t>(chunked_array_length), kLimitIndex);
+    }
+    const auto max_random_index = static_cast<IndexType>(chunked_array_length);
+    auto offsets = GenChunkedArrayOffsets();
+    auto logical_indices = GenRandomIndices<IndexType>(max_random_index, sorted);
+    ChunkResolver resolver(std::move(offsets));
+    std::vector<TypedChunkLocation<IndexType>> chunk_location_vec(num_logical_indices);
+    BENCHMARK_UNUSED bool all_succeeded = true;
+    for (auto _ : state) {
+      const bool success = resolver.ResolveMany<IndexType>(
+          num_logical_indices, logical_indices.data(), chunk_location_vec.data());
+      all_succeeded &= success;
+    }
+    ARROW_CHECK(all_succeeded);
+    state.counters["logical_len"] = static_cast<double>(chunked_array_length);
+    state.counters["num_chunks"] = static_cast<double>(num_chunks);
+    state.SetItemsProcessed(state.iterations() * num_logical_indices);
+  }
+};
+
+template <typename IndexType>
+void ResolveManySetArgs(benchmark::internal::Benchmark* bench) {
+  constexpr int32_t kNonAligned = 3;

Review Comment:
   The optimizations I was experimenting with involved some unrolling so I didn't want input values to neatly align to powers of 2.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] GH-43953: [C++] Add tests based on random data and benchmarks to ChunkResolver::ResolveMany [arrow]

Posted by "felipecrv (via GitHub)" <gi...@apache.org>.
felipecrv commented on PR #43954:
URL: https://github.com/apache/arrow/pull/43954#issuecomment-2329329142

   The `chunk_hint` stuff really works. I forgot to plot it, but without it the throughput gains don't exist when indices are sorted.
   
   ![resolvemany](https://github.com/user-attachments/assets/a2ec22ed-7cfa-4c19-a5dd-c5ccd4711eab)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] GH-43953: [C++] Add tests based on random data and benchmarks to ChunkResolver::ResolveMany [arrow]

Posted by "pitrou (via GitHub)" <gi...@apache.org>.
pitrou commented on code in PR #43954:
URL: https://github.com/apache/arrow/pull/43954#discussion_r1744018656


##########
cpp/src/arrow/chunk_resolver_benchmark.cc:
##########
@@ -0,0 +1,166 @@
+// 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 <algorithm>
+#include <cstdint>
+#include <random>
+#include <vector>
+
+#include "arrow/chunk_resolver.h"
+#include "arrow/util/benchmark_util.h"
+#include "arrow/util/pcg_random.h"
+
+namespace arrow {
+
+using internal::ChunkResolver;
+using internal::TypedChunkLocation;
+
+namespace {
+
+int64_t constexpr kChunkedArrayLength = std::numeric_limits<uint16_t>::max();
+
+struct ResolveManyBenchmark {
+  benchmark::State& state;
+  random::pcg64 rng;
+  // Values from the state.range(i)
+  int64_t chunked_array_length;
+  int32_t num_chunks;
+  int64_t num_logical_indices;
+
+  explicit ResolveManyBenchmark(benchmark::State& state)
+      : state(state),
+        rng(42),
+        chunked_array_length(state.range(0)),
+        num_chunks(static_cast<int32_t>(state.range(1))),
+        num_logical_indices(state.range(2)) {}
+
+  std::vector<int64_t> GenChunkedArrayOffsets() {
+    std::uniform_int_distribution<int64_t> offset_gen(1, chunked_array_length);
+    std::vector<int64_t> offsets;
+    offsets.reserve(num_chunks + 1);
+    offsets.push_back(0);
+    while (offsets.size() < static_cast<size_t>(num_chunks)) {
+      offsets.push_back(offset_gen(rng));
+    }
+    offsets.push_back(chunked_array_length);
+    std::sort(offsets.begin() + 1, offsets.end());
+    return offsets;
+  }
+
+  template <typename IndexType>
+  std::vector<IndexType> GenRandomIndices(IndexType max_index, bool sorted) {
+    std::uniform_int_distribution<IndexType> index_gen(0, max_index);
+    std::vector<IndexType> indices;
+    indices.reserve(num_logical_indices);
+    while (indices.size() < static_cast<size_t>(num_logical_indices)) {
+      indices.push_back(index_gen(rng));
+    }
+    if (sorted) {
+      std::sort(indices.begin(), indices.end());
+    }
+    return indices;
+  }
+
+  template <typename IndexType>
+  void Bench(bool sorted) {
+    if constexpr (sizeof(IndexType) < 8) {
+      constexpr uint64_t kLimitIndex = std::numeric_limits<IndexType>::max();
+      ARROW_CHECK_LE(static_cast<uint64_t>(chunked_array_length), kLimitIndex);
+    }
+    const auto max_random_index = static_cast<IndexType>(chunked_array_length);
+    auto offsets = GenChunkedArrayOffsets();
+    auto logical_indices = GenRandomIndices<IndexType>(max_random_index, sorted);
+    ChunkResolver resolver(std::move(offsets));
+    std::vector<TypedChunkLocation<IndexType>> chunk_location_vec(num_logical_indices);
+    BENCHMARK_UNUSED bool all_succeeded = true;
+    for (auto _ : state) {
+      const bool success = resolver.ResolveMany<IndexType>(
+          num_logical_indices, logical_indices.data(), chunk_location_vec.data());
+      all_succeeded &= success;
+    }
+    ARROW_CHECK(all_succeeded);
+    state.counters["logical_len"] = static_cast<double>(chunked_array_length);
+    state.counters["num_chunks"] = static_cast<double>(num_chunks);
+    state.SetItemsProcessed(state.iterations() * num_logical_indices);
+  }
+};
+
+template <typename IndexType>
+void ResolveManySetArgs(benchmark::internal::Benchmark* bench) {
+  constexpr int32_t kNonAligned = 3;

Review Comment:
   Can you explain what this is for?



##########
cpp/src/arrow/chunk_resolver_benchmark.cc:
##########
@@ -0,0 +1,166 @@
+// 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 <algorithm>
+#include <cstdint>
+#include <random>
+#include <vector>
+
+#include "arrow/chunk_resolver.h"
+#include "arrow/util/benchmark_util.h"
+#include "arrow/util/pcg_random.h"
+
+namespace arrow {
+
+using internal::ChunkResolver;
+using internal::TypedChunkLocation;
+
+namespace {
+
+int64_t constexpr kChunkedArrayLength = std::numeric_limits<uint16_t>::max();
+
+struct ResolveManyBenchmark {
+  benchmark::State& state;
+  random::pcg64 rng;
+  // Values from the state.range(i)
+  int64_t chunked_array_length;
+  int32_t num_chunks;
+  int64_t num_logical_indices;
+
+  explicit ResolveManyBenchmark(benchmark::State& state)
+      : state(state),
+        rng(42),
+        chunked_array_length(state.range(0)),
+        num_chunks(static_cast<int32_t>(state.range(1))),
+        num_logical_indices(state.range(2)) {}
+
+  std::vector<int64_t> GenChunkedArrayOffsets() {
+    std::uniform_int_distribution<int64_t> offset_gen(1, chunked_array_length);
+    std::vector<int64_t> offsets;
+    offsets.reserve(num_chunks + 1);
+    offsets.push_back(0);
+    while (offsets.size() < static_cast<size_t>(num_chunks)) {
+      offsets.push_back(offset_gen(rng));
+    }
+    offsets.push_back(chunked_array_length);
+    std::sort(offsets.begin() + 1, offsets.end());
+    return offsets;
+  }
+
+  template <typename IndexType>
+  std::vector<IndexType> GenRandomIndices(IndexType max_index, bool sorted) {
+    std::uniform_int_distribution<IndexType> index_gen(0, max_index);
+    std::vector<IndexType> indices;
+    indices.reserve(num_logical_indices);
+    while (indices.size() < static_cast<size_t>(num_logical_indices)) {
+      indices.push_back(index_gen(rng));
+    }
+    if (sorted) {
+      std::sort(indices.begin(), indices.end());
+    }
+    return indices;
+  }
+
+  template <typename IndexType>
+  void Bench(bool sorted) {
+    if constexpr (sizeof(IndexType) < 8) {
+      constexpr uint64_t kLimitIndex = std::numeric_limits<IndexType>::max();
+      ARROW_CHECK_LE(static_cast<uint64_t>(chunked_array_length), kLimitIndex);
+    }
+    const auto max_random_index = static_cast<IndexType>(chunked_array_length);
+    auto offsets = GenChunkedArrayOffsets();
+    auto logical_indices = GenRandomIndices<IndexType>(max_random_index, sorted);
+    ChunkResolver resolver(std::move(offsets));
+    std::vector<TypedChunkLocation<IndexType>> chunk_location_vec(num_logical_indices);
+    BENCHMARK_UNUSED bool all_succeeded = true;
+    for (auto _ : state) {
+      const bool success = resolver.ResolveMany<IndexType>(
+          num_logical_indices, logical_indices.data(), chunk_location_vec.data());
+      all_succeeded &= success;
+    }
+    ARROW_CHECK(all_succeeded);
+    state.counters["logical_len"] = static_cast<double>(chunked_array_length);
+    state.counters["num_chunks"] = static_cast<double>(num_chunks);
+    state.SetItemsProcessed(state.iterations() * num_logical_indices);
+  }
+};
+
+template <typename IndexType>
+void ResolveManySetArgs(benchmark::internal::Benchmark* bench) {
+  constexpr int32_t kNonAligned = 3;
+  const int64_t kNumIndicesFew = (kChunkedArrayLength >> 7) - kNonAligned;
+  const int64_t kNumIndicesMany = (kChunkedArrayLength >> 1) - kNonAligned;
+
+  switch (sizeof(IndexType)) {
+    case 1:
+      // Unexpected. See comments below.
+    case 2:
+    case 4:
+    case 8:
+      bench->Args({kChunkedArrayLength, /*num_chunks*/ 10000, kNumIndicesFew});

Review Comment:
   10000 chunks is really a lot and I'm not sure it's really useful to test different numbers of chunks. By accumulating different combinations of parameters we make the benchmark results less immediately readable.



##########
cpp/src/arrow/chunked_array_test.cc:
##########
@@ -373,10 +374,27 @@ TEST(TestChunkResolver, Resolve) {
   ASSERT_EQ(resolver.Resolve(10).chunk_index, 3);
 }
 
+template <class RNG>
+std::vector<int64_t> GenChunkedArrayOffsets(RNG& rng, int32_t num_chunks,
+                                            int64_t chunked_array_len) {
+  std::uniform_int_distribution<int64_t> offset_gen(1, chunked_array_len - 1);
+  std::vector<int64_t> offsets;
+  offsets.reserve(num_chunks + 1);
+  offsets.push_back(0);
+  while (offsets.size() < static_cast<size_t>(num_chunks)) {
+    offsets.push_back(offset_gen(rng));
+  }
+  offsets.push_back(chunked_array_len);
+  std::sort(offsets.begin() + 1, offsets.end());
+  return offsets;
+}
+
 template <typename T>
 class TestChunkResolverMany : public ::testing::Test {
  public:
   using IndexType = T;
+  static constexpr int32_t kMaxInt32 = std::numeric_limits<int32_t>::max();
+  static constexpr size_t kMaxValidIndex = std::numeric_limits<IndexType>::max();

Review Comment:
   Shouldn't this be `uint64_t`? Especially for 32-bit platforms.



##########
cpp/src/arrow/chunked_array.cc:
##########
@@ -55,7 +55,7 @@ ChunkedArray::ChunkedArray(ArrayVector chunks, std::shared_ptr<DataType> type)
         << "cannot construct ChunkedArray from empty vector and omitted type";
     type_ = chunks_[0]->type();
   }
-
+  ARROW_CHECK_LE(chunks.size(), std::numeric_limits<int>::max());

Review Comment:
   Is this limit useful if it ends up not making performance better anyway?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] GH-43953: [C++] Add tests based on random data and benchmarks to ChunkResolver::ResolveMany [arrow]

Posted by "pitrou (via GitHub)" <gi...@apache.org>.
pitrou commented on PR #43954:
URL: https://github.com/apache/arrow/pull/43954#issuecomment-2329385204

   Results here (AMD Zen 2 CPU, gcc):
   ```
   ResolveManyUInt16Random/65535/10000/508         7072 ns         7071 ns        98917 items_per_second=71.8471M/s logical_len=65.535k num_chunks=10k
   ResolveManyUInt16Random/65535/100/508           4098 ns         4097 ns       170804 items_per_second=123.986M/s logical_len=65.535k num_chunks=100
   ResolveManyUInt16Random/65535/10000/32764    1812677 ns      1812178 ns          393 items_per_second=18.0799M/s logical_len=65.535k num_chunks=10k
   ResolveManyUInt16Random/65535/100/32764       723697 ns       723335 ns          876 items_per_second=45.2958M/s logical_len=65.535k num_chunks=100
   
   ResolveManyUInt32Random/65535/10000/508         7796 ns         7795 ns        88954 items_per_second=65.1731M/s logical_len=65.535k num_chunks=10k
   ResolveManyUInt32Random/65535/100/508           4397 ns         4396 ns       157489 items_per_second=115.566M/s logical_len=65.535k num_chunks=100
   ResolveManyUInt32Random/65535/10000/32764    1848926 ns      1848181 ns          379 items_per_second=17.7277M/s logical_len=65.535k num_chunks=10k
   ResolveManyUInt32Random/65535/100/32764       752273 ns       752045 ns          917 items_per_second=43.5665M/s logical_len=65.535k num_chunks=100
   
   ResolveManyUInt64Random/65535/10000/508         6731 ns         6730 ns       103505 items_per_second=75.4878M/s logical_len=65.535k num_chunks=10k
   ResolveManyUInt64Random/65535/100/508           4042 ns         4041 ns       172940 items_per_second=125.717M/s logical_len=65.535k num_chunks=100
   ResolveManyUInt64Random/65535/10000/32764    1809563 ns      1809068 ns          387 items_per_second=18.111M/s logical_len=65.535k num_chunks=10k
   ResolveManyUInt64Random/65535/100/32764       731165 ns       730968 ns          953 items_per_second=44.8227M/s logical_len=65.535k num_chunks=100
   
   ResolveManyUInt16Sorted/65535/10000/508         6233 ns         6231 ns       111713 items_per_second=81.5236M/s logical_len=65.535k num_chunks=10k
   ResolveManyUInt16Sorted/65535/100/508            955 ns          955 ns       728588 items_per_second=532.031M/s logical_len=65.535k num_chunks=100
   ResolveManyUInt16Sorted/65535/10000/32764     314016 ns       313931 ns         2221 items_per_second=104.367M/s logical_len=65.535k num_chunks=10k
   ResolveManyUInt16Sorted/65535/100/32764        41365 ns        41356 ns        17068 items_per_second=792.247M/s logical_len=65.535k num_chunks=100
   
   ResolveManyUInt32Sorted/65535/10000/508         7176 ns         7174 ns        91879 items_per_second=70.8084M/s logical_len=65.535k num_chunks=10k
   ResolveManyUInt32Sorted/65535/100/508            928 ns          928 ns       749739 items_per_second=547.568M/s logical_len=65.535k num_chunks=100
   ResolveManyUInt32Sorted/65535/10000/32764     326595 ns       326507 ns         2145 items_per_second=100.347M/s logical_len=65.535k num_chunks=10k
   ResolveManyUInt32Sorted/65535/100/32764        34162 ns        34154 ns        20518 items_per_second=959.309M/s logical_len=65.535k num_chunks=100
   
   ResolveManyUInt64Sorted/65535/10000/508         6057 ns         6055 ns       113029 items_per_second=83.8968M/s logical_len=65.535k num_chunks=10k
   ResolveManyUInt64Sorted/65535/100/508            994 ns          993 ns       700153 items_per_second=511.41M/s logical_len=65.535k num_chunks=100
   ResolveManyUInt64Sorted/65535/10000/32764     316107 ns       316023 ns         2212 items_per_second=103.676M/s logical_len=65.535k num_chunks=10k
   ResolveManyUInt64Sorted/65535/100/32764        38441 ns        38427 ns        20599 items_per_second=852.64M/s logical_len=65.535k num_chunks=100
   ```


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] GH-43953: [C++] Add tests based on random data and benchmarks to ChunkResolver::ResolveMany [arrow]

Posted by "pitrou (via GitHub)" <gi...@apache.org>.
pitrou commented on PR #43954:
URL: https://github.com/apache/arrow/pull/43954#issuecomment-2355881165

   There are still a couple compilation errors on CI it seems :-)


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] GH-43953: [C++] Add tests based on random data and benchmarks to ChunkResolver::ResolveMany [arrow]

Posted by "pitrou (via GitHub)" <gi...@apache.org>.
pitrou commented on PR #43954:
URL: https://github.com/apache/arrow/pull/43954#issuecomment-2329593768

   There are a number of CI failures that need fixing.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] GH-43953: [C++] Add tests based on random data and benchmarks to ChunkResolver::ResolveMany [arrow]

Posted by "pitrou (via GitHub)" <gi...@apache.org>.
pitrou commented on PR #43954:
URL: https://github.com/apache/arrow/pull/43954#issuecomment-2346346123

   There are still a couple CI failures that need fixing.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: github-unsubscribe@arrow.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org