Path: blob/main/contrib/llvm-project/compiler-rt/lib/ctx_profile/tests/RootAutoDetectorTest.cpp
213799 views
#include "../RootAutoDetector.h"1#include "sanitizer_common/sanitizer_array_ref.h"2#include "gmock/gmock.h"3#include "gtest/gtest.h"45using namespace __ctx_profile;6using ::testing::IsEmpty;7using ::testing::Not;8using ::testing::SizeIs;910// Utility for describing a preorder traversal. By default it captures the11// address and count at a callsite node. Implicitly nodes are expected to have 112// child. If they have none, we place a Marker::term and if they have more than13// one, we place a Marker::split(nr_of_children) For example, using a list14// notation, and letters to denote a pair of address and count:15// (A (B C) (D (E F))) is a list of markers: A, split(2), B, term, C,16// term, D, split(2), E, term, F, term17class Marker {18enum class Kind { End, Value, Split };19const uptr Value;20const uptr Count;21const Kind K;22Marker(uptr V, uptr C, Kind S) : Value(V), Count(C), K(S) {}2324public:25Marker(uptr V, uptr C) : Marker(V, C, Kind::Value) {}2627static Marker split(uptr V) { return Marker(V, 0, Kind::Split); }28static Marker term() { return Marker(0, 0, Kind::End); }2930bool isSplit() const { return K == Kind::Split; }31bool isTerm() const { return K == Kind::End; }32bool isVal() const { return K == Kind::Value; }3334bool operator==(const Marker &M) const {35return Value == M.Value && Count == M.Count && K == M.K;36}37};3839class MockCallsiteTrie final : public PerThreadCallsiteTrie {40// Return the first multiple of 100.41uptr getFctStartAddr(uptr CallsiteAddress) const override {42return (CallsiteAddress / 100) * 100;43}4445static void popAndCheck(ArrayRef<Marker> &Preorder, Marker M) {46ASSERT_THAT(Preorder, Not(IsEmpty()));47ASSERT_EQ(Preorder[0], M);48Preorder = Preorder.drop_front();49}5051static void checkSameImpl(const Trie &T, ArrayRef<Marker> &Preorder) {52popAndCheck(Preorder, {T.CallsiteAddress, T.Count});5354if (T.Children.empty()) {55popAndCheck(Preorder, Marker::term());56return;57}5859if (T.Children.size() > 1)60popAndCheck(Preorder, Marker::split(T.Children.size()));6162T.Children.forEach([&](const auto &KVP) {63checkSameImpl(KVP.second, Preorder);64return true;65});66}6768public:69void checkSame(ArrayRef<Marker> Preorder) const {70checkSameImpl(TheTrie, Preorder);71ASSERT_THAT(Preorder, IsEmpty());72}73};7475TEST(PerThreadCallsiteTrieTest, Insert) {76MockCallsiteTrie R;77uptr Stack1[]{4, 3, 2, 1};78R.insertStack(StackTrace(Stack1, 4));79R.checkSame(ArrayRef<Marker>(80{{0, 1}, {1, 1}, {2, 1}, {3, 1}, {4, 1}, Marker::term()}));8182uptr Stack2[]{5, 4, 3, 2, 1};83R.insertStack(StackTrace(Stack2, 5));84R.checkSame(ArrayRef<Marker>(85{{0, 2}, {1, 2}, {2, 2}, {3, 2}, {4, 2}, {5, 1}, Marker::term()}));8687uptr Stack3[]{6, 3, 2, 1};88R.insertStack(StackTrace(Stack3, 4));89R.checkSame(ArrayRef<Marker>({{0, 3},90{1, 3},91{2, 3},92{3, 3},93Marker::split(2),94{4, 2},95{5, 1},96Marker::term(),97{6, 1},98Marker::term()}));99uptr Stack4[]{7, 2, 1};100R.insertStack(StackTrace(Stack4, 3));101R.checkSame(ArrayRef<Marker>({{0, 4},102{1, 4},103{2, 4},104Marker::split(2),105{7, 1},106Marker::term(),107{3, 3},108Marker::split(2),109{4, 2},110{5, 1},111Marker::term(),112{6, 1},113Marker::term()}));114}115116TEST(PerThreadCallsiteTrieTest, DetectRoots) {117MockCallsiteTrie T;118119uptr Stack1[]{501, 302, 202, 102};120uptr Stack2[]{601, 402, 203, 102};121T.insertStack({Stack1, 4});122T.insertStack({Stack2, 4});123124auto R = T.determineRoots();125EXPECT_THAT(R, SizeIs(2U));126EXPECT_TRUE(R.contains(300));127EXPECT_TRUE(R.contains(400));128}129130TEST(PerThreadCallsiteTrieTest, DetectRootsNoBranches) {131MockCallsiteTrie T;132133uptr Stack1[]{501, 302, 202, 102};134T.insertStack({Stack1, 4});135136auto R = T.determineRoots();137EXPECT_THAT(R, IsEmpty());138}139140TEST(PerThreadCallsiteTrieTest, DetectRootsUnknownFct) {141MockCallsiteTrie T;142143uptr Stack1[]{501, 302, 202, 102};144// The MockCallsiteTree address resolver resolves addresses over 100, so 40145// will be mapped to 0.146uptr Stack2[]{601, 40, 203, 102};147T.insertStack({Stack1, 4});148T.insertStack({Stack2, 4});149150auto R = T.determineRoots();151ASSERT_THAT(R, SizeIs(2U));152EXPECT_TRUE(R.contains(300));153EXPECT_TRUE(R.contains(0));154}155156157