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