From c33f429a97593009e407782df0a5054251d15eba Mon Sep 17 00:00:00 2001 From: HÃ¥vard Pettersen Date: Tue, 17 Jan 2023 13:11:40 +0000 Subject: profile source blender children more testing (termwise) extend simplesearch with strictness and initRange --- .../profiled_iterator/profiled_iterator_test.cpp | 172 +++++++++++++++++++-- 1 file changed, 160 insertions(+), 12 deletions(-) (limited to 'searchlib/src/tests') diff --git a/searchlib/src/tests/queryeval/profiled_iterator/profiled_iterator_test.cpp b/searchlib/src/tests/queryeval/profiled_iterator/profiled_iterator_test.cpp index b89dc8f9e17..010e72428e2 100644 --- a/searchlib/src/tests/queryeval/profiled_iterator/profiled_iterator_test.cpp +++ b/searchlib/src/tests/queryeval/profiled_iterator/profiled_iterator_test.cpp @@ -2,30 +2,171 @@ #include #include +#include +#include #include #include #include +#include #include #include +#include #include +#include using namespace search::queryeval; +using search::FixedSourceSelector; using vespalib::ExecutionProfiler; using vespalib::Slime; +using vespalib::Trinary; -SearchIterator::UP create_term(const vespalib::string &name, std::vector hits) { - auto search = std::make_unique(SimpleResult(hits)); - search->tag(name); +size_t num_docs = 100; + +bool is_true(Trinary a) { + REQUIRE(a != Trinary::Undefined); + return (a == Trinary::True); +} + +bool is_true(Trinary a, Trinary b) { + return is_true(a) && is_true(b); +} + +struct MySources { + FixedSourceSelector selector; + MySources(const std::vector> &entries) + : selector(123, "", num_docs) + { + for (const auto &entry: entries) { + selector.setSource(entry.first, entry.second); + } + } +}; +MySources my_sources({{1,3},{3,3},{5,3}, + {2,5},{4,5},{6,5}}); + +SearchIterator::UP t(std::vector hits) { + auto search = std::make_unique(SimpleResult(hits), false); + search->tag("t"); + return search; +} + +SearchIterator::UP T(std::vector hits) { + auto search = std::make_unique(SimpleResult(hits), true); + search->tag("T"); return search; } +SearchIterator::UP OR(SearchIterator::UP s1, SearchIterator::UP s2) { + bool strict = is_true(s1->is_strict(), s2->is_strict()); + return OrSearch::create({std::move(s1), std::move(s2)}, strict); +} + +SearchIterator::UP AND(SearchIterator::UP s1, SearchIterator::UP s2) { + bool strict = is_true(s1->is_strict()); + return AndSearch::create({std::move(s1), std::move(s2)}, strict); +} + +SearchIterator::UP blend(SearchIterator::UP s1, uint32_t id1, + SearchIterator::UP s2, uint32_t id2) +{ + bool strict = is_true(s1->is_strict(), s2->is_strict()); + SourceBlenderSearch::Children list; + list.emplace_back(s1.release(), id1); + list.emplace_back(s2.release(), id2); + return SourceBlenderSearch::create(my_sources.selector.createIterator(), list, strict); +} + SearchIterator::UP create_iterator_tree() { - return AndSearch::create({OrSearch::create({create_term("A", {1,3,5}), - create_term("B", {2,4,6})}, true), - OrSearch::create({create_term("C", {4,6,8}), - create_term("D", {5,7,9})}, false)}, - true); + return AND(OR(T({4,6,8}), + T({5,7,9})), + blend(t({1,3,5,7,9}), 3, + t({2,4,6,8}), 5)); +} + +void collect(std::map &counts, const auto &node) { + if (!node.valid()) { + return; + } + collect(counts, node["roots"]); + collect(counts, node["children"]); + for (size_t i = 0; i < node.entries(); ++i) { + collect(counts, node[i]); + } + const auto &name = node["name"]; + if (name.valid()) { + auto name_str = name.asString().make_string(); + counts[name_str] += node["count"].asLong(); + } +}; + +std::map collect_counts(const auto &root) { + std::map counts; + collect(counts, root); + return counts; +} + +void print_counts(const std::map &counts) { + for (const auto &[name, count]: counts) { + fprintf(stderr, "%s: %zu\n", name.c_str(), count); + } +} + +void verify_result(SearchIterator &search, const std::vector &hits) { + SimpleResult actual; + SimpleResult expect(hits); + actual.searchStrict(search, num_docs); + EXPECT_EQ(actual, expect); +} + +void verify_termwise_result(SearchIterator &search, const std::vector &hits) { + search.initRange(1, num_docs); + auto result = search.get_hits(1); + ASSERT_EQ(result->size(), num_docs); + uint32_t pos = 1; + for (uint32_t hit: hits) { + while (pos < hit) { + EXPECT_FALSE(result->testBit(pos++)); + } + EXPECT_TRUE(result->testBit(pos++)); + } +} + +void verify_operation(ExecutionProfiler &profiler, std::map &seen, const vespalib::string &expect) { + Slime slime; + profiler.report(slime.setObject()); + auto counts = collect_counts(slime.get()); + for (const auto &[name, count]: counts) { + if (name == expect) { + EXPECT_EQ(count, ++seen[name]); + } else { + EXPECT_EQ(count, seen[name]); + } + } +} + +TEST(ProfiledIteratorTest, init_seek_unpack_termwise_is_profiled) { + ExecutionProfiler profiler(64); + std::map seen; + auto root = ProfiledIterator::profile(profiler, T({1,2,3})); + root->initRange(1,4); + verify_operation(profiler, seen, "/SimpleSearch/init"); + root->seek(2); + verify_operation(profiler, seen, "/SimpleSearch/seek"); + root->unpack(2); + verify_operation(profiler, seen, "/SimpleSearch/unpack"); + root->initRange(1,4); + verify_operation(profiler, seen, "/SimpleSearch/init"); + auto bits = root->get_hits(1); + verify_operation(profiler, seen, "/SimpleSearch/termwise"); + root->initRange(1,4); + verify_operation(profiler, seen, "/SimpleSearch/init"); + root->or_hits_into(*bits, 1); + verify_operation(profiler, seen, "/SimpleSearch/termwise"); + root->initRange(1,4); + verify_operation(profiler, seen, "/SimpleSearch/init"); + root->and_hits_into(*bits, 1); + verify_operation(profiler, seen, "/SimpleSearch/termwise"); } TEST(ProfiledIteratorTest, iterator_tree_can_be_profiled) { @@ -33,13 +174,20 @@ TEST(ProfiledIteratorTest, iterator_tree_can_be_profiled) { auto root = create_iterator_tree(); root = ProfiledIterator::profile(profiler, std::move(root)); fprintf(stderr, "%s", root->asString().c_str()); - SimpleResult expect({4,5,6}); - SimpleResult actual; - actual.searchStrict(*root, 100); - EXPECT_EQ(actual, expect); + verify_termwise_result(*root, {4,5,6}); + verify_result(*root, {4,5,6}); Slime slime; profiler.report(slime.setObject()); fprintf(stderr, "%s", slime.toString().c_str()); + auto counts = collect_counts(slime.get()); + print_counts(counts); + EXPECT_EQ(counts["/AndSearchStrict/init"], 2); + EXPECT_EQ(counts["/0/OrLikeSearch/init"], 2); + EXPECT_EQ(counts["/0/0/SimpleSearch/init"], 2); + EXPECT_EQ(counts["/0/1/SimpleSearch/init"], 2); + EXPECT_EQ(counts["/1/SourceBlenderSearchNonStrict/init"], 2); + EXPECT_EQ(counts["/1/0/SimpleSearch/init"], 2); + EXPECT_EQ(counts["/1/1/SimpleSearch/init"], 2); } GTEST_MAIN_RUN_ALL_TESTS() -- cgit v1.2.3