1 //===-- ClusteringTest.cpp --------------------------------------*- C++ -*-===//
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 "Clustering.h"
10 #include "BenchmarkResult.h"
11 #include "llvm/Support/Error.h"
12 #include "llvm/Support/raw_ostream.h"
13 #include "gmock/gmock.h"
14 #include "gtest/gtest.h"
15 
16 namespace llvm {
17 namespace exegesis {
18 
19 namespace {
20 
21 using testing::Field;
22 using testing::UnorderedElementsAre;
23 using testing::UnorderedElementsAreArray;
24 
25 static const auto HasPoints = [](const std::vector<int> &Indices) {
26   return Field(&InstructionBenchmarkClustering::Cluster::PointIndices,
27                  UnorderedElementsAreArray(Indices));
28 };
29 
30 TEST(ClusteringTest, Clusters3D) {
31   std::vector<InstructionBenchmark> Points(6);
32 
33   // Cluster around (x=0, y=1, z=2): points {0, 3}.
34   Points[0].Measurements = {
35       {"x", 0.01, 0.0}, {"y", 1.02, 0.0}, {"z", 1.98, 0.0}};
36   Points[3].Measurements = {
37       {"x", -0.01, 0.0}, {"y", 1.02, 0.0}, {"z", 1.98, 0.0}};
38   // Cluster around (x=1, y=1, z=2): points {1, 4}.
39   Points[1].Measurements = {
40       {"x", 1.01, 0.0}, {"y", 1.02, 0.0}, {"z", 1.98, 0.0}};
41   Points[4].Measurements = {
42       {"x", 0.99, 0.0}, {"y", 1.02, 0.0}, {"z", 1.98, 0.0}};
43   // Cluster around (x=0, y=0, z=0): points {5}, marked as noise.
44   Points[5].Measurements = {
45       {"x", 0.0, 0.0}, {"y", 0.01, 0.0}, {"z", -0.02, 0.0}};
46   // Error cluster: points {2}
47   Points[2].Error = "oops";
48 
49   auto Clustering = InstructionBenchmarkClustering::create(Points, 2, 0.25);
50   ASSERT_TRUE((bool)Clustering);
51   EXPECT_THAT(Clustering.get().getValidClusters(),
52               UnorderedElementsAre(HasPoints({0, 3}), HasPoints({1, 4})));
53   EXPECT_THAT(Clustering.get().getCluster(
54                   InstructionBenchmarkClustering::ClusterId::noise()),
55               HasPoints({5}));
56   EXPECT_THAT(Clustering.get().getCluster(
57                   InstructionBenchmarkClustering::ClusterId::error()),
58               HasPoints({2}));
59 
60   EXPECT_EQ(Clustering.get().getClusterIdForPoint(2),
61             InstructionBenchmarkClustering::ClusterId::error());
62   EXPECT_EQ(Clustering.get().getClusterIdForPoint(5),
63             InstructionBenchmarkClustering::ClusterId::noise());
64   EXPECT_EQ(Clustering.get().getClusterIdForPoint(0),
65             Clustering.get().getClusterIdForPoint(3));
66   EXPECT_EQ(Clustering.get().getClusterIdForPoint(1),
67             Clustering.get().getClusterIdForPoint(4));
68 }
69 
70 TEST(ClusteringTest, Clusters3D_InvalidSize) {
71   std::vector<InstructionBenchmark> Points(6);
72   Points[0].Measurements = {
73       {"x", 0.01, 0.0}, {"y", 1.02, 0.0}, {"z", 1.98, 0.0}};
74   Points[1].Measurements = {{"y", 1.02, 0.0}, {"z", 1.98, 0.0}};
75   auto Error =
76       InstructionBenchmarkClustering::create(Points, 2, 0.25).takeError();
77   ASSERT_TRUE((bool)Error);
78   consumeError(std::move(Error));
79 }
80 
81 TEST(ClusteringTest, Clusters3D_InvalidOrder) {
82   std::vector<InstructionBenchmark> Points(6);
83   Points[0].Measurements = {{"x", 0.01, 0.0}, {"y", 1.02, 0.0}};
84   Points[1].Measurements = {{"y", 1.02, 0.0}, {"x", 1.98, 0.0}};
85   auto Error =
86       InstructionBenchmarkClustering::create(Points, 2, 0.25).takeError();
87   ASSERT_TRUE((bool)Error);
88   consumeError(std::move(Error));
89 }
90 
91 TEST(ClusteringTest, Ordering) {
92   ASSERT_LT(InstructionBenchmarkClustering::ClusterId::makeValid(1),
93             InstructionBenchmarkClustering::ClusterId::makeValid(2));
94 
95   ASSERT_LT(InstructionBenchmarkClustering::ClusterId::makeValid(2),
96             InstructionBenchmarkClustering::ClusterId::noise());
97 
98   ASSERT_LT(InstructionBenchmarkClustering::ClusterId::makeValid(2),
99             InstructionBenchmarkClustering::ClusterId::error());
100 
101   ASSERT_LT(InstructionBenchmarkClustering::ClusterId::noise(),
102             InstructionBenchmarkClustering::ClusterId::error());
103 }
104 
105 TEST(ClusteringTest, Ordering1) {
106   std::vector<InstructionBenchmark> Points(3);
107 
108   Points[0].Measurements = {
109       {"x", 0.0, 0.0}};
110   Points[1].Measurements = {
111       {"x", 1.0, 0.0}};
112   Points[2].Measurements = {
113       {"x", 2.0, 0.0}};
114 
115   auto Clustering = InstructionBenchmarkClustering::create(Points, 2, 1.1);
116   ASSERT_TRUE((bool)Clustering);
117   EXPECT_THAT(Clustering.get().getValidClusters(),
118               UnorderedElementsAre(HasPoints({0, 1, 2})));
119 }
120 
121 TEST(ClusteringTest, Ordering2) {
122   std::vector<InstructionBenchmark> Points(3);
123 
124   Points[0].Measurements = {
125       {"x", 0.0, 0.0}};
126   Points[1].Measurements = {
127       {"x", 2.0, 0.0}};
128   Points[2].Measurements = {
129       {"x", 1.0, 0.0}};
130 
131   auto Clustering = InstructionBenchmarkClustering::create(Points, 2, 1.1);
132   ASSERT_TRUE((bool)Clustering);
133   EXPECT_THAT(Clustering.get().getValidClusters(),
134               UnorderedElementsAre(HasPoints({0, 1, 2})));
135 }
136 
137 } // namespace
138 } // namespace exegesis
139 } // namespace llvm
140