diff --git a/CMakeLists.txt b/CMakeLists.txt
index 83abc193..e56dc2d2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1209,6 +1209,15 @@ if(BUILD_SHARED)
COMPONENT PerfTools)
endif()
endforeach()
+
+ if(BUILD_STATIC)
+ add_executable(benchmark_radix_tree perf/benchmark_radix_tree.cpp)
+ target_link_libraries(benchmark_radix_tree libzmq-static)
+ target_include_directories(benchmark_radix_tree
+ PUBLIC
+ "${CMAKE_SOURCE_DIR}/src")
+ endif()
+
endif()
elseif(WITH_PERF_TOOL)
message(FATAL_ERROR "Shared library disabled - perf-tools unavailable.")
diff --git a/Makefile.am b/Makefile.am
index dc379169..71e3f7a2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -372,6 +372,17 @@ perf_inproc_lat_SOURCES = perf/inproc_lat.cpp
perf_inproc_thr_LDADD = src/libzmq.la
perf_inproc_thr_SOURCES = perf/inproc_thr.cpp
+
+if ENABLE_STATIC
+noinst_PROGRAMS += \
+ perf/benchmark_radix_tree
+
+perf_benchmark_radix_tree_DEPENDENCIES = src/libzmq.la
+perf_benchmark_radix_tree_CPPFLAGS = -I$(top_srcdir)/src
+perf_benchmark_radix_tree_LDADD = $(top_builddir)/src/.libs/libzmq.a \
+ ${src_libzmq_la_LIBADD}
+perf_benchmark_radix_tree_SOURCES = perf/benchmark_radix_tree.cpp
+endif
endif
if ENABLE_CURVE_KEYGEN
diff --git a/perf/benchmark_radix_tree.cpp b/perf/benchmark_radix_tree.cpp
new file mode 100644
index 00000000..efc889cc
--- /dev/null
+++ b/perf/benchmark_radix_tree.cpp
@@ -0,0 +1,123 @@
+/*
+ Copyright (c) 2018 Contributors as noted in the AUTHORS file
+
+ This file is part of libzmq, the ZeroMQ core engine in C++.
+
+ libzmq is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License (LGPL) as published
+ by the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ As a special exception, the Contributors give you permission to link
+ this library with independent modules to produce an executable,
+ regardless of the license terms of these independent modules, and to
+ copy and distribute the resulting executable under terms of your choice,
+ provided that you also meet, for each linked independent module, the
+ terms and conditions of the license of that module. An independent
+ module is a module which is not derived from or based on this library.
+ If you modify this library, you must extend this exception to your
+ version of the library.
+
+ libzmq is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see .
+*/
+
+#if __cplusplus >= 201103L
+
+#include "radix_tree.hpp"
+#include "trie.hpp"
+
+#include
+#include
+#include
+#include
+#include
+
+const std::size_t nkeys = 10000;
+const std::size_t nqueries = 100000;
+const std::size_t warmup_runs = 10;
+const std::size_t samples = 10;
+const std::size_t key_length = 20;
+const char *chars = "abcdefghijklmnopqrstuvwxyz0123456789";
+const int chars_len = 36;
+
+template
+void benchmark_lookup (T &t,
+ std::vector &input_set,
+ std::vector &queries)
+{
+ std::puts ("Starting warmup...");
+ for (std::size_t run = 0; run < warmup_runs; ++run) {
+ for (auto &query : queries)
+ t.check (query, key_length);
+ }
+
+ std::puts ("Collecting samples...");
+ std::vector samples_vec;
+ samples_vec.reserve (samples);
+ for (std::size_t run = 0; run < samples; ++run) {
+ auto start = std::chrono::high_resolution_clock::now ();
+ for (auto &query : queries)
+ t.check (query, key_length);
+ auto end = std::chrono::high_resolution_clock::now ();
+ samples_vec.push_back (
+ std::chrono::duration_cast ((end - start))
+ .count ());
+ }
+
+ for (const auto &sample : samples_vec)
+ std::printf ("%.2lf\n", sample);
+}
+
+int main ()
+{
+ // Generate input set.
+ std::minstd_rand rng (123456789);
+ std::vector input_set;
+ std::vector queries;
+ input_set.reserve (nkeys);
+ queries.reserve (nqueries);
+
+ for (std::size_t i = 0; i < nkeys; ++i) {
+ unsigned char *key = new unsigned char[key_length];
+ for (std::size_t j = 0; j < key_length; j++)
+ key[j] = static_cast (chars[rng () % chars_len]);
+ input_set.emplace_back (key);
+ }
+ for (std::size_t i = 0; i < nqueries; ++i)
+ queries.push_back (input_set[rng () % nkeys]);
+
+ // Initialize both data structures.
+ //
+ // Keeping initialization out of the benchmarking function helps
+ // heaptrack detect peak memory consumption of the radix tree.
+ zmq::trie_t trie;
+ zmq::radix_tree radix_tree;
+ for (auto &key : input_set) {
+ trie.add (key, key_length);
+ radix_tree.add (key, key_length);
+ }
+
+ // Create a benchmark.
+ std::puts ("[trie]");
+ benchmark_lookup (trie, input_set, queries);
+
+ std::puts ("[radix_tree]");
+ benchmark_lookup (radix_tree, input_set, queries);
+
+ for (auto &op : input_set)
+ delete[] op;
+}
+
+#else
+
+int main ()
+{
+}
+
+#endif
diff --git a/src/radix_tree.cpp b/src/radix_tree.cpp
index 7bc84508..64e305f5 100644
--- a/src/radix_tree.cpp
+++ b/src/radix_tree.cpp
@@ -210,9 +210,9 @@ match_result::match_result (size_t i,
{
}
-inline match_result zmq::radix_tree::match (const unsigned char *key,
- size_t size,
- bool check = false) const
+match_result zmq::radix_tree::match (const unsigned char *key,
+ size_t size,
+ bool check = false) const
{
zmq_assert (key);
@@ -553,26 +553,3 @@ size_t zmq::radix_tree::size () const
{
return size_;
}
-
-static void visit_child (node child_node, size_t level)
-{
- zmq_assert (level > 0);
-
- for (size_t i = 0; i < 4 * (level - 1) + level; ++i)
- putchar (' ');
- printf ("`-> ");
- for (uint32_t i = 0; i < child_node.prefix_length (); ++i)
- printf ("%c", child_node.prefix ()[i]);
- if (child_node.refcount () > 0)
- printf (" [*]");
- printf ("\n");
- for (uint32_t i = 0; i < child_node.edgecount (); ++i)
- visit_child (child_node.node_at (i), level + 1);
-}
-
-void zmq::radix_tree::print ()
-{
- puts ("[root]");
- for (uint32_t i = 0; i < root_.edgecount (); ++i)
- visit_child (root_.node_at (i), 1);
-}
diff --git a/src/radix_tree.hpp b/src/radix_tree.hpp
index b07e4e4f..3e3834ea 100644
--- a/src/radix_tree.hpp
+++ b/src/radix_tree.hpp
@@ -133,11 +133,10 @@ class radix_tree
void apply (void (*func) (unsigned char *data_, size_t size_, void *arg_),
void *arg);
- void print ();
size_t size () const;
private:
- match_result
+ inline match_result
match (const unsigned char *key, size_t size, bool check) const;
node root_;
diff --git a/unittests/unittest_radix_tree.cpp b/unittests/unittest_radix_tree.cpp
index 10c2d750..6d999e3a 100644
--- a/unittests/unittest_radix_tree.cpp
+++ b/unittests/unittest_radix_tree.cpp
@@ -256,26 +256,6 @@ void test_apply ()
delete vec;
}
-void test_print ()
-{
- zmq::radix_tree tree;
-
- // Adapted from the example on wikipedia.
- std::vector keys;
- keys.push_back ("tester");
- keys.push_back ("water");
- keys.push_back ("slow");
- keys.push_back ("slower");
- keys.push_back ("test");
- keys.push_back ("team");
- keys.push_back ("toast");
-
- for (size_t i = 0; i < keys.size (); ++i)
- tree_add (tree, keys[i]);
-
- tree.print ();
-}
-
int main (void)
{
setup_test_environment ();
@@ -306,7 +286,5 @@ int main (void)
RUN_TEST (test_apply);
- RUN_TEST (test_print);
-
return UNITY_END ();
}