xref: /llvm-project/llvm/unittests/XRay/ProfileTest.cpp (revision 2946cd701067404b99c39fb29dc9c74bd7193eb3)
1f6c87eb9SDean Michael Berris //===- ProfileTest.cpp - XRay Profile unit tests ----------------*- C++ -*-===//
2f6c87eb9SDean Michael Berris //
3*2946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*2946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
5*2946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f6c87eb9SDean Michael Berris //
7f6c87eb9SDean Michael Berris //===----------------------------------------------------------------------===//
8f6c87eb9SDean Michael Berris #include "llvm/XRay/Profile.h"
9f6c87eb9SDean Michael Berris #include "gmock/gmock.h"
10f6c87eb9SDean Michael Berris #include "gtest/gtest.h"
11f6c87eb9SDean Michael Berris 
12f6c87eb9SDean Michael Berris #include <numeric>
13f6c87eb9SDean Michael Berris 
14f6c87eb9SDean Michael Berris namespace llvm {
15f6c87eb9SDean Michael Berris namespace xray {
16f6c87eb9SDean Michael Berris namespace {
17f6c87eb9SDean Michael Berris 
18f6c87eb9SDean Michael Berris using ::testing::AllOf;
19f6c87eb9SDean Michael Berris using ::testing::ElementsAre;
20f6c87eb9SDean Michael Berris using ::testing::Eq;
21f6c87eb9SDean Michael Berris using ::testing::Field;
22f6c87eb9SDean Michael Berris using ::testing::Not;
23f6c87eb9SDean Michael Berris using ::testing::Pair;
24f6c87eb9SDean Michael Berris using ::testing::UnorderedElementsAre;
25f6c87eb9SDean Michael Berris 
TEST(ProfileTest,CreateProfile)26f6c87eb9SDean Michael Berris TEST(ProfileTest, CreateProfile) { Profile P; }
27f6c87eb9SDean Michael Berris 
TEST(ProfileTest,InternPath)28f6c87eb9SDean Michael Berris TEST(ProfileTest, InternPath) {
29f6c87eb9SDean Michael Berris   Profile P;
30f6c87eb9SDean Michael Berris   auto Path0 = P.internPath({3, 2, 1});
31f6c87eb9SDean Michael Berris   auto Path1 = P.internPath({3, 2, 1});
32f6c87eb9SDean Michael Berris   auto Path2 = P.internPath({2, 1});
33f6c87eb9SDean Michael Berris   EXPECT_THAT(Path0, Eq(Path1));
34f6c87eb9SDean Michael Berris   EXPECT_THAT(Path0, Not(Eq(Path2)));
35f6c87eb9SDean Michael Berris }
36f6c87eb9SDean Michael Berris 
TEST(ProfileTest,ExpandPath)37f6c87eb9SDean Michael Berris TEST(ProfileTest, ExpandPath) {
38f6c87eb9SDean Michael Berris   Profile P;
39f6c87eb9SDean Michael Berris   auto PathID = P.internPath({3, 2, 1});
40f6c87eb9SDean Michael Berris   auto PathOrError = P.expandPath(PathID);
41f6c87eb9SDean Michael Berris   if (!PathOrError)
42f6c87eb9SDean Michael Berris     FAIL() << "Error: " << PathOrError.takeError();
43f6c87eb9SDean Michael Berris   EXPECT_THAT(PathOrError.get(), ElementsAre(3, 2, 1));
44f6c87eb9SDean Michael Berris }
45f6c87eb9SDean Michael Berris 
TEST(ProfileTest,AddBlocks)46f6c87eb9SDean Michael Berris TEST(ProfileTest, AddBlocks) {
47f6c87eb9SDean Michael Berris   Profile P;
48f6c87eb9SDean Michael Berris   // Expect an error on adding empty blocks.
49f6c87eb9SDean Michael Berris   EXPECT_TRUE(errorToBool(P.addBlock({})));
50f6c87eb9SDean Michael Berris 
51f6c87eb9SDean Michael Berris   // Thread blocks may not be empty.
52f6c87eb9SDean Michael Berris   EXPECT_TRUE(errorToBool(P.addBlock({1, {}})));
53f6c87eb9SDean Michael Berris 
54f6c87eb9SDean Michael Berris   // Thread blocks with data must succeed.
55f6c87eb9SDean Michael Berris   EXPECT_FALSE(errorToBool(P.addBlock(
56f6c87eb9SDean Michael Berris       Profile::Block{Profile::ThreadID{1},
57f6c87eb9SDean Michael Berris                      {
58f6c87eb9SDean Michael Berris                          {P.internPath({2, 1}), Profile::Data{1, 1000}},
59f6c87eb9SDean Michael Berris                          {P.internPath({3, 2, 1}), Profile::Data{10, 100}},
60f6c87eb9SDean Michael Berris                      }})));
61f6c87eb9SDean Michael Berris }
62f6c87eb9SDean Michael Berris 
TEST(ProfileTest,CopyProfile)63f6c87eb9SDean Michael Berris TEST(ProfileTest, CopyProfile) {
64f6c87eb9SDean Michael Berris   Profile P0, P1;
65f6c87eb9SDean Michael Berris   EXPECT_FALSE(errorToBool(P0.addBlock(
66f6c87eb9SDean Michael Berris       Profile::Block{Profile::ThreadID{1},
67f6c87eb9SDean Michael Berris                      {
68f6c87eb9SDean Michael Berris                          {P0.internPath({2, 1}), Profile::Data{1, 1000}},
69f6c87eb9SDean Michael Berris                          {P0.internPath({3, 2, 1}), Profile::Data{10, 100}},
70f6c87eb9SDean Michael Berris                      }})));
71f6c87eb9SDean Michael Berris   P1 = P0;
72f6c87eb9SDean Michael Berris   EXPECT_THAT(
73f6c87eb9SDean Michael Berris       P1, UnorderedElementsAre(AllOf(
74f6c87eb9SDean Michael Berris               Field(&Profile::Block::Thread, Eq(Profile::ThreadID{1})),
75f6c87eb9SDean Michael Berris               Field(&Profile::Block::PathData,
76f6c87eb9SDean Michael Berris                     UnorderedElementsAre(
77f6c87eb9SDean Michael Berris                         Pair(P1.internPath({2, 1}),
78f6c87eb9SDean Michael Berris                              AllOf(Field(&Profile::Data::CallCount, Eq(1u)),
79f6c87eb9SDean Michael Berris                                    Field(&Profile::Data::CumulativeLocalTime,
80f6c87eb9SDean Michael Berris                                          Eq(1000u)))),
81f6c87eb9SDean Michael Berris                         Pair(P1.internPath({3, 2, 1}),
82f6c87eb9SDean Michael Berris                              AllOf(Field(&Profile::Data::CallCount, Eq(10u)),
83f6c87eb9SDean Michael Berris                                    Field(&Profile::Data::CumulativeLocalTime,
84f6c87eb9SDean Michael Berris                                          Eq(100u)))))))));
85f6c87eb9SDean Michael Berris }
86f6c87eb9SDean Michael Berris 
TEST(ProfileTest,MoveProfile)87f6c87eb9SDean Michael Berris TEST(ProfileTest, MoveProfile) {
88f6c87eb9SDean Michael Berris   Profile P0, P1;
89f6c87eb9SDean Michael Berris   EXPECT_FALSE(errorToBool(P0.addBlock(
90f6c87eb9SDean Michael Berris       Profile::Block{Profile::ThreadID{1},
91f6c87eb9SDean Michael Berris                      {
92f6c87eb9SDean Michael Berris                          {P0.internPath({2, 1}), Profile::Data{1, 1000}},
93f6c87eb9SDean Michael Berris                          {P0.internPath({3, 2, 1}), Profile::Data{10, 100}},
94f6c87eb9SDean Michael Berris                      }})));
95f6c87eb9SDean Michael Berris   P1 = std::move(P0);
96f6c87eb9SDean Michael Berris   EXPECT_THAT(
97f6c87eb9SDean Michael Berris       P1, UnorderedElementsAre(AllOf(
98f6c87eb9SDean Michael Berris               Field(&Profile::Block::Thread, Eq(Profile::ThreadID{1})),
99f6c87eb9SDean Michael Berris               Field(&Profile::Block::PathData,
100f6c87eb9SDean Michael Berris                     UnorderedElementsAre(
101f6c87eb9SDean Michael Berris                         Pair(P1.internPath({2, 1}),
102f6c87eb9SDean Michael Berris                              AllOf(Field(&Profile::Data::CallCount, Eq(1u)),
103f6c87eb9SDean Michael Berris                                    Field(&Profile::Data::CumulativeLocalTime,
104f6c87eb9SDean Michael Berris                                          Eq(1000u)))),
105f6c87eb9SDean Michael Berris                         Pair(P1.internPath({3, 2, 1}),
106f6c87eb9SDean Michael Berris                              AllOf(Field(&Profile::Data::CallCount, Eq(10u)),
107f6c87eb9SDean Michael Berris                                    Field(&Profile::Data::CumulativeLocalTime,
108f6c87eb9SDean Michael Berris                                          Eq(100u)))))))));
109f6c87eb9SDean Michael Berris   EXPECT_THAT(P0, UnorderedElementsAre());
110f6c87eb9SDean Michael Berris }
111f6c87eb9SDean Michael Berris 
TEST(ProfileTest,MergeProfilesByThread)112f6c87eb9SDean Michael Berris TEST(ProfileTest, MergeProfilesByThread) {
113f6c87eb9SDean Michael Berris   Profile P0, P1;
114f6c87eb9SDean Michael Berris 
115f6c87eb9SDean Michael Berris   // Set up the blocks for two different threads in P0.
116f6c87eb9SDean Michael Berris   EXPECT_FALSE(errorToBool(P0.addBlock(
117f6c87eb9SDean Michael Berris       Profile::Block{Profile::ThreadID{1},
118f6c87eb9SDean Michael Berris                      {{P0.internPath({2, 1}), Profile::Data{1, 1000}},
119f6c87eb9SDean Michael Berris                       {P0.internPath({4, 1}), Profile::Data{1, 1000}}}})));
120f6c87eb9SDean Michael Berris   EXPECT_FALSE(errorToBool(P0.addBlock(
121f6c87eb9SDean Michael Berris       Profile::Block{Profile::ThreadID{2},
122f6c87eb9SDean Michael Berris                      {{P0.internPath({3, 1}), Profile::Data{1, 1000}}}})));
123f6c87eb9SDean Michael Berris 
124f6c87eb9SDean Michael Berris   // Set up the blocks for two different threads in P1.
125f6c87eb9SDean Michael Berris   EXPECT_FALSE(errorToBool(P1.addBlock(
126f6c87eb9SDean Michael Berris       Profile::Block{Profile::ThreadID{1},
127f6c87eb9SDean Michael Berris                      {{P1.internPath({2, 1}), Profile::Data{1, 1000}}}})));
128f6c87eb9SDean Michael Berris   EXPECT_FALSE(errorToBool(P1.addBlock(
129f6c87eb9SDean Michael Berris       Profile::Block{Profile::ThreadID{2},
130f6c87eb9SDean Michael Berris                      {{P1.internPath({3, 1}), Profile::Data{1, 1000}},
131f6c87eb9SDean Michael Berris                       {P1.internPath({4, 1}), Profile::Data{1, 1000}}}})));
132f6c87eb9SDean Michael Berris 
133f6c87eb9SDean Michael Berris   Profile Merged = mergeProfilesByThread(P0, P1);
134f6c87eb9SDean Michael Berris   EXPECT_THAT(
135f6c87eb9SDean Michael Berris       Merged,
136f6c87eb9SDean Michael Berris       UnorderedElementsAre(
137f6c87eb9SDean Michael Berris           // We want to see two threads after the merge.
138f6c87eb9SDean Michael Berris           AllOf(Field(&Profile::Block::Thread, Eq(Profile::ThreadID{1})),
139f6c87eb9SDean Michael Berris                 Field(&Profile::Block::PathData,
140f6c87eb9SDean Michael Berris                       UnorderedElementsAre(
141f6c87eb9SDean Michael Berris                           Pair(Merged.internPath({2, 1}),
142f6c87eb9SDean Michael Berris                                AllOf(Field(&Profile::Data::CallCount, Eq(2u)),
143f6c87eb9SDean Michael Berris                                      Field(&Profile::Data::CumulativeLocalTime,
144f6c87eb9SDean Michael Berris                                            Eq(2000u)))),
145f6c87eb9SDean Michael Berris                           Pair(Merged.internPath({4, 1}),
146f6c87eb9SDean Michael Berris                                AllOf(Field(&Profile::Data::CallCount, Eq(1u)),
147f6c87eb9SDean Michael Berris                                      Field(&Profile::Data::CumulativeLocalTime,
148f6c87eb9SDean Michael Berris                                            Eq(1000u))))))),
149f6c87eb9SDean Michael Berris           AllOf(Field(&Profile::Block::Thread, Eq(Profile::ThreadID{2})),
150f6c87eb9SDean Michael Berris                 Field(&Profile::Block::PathData,
151f6c87eb9SDean Michael Berris                       UnorderedElementsAre(
152f6c87eb9SDean Michael Berris                           Pair(Merged.internPath({3, 1}),
153f6c87eb9SDean Michael Berris                                AllOf(Field(&Profile::Data::CallCount, Eq(2u)),
154f6c87eb9SDean Michael Berris                                      Field(&Profile::Data::CumulativeLocalTime,
155f6c87eb9SDean Michael Berris                                            Eq(2000u)))),
156f6c87eb9SDean Michael Berris                           Pair(Merged.internPath({4, 1}),
157f6c87eb9SDean Michael Berris                                AllOf(Field(&Profile::Data::CallCount, Eq(1u)),
158f6c87eb9SDean Michael Berris                                      Field(&Profile::Data::CumulativeLocalTime,
159f6c87eb9SDean Michael Berris                                            Eq(1000u)))))))));
160f6c87eb9SDean Michael Berris }
161f6c87eb9SDean Michael Berris 
TEST(ProfileTest,MergeProfilesByStack)162f6c87eb9SDean Michael Berris TEST(ProfileTest, MergeProfilesByStack) {
163f6c87eb9SDean Michael Berris   Profile P0, P1;
164f6c87eb9SDean Michael Berris   EXPECT_FALSE(errorToBool(P0.addBlock(
165f6c87eb9SDean Michael Berris       Profile::Block{Profile::ThreadID{1},
166f6c87eb9SDean Michael Berris                      {{P0.internPath({2, 1}), Profile::Data{1, 1000}}}})));
167f6c87eb9SDean Michael Berris   EXPECT_FALSE(errorToBool(P1.addBlock(
168f6c87eb9SDean Michael Berris       Profile::Block{Profile::ThreadID{2},
169f6c87eb9SDean Michael Berris                      {{P1.internPath({2, 1}), Profile::Data{1, 1000}}}})));
170f6c87eb9SDean Michael Berris 
171f6c87eb9SDean Michael Berris   Profile Merged = mergeProfilesByStack(P0, P1);
172f6c87eb9SDean Michael Berris   EXPECT_THAT(Merged,
173f6c87eb9SDean Michael Berris               ElementsAre(AllOf(
174f6c87eb9SDean Michael Berris                   // We expect that we lose the ThreadID dimension in this
175f6c87eb9SDean Michael Berris                   // algorithm.
176f6c87eb9SDean Michael Berris                   Field(&Profile::Block::Thread, Eq(Profile::ThreadID{0})),
177f6c87eb9SDean Michael Berris                   Field(&Profile::Block::PathData,
178f6c87eb9SDean Michael Berris                         ElementsAre(Pair(
179f6c87eb9SDean Michael Berris                             Merged.internPath({2, 1}),
180f6c87eb9SDean Michael Berris                             AllOf(Field(&Profile::Data::CallCount, Eq(2u)),
181f6c87eb9SDean Michael Berris                                   Field(&Profile::Data::CumulativeLocalTime,
182f6c87eb9SDean Michael Berris                                         Eq(2000u)))))))));
183f6c87eb9SDean Michael Berris }
184f6c87eb9SDean Michael Berris 
TEST(ProfileTest,MergeProfilesByStackAccumulate)185f6c87eb9SDean Michael Berris TEST(ProfileTest, MergeProfilesByStackAccumulate) {
186f6c87eb9SDean Michael Berris   std::vector<Profile> Profiles(3);
187f6c87eb9SDean Michael Berris   EXPECT_FALSE(errorToBool(Profiles[0].addBlock(Profile::Block{
188f6c87eb9SDean Michael Berris       Profile::ThreadID{1},
189f6c87eb9SDean Michael Berris       {{Profiles[0].internPath({2, 1}), Profile::Data{1, 1000}}}})));
190f6c87eb9SDean Michael Berris   EXPECT_FALSE(errorToBool(Profiles[1].addBlock(Profile::Block{
191f6c87eb9SDean Michael Berris       Profile::ThreadID{2},
192f6c87eb9SDean Michael Berris       {{Profiles[1].internPath({2, 1}), Profile::Data{1, 1000}}}})));
193f6c87eb9SDean Michael Berris   EXPECT_FALSE(errorToBool(Profiles[2].addBlock(Profile::Block{
194f6c87eb9SDean Michael Berris       Profile::ThreadID{3},
195f6c87eb9SDean Michael Berris       {{Profiles[2].internPath({2, 1}), Profile::Data{1, 1000}}}})));
196f6c87eb9SDean Michael Berris   Profile Merged = std::accumulate(Profiles.begin(), Profiles.end(), Profile(),
197f6c87eb9SDean Michael Berris                                    mergeProfilesByStack);
198f6c87eb9SDean Michael Berris   EXPECT_THAT(Merged,
199f6c87eb9SDean Michael Berris               ElementsAre(AllOf(
200f6c87eb9SDean Michael Berris                   // We expect that we lose the ThreadID dimension in this
201f6c87eb9SDean Michael Berris                   // algorithm.
202f6c87eb9SDean Michael Berris                   Field(&Profile::Block::Thread, Eq(Profile::ThreadID{0})),
203f6c87eb9SDean Michael Berris                   Field(&Profile::Block::PathData,
204f6c87eb9SDean Michael Berris                         ElementsAre(Pair(
205f6c87eb9SDean Michael Berris                             Merged.internPath({2, 1}),
206f6c87eb9SDean Michael Berris                             AllOf(Field(&Profile::Data::CallCount, Eq(3u)),
207f6c87eb9SDean Michael Berris                                   Field(&Profile::Data::CumulativeLocalTime,
208f6c87eb9SDean Michael Berris                                         Eq(3000u)))))))));
209f6c87eb9SDean Michael Berris }
210f6c87eb9SDean Michael Berris 
TEST(ProfileTest,MergeProfilesByThreadAccumulate)211f6c87eb9SDean Michael Berris TEST(ProfileTest, MergeProfilesByThreadAccumulate) {
212f6c87eb9SDean Michael Berris   std::vector<Profile> Profiles(2);
213f6c87eb9SDean Michael Berris 
214f6c87eb9SDean Michael Berris   // Set up the blocks for two different threads in Profiles[0].
215f6c87eb9SDean Michael Berris   EXPECT_FALSE(errorToBool(Profiles[0].addBlock(Profile::Block{
216f6c87eb9SDean Michael Berris       Profile::ThreadID{1},
217f6c87eb9SDean Michael Berris       {{Profiles[0].internPath({2, 1}), Profile::Data{1, 1000}},
218f6c87eb9SDean Michael Berris        {Profiles[0].internPath({4, 1}), Profile::Data{1, 1000}}}})));
219f6c87eb9SDean Michael Berris   EXPECT_FALSE(errorToBool(Profiles[0].addBlock(Profile::Block{
220f6c87eb9SDean Michael Berris       Profile::ThreadID{2},
221f6c87eb9SDean Michael Berris       {{Profiles[0].internPath({3, 1}), Profile::Data{1, 1000}}}})));
222f6c87eb9SDean Michael Berris 
223f6c87eb9SDean Michael Berris   // Set up the blocks for two different threads in Profiles[1].
224f6c87eb9SDean Michael Berris   EXPECT_FALSE(errorToBool(Profiles[1].addBlock(Profile::Block{
225f6c87eb9SDean Michael Berris       Profile::ThreadID{1},
226f6c87eb9SDean Michael Berris       {{Profiles[1].internPath({2, 1}), Profile::Data{1, 1000}}}})));
227f6c87eb9SDean Michael Berris   EXPECT_FALSE(errorToBool(Profiles[1].addBlock(Profile::Block{
228f6c87eb9SDean Michael Berris       Profile::ThreadID{2},
229f6c87eb9SDean Michael Berris       {{Profiles[1].internPath({3, 1}), Profile::Data{1, 1000}},
230f6c87eb9SDean Michael Berris        {Profiles[1].internPath({4, 1}), Profile::Data{1, 1000}}}})));
231f6c87eb9SDean Michael Berris 
232f6c87eb9SDean Michael Berris   Profile Merged = std::accumulate(Profiles.begin(), Profiles.end(), Profile(),
233f6c87eb9SDean Michael Berris                                    mergeProfilesByThread);
234f6c87eb9SDean Michael Berris   EXPECT_THAT(
235f6c87eb9SDean Michael Berris       Merged,
236f6c87eb9SDean Michael Berris       UnorderedElementsAre(
237f6c87eb9SDean Michael Berris           // We want to see two threads after the merge.
238f6c87eb9SDean Michael Berris           AllOf(Field(&Profile::Block::Thread, Eq(Profile::ThreadID{1})),
239f6c87eb9SDean Michael Berris                 Field(&Profile::Block::PathData,
240f6c87eb9SDean Michael Berris                       UnorderedElementsAre(
241f6c87eb9SDean Michael Berris                           Pair(Merged.internPath({2, 1}),
242f6c87eb9SDean Michael Berris                                AllOf(Field(&Profile::Data::CallCount, Eq(2u)),
243f6c87eb9SDean Michael Berris                                      Field(&Profile::Data::CumulativeLocalTime,
244f6c87eb9SDean Michael Berris                                            Eq(2000u)))),
245f6c87eb9SDean Michael Berris                           Pair(Merged.internPath({4, 1}),
246f6c87eb9SDean Michael Berris                                AllOf(Field(&Profile::Data::CallCount, Eq(1u)),
247f6c87eb9SDean Michael Berris                                      Field(&Profile::Data::CumulativeLocalTime,
248f6c87eb9SDean Michael Berris                                            Eq(1000u))))))),
249f6c87eb9SDean Michael Berris           AllOf(Field(&Profile::Block::Thread, Eq(Profile::ThreadID{2})),
250f6c87eb9SDean Michael Berris                 Field(&Profile::Block::PathData,
251f6c87eb9SDean Michael Berris                       UnorderedElementsAre(
252f6c87eb9SDean Michael Berris                           Pair(Merged.internPath({3, 1}),
253f6c87eb9SDean Michael Berris                                AllOf(Field(&Profile::Data::CallCount, Eq(2u)),
254f6c87eb9SDean Michael Berris                                      Field(&Profile::Data::CumulativeLocalTime,
255f6c87eb9SDean Michael Berris                                            Eq(2000u)))),
256f6c87eb9SDean Michael Berris                           Pair(Merged.internPath({4, 1}),
257f6c87eb9SDean Michael Berris                                AllOf(Field(&Profile::Data::CallCount, Eq(1u)),
258f6c87eb9SDean Michael Berris                                      Field(&Profile::Data::CumulativeLocalTime,
259f6c87eb9SDean Michael Berris                                            Eq(1000u)))))))));
260f6c87eb9SDean Michael Berris }
261f6c87eb9SDean Michael Berris // FIXME: Add a test creating a Trace and generating a Profile
262f6c87eb9SDean Michael Berris // FIXME: Add tests for ranking/sorting profile blocks by dimension
263f6c87eb9SDean Michael Berris 
264f6c87eb9SDean Michael Berris } // namespace
265f6c87eb9SDean Michael Berris } // namespace xray
266f6c87eb9SDean Michael Berris } // namespace llvm
267