mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 12:12:47 +01:00
079fdb41d4
Summary: This is an alternative to D59539. Let's suppose we have measured 4 different opcodes, and got: `0.5`, `1.0`, `1.5`, `2.0`. Let's suppose we are using `-analysis-clustering-epsilon=0.5`. By default now we will start processing the `0.5` point, find that `1.0` is it's neighbor, add them to a new cluster. Then we will notice that `1.5` is a neighbor of `1.0` and add it to that same cluster. Then we will notice that `2.0` is a neighbor of `1.5` and add it to that same cluster. So all these points ended up in the same cluster. This may or may not be a correct implementation of dbscan clustering algorithm. But this is rather horribly broken for the reasons of comparing the clusters with the LLVM sched data. Let's suppose all those opcodes are currently in the same sched cluster. If i specify `-analysis-inconsistency-epsilon=0.5`, then no matter the LLVM values this cluster will **never** match the LLVM values, and thus this cluster will **always** be displayed as inconsistent. The solution is obviously to split off some of these opcodes into different sched cluster. But how do i do that? Out of 4 opcodes displayed in the inconsistency report, which ones are the "bad ones"? Which ones are the most different from the checked-in data? I'd need to go in to the `.yaml` and look it up manually. The trivial solution is to, when creating clusters, don't use the full dbscan algorithm, but instead "pick some unclustered point, pick all unclustered points that are it's neighbor, put them all into a new cluster, repeat". And just so as it happens, we can arrive at that algorithm by not performing the "add neighbors of a neighbor to the cluster" step. But that won't work well once we teach analyze mode to operate in on-1D mode (i.e. on more than a single measurement type at a time), because the clustering would depend on the order of the measurements. Instead, let's just create a single cluster per opcode, and put all the points of that opcode into said cluster. And simultaneously check that every point in that cluster is a neighbor of every other point in the cluster, and if they are not, the cluster (==opcode) is unstable. This is //yet another// step to bring me closer to being able to continue cleanup of bdver2 sched model.. Fixes [[ https://bugs.llvm.org/show_bug.cgi?id=40880 | PR40880 ]]. Reviewers: courbet, gchatelet Reviewed By: courbet Subscribers: tschuett, jdoerfert, RKSimon, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D59820 llvm-svn: 357152
147 lines
5.2 KiB
C++
147 lines
5.2 KiB
C++
//===-- ClusteringTest.cpp --------------------------------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "Clustering.h"
|
|
#include "BenchmarkResult.h"
|
|
#include "llvm/Support/Error.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include "gmock/gmock.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
namespace llvm {
|
|
namespace exegesis {
|
|
|
|
namespace {
|
|
|
|
using testing::Field;
|
|
using testing::UnorderedElementsAre;
|
|
using testing::UnorderedElementsAreArray;
|
|
|
|
static const auto HasPoints = [](const std::vector<int> &Indices) {
|
|
return Field(&InstructionBenchmarkClustering::Cluster::PointIndices,
|
|
UnorderedElementsAreArray(Indices));
|
|
};
|
|
|
|
TEST(ClusteringTest, Clusters3D) {
|
|
std::vector<InstructionBenchmark> Points(6);
|
|
|
|
// Cluster around (x=0, y=1, z=2): points {0, 3}.
|
|
Points[0].Measurements = {
|
|
{"x", 0.01, 0.0}, {"y", 1.02, 0.0}, {"z", 1.98, 0.0}};
|
|
Points[3].Measurements = {
|
|
{"x", -0.01, 0.0}, {"y", 1.02, 0.0}, {"z", 1.98, 0.0}};
|
|
// Cluster around (x=1, y=1, z=2): points {1, 4}.
|
|
Points[1].Measurements = {
|
|
{"x", 1.01, 0.0}, {"y", 1.02, 0.0}, {"z", 1.98, 0.0}};
|
|
Points[4].Measurements = {
|
|
{"x", 0.99, 0.0}, {"y", 1.02, 0.0}, {"z", 1.98, 0.0}};
|
|
// Cluster around (x=0, y=0, z=0): points {5}, marked as noise.
|
|
Points[5].Measurements = {
|
|
{"x", 0.0, 0.0}, {"y", 0.01, 0.0}, {"z", -0.02, 0.0}};
|
|
// Error cluster: points {2}
|
|
Points[2].Error = "oops";
|
|
|
|
auto Clustering = InstructionBenchmarkClustering::create(
|
|
Points, InstructionBenchmarkClustering::ModeE::Dbscan, 2, 0.25);
|
|
ASSERT_TRUE((bool)Clustering);
|
|
EXPECT_THAT(Clustering.get().getValidClusters(),
|
|
UnorderedElementsAre(HasPoints({0, 3}), HasPoints({1, 4})));
|
|
EXPECT_THAT(Clustering.get().getCluster(
|
|
InstructionBenchmarkClustering::ClusterId::noise()),
|
|
HasPoints({5}));
|
|
EXPECT_THAT(Clustering.get().getCluster(
|
|
InstructionBenchmarkClustering::ClusterId::error()),
|
|
HasPoints({2}));
|
|
|
|
EXPECT_EQ(Clustering.get().getClusterIdForPoint(2),
|
|
InstructionBenchmarkClustering::ClusterId::error());
|
|
EXPECT_EQ(Clustering.get().getClusterIdForPoint(5),
|
|
InstructionBenchmarkClustering::ClusterId::noise());
|
|
EXPECT_EQ(Clustering.get().getClusterIdForPoint(0),
|
|
Clustering.get().getClusterIdForPoint(3));
|
|
EXPECT_EQ(Clustering.get().getClusterIdForPoint(1),
|
|
Clustering.get().getClusterIdForPoint(4));
|
|
}
|
|
|
|
TEST(ClusteringTest, Clusters3D_InvalidSize) {
|
|
std::vector<InstructionBenchmark> Points(6);
|
|
Points[0].Measurements = {
|
|
{"x", 0.01, 0.0}, {"y", 1.02, 0.0}, {"z", 1.98, 0.0}};
|
|
Points[1].Measurements = {{"y", 1.02, 0.0}, {"z", 1.98, 0.0}};
|
|
auto Error =
|
|
InstructionBenchmarkClustering::create(
|
|
Points, InstructionBenchmarkClustering::ModeE::Dbscan, 2, 0.25)
|
|
.takeError();
|
|
ASSERT_TRUE((bool)Error);
|
|
consumeError(std::move(Error));
|
|
}
|
|
|
|
TEST(ClusteringTest, Clusters3D_InvalidOrder) {
|
|
std::vector<InstructionBenchmark> Points(6);
|
|
Points[0].Measurements = {{"x", 0.01, 0.0}, {"y", 1.02, 0.0}};
|
|
Points[1].Measurements = {{"y", 1.02, 0.0}, {"x", 1.98, 0.0}};
|
|
auto Error =
|
|
InstructionBenchmarkClustering::create(
|
|
Points, InstructionBenchmarkClustering::ModeE::Dbscan, 2, 0.25)
|
|
.takeError();
|
|
ASSERT_TRUE((bool)Error);
|
|
consumeError(std::move(Error));
|
|
}
|
|
|
|
TEST(ClusteringTest, Ordering) {
|
|
ASSERT_LT(InstructionBenchmarkClustering::ClusterId::makeValid(1),
|
|
InstructionBenchmarkClustering::ClusterId::makeValid(2));
|
|
|
|
ASSERT_LT(InstructionBenchmarkClustering::ClusterId::makeValid(2),
|
|
InstructionBenchmarkClustering::ClusterId::noise());
|
|
|
|
ASSERT_LT(InstructionBenchmarkClustering::ClusterId::makeValid(2),
|
|
InstructionBenchmarkClustering::ClusterId::error());
|
|
|
|
ASSERT_LT(InstructionBenchmarkClustering::ClusterId::noise(),
|
|
InstructionBenchmarkClustering::ClusterId::error());
|
|
}
|
|
|
|
TEST(ClusteringTest, Ordering1) {
|
|
std::vector<InstructionBenchmark> Points(3);
|
|
|
|
Points[0].Measurements = {
|
|
{"x", 0.0, 0.0}};
|
|
Points[1].Measurements = {
|
|
{"x", 1.0, 0.0}};
|
|
Points[2].Measurements = {
|
|
{"x", 2.0, 0.0}};
|
|
|
|
auto Clustering = InstructionBenchmarkClustering::create(
|
|
Points, InstructionBenchmarkClustering::ModeE::Dbscan, 2, 1.1);
|
|
ASSERT_TRUE((bool)Clustering);
|
|
EXPECT_THAT(Clustering.get().getValidClusters(),
|
|
UnorderedElementsAre(HasPoints({0, 1, 2})));
|
|
}
|
|
|
|
TEST(ClusteringTest, Ordering2) {
|
|
std::vector<InstructionBenchmark> Points(3);
|
|
|
|
Points[0].Measurements = {
|
|
{"x", 0.0, 0.0}};
|
|
Points[1].Measurements = {
|
|
{"x", 2.0, 0.0}};
|
|
Points[2].Measurements = {
|
|
{"x", 1.0, 0.0}};
|
|
|
|
auto Clustering = InstructionBenchmarkClustering::create(
|
|
Points, InstructionBenchmarkClustering::ModeE::Dbscan, 2, 1.1);
|
|
ASSERT_TRUE((bool)Clustering);
|
|
EXPECT_THAT(Clustering.get().getValidClusters(),
|
|
UnorderedElementsAre(HasPoints({0, 1, 2})));
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace exegesis
|
|
} // namespace llvm
|