xref: /llvm-project/libc/benchmarks/JSONTest.cpp (revision 438f7fc068f9ba5555052c4af0b10f5e816c3a01)
1 //===-- JSON Tests --------------------------------------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "JSON.h"
10 #include "LibcBenchmark.h"
11 #include "LibcMemoryBenchmark.h"
12 #include "llvm/Support/JSON.h"
13 #include "llvm/Support/raw_ostream.h"
14 #include "gmock/gmock.h"
15 #include "gtest/gtest.h"
16 
17 using testing::AllOf;
18 using testing::ExplainMatchResult;
19 using testing::Field;
20 using testing::Pointwise;
21 
22 namespace llvm {
23 namespace libc_benchmarks {
24 namespace {
25 
26 Study getStudy() {
27   return Study{
28       HostState{
29           "CpuName", 123, {CacheInfo{"A", 1, 2, 3}, CacheInfo{"B", 4, 5, 6}}},
30       BenchmarkOptions{std::chrono::seconds(1), std::chrono::seconds(2), 10,
31                        100, 6, 100, 0.1, 2, BenchmarkLog::Full},
32       StudyConfiguration{2, 3, SizeRange{4, 5, 6}, Align(8), 9, 10},
33       {FunctionMeasurements{"A",
34                             {Measurement{3, std::chrono::seconds(3)},
35                              Measurement{3, std::chrono::seconds(4)}}},
36        FunctionMeasurements{"B", {}}}};
37 }
38 
39 static std::string SerializeToString(const Study &S) {
40   std::string Buffer;
41   raw_string_ostream RSO(Buffer);
42   json::OStream JOS(RSO);
43   SerializeToJson(S, JOS);
44   return Buffer;
45 }
46 
47 MATCHER(EqualsCacheInfo, "") {
48   const CacheInfo &A = ::testing::get<0>(arg);
49   const CacheInfo &B = ::testing::get<1>(arg);
50   return ExplainMatchResult(AllOf(Field(&CacheInfo::Type, B.Type),
51                                   Field(&CacheInfo::Level, B.Level),
52                                   Field(&CacheInfo::Size, B.Size),
53                                   Field(&CacheInfo::NumSharing, B.NumSharing)),
54                             A, result_listener);
55 }
56 
57 auto Equals(const HostState &H) -> auto {
58   return AllOf(
59       Field(&HostState::CpuName, H.CpuName),
60       Field(&HostState::CpuFrequency, H.CpuFrequency),
61       Field(&HostState::Caches, Pointwise(EqualsCacheInfo(), H.Caches)));
62 }
63 
64 auto Equals(const BenchmarkOptions &BO) -> auto {
65   return AllOf(
66       Field(&BenchmarkOptions::MinDuration, BO.MinDuration),
67       Field(&BenchmarkOptions::MaxDuration, BO.MaxDuration),
68       Field(&BenchmarkOptions::InitialIterations, BO.InitialIterations),
69       Field(&BenchmarkOptions::MaxIterations, BO.MaxIterations),
70       Field(&BenchmarkOptions::MinSamples, BO.MinSamples),
71       Field(&BenchmarkOptions::MaxSamples, BO.MaxSamples),
72       Field(&BenchmarkOptions::Epsilon, BO.Epsilon),
73       Field(&BenchmarkOptions::ScalingFactor, BO.ScalingFactor),
74       Field(&BenchmarkOptions::Log, BO.Log));
75 }
76 
77 auto Equals(const SizeRange &SR) -> auto {
78   return AllOf(Field(&SizeRange::From, SR.From), Field(&SizeRange::To, SR.To),
79                Field(&SizeRange::Step, SR.Step));
80 }
81 
82 auto Equals(const StudyConfiguration &SC) -> auto {
83   return AllOf(
84       Field(&StudyConfiguration::Runs, SC.Runs),
85       Field(&StudyConfiguration::BufferSize, SC.BufferSize),
86       Field(&StudyConfiguration::Size, Equals(SC.Size)),
87       Field(&StudyConfiguration::AddressAlignment, SC.AddressAlignment),
88       Field(&StudyConfiguration::MemsetValue, SC.MemsetValue),
89       Field(&StudyConfiguration::MemcmpMismatchAt, SC.MemcmpMismatchAt));
90 }
91 
92 MATCHER(EqualsMeasurement, "") {
93   const Measurement &A = ::testing::get<0>(arg);
94   const Measurement &B = ::testing::get<1>(arg);
95   return ExplainMatchResult(AllOf(Field(&Measurement::Size, B.Size),
96                                   Field(&Measurement::Runtime, B.Runtime)),
97                             A, result_listener);
98 }
99 
100 MATCHER(EqualsFunctions, "") {
101   const FunctionMeasurements &A = ::testing::get<0>(arg);
102   const FunctionMeasurements &B = ::testing::get<1>(arg);
103   return ExplainMatchResult(
104       AllOf(Field(&FunctionMeasurements::Name, B.Name),
105             Field(&FunctionMeasurements::Measurements,
106                   Pointwise(EqualsMeasurement(), B.Measurements))),
107       A, result_listener);
108 }
109 
110 auto Equals(const Study &S) -> auto {
111   return AllOf(
112       Field(&Study::Host, Equals(S.Host)),
113       Field(&Study::Options, Equals(S.Options)),
114       Field(&Study::Configuration, Equals(S.Configuration)),
115       Field(&Study::Functions, Pointwise(EqualsFunctions(), S.Functions)));
116 }
117 
118 TEST(JsonTest, RoundTrip) {
119   const Study S = getStudy();
120   auto StudyOrError = ParseJsonStudy(SerializeToString(S));
121   if (auto Err = StudyOrError.takeError())
122     EXPECT_FALSE(Err) << "Unexpected error";
123   const Study &Parsed = *StudyOrError;
124   EXPECT_THAT(Parsed, Equals(S));
125 }
126 
127 TEST(JsonTest, SupplementaryField) {
128   auto Failure = ParseJsonStudy(R"({
129       "UnknownField": 10
130     }
131   )");
132   EXPECT_EQ(toString(Failure.takeError()), "Unknown field: UnknownField");
133 }
134 
135 TEST(JsonTest, InvalidType) {
136   auto Failure = ParseJsonStudy(R"({
137       "Options": 1
138     }
139   )");
140   EXPECT_EQ(toString(Failure.takeError()), "Expected JSON Object");
141 }
142 
143 TEST(JsonTest, InvalidDuration) {
144   auto Failure = ParseJsonStudy(R"({
145       "Options": {
146         "MinDuration": "Duration should be a Number"
147       }
148     }
149   )");
150   EXPECT_EQ(toString(Failure.takeError()), "Can't parse Duration");
151 }
152 
153 TEST(JsonTest, InvalidAlignType) {
154   auto Failure = ParseJsonStudy(R"({
155       "Configuration":{
156         "AddressAlignment": "Align should be an Integer"
157       }
158     }
159   )");
160   EXPECT_EQ(toString(Failure.takeError()), "Can't parse Align, not an Integer");
161 }
162 
163 TEST(JsonTest, InvalidAlign) {
164   auto Failure = ParseJsonStudy(R"({
165       "Configuration":{
166         "AddressAlignment":3
167       }
168     }
169   )");
170   EXPECT_EQ(toString(Failure.takeError()),
171             "Can't parse Align, not a power of two");
172 }
173 
174 TEST(JsonTest, InvalidBenchmarkLogType) {
175   auto Failure = ParseJsonStudy(R"({
176       "Options":{
177         "Log": 3
178       }
179     }
180   )");
181   EXPECT_EQ(toString(Failure.takeError()),
182             "Can't parse BenchmarkLog, not a String");
183 }
184 
185 TEST(JsonTest, InvalidBenchmarkLog) {
186   auto Failure = ParseJsonStudy(R"({
187       "Options":{
188         "Log": "Unknown"
189       }
190     }
191   )");
192   EXPECT_EQ(toString(Failure.takeError()),
193             "Can't parse BenchmarkLog, invalid value 'Unknown'");
194 }
195 
196 } // namespace
197 } // namespace libc_benchmarks
198 } // namespace llvm
199