From 48e5f48871047eca5f1355c9c3ed03a0a662b60b Mon Sep 17 00:00:00 2001 From: Ye Kuang Date: Sun, 11 Oct 2020 05:45:41 +0900 Subject: [PATCH] [test] Add a benchmark for SFG edges' two-level map (#1927) --- tests/cpp/benchmark_sfg_edges.cpp | 286 ++++++++++++++++++++++++++++++ 1 file changed, 286 insertions(+) create mode 100644 tests/cpp/benchmark_sfg_edges.cpp diff --git a/tests/cpp/benchmark_sfg_edges.cpp b/tests/cpp/benchmark_sfg_edges.cpp new file mode 100644 index 0000000000000..9fb6d21f28224 --- /dev/null +++ b/tests/cpp/benchmark_sfg_edges.cpp @@ -0,0 +1,286 @@ +#include +#include // std::chrono::system_clock +#include // std::default_random_engine +#include +#include +#include +#include + +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/SmallVector.h" +#include "taichi/system/profiler.h" +#include "taichi/util/testing.h" + +TLANG_NAMESPACE_BEGIN + +using PairData = std::pair; + +struct Empty {}; +using UnorderedMapSet = std::unordered_map>; +using LLVMVecSet = llvm::SmallVector>, 4>; +using LLVMVecVec = + llvm::SmallVector>, 4>; +using StlVecSet = std::vector>>; +using StlVecVec = std::vector>>; + +using FlattenSet = llvm::SmallSet; +using FlattenVec = llvm::SmallVector; + +// https://stackoverflow.com/a/1055563/12003165 +// Over-engineering a bit. typeid().name() is mangled and hard to read... +template +struct TypeNameTraits; + +#define REGISTER_TYPE_NAME(X) \ + template <> \ + struct TypeNameTraits { \ + static const char *name; \ + }; \ + const char *TypeNameTraits::name = #X + +REGISTER_TYPE_NAME(LLVMVecSet); +REGISTER_TYPE_NAME(LLVMVecVec); +REGISTER_TYPE_NAME(StlVecSet); +REGISTER_TYPE_NAME(StlVecVec); + +void insert(const PairData &d, Empty *m) { + TI_PROFILER("Empty insert"); +} + +bool lookup(const PairData &d, const Empty &m, const std::string &found) { + TI_PROFILER("Empty lookup " + found); + return false; +} + +void insert(const PairData &d, UnorderedMapSet *m) { + TI_PROFILER("UnorderedMapSet insert"); + (*m)[d.first].insert(d.second); +} + +bool lookup(const PairData &d, + const UnorderedMapSet &m, + const std::string &found) { + TI_PROFILER("UnorderedMapSet lookup " + found); + auto itr = m.find(d.first); + if (itr == m.end()) { + return false; + } + return itr->second.count(d.second) > 0; +} + +template +void insert_vecset(const PairData &d, VecSet *m) { + auto pname = fmt::format("{} insert", TypeNameTraits::name); + TI_PROFILER(pname); + int i1 = 0; + for (; i1 < m->size(); ++i1) { + if ((*m)[i1].first == d.first) { + break; + } + } + if (i1 == m->size()) { + m->push_back({}); + m->back().first = d.first; + } + (*m)[i1].second.insert(d.second); +} + +template +bool lookup_vecset(const PairData &d, + const VecSet &m, + const std::string &found) { + auto pname = fmt::format("{} lookup {}", TypeNameTraits::name, found); + TI_PROFILER(pname); + int i1 = 0; + for (; i1 < m.size(); ++i1) { + if (m[i1].first == d.first) { + break; + } + } + if (i1 == m.size()) { + return false; + } + return m[i1].second.count(d.second) > 0; +} + +template +void insert_vecvec(const PairData &d, VecVec *m) { + auto pname = fmt::format("{} insert", TypeNameTraits::name); + TI_PROFILER(pname); + int i1 = 0; + for (; i1 < m->size(); ++i1) { + if ((*m)[i1].first == d.first) { + break; + } + } + if (i1 == m->size()) { + m->push_back({}); + m->back().first = d.first; + } + + auto &v2 = (*m)[i1].second; + for (int i2 = 0; i2 < v2.size(); ++i2) { + if (v2[i2] == d.second) { + return; + } + } + v2.push_back(d.second); +} + +template +bool lookup_vecvec(const PairData &d, + const VecVec &m, + const std::string &found) { + auto pname = fmt::format("{} lookup {}", TypeNameTraits::name, found); + TI_PROFILER(pname); + int i1 = 0; + for (; i1 < m.size(); ++i1) { + if (m[i1].first == d.first) { + break; + } + } + if (i1 == m.size()) { + return false; + } + const auto &v2 = m[i1].second; + for (int i2 = 0; i2 < v2.size(); ++i2) { + if (v2[i2] == d.second) { + return true; + } + } + return false; +} + +template +void insert(const PairData &d, C *m) { + if constexpr (std::is_same_v || std::is_same_v) { + insert_vecset(d, m); + } else if constexpr (std::is_same_v || + std::is_same_v) { + insert_vecvec(d, m); + } +} + +template +bool lookup(const PairData &d, const C &m, const std::string &found) { + if constexpr (std::is_same_v || std::is_same_v) { + return lookup_vecset(d, m, found); + } else if constexpr (std::is_same_v || + std::is_same_v) { + return lookup_vecvec(d, m, found); + } +} + +void insert(const PairData &d, FlattenSet *m) { + TI_PROFILER("FlattenSet insert"); + m->insert(d); +} + +bool lookup(const PairData &d, const FlattenSet &m, const std::string &found) { + TI_PROFILER("FlattenSet lookup " + found); + return m.count(d) > 0; +} + +bool lookup(const PairData &d, const FlattenVec &m, const std::string &found) { + TI_PROFILER("FlattenVec lookup " + found); + + auto itr = std::lower_bound(m.begin(), m.end(), d); + return (itr != m.end()) && (*itr == d); +} + +void insert(const PairData &d, FlattenVec *m) { + TI_PROFILER("FlattenVec insert"); + + auto itr = std::lower_bound(m->begin(), m->end(), d); + if ((itr != m->end()) && (*itr == d)) { + return; + } + + m->insert(itr, d); + // m->push_back(d); + // std::sort(m->begin(), m->end()); +} + +template +void run_test(const std::vector &data, + const std::vector &non_exists) { + for (int i = 0; i < 10; ++i) { + M m; + for (const auto &p : data) { + insert(p, &m); + } + + for (const auto &p : data) { + bool l = lookup(p, m, "found"); + if constexpr (!std::is_same_v) { + TI_CHECK(l); + } + } + + for (const auto &p : non_exists) { + bool l = lookup(p, m, "not found"); + TI_CHECK(!l); + } + } +} + +// Basic tests within a basic block +TI_TEST("benchmark_sfg") { + std::vector data = { + {0, 0}, {0, 2}, {0, 2}, {0, 5}, // 0 + {1, 1}, {1, 2}, {1, 3}, {1, 3}, {1, 6}, {1, 6}, // 1 + {2, 0}, {2, 0}, {2, 2}, // 2 + {3, 5}, {3, 6}, {3, 7}, // 3 + {5, 0}, {5, 2}, {5, 2}, {5, 2}, {5, 2}, // 5 + {6, 1}, {6, 2}, {6, 2}, // 6 + {9, 9}, // 9 + }; + std::vector non_exists = { + {0, 1}, {0, 3}, // 0 + {1, 4}, {1, 5}, // 1 + {3, 0}, {3, 1}, {3, 2}, // 3 + {4, 1}, // 4 + {6, 3}, // 6 + {7, 8}, // 7 + }; + const auto seed = std::chrono::system_clock::now().time_since_epoch().count(); + std::default_random_engine rng(seed); + std::shuffle(data.begin(), data.end(), rng); + std::shuffle(non_exists.begin(), non_exists.end(), rng); + + SECTION("Empty") { + // Get an idea of the overhead of the profiler itself. + run_test(data, non_exists); + } + + SECTION("UnorderedMapSet") { + run_test(data, non_exists); + } + + SECTION("LLVMVecSet") { + run_test(data, non_exists); + } + + SECTION("LLVMVecVec") { + run_test(data, non_exists); + } + + SECTION("StlVecSet") { + run_test(data, non_exists); + } + + SECTION("StlVecVec") { + run_test(data, non_exists); + } + + SECTION("FlattenSet") { + run_test(data, non_exists); + } + + SECTION("FlattenVec") { + run_test(data, non_exists); + } + Profiling::get_instance().print_profile_info(); +} + +TLANG_NAMESPACE_END