1 //===-- Automemcpy Json Results Analyzer Test ----------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "automemcpy/ResultAnalyzer.h"
10 #include "gmock/gmock.h"
11 #include "gtest/gtest.h"
13 using testing::DoubleNear
;
14 using testing::ElementsAre
;
16 using testing::SizeIs
;
19 namespace automemcpy
{
22 TEST(AutomemcpyJsonResultsAnalyzer
, getThroughputsOneSample
) {
23 static constexpr FunctionId Foo1
= {"memcpy1", FunctionType::MEMCPY
};
24 static constexpr DistributionId DistA
= {{"A"}};
25 static constexpr SampleId Id
= {Foo1
, DistA
};
26 static constexpr Sample kSamples
[] = {
27 Sample
{Id
, SampleType::ITERATION
, 4},
28 Sample
{Id
, SampleType::AGGREGATE
, -1}, // Aggegates gets discarded
31 const std::vector
<FunctionData
> Data
= getThroughputs(kSamples
);
32 EXPECT_THAT(Data
, SizeIs(1));
33 EXPECT_THAT(Data
[0].Id
, Foo1
);
34 EXPECT_THAT(Data
[0].PerDistributionData
, SizeIs(1));
35 // A single value is provided.
36 const auto &DistributionData
= Data
[0].PerDistributionData
.lookup(DistA
.Name
);
37 EXPECT_THAT(DistributionData
.BytesPerSecondMedian
, 4);
38 EXPECT_THAT(DistributionData
.BytesPerSecondMean
, 4);
39 EXPECT_THAT(DistributionData
.BytesPerSecondVariance
, 0);
42 TEST(AutomemcpyJsonResultsAnalyzer
, getThroughputsManySamplesSameBucket
) {
43 static constexpr FunctionId Foo1
= {"memcpy1", FunctionType::MEMCPY
};
44 static constexpr DistributionId DistA
= {{"A"}};
45 static constexpr SampleId Id
= {Foo1
, DistA
};
46 static constexpr Sample kSamples
[] = {Sample
{Id
, SampleType::ITERATION
, 4},
47 Sample
{Id
, SampleType::ITERATION
, 5},
48 Sample
{Id
, SampleType::ITERATION
, 5}};
50 const std::vector
<FunctionData
> Data
= getThroughputs(kSamples
);
51 EXPECT_THAT(Data
, SizeIs(1));
52 EXPECT_THAT(Data
[0].Id
, Foo1
);
53 EXPECT_THAT(Data
[0].PerDistributionData
, SizeIs(1));
54 // When multiple values are provided we pick the median one (here median of 4,
56 const auto &DistributionData
= Data
[0].PerDistributionData
.lookup(DistA
.Name
);
57 EXPECT_THAT(DistributionData
.BytesPerSecondMedian
, 5);
58 EXPECT_THAT(DistributionData
.BytesPerSecondMean
, DoubleNear(4.6, 0.1));
59 EXPECT_THAT(DistributionData
.BytesPerSecondVariance
, DoubleNear(0.33, 0.01));
62 TEST(AutomemcpyJsonResultsAnalyzer
, getThroughputsServeralFunctionAndDist
) {
63 static constexpr FunctionId Foo1
= {"memcpy1", FunctionType::MEMCPY
};
64 static constexpr DistributionId DistA
= {{"A"}};
65 static constexpr FunctionId Foo2
= {"memcpy2", FunctionType::MEMCPY
};
66 static constexpr DistributionId DistB
= {{"B"}};
67 static constexpr Sample kSamples
[] = {
68 Sample
{{Foo1
, DistA
}, SampleType::ITERATION
, 1},
69 Sample
{{Foo1
, DistB
}, SampleType::ITERATION
, 2},
70 Sample
{{Foo2
, DistA
}, SampleType::ITERATION
, 3},
71 Sample
{{Foo2
, DistB
}, SampleType::ITERATION
, 4}};
72 // Data is aggregated per function.
73 const std::vector
<FunctionData
> Data
= getThroughputs(kSamples
);
74 EXPECT_THAT(Data
, SizeIs(2)); // 2 functions Foo1 and Foo2.
75 // Each function has data for both distributions DistA and DistB.
76 EXPECT_THAT(Data
[0].PerDistributionData
, SizeIs(2));
77 EXPECT_THAT(Data
[1].PerDistributionData
, SizeIs(2));
80 TEST(AutomemcpyJsonResultsAnalyzer
, getScore
) {
81 static constexpr FunctionId Foo1
= {"memcpy1", FunctionType::MEMCPY
};
82 static constexpr FunctionId Foo2
= {"memcpy2", FunctionType::MEMCPY
};
83 static constexpr FunctionId Foo3
= {"memcpy3", FunctionType::MEMCPY
};
84 static constexpr DistributionId Dist
= {{"A"}};
85 static constexpr Sample kSamples
[] = {
86 Sample
{{Foo1
, Dist
}, SampleType::ITERATION
, 1},
87 Sample
{{Foo2
, Dist
}, SampleType::ITERATION
, 2},
88 Sample
{{Foo3
, Dist
}, SampleType::ITERATION
, 3}};
90 // Data is aggregated per function.
91 std::vector
<FunctionData
> Data
= getThroughputs(kSamples
);
93 // Sort Data by function name so we can test them.
95 Data
.begin(), Data
.end(),
96 [](const FunctionData
&A
, const FunctionData
&B
) { return A
.Id
< B
.Id
; });
98 EXPECT_THAT(Data
[0].Id
, Foo1
);
99 EXPECT_THAT(Data
[0].PerDistributionData
.lookup("A").BytesPerSecondMedian
, 1);
100 EXPECT_THAT(Data
[1].Id
, Foo2
);
101 EXPECT_THAT(Data
[1].PerDistributionData
.lookup("A").BytesPerSecondMedian
, 2);
102 EXPECT_THAT(Data
[2].Id
, Foo3
);
103 EXPECT_THAT(Data
[2].PerDistributionData
.lookup("A").BytesPerSecondMedian
, 3);
105 // Normalizes throughput per distribution.
107 EXPECT_THAT(Data
[0].PerDistributionData
.lookup("A").Score
, 0);
108 EXPECT_THAT(Data
[1].PerDistributionData
.lookup("A").Score
, 0.5);
109 EXPECT_THAT(Data
[2].PerDistributionData
.lookup("A").Score
, 1);
112 TEST(AutomemcpyJsonResultsAnalyzer
, castVotes
) {
113 static constexpr double kAbsErr
= 0.01;
115 static constexpr FunctionId Foo1
= {"memcpy1", FunctionType::MEMCPY
};
116 static constexpr FunctionId Foo2
= {"memcpy2", FunctionType::MEMCPY
};
117 static constexpr FunctionId Foo3
= {"memcpy3", FunctionType::MEMCPY
};
118 static constexpr DistributionId DistA
= {{"A"}};
119 static constexpr DistributionId DistB
= {{"B"}};
120 static constexpr Sample kSamples
[] = {
121 Sample
{{Foo1
, DistA
}, SampleType::ITERATION
, 0},
122 Sample
{{Foo1
, DistB
}, SampleType::ITERATION
, 30},
123 Sample
{{Foo2
, DistA
}, SampleType::ITERATION
, 1},
124 Sample
{{Foo2
, DistB
}, SampleType::ITERATION
, 100},
125 Sample
{{Foo3
, DistA
}, SampleType::ITERATION
, 7},
126 Sample
{{Foo3
, DistB
}, SampleType::ITERATION
, 100},
129 // DistA Thoughput ranges from 0 to 7.
130 // DistB Thoughput ranges from 30 to 100.
132 // Data is aggregated per function.
133 std::vector
<FunctionData
> Data
= getThroughputs(kSamples
);
135 // Sort Data by function name so we can test them.
137 Data
.begin(), Data
.end(),
138 [](const FunctionData
&A
, const FunctionData
&B
) { return A
.Id
< B
.Id
; });
140 // Normalizes throughput per distribution.
146 EXPECT_THAT(Data
[0].Id
, Foo1
);
147 EXPECT_THAT(Data
[1].Id
, Foo2
);
148 EXPECT_THAT(Data
[2].Id
, Foo3
);
150 const auto GetDistData
= [&Data
](size_t Index
, StringRef Name
) {
151 return Data
[Index
].PerDistributionData
.lookup(Name
);
155 // Throughput is 0, 1 and 7, so normalized scores are 0, 1/7 and 1.
156 EXPECT_THAT(GetDistData(0, "A").Score
, DoubleNear(0, kAbsErr
));
157 EXPECT_THAT(GetDistData(1, "A").Score
, DoubleNear(1. / 7, kAbsErr
));
158 EXPECT_THAT(GetDistData(2, "A").Score
, DoubleNear(1, kAbsErr
));
159 // which are turned into grades BAD, MEDIOCRE and EXCELLENT.
160 EXPECT_THAT(GetDistData(0, "A").Grade
, Grade::BAD
);
161 EXPECT_THAT(GetDistData(1, "A").Grade
, Grade::MEDIOCRE
);
162 EXPECT_THAT(GetDistData(2, "A").Grade
, Grade::EXCELLENT
);
165 // Throughput is 30, 100 and 100, so normalized scores are 0, 1 and 1.
166 EXPECT_THAT(GetDistData(0, "B").Score
, DoubleNear(0, kAbsErr
));
167 EXPECT_THAT(GetDistData(1, "B").Score
, DoubleNear(1, kAbsErr
));
168 EXPECT_THAT(GetDistData(2, "B").Score
, DoubleNear(1, kAbsErr
));
169 // which are turned into grades BAD, EXCELLENT and EXCELLENT.
170 EXPECT_THAT(GetDistData(0, "B").Grade
, Grade::BAD
);
171 EXPECT_THAT(GetDistData(1, "B").Grade
, Grade::EXCELLENT
);
172 EXPECT_THAT(GetDistData(2, "B").Grade
, Grade::EXCELLENT
);
174 // Now looking from the functions point of view.
175 EXPECT_THAT(Data
[0].ScoresGeoMean
, DoubleNear(0, kAbsErr
));
176 EXPECT_THAT(Data
[1].ScoresGeoMean
, DoubleNear(1. * (1. / 7), kAbsErr
));
177 EXPECT_THAT(Data
[2].ScoresGeoMean
, DoubleNear(1, kAbsErr
));
179 // Note the array is indexed by GradeEnum values (EXCELLENT=0 / BAD = 6)
180 EXPECT_THAT(Data
[0].GradeHisto
, ElementsAre(0, 0, 0, 0, 0, 0, 2));
181 EXPECT_THAT(Data
[1].GradeHisto
, ElementsAre(1, 0, 0, 0, 0, 1, 0));
182 EXPECT_THAT(Data
[2].GradeHisto
, ElementsAre(2, 0, 0, 0, 0, 0, 0));
184 EXPECT_THAT(Data
[0].FinalGrade
, Grade::BAD
);
185 EXPECT_THAT(Data
[1].FinalGrade
, Grade::MEDIOCRE
);
186 EXPECT_THAT(Data
[2].FinalGrade
, Grade::EXCELLENT
);
190 } // namespace automemcpy