1 //===- ProfileTest.cpp - XRay Profile unit tests ----------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
9 #include "llvm/XRay/Profile.h"
10 #include "gmock/gmock.h"
11 #include "gtest/gtest.h"
19 using ::testing::AllOf
;
20 using ::testing::ElementsAre
;
22 using ::testing::Field
;
24 using ::testing::Pair
;
25 using ::testing::UnorderedElementsAre
;
27 TEST(ProfileTest
, CreateProfile
) { Profile P
; }
29 TEST(ProfileTest
, InternPath
) {
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
) {
40 auto PathID
= P
.internPath({3, 2, 1});
41 auto PathOrError
= P
.expandPath(PathID
);
43 FAIL() << "Error: " << PathOrError
.takeError();
44 EXPECT_THAT(PathOrError
.get(), ElementsAre(3, 2, 1));
47 TEST(ProfileTest
, AddBlocks
) {
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}},
64 TEST(ProfileTest
, CopyProfile
) {
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}},
74 P1
, UnorderedElementsAre(AllOf(
75 Field(&Profile::Block::Thread
, Eq(Profile::ThreadID
{1})),
76 Field(&Profile::Block::PathData
,
78 Pair(P1
.internPath({2, 1}),
79 AllOf(Field(&Profile::Data::CallCount
, Eq(1u)),
80 Field(&Profile::Data::CumulativeLocalTime
,
82 Pair(P1
.internPath({3, 2, 1}),
83 AllOf(Field(&Profile::Data::CallCount
, Eq(10u)),
84 Field(&Profile::Data::CumulativeLocalTime
,
88 TEST(ProfileTest
, MoveProfile
) {
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}},
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
,
106 Pair(P1
.internPath({3, 2, 1}),
107 AllOf(Field(&Profile::Data::CallCount
, Eq(10u)),
108 Field(&Profile::Data::CumulativeLocalTime
,
110 EXPECT_THAT(P0
, UnorderedElementsAre());
113 TEST(ProfileTest
, MergeProfilesByThread
) {
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
);
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
,
146 Pair(Merged
.internPath({4, 1}),
147 AllOf(Field(&Profile::Data::CallCount
, Eq(1u)),
148 Field(&Profile::Data::CumulativeLocalTime
,
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
,
157 Pair(Merged
.internPath({4, 1}),
158 AllOf(Field(&Profile::Data::CallCount
, Eq(1u)),
159 Field(&Profile::Data::CumulativeLocalTime
,
163 TEST(ProfileTest
, MergeProfilesByStack
) {
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
);
175 // We expect that we lose the ThreadID dimension in this
177 Field(&Profile::Block::Thread
, Eq(Profile::ThreadID
{0})),
178 Field(&Profile::Block::PathData
,
180 Merged
.internPath({2, 1}),
181 AllOf(Field(&Profile::Data::CallCount
, Eq(2u)),
182 Field(&Profile::Data::CumulativeLocalTime
,
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
);
201 // We expect that we lose the ThreadID dimension in this
203 Field(&Profile::Block::Thread
, Eq(Profile::ThreadID
{0})),
204 Field(&Profile::Block::PathData
,
206 Merged
.internPath({2, 1}),
207 AllOf(Field(&Profile::Data::CallCount
, Eq(3u)),
208 Field(&Profile::Data::CumulativeLocalTime
,
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
);
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
,
246 Pair(Merged
.internPath({4, 1}),
247 AllOf(Field(&Profile::Data::CallCount
, Eq(1u)),
248 Field(&Profile::Data::CumulativeLocalTime
,
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
,
257 Pair(Merged
.internPath({4, 1}),
258 AllOf(Field(&Profile::Data::CallCount
, Eq(1u)),
259 Field(&Profile::Data::CumulativeLocalTime
,
262 // FIXME: Add a test creating a Trace and generating a Profile
263 // FIXME: Add tests for ranking/sorting profile blocks by dimension