Skip to content

Commit 6029803

Browse files
committed
Add micro-benchmark for count_min_sketch serialization
1 parent 76edd74 commit 6029803

3 files changed

Lines changed: 205 additions & 0 deletions

File tree

CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ if (BUILD_TESTS)
7474
enable_testing()
7575
endif()
7676

77+
option(BUILD_BENCHMARKS "Build benchmarks" OFF)
78+
7779
option(COVERAGE "Enable code coverage reporting (g++/clang only)" OFF)
7880
if(COVERAGE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
7981
set(CMAKE_BUILD_TYPE "Debug" FORCE)
@@ -120,6 +122,10 @@ add_subdirectory(count)
120122
add_subdirectory(density)
121123
add_subdirectory(tdigest)
122124

125+
if (BUILD_BENCHMARKS)
126+
add_subdirectory(benchmarks)
127+
endif()
128+
123129
if (WITH_PYTHON)
124130
add_subdirectory(python)
125131
endif()

benchmarks/CMakeLists.txt

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
18+
if (NOT TARGET benchmark::benchmark_main)
19+
include(FetchContent)
20+
21+
set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "Disable google-benchmark tests" FORCE)
22+
set(BENCHMARK_ENABLE_GTEST_TESTS OFF CACHE BOOL "Disable google-benchmark gtest tests" FORCE)
23+
set(BENCHMARK_ENABLE_INSTALL OFF CACHE BOOL "Disable google-benchmark install rules" FORCE)
24+
set(BENCHMARK_INSTALL_DOCS OFF CACHE BOOL "Disable google-benchmark documentation install" FORCE)
25+
set(BENCHMARK_ENABLE_WERROR OFF CACHE BOOL "Disable google-benchmark warnings as errors" FORCE)
26+
27+
FetchContent_Declare(
28+
googlebenchmark
29+
GIT_REPOSITORY https://github.com/google/benchmark.git
30+
GIT_TAG v1.7.1
31+
)
32+
33+
FetchContent_MakeAvailable(googlebenchmark)
34+
endif()
35+
36+
add_executable(count_min_sketch_benchmark)
37+
38+
target_link_libraries(count_min_sketch_benchmark
39+
PRIVATE
40+
count
41+
benchmark::benchmark_main
42+
)
43+
44+
set_target_properties(count_min_sketch_benchmark PROPERTIES
45+
CXX_STANDARD_REQUIRED YES
46+
)
47+
48+
set(COUNT_MIN_SKETCH_BENCHMARK_SOURCES
49+
benchmark_count_min_sketch_serialization.cpp
50+
)
51+
52+
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/benchmark_count_min_sketch.cpp")
53+
list(APPEND COUNT_MIN_SKETCH_BENCHMARK_SOURCES benchmark_count_min_sketch.cpp)
54+
endif()
55+
56+
target_sources(count_min_sketch_benchmark
57+
PRIVATE
58+
${COUNT_MIN_SKETCH_BENCHMARK_SOURCES}
59+
)
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
#include <benchmark/benchmark.h>
21+
#include <count_min.hpp>
22+
23+
#include <algorithm>
24+
#include <cstddef>
25+
#include <cstdint>
26+
#include <cstring>
27+
#include <ostream>
28+
#include <streambuf>
29+
#include <vector>
30+
31+
namespace
32+
{
33+
34+
using Sketch = datasketches::count_min_sketch<uint64_t>;
35+
36+
// Roughly 99.9% confidence. Serialization cost then scales with the bucket count.
37+
constexpr uint8_t NUM_HASHES = 7;
38+
39+
Sketch makeSketch(uint32_t num_buckets)
40+
{
41+
Sketch sketch(NUM_HASHES, num_buckets);
42+
for (uint64_t i = 0; i < NUM_HASHES; ++i)
43+
sketch.update(i, i + 1);
44+
return sketch;
45+
}
46+
47+
class fixed_buffer_streambuf final: public std::streambuf
48+
{
49+
public:
50+
explicit fixed_buffer_streambuf(std::vector<uint8_t>& buffer): buffer_(buffer), position_(0) {}
51+
52+
void reset()
53+
{
54+
position_ = 0;
55+
}
56+
57+
size_t bytes_written() const
58+
{
59+
return position_;
60+
}
61+
62+
protected:
63+
std::streamsize xsputn(const char* data, std::streamsize size) override
64+
{
65+
const size_t requested = static_cast<size_t>(size);
66+
const size_t available = buffer_.size() - position_;
67+
const size_t bytes_to_write = std::min(requested, available);
68+
if (bytes_to_write > 0) {
69+
std::memcpy(buffer_.data() + position_, data, bytes_to_write);
70+
position_ += bytes_to_write;
71+
}
72+
return static_cast<std::streamsize>(bytes_to_write);
73+
}
74+
75+
int_type overflow(int_type ch) override
76+
{
77+
if (traits_type::eq_int_type(ch, traits_type::eof()))
78+
return traits_type::not_eof(ch);
79+
if (position_ == buffer_.size())
80+
return traits_type::eof();
81+
buffer_[position_++] = static_cast<uint8_t>(traits_type::to_char_type(ch));
82+
return ch;
83+
}
84+
85+
private:
86+
std::vector<uint8_t>& buffer_;
87+
size_t position_;
88+
};
89+
90+
void BM_CountMinGetSerializedSizeBytes(benchmark::State& state)
91+
{
92+
const auto sketch = makeSketch(static_cast<uint32_t>(state.range(0)));
93+
94+
for (auto _ : state) {
95+
const auto size = sketch.get_serialized_size_bytes();
96+
benchmark::DoNotOptimize(size);
97+
}
98+
99+
state.SetItemsProcessed(state.iterations());
100+
}
101+
102+
void BM_CountMinSerializeVector(benchmark::State& state)
103+
{
104+
const auto sketch = makeSketch(static_cast<uint32_t>(state.range(0)));
105+
const auto serialized_size = sketch.get_serialized_size_bytes();
106+
107+
for (auto _ : state) {
108+
auto bytes = sketch.serialize();
109+
benchmark::DoNotOptimize(bytes.data());
110+
benchmark::DoNotOptimize(bytes.size());
111+
benchmark::ClobberMemory();
112+
}
113+
114+
state.SetBytesProcessed(state.iterations() * static_cast<int64_t>(serialized_size));
115+
}
116+
117+
void BM_CountMinSerializeOStream(benchmark::State& state)
118+
{
119+
const auto sketch = makeSketch(static_cast<uint32_t>(state.range(0)));
120+
const auto serialized_size = sketch.get_serialized_size_bytes();
121+
std::vector<uint8_t> bytes(serialized_size);
122+
fixed_buffer_streambuf stream_buffer(bytes);
123+
std::ostream os(&stream_buffer);
124+
125+
for (auto _ : state) {
126+
stream_buffer.reset();
127+
os.clear();
128+
sketch.serialize(os);
129+
benchmark::DoNotOptimize(stream_buffer.bytes_written());
130+
benchmark::ClobberMemory();
131+
}
132+
133+
state.SetBytesProcessed(state.iterations() * static_cast<int64_t>(serialized_size));
134+
}
135+
136+
}
137+
138+
BENCHMARK(BM_CountMinGetSerializedSizeBytes)->RangeMultiplier(8)->Range(1024, 65536);
139+
BENCHMARK(BM_CountMinSerializeVector)->RangeMultiplier(8)->Range(1024, 65536);
140+
BENCHMARK(BM_CountMinSerializeOStream)->RangeMultiplier(8)->Range(1024, 65536);

0 commit comments

Comments
 (0)