blob: 8486b7b27e8bce0aa28caf658007cde433e357e8 [file] [log] [blame]
Dean Michael Berris9969df32018-08-30 01:43:22 +00001//===- 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"
12
13#include <numeric>
14
15namespace llvm {
16namespace xray {
17namespace {
18
19using ::testing::AllOf;
20using ::testing::ElementsAre;
21using ::testing::Eq;
22using ::testing::Field;
23using ::testing::Not;
24using ::testing::Pair;
25using ::testing::UnorderedElementsAre;
26
27TEST(ProfileTest, CreateProfile) { Profile P; }
28
29TEST(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)));
36}
37
38TEST(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));
45}
46
47TEST(ProfileTest, AddBlocks) {
48 Profile P;
49 // Expect an error on adding empty blocks.
50 EXPECT_TRUE(errorToBool(P.addBlock({})));
51
52 // Thread blocks may not be empty.
53 EXPECT_TRUE(errorToBool(P.addBlock({1, {}})));
54
55 // Thread blocks with data must succeed.
56 EXPECT_FALSE(errorToBool(P.addBlock(
57 Profile::Block{Profile::ThreadID{1},
58 {
59 {P.internPath({2, 1}), Profile::Data{1, 1000}},
60 {P.internPath({3, 2, 1}), Profile::Data{10, 100}},
61 }})));
62}
63
64TEST(ProfileTest, CopyProfile) {
65 Profile P0, P1;
66 EXPECT_FALSE(errorToBool(P0.addBlock(
67 Profile::Block{Profile::ThreadID{1},
68 {
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)))))))));
86}
87
88TEST(ProfileTest, MoveProfile) {
89 Profile P0, P1;
90 EXPECT_FALSE(errorToBool(P0.addBlock(
91 Profile::Block{Profile::ThreadID{1},
92 {
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());
111}
112
113TEST(ProfileTest, MergeProfilesByThread) {
114 Profile P0, P1;
115
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}}}})));
124
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}}}})));
133
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)))))))));
161}
162
163TEST(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}}}})));
171
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)))))))));
184}
185
186TEST(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)))))))));
210}
211
212TEST(ProfileTest, MergeProfilesByThreadAccumulate) {
213 std::vector<Profile> Profiles(2);
214
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}}}})));
223
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}}}})));
232
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)))))))));
261}
262// FIXME: Add a test creating a Trace and generating a Profile
263// FIXME: Add tests for ranking/sorting profile blocks by dimension
264
265} // namespace
266} // namespace xray
267} // namespace llvm