Skip to content

[llvm-exegesis] Add middle half repetition mode #77020

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jan 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions llvm/docs/CommandGuide/llvm-exegesis.rst
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ OPTIONS
enabled can help determine the effects of the frontend and can be used to
improve latency and throughput estimates.

.. option:: --repetition-mode=[duplicate|loop|min]
.. option:: --repetition-mode=[duplicate|loop|min|middle-half-duplicate|middle-half-loop]

Specify the repetition mode. `duplicate` will create a large, straight line
basic block with `num-repetitions` instructions (repeating the snippet
Expand All @@ -314,7 +314,11 @@ OPTIONS
that cache decoded instructions, but consumes a register for counting
iterations. If performing an analysis over many opcodes, it may be best to
instead use the `min` mode, which will run each other mode,
and produce the minimal measured result.
and produce the minimal measured result. The middle half repetition modes
will either duplicate or run the snippet in a loop depending upon the specific
mode. The middle half repetition modes will run two benchmarks, one twice the
length of the first one, and then subtract the difference between them to get
values without overhead.

.. option:: --num-repetitions=<Number of repetitions>

Expand Down
8 changes: 8 additions & 0 deletions llvm/test/tools/llvm-exegesis/X86/latency/middle-half.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# REQUIRES: exegesis-can-measure-latency, x86_64-linux

# Check that we can use the middle-half repetition mode without crashing

# RUN: llvm-exegesis -mtriple=x86_64-unknown-unknown -mode=latency -opcode-name=ADD64rr -repetition-mode=middle-half-duplicate | FileCheck %s
# RUN: llvm-exegesis -mtriple=x86_64-unknown-unknown -mode=latency -opcode-name=ADD64rr -repetition-mode=middle-half-loop | FileCheck %s

# CHECK: - { key: latency, value: {{[0-9.]*}}, per_snippet_value: {{[0-9.]*}}
12 changes: 10 additions & 2 deletions llvm/tools/llvm-exegesis/lib/BenchmarkResult.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ struct BenchmarkMeasure {
static BenchmarkMeasure
Create(std::string Key, double Value,
std::map<ValidationEvent, int64_t> ValCounters) {
return {Key, Value, Value, ValCounters};
return {Key, Value, Value, Value, ValCounters};
}
std::string Key;
// This is the per-instruction value, i.e. measured quantity scaled per
Expand All @@ -99,6 +99,8 @@ struct BenchmarkMeasure {
// This is the per-snippet value, i.e. measured quantity for one repetition of
// the whole snippet.
double PerSnippetValue;
// This is the raw value collected from the full execution.
double RawValue;
// These are the validation counter values.
std::map<ValidationEvent, int64_t> ValidationCounters;
};
Expand All @@ -115,7 +117,13 @@ struct Benchmark {
// The number of instructions inside the repeated snippet. For example, if a
// snippet of 3 instructions is repeated 4 times, this is 12.
unsigned NumRepetitions = 0;
enum RepetitionModeE { Duplicate, Loop, AggregateMin };
enum RepetitionModeE {
Duplicate,
Loop,
AggregateMin,
MiddleHalfDuplicate,
MiddleHalfLoop
};
// Note that measurements are per instruction.
std::vector<BenchmarkMeasure> Measurements;
std::string Error;
Expand Down
1 change: 1 addition & 0 deletions llvm/tools/llvm-exegesis/lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ add_llvm_library(LLVMExegesis
PerfHelper.cpp
RegisterAliasing.cpp
RegisterValue.cpp
ResultAggregator.cpp
SchedClassResolution.cpp
SerialSnippetGenerator.cpp
SnippetFile.cpp
Expand Down
95 changes: 95 additions & 0 deletions llvm/tools/llvm-exegesis/lib/ResultAggregator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
//===-- ResultAggregator.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 "ResultAggregator.h"

namespace llvm {
namespace exegesis {

class DefaultResultAggregator : public ResultAggregator {
void AggregateResults(Benchmark &Result,
ArrayRef<Benchmark> OtherResults) const override{};
void AggregateMeasurement(BenchmarkMeasure &Measurement,
const BenchmarkMeasure &NewMeasurement,
const Benchmark &Result) const override{};
};

class MinimumResultAggregator : public ResultAggregator {
void AggregateMeasurement(BenchmarkMeasure &Measurement,
const BenchmarkMeasure &NewMeasurement,
const Benchmark &Result) const override;
};

void MinimumResultAggregator::AggregateMeasurement(
BenchmarkMeasure &Measurement, const BenchmarkMeasure &NewMeasurement,
const Benchmark &Result) const {
Measurement.PerInstructionValue = std::min(
Measurement.PerInstructionValue, NewMeasurement.PerInstructionValue);
Measurement.PerSnippetValue =
std::min(Measurement.PerSnippetValue, NewMeasurement.PerSnippetValue);
Measurement.RawValue =
std::min(Measurement.RawValue, NewMeasurement.RawValue);
}

class MiddleHalfResultAggregator : public ResultAggregator {
void AggregateMeasurement(BenchmarkMeasure &Measurement,
const BenchmarkMeasure &NewMeasurement,
const Benchmark &Result) const override;
};

void MiddleHalfResultAggregator::AggregateMeasurement(
BenchmarkMeasure &Measurement, const BenchmarkMeasure &NewMeasurement,
const Benchmark &Result) const {
Measurement.RawValue = NewMeasurement.RawValue - Measurement.RawValue;
Measurement.PerInstructionValue = Measurement.RawValue;
Measurement.PerInstructionValue /= Result.NumRepetitions;
Measurement.PerSnippetValue = Measurement.RawValue;
Measurement.PerSnippetValue /=
std::ceil(Result.NumRepetitions /
static_cast<double>(Result.Key.Instructions.size()));
}

void ResultAggregator::AggregateResults(
Benchmark &Result, ArrayRef<Benchmark> OtherResults) const {
for (const Benchmark &OtherResult : OtherResults) {
append_range(Result.AssembledSnippet, OtherResult.AssembledSnippet);

if (OtherResult.Measurements.empty())
continue;

assert(OtherResult.Measurements.size() == Result.Measurements.size() &&
"Expected to have an identical number of measurements");

for (auto I : zip(Result.Measurements, OtherResult.Measurements)) {
BenchmarkMeasure &Measurement = std::get<0>(I);
const BenchmarkMeasure &NewMeasurement = std::get<1>(I);

assert(Measurement.Key == NewMeasurement.Key &&
"Expected measurements to be symmetric");

AggregateMeasurement(Measurement, NewMeasurement, Result);
}
}
}

std::unique_ptr<ResultAggregator>
ResultAggregator::CreateAggregator(Benchmark::RepetitionModeE RepetitionMode) {
switch (RepetitionMode) {
case Benchmark::RepetitionModeE::Duplicate:
case Benchmark::RepetitionModeE::Loop:
return std::make_unique<DefaultResultAggregator>();
case Benchmark::RepetitionModeE::AggregateMin:
return std::make_unique<MinimumResultAggregator>();
case Benchmark::RepetitionModeE::MiddleHalfDuplicate:
case Benchmark::RepetitionModeE::MiddleHalfLoop:
return std::make_unique<MiddleHalfResultAggregator>();
}
}

} // namespace exegesis
} // namespace llvm
35 changes: 35 additions & 0 deletions llvm/tools/llvm-exegesis/lib/ResultAggregator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//===-- ResultAggregator.h --------------------------------------*- 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// Defines result aggregators that are used to aggregate the results from
/// multiple full benchmark runs.
///
//===----------------------------------------------------------------------===//

#include "BenchmarkResult.h"

namespace llvm {
namespace exegesis {

class ResultAggregator {
public:
static std::unique_ptr<ResultAggregator>
CreateAggregator(Benchmark::RepetitionModeE RepetitionMode);

virtual void AggregateResults(Benchmark &Result,
ArrayRef<Benchmark> OtherResults) const;
virtual void AggregateMeasurement(BenchmarkMeasure &Measurement,
const BenchmarkMeasure &NewMeasurement,
const Benchmark &Result) const = 0;

virtual ~ResultAggregator() = default;
};

} // namespace exegesis
} // namespace llvm
2 changes: 2 additions & 0 deletions llvm/tools/llvm-exegesis/lib/SnippetRepetitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,10 @@ SnippetRepetitor::Create(Benchmark::RepetitionModeE Mode,
const LLVMState &State) {
switch (Mode) {
case Benchmark::Duplicate:
case Benchmark::MiddleHalfDuplicate:
return std::make_unique<DuplicateSnippetRepetitor>(State);
case Benchmark::Loop:
case Benchmark::MiddleHalfLoop:
return std::make_unique<LoopSnippetRepetitor>(State);
case Benchmark::AggregateMin:
break;
Expand Down
76 changes: 35 additions & 41 deletions llvm/tools/llvm-exegesis/llvm-exegesis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "lib/LlvmState.h"
#include "lib/PerfHelper.h"
#include "lib/ProgressMeter.h"
#include "lib/ResultAggregator.h"
#include "lib/SnippetFile.h"
#include "lib/SnippetRepetitor.h"
#include "lib/Target.h"
Expand Down Expand Up @@ -106,10 +107,13 @@ static cl::opt<exegesis::Benchmark::RepetitionModeE> RepetitionMode(
cl::values(
clEnumValN(exegesis::Benchmark::Duplicate, "duplicate",
"Duplicate the snippet"),
clEnumValN(exegesis::Benchmark::Loop, "loop",
"Loop over the snippet"),
clEnumValN(exegesis::Benchmark::Loop, "loop", "Loop over the snippet"),
clEnumValN(exegesis::Benchmark::AggregateMin, "min",
"All of the above and take the minimum of measurements")),
"All of the above and take the minimum of measurements"),
clEnumValN(exegesis::Benchmark::MiddleHalfDuplicate,
"middle-half-duplicate", "Middle half duplicate mode"),
clEnumValN(exegesis::Benchmark::MiddleHalfLoop, "middle-half-loop",
"Middle half loop mode")),
cl::init(exegesis::Benchmark::Duplicate));

static cl::opt<bool> BenchmarkMeasurementsPrintProgress(
Expand Down Expand Up @@ -421,30 +425,39 @@ static void runBenchmarkConfigurations(
std::optional<ProgressMeter<>> Meter;
if (BenchmarkMeasurementsPrintProgress)
Meter.emplace(Configurations.size());

SmallVector<unsigned, 2> MinInstructions = {NumRepetitions};
if (RepetitionMode == Benchmark::MiddleHalfDuplicate ||
RepetitionMode == Benchmark::MiddleHalfLoop)
MinInstructions.push_back(NumRepetitions * 2);

for (const BenchmarkCode &Conf : Configurations) {
ProgressMeter<>::ProgressMeterStep MeterStep(Meter ? &*Meter : nullptr);
SmallVector<Benchmark, 2> AllResults;

for (const std::unique_ptr<const SnippetRepetitor> &Repetitor :
Repetitors) {
auto RC = ExitOnErr(Runner.getRunnableConfiguration(
Conf, NumRepetitions, LoopBodySize, *Repetitor));
std::optional<StringRef> DumpFile;
if (DumpObjectToDisk.getNumOccurrences())
DumpFile = DumpObjectToDisk;
auto [Err, BenchmarkResult] =
Runner.runConfiguration(std::move(RC), DumpFile);
if (Err) {
// Errors from executing the snippets are fine.
// All other errors are a framework issue and should fail.
if (!Err.isA<SnippetExecutionFailure>()) {
errs() << "llvm-exegesis error: " << toString(std::move(Err));
exit(1);
for (unsigned IterationRepetitions : MinInstructions) {
auto RC = ExitOnErr(Runner.getRunnableConfiguration(
Conf, IterationRepetitions, LoopBodySize, *Repetitor));
std::optional<StringRef> DumpFile;
if (DumpObjectToDisk.getNumOccurrences())
DumpFile = DumpObjectToDisk;
auto [Err, BenchmarkResult] =
Runner.runConfiguration(std::move(RC), DumpFile);
if (Err) {
// Errors from executing the snippets are fine.
// All other errors are a framework issue and should fail.
if (!Err.isA<SnippetExecutionFailure>()) {
llvm::errs() << "llvm-exegesis error: " << toString(std::move(Err));
exit(1);
}
BenchmarkResult.Error = toString(std::move(Err));
}
BenchmarkResult.Error = toString(std::move(Err));
AllResults.push_back(std::move(BenchmarkResult));
}
AllResults.push_back(std::move(BenchmarkResult));
}

Benchmark &Result = AllResults.front();

// If any of our measurements failed, pretend they all have failed.
Expand All @@ -454,29 +467,10 @@ static void runBenchmarkConfigurations(
}))
Result.Measurements.clear();

if (RepetitionMode == Benchmark::RepetitionModeE::AggregateMin) {
for (const Benchmark &OtherResult :
ArrayRef<Benchmark>(AllResults).drop_front()) {
append_range(Result.AssembledSnippet, OtherResult.AssembledSnippet);
// Aggregate measurements, but only if all measurements succeeded.
if (Result.Measurements.empty())
continue;
assert(OtherResult.Measurements.size() == Result.Measurements.size() &&
"Expected to have identical number of measurements.");
for (auto I : zip(Result.Measurements, OtherResult.Measurements)) {
BenchmarkMeasure &Measurement = std::get<0>(I);
const BenchmarkMeasure &NewMeasurement = std::get<1>(I);
assert(Measurement.Key == NewMeasurement.Key &&
"Expected measurements to be symmetric");

Measurement.PerInstructionValue =
std::min(Measurement.PerInstructionValue,
NewMeasurement.PerInstructionValue);
Measurement.PerSnippetValue = std::min(
Measurement.PerSnippetValue, NewMeasurement.PerSnippetValue);
}
}
}
std::unique_ptr<ResultAggregator> ResultAgg =
ResultAggregator::CreateAggregator(RepetitionMode);
ResultAgg->AggregateResults(Result,
ArrayRef<Benchmark>(AllResults).drop_front());

// With dummy counters, measurements are rather meaningless,
// so drop them altogether.
Expand Down
1 change: 1 addition & 0 deletions llvm/unittests/tools/llvm-exegesis/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ set(exegesis_sources
ClusteringTest.cpp
ProgressMeterTest.cpp
RegisterValueTest.cpp
ResultAggregatorTest.cpp
)

set(exegesis_link_libraries LLVMExegesis)
Expand Down
Loading