[llvm-branch-commits] [libcxx] [libc++] Implements filebuf unbuffered. (PR #76629)
https://github.com/mordante created https://github.com/llvm/llvm-project/pull/76629 When calling setbuf(nullptr, 0) before performing file operations it should set the file to unbuffered mode. Currently the code avoids buffering internally, but the underlying stream still can buffer. This is addressed by disabling the buffering of the underlying stream. Fixes: https://github.com/llvm/llvm-project/issues/60509 >From a68f28e4b5e2ef7c2df9ce286a747931bbf0dfe7 Mon Sep 17 00:00:00 2001 From: Mark de Wever Date: Sat, 30 Dec 2023 20:33:25 +0100 Subject: [PATCH] [libc++] Implements filebuf unbuffered. When calling setbuf(nullptr, 0) before performing file operations it should set the file to unbuffered mode. Currently the code avoids buffering internally, but the underlying stream still can buffer. This is addressed by disabling the buffering of the underlying stream. Fixes: https://github.com/llvm/llvm-project/issues/60509 --- libcxx/include/fstream| 47 ++- .../fstreams/filebuf.virtuals/setbuf.pass.cpp | 118 ++ 2 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 libcxx/test/std/input.output/file.streams/fstreams/filebuf.virtuals/setbuf.pass.cpp diff --git a/libcxx/include/fstream b/libcxx/include/fstream index 21fee202873e76..8a2df123486556 100644 --- a/libcxx/include/fstream +++ b/libcxx/include/fstream @@ -276,6 +276,30 @@ private: state_type __st_; state_type __st_last_; ios_base::openmode __om_; + // Used to track the currently used mode and track whether the output should + // be unbuffered. + // [filebuf.virtuals]/12 + // If setbuf(0, 0) is called on a stream before any I/O has occurred on + // that stream, the stream becomes unbuffered. Otherwise the results are + // implementation-defined. + // This allows calling setbuf(0, 0) + // - before opening a file, + // - after opening a file, before + // - a read + // - a write + // - a seek. + // Note that opening a file with ios_base::ate does a seek operation. + // Normally underflow, overflow, and sync change this flag to + // ios_base::in, ios_base_out, or 0. + // + // The ios_base::trunc and ios_base::ate flags are used in the following way: + // - ios_base::trunc is set upon construction to indicate the unbuffered + // state can be set. When requesting unbuffered output and the file is open + // sets the mode. Else places a request by adding the ios_base::ate flag. + // - When a file is opened it checks whether both ios_base::trunc and + // ios_base::ate are set. If so switches to unbuffered mode. + // - Using ase::ate in the open mode sets the flag to 0 so future calls to + // setbuf no longer try to set the unbuffered mode. ios_base::openmode __cm_; bool __owns_eb_; bool __owns_ib_; @@ -294,7 +318,10 @@ private: return nullptr; __om_ = __mode; + __try_set_unbuffered_mode(); + if (__mode & ios_base::ate) { + __cm_ = 0; if (fseek(__file_, 0, SEEK_END)) { fclose(__file_); __file_ = nullptr; @@ -304,6 +331,23 @@ private: return this; } + + _LIBCPP_HIDE_FROM_ABI void __try_set_unbuffered_mode() { +if (__cm_ == (ios_base::trunc | ios_base::ate)) { + std::setbuf(__file_, nullptr); + __cm_ = 0; +} + } + _LIBCPP_HIDE_FROM_ABI void __try_set_unbuffered_mode(char_type* __s, streamsize __n) { +if (__cm_ == ios_base::trunc && __s == nullptr && __n == 0) { + if (__file_) { +std::setbuf(__file_, nullptr); +__cm_ = 0; + } else { +__cm_ = ios_base::trunc | ios_base::ate; + } +} + } }; template @@ -319,7 +363,7 @@ basic_filebuf<_CharT, _Traits>::basic_filebuf() __st_(), __st_last_(), __om_(0), - __cm_(0), + __cm_(ios_base::trunc), __owns_eb_(false), __owns_ib_(false), __always_noconv_(false) { @@ -780,6 +824,7 @@ template basic_streambuf<_CharT, _Traits>* basic_filebuf<_CharT, _Traits>::setbuf(char_type* __s, streamsize __n) { this->setg(nullptr, nullptr, nullptr); this->setp(nullptr, nullptr); + __try_set_unbuffered_mode(__s, __n); if (__owns_eb_) delete[] __extbuf_; if (__owns_ib_) diff --git a/libcxx/test/std/input.output/file.streams/fstreams/filebuf.virtuals/setbuf.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.virtuals/setbuf.pass.cpp new file mode 100644 index 00..3f561170f5fb24 --- /dev/null +++ b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.virtuals/setbuf.pass.cpp @@ -0,0 +1,118 @@ +//===--===// +// +// 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 +// +//===--===// + +// + +/
[llvm-branch-commits] [libcxx] [libc++] Implements filebuf unbuffered. (PR #76629)
llvmbot wrote: @llvm/pr-subscribers-libcxx Author: Mark de Wever (mordante) Changes When calling setbuf(nullptr, 0) before performing file operations it should set the file to unbuffered mode. Currently the code avoids buffering internally, but the underlying stream still can buffer. This is addressed by disabling the buffering of the underlying stream. Fixes: https://github.com/llvm/llvm-project/issues/60509 --- Full diff: https://github.com/llvm/llvm-project/pull/76629.diff 2 Files Affected: - (modified) libcxx/include/fstream (+46-1) - (added) libcxx/test/std/input.output/file.streams/fstreams/filebuf.virtuals/setbuf.pass.cpp (+118) ``diff diff --git a/libcxx/include/fstream b/libcxx/include/fstream index 21fee202873e76..8a2df123486556 100644 --- a/libcxx/include/fstream +++ b/libcxx/include/fstream @@ -276,6 +276,30 @@ private: state_type __st_; state_type __st_last_; ios_base::openmode __om_; + // Used to track the currently used mode and track whether the output should + // be unbuffered. + // [filebuf.virtuals]/12 + // If setbuf(0, 0) is called on a stream before any I/O has occurred on + // that stream, the stream becomes unbuffered. Otherwise the results are + // implementation-defined. + // This allows calling setbuf(0, 0) + // - before opening a file, + // - after opening a file, before + // - a read + // - a write + // - a seek. + // Note that opening a file with ios_base::ate does a seek operation. + // Normally underflow, overflow, and sync change this flag to + // ios_base::in, ios_base_out, or 0. + // + // The ios_base::trunc and ios_base::ate flags are used in the following way: + // - ios_base::trunc is set upon construction to indicate the unbuffered + // state can be set. When requesting unbuffered output and the file is open + // sets the mode. Else places a request by adding the ios_base::ate flag. + // - When a file is opened it checks whether both ios_base::trunc and + // ios_base::ate are set. If so switches to unbuffered mode. + // - Using ase::ate in the open mode sets the flag to 0 so future calls to + // setbuf no longer try to set the unbuffered mode. ios_base::openmode __cm_; bool __owns_eb_; bool __owns_ib_; @@ -294,7 +318,10 @@ private: return nullptr; __om_ = __mode; + __try_set_unbuffered_mode(); + if (__mode & ios_base::ate) { + __cm_ = 0; if (fseek(__file_, 0, SEEK_END)) { fclose(__file_); __file_ = nullptr; @@ -304,6 +331,23 @@ private: return this; } + + _LIBCPP_HIDE_FROM_ABI void __try_set_unbuffered_mode() { +if (__cm_ == (ios_base::trunc | ios_base::ate)) { + std::setbuf(__file_, nullptr); + __cm_ = 0; +} + } + _LIBCPP_HIDE_FROM_ABI void __try_set_unbuffered_mode(char_type* __s, streamsize __n) { +if (__cm_ == ios_base::trunc && __s == nullptr && __n == 0) { + if (__file_) { +std::setbuf(__file_, nullptr); +__cm_ = 0; + } else { +__cm_ = ios_base::trunc | ios_base::ate; + } +} + } }; template @@ -319,7 +363,7 @@ basic_filebuf<_CharT, _Traits>::basic_filebuf() __st_(), __st_last_(), __om_(0), - __cm_(0), + __cm_(ios_base::trunc), __owns_eb_(false), __owns_ib_(false), __always_noconv_(false) { @@ -780,6 +824,7 @@ template basic_streambuf<_CharT, _Traits>* basic_filebuf<_CharT, _Traits>::setbuf(char_type* __s, streamsize __n) { this->setg(nullptr, nullptr, nullptr); this->setp(nullptr, nullptr); + __try_set_unbuffered_mode(__s, __n); if (__owns_eb_) delete[] __extbuf_; if (__owns_ib_) diff --git a/libcxx/test/std/input.output/file.streams/fstreams/filebuf.virtuals/setbuf.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.virtuals/setbuf.pass.cpp new file mode 100644 index 00..3f561170f5fb24 --- /dev/null +++ b/libcxx/test/std/input.output/file.streams/fstreams/filebuf.virtuals/setbuf.pass.cpp @@ -0,0 +1,118 @@ +//===--===// +// +// 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 +// +//===--===// + +// + +// basic_streambuf* setbuf(char_type* s, streamsize n) override; + +#include +#include + +#include "test_macros.h" + +template +static std::size_t file_size(const char* filename) { + FILE* f = std::fopen(filename, "rb"); + fseek(f, 0, SEEK_END); + long result = ftell(f); + fclose(f); + return result; +} + +template +struct filebuf : public std::basic_filebuf { + CharT* base() { return this->pbase(); } + CharT* ptr() { return this->pptr(); } +}; + +template +static void buffered_request() { + filebuf buffer; + + CharT b[10] = {0}; + a
[llvm-branch-commits] [libcxx] [libc++] Implements filebuf unbuffered. (PR #76629)
@@ -276,6 +276,30 @@ private: state_type __st_; state_type __st_last_; ios_base::openmode __om_; + // Used to track the currently used mode and track whether the output should mordante wrote: Review note: It might be possible to use other fields to achieve the same goal. Unfortunately there's no implementation documentation for this class. This changes seems the simplest and the easiest to validate. https://github.com/llvm/llvm-project/pull/76629 ___ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
[llvm-branch-commits] [llvm] [llvm-exegesis] Add tablegen support for validation counters (PR #76652)
https://github.com/boomanaiden154 created https://github.com/llvm/llvm-project/pull/76652 This patch adds support in the llvm-exegesis tablegen emitter for validation counters. Full support for validation counters in llvm-exegesis is added in a future patch. >From 75261b9626878b92fa4bde2b4801815251238748 Mon Sep 17 00:00:00 2001 From: Aiden Grossman Date: Sat, 30 Dec 2023 17:03:59 -0800 Subject: [PATCH] [llvm-exegesis] Add tablegen support for validation counters --- llvm/include/llvm/Target/TargetPfmCounters.td | 19 + llvm/lib/Target/X86/X86PfmCounters.td | 6 llvm/tools/llvm-exegesis/lib/Target.cpp | 13 + llvm/tools/llvm-exegesis/lib/Target.h | 11 llvm/utils/TableGen/ExegesisEmitter.cpp | 28 +-- 5 files changed, 69 insertions(+), 8 deletions(-) diff --git a/llvm/include/llvm/Target/TargetPfmCounters.td b/llvm/include/llvm/Target/TargetPfmCounters.td index b00f3e19c35f90..72f6b39f4878f4 100644 --- a/llvm/include/llvm/Target/TargetPfmCounters.td +++ b/llvm/include/llvm/Target/TargetPfmCounters.td @@ -28,6 +28,22 @@ class PfmIssueCounter string ResourceName = resource_name; } +class ValidationEvent { + int EventNumber = event_number; +} + +def L1DCacheLoadMiss: ValidationEvent<0>; +def InstructionRetired : ValidationEvent<1>; +def DataTLBLoadMiss : ValidationEvent<2>; +def DataTLBStoreMiss: ValidationEvent<3>; + +// Validation counters can be tied to a specific event +class PfmValidationCounter +: PfmCounter { + // The name of the event that the validation counter detects. + ValidationEvent EventType = event_type; +} + def NoPfmCounter : PfmCounter <""> {} // Set of PfmCounters for measuring sched model characteristics. @@ -38,6 +54,9 @@ class ProcPfmCounters { PfmCounter UopsCounter = NoPfmCounter; // Processors can define how to measure issued uops by defining IssueCounters. list IssueCounters = []; + // Processor can list mappings between validation events and real counters + // to measure the specified events. + list ValidationCounters = []; } // A binding of a set of counters to a CPU. diff --git a/llvm/lib/Target/X86/X86PfmCounters.td b/llvm/lib/Target/X86/X86PfmCounters.td index 49ef6efc6aecf2..99cac504f157d3 100644 --- a/llvm/lib/Target/X86/X86PfmCounters.td +++ b/llvm/lib/Target/X86/X86PfmCounters.td @@ -275,6 +275,9 @@ def ZnVer2PfmCounters : ProcPfmCounters { PfmIssueCounter<"Zn2AGU", "ls_dispatch:ld_st_dispatch + ls_dispatch:ld_dispatch + ls_dispatch:store_dispatch">, PfmIssueCounter<"Zn2Divider", "div_op_count"> ]; + let ValidationCounters = [ +PfmValidationCounter + ]; } def : PfmCountersBinding<"znver2", ZnVer2PfmCounters>; @@ -288,6 +291,9 @@ def ZnVer3PfmCounters : ProcPfmCounters { PfmIssueCounter<"Zn3Store", "ls_dispatch:store_dispatch">, PfmIssueCounter<"Zn3Divider", "div_op_count"> ]; + let ValidationCounters = [ +PfmValidationCounter + ]; } def : PfmCountersBinding<"znver3", ZnVer3PfmCounters>; diff --git a/llvm/tools/llvm-exegesis/lib/Target.cpp b/llvm/tools/llvm-exegesis/lib/Target.cpp index 23c80e5b98953a..20b4afb9b8f676 100644 --- a/llvm/tools/llvm-exegesis/lib/Target.cpp +++ b/llvm/tools/llvm-exegesis/lib/Target.cpp @@ -147,13 +147,14 @@ std::unique_ptr ExegesisTarget::createUopsBenchmarkRunner( ExecutionMode); } -static_assert(std::is_trivial_v, - "We shouldn't have dynamic initialization here"); -const PfmCountersInfo PfmCountersInfo::Default = {nullptr, nullptr, nullptr, - 0u}; +const PfmCountersInfo PfmCountersInfo::Default = { +nullptr, nullptr, nullptr, 0u, {}}; const PfmCountersInfo PfmCountersInfo::Dummy = { -pfm::PerfEvent::DummyEventString, pfm::PerfEvent::DummyEventString, nullptr, -0u}; +pfm::PerfEvent::DummyEventString, +pfm::PerfEvent::DummyEventString, +nullptr, +0u, +{}}; const PfmCountersInfo &ExegesisTarget::getPfmCounters(StringRef CpuName) const { assert(llvm::is_sorted( diff --git a/llvm/tools/llvm-exegesis/lib/Target.h b/llvm/tools/llvm-exegesis/lib/Target.h index c37dd8b7082162..3956bc983181f6 100644 --- a/llvm/tools/llvm-exegesis/lib/Target.h +++ b/llvm/tools/llvm-exegesis/lib/Target.h @@ -32,6 +32,8 @@ #include "llvm/TargetParser/SubtargetFeature.h" #include "llvm/TargetParser/Triple.h" +#include + namespace llvm { namespace exegesis { @@ -39,6 +41,13 @@ extern cl::OptionCategory Options; extern cl::OptionCategory BenchmarkOptions; extern cl::OptionCategory AnalysisOptions; +enum ValidationEvent { + L1DCacheLoadMiss, + InstructionRetired, + DataTLBLoadMiss, + DataTLBStoreMiss +}; + struct PfmCountersInfo { // An optional name of a performance counter that can be used to measure // cycles. @@ -59,6 +68,8 @@ struct PfmCountersInfo { const IssueCounter *IssueCounters; unsigned NumIssueCoun
[llvm-branch-commits] [llvm] [llvm-exegesis] Add tablegen support for validation counters (PR #76652)
llvmbot wrote: @llvm/pr-subscribers-backend-x86 Author: Aiden Grossman (boomanaiden154) Changes This patch adds support in the llvm-exegesis tablegen emitter for validation counters. Full support for validation counters in llvm-exegesis is added in a future patch. --- Full diff: https://github.com/llvm/llvm-project/pull/76652.diff 5 Files Affected: - (modified) llvm/include/llvm/Target/TargetPfmCounters.td (+19) - (modified) llvm/lib/Target/X86/X86PfmCounters.td (+6) - (modified) llvm/tools/llvm-exegesis/lib/Target.cpp (+7-6) - (modified) llvm/tools/llvm-exegesis/lib/Target.h (+11) - (modified) llvm/utils/TableGen/ExegesisEmitter.cpp (+26-2) ``diff diff --git a/llvm/include/llvm/Target/TargetPfmCounters.td b/llvm/include/llvm/Target/TargetPfmCounters.td index b00f3e19c35f90..72f6b39f4878f4 100644 --- a/llvm/include/llvm/Target/TargetPfmCounters.td +++ b/llvm/include/llvm/Target/TargetPfmCounters.td @@ -28,6 +28,22 @@ class PfmIssueCounter string ResourceName = resource_name; } +class ValidationEvent { + int EventNumber = event_number; +} + +def L1DCacheLoadMiss: ValidationEvent<0>; +def InstructionRetired : ValidationEvent<1>; +def DataTLBLoadMiss : ValidationEvent<2>; +def DataTLBStoreMiss: ValidationEvent<3>; + +// Validation counters can be tied to a specific event +class PfmValidationCounter +: PfmCounter { + // The name of the event that the validation counter detects. + ValidationEvent EventType = event_type; +} + def NoPfmCounter : PfmCounter <""> {} // Set of PfmCounters for measuring sched model characteristics. @@ -38,6 +54,9 @@ class ProcPfmCounters { PfmCounter UopsCounter = NoPfmCounter; // Processors can define how to measure issued uops by defining IssueCounters. list IssueCounters = []; + // Processor can list mappings between validation events and real counters + // to measure the specified events. + list ValidationCounters = []; } // A binding of a set of counters to a CPU. diff --git a/llvm/lib/Target/X86/X86PfmCounters.td b/llvm/lib/Target/X86/X86PfmCounters.td index 49ef6efc6aecf2..99cac504f157d3 100644 --- a/llvm/lib/Target/X86/X86PfmCounters.td +++ b/llvm/lib/Target/X86/X86PfmCounters.td @@ -275,6 +275,9 @@ def ZnVer2PfmCounters : ProcPfmCounters { PfmIssueCounter<"Zn2AGU", "ls_dispatch:ld_st_dispatch + ls_dispatch:ld_dispatch + ls_dispatch:store_dispatch">, PfmIssueCounter<"Zn2Divider", "div_op_count"> ]; + let ValidationCounters = [ +PfmValidationCounter + ]; } def : PfmCountersBinding<"znver2", ZnVer2PfmCounters>; @@ -288,6 +291,9 @@ def ZnVer3PfmCounters : ProcPfmCounters { PfmIssueCounter<"Zn3Store", "ls_dispatch:store_dispatch">, PfmIssueCounter<"Zn3Divider", "div_op_count"> ]; + let ValidationCounters = [ +PfmValidationCounter + ]; } def : PfmCountersBinding<"znver3", ZnVer3PfmCounters>; diff --git a/llvm/tools/llvm-exegesis/lib/Target.cpp b/llvm/tools/llvm-exegesis/lib/Target.cpp index 23c80e5b98953a..20b4afb9b8f676 100644 --- a/llvm/tools/llvm-exegesis/lib/Target.cpp +++ b/llvm/tools/llvm-exegesis/lib/Target.cpp @@ -147,13 +147,14 @@ std::unique_ptr ExegesisTarget::createUopsBenchmarkRunner( ExecutionMode); } -static_assert(std::is_trivial_v, - "We shouldn't have dynamic initialization here"); -const PfmCountersInfo PfmCountersInfo::Default = {nullptr, nullptr, nullptr, - 0u}; +const PfmCountersInfo PfmCountersInfo::Default = { +nullptr, nullptr, nullptr, 0u, {}}; const PfmCountersInfo PfmCountersInfo::Dummy = { -pfm::PerfEvent::DummyEventString, pfm::PerfEvent::DummyEventString, nullptr, -0u}; +pfm::PerfEvent::DummyEventString, +pfm::PerfEvent::DummyEventString, +nullptr, +0u, +{}}; const PfmCountersInfo &ExegesisTarget::getPfmCounters(StringRef CpuName) const { assert(llvm::is_sorted( diff --git a/llvm/tools/llvm-exegesis/lib/Target.h b/llvm/tools/llvm-exegesis/lib/Target.h index c37dd8b7082162..3956bc983181f6 100644 --- a/llvm/tools/llvm-exegesis/lib/Target.h +++ b/llvm/tools/llvm-exegesis/lib/Target.h @@ -32,6 +32,8 @@ #include "llvm/TargetParser/SubtargetFeature.h" #include "llvm/TargetParser/Triple.h" +#include + namespace llvm { namespace exegesis { @@ -39,6 +41,13 @@ extern cl::OptionCategory Options; extern cl::OptionCategory BenchmarkOptions; extern cl::OptionCategory AnalysisOptions; +enum ValidationEvent { + L1DCacheLoadMiss, + InstructionRetired, + DataTLBLoadMiss, + DataTLBStoreMiss +}; + struct PfmCountersInfo { // An optional name of a performance counter that can be used to measure // cycles. @@ -59,6 +68,8 @@ struct PfmCountersInfo { const IssueCounter *IssueCounters; unsigned NumIssueCounters; + std::unordered_map ValidationCounters; + static const PfmCountersInfo Default; static const PfmCountersInfo Dummy; }; diff --git a/llvm/utils/Tab
[llvm-branch-commits] [llvm] [llvm-exegesis] Add support for validation counters (PR #76653)
https://github.com/boomanaiden154 created https://github.com/llvm/llvm-project/pull/76653 This patch adds support for validation counters. Validation counters can be used to measure events that occur during snippet execution like cache misses to ensure that certain assumed invariants about the benchmark actually hold. Validation counters are setup within a perf event group, so are turned on and off at exactly the same time as the "group leader" counter that measures the desired value. >From 76f199f4fc7244c3d972736595c685d7316c5203 Mon Sep 17 00:00:00 2001 From: Aiden Grossman Date: Sat, 30 Dec 2023 18:18:12 -0800 Subject: [PATCH] [llvm-exegesis] Add support for validation counters This patch adds support for validation counters. Validation counters can be used to measure events that occur during snippet execution like cache misses to ensure that certain assumed invariants about the benchmark actually hold. Validation counters are setup within a perf event group, so are turned on and off at exactly the same time as the "group leader" counter that measures the desired value. --- .../llvm-exegesis/lib/BenchmarkResult.cpp | 52 +++ .../tools/llvm-exegesis/lib/BenchmarkResult.h | 15 +- .../llvm-exegesis/lib/BenchmarkRunner.cpp | 52 +-- .../tools/llvm-exegesis/lib/BenchmarkRunner.h | 8 ++- .../lib/LatencyBenchmarkRunner.cpp| 46 .../lib/LatencyBenchmarkRunner.h | 3 ++ llvm/tools/llvm-exegesis/lib/PerfHelper.cpp | 37 +++-- llvm/tools/llvm-exegesis/lib/PerfHelper.h | 10 +++- llvm/tools/llvm-exegesis/lib/Target.cpp | 35 + llvm/tools/llvm-exegesis/lib/Target.h | 13 ++--- .../llvm-exegesis/lib/UopsBenchmarkRunner.cpp | 37 ++--- .../llvm-exegesis/lib/UopsBenchmarkRunner.h | 9 +++- llvm/tools/llvm-exegesis/lib/X86/Target.cpp | 11 +++- .../llvm-exegesis/lib/X86/X86Counter.cpp | 2 +- llvm/tools/llvm-exegesis/llvm-exegesis.cpp| 18 ++- .../tools/llvm-exegesis/ClusteringTest.cpp| 36 ++--- .../Mips/BenchmarkResultTest.cpp | 12 ++--- .../llvm-exegesis/X86/BenchmarkResultTest.cpp | 12 ++--- 18 files changed, 311 insertions(+), 97 deletions(-) diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp b/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp index 02c4da11e032d6..1079df24b457b8 100644 --- a/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp +++ b/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp @@ -14,6 +14,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/bit.h" #include "llvm/ObjectYAML/YAML.h" +#include "llvm/Support/Errc.h" #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" @@ -192,6 +193,56 @@ template <> struct SequenceElementTraits { static const bool flow = false; }; +const char *validationEventToString(exegesis::ValidationEvent VE) { + switch (VE) { + case exegesis::ValidationEvent::L1DCacheLoadMiss: +return "l1d-load-miss"; + case exegesis::ValidationEvent::InstructionRetired: +return "instructions-retired"; + case exegesis::ValidationEvent::DataTLBLoadMiss: +return "data-tlb-load-misses"; + case exegesis::ValidationEvent::DataTLBStoreMiss: +return "data-tlb-store-misses"; + } +} + +Expected stringToValidationEvent(StringRef Input) { + if (Input == "l1d-load-miss") +return exegesis::ValidationEvent::L1DCacheLoadMiss; + else if (Input == "instructions-retired") +return exegesis::ValidationEvent::InstructionRetired; + else if (Input == "data-tlb-load-misses") +return exegesis::ValidationEvent::DataTLBLoadMiss; + else if (Input == "data-tlb-store-misses") +return exegesis::ValidationEvent::DataTLBStoreMiss; + else +return make_error("Invalid validation event string", + errc::invalid_argument); +} + +template <> +struct CustomMappingTraits< +std::unordered_map> { + static void + inputOne(IO &Io, StringRef KeyStr, + std::unordered_map &VI) { +Expected Key = stringToValidationEvent(KeyStr); +if (!Key) { + Io.setError("Key is not a valid validation event"); + return; +} +Io.mapRequired(KeyStr.str().c_str(), VI[*Key]); + } + + static void + output(IO &Io, std::unordered_map &VI) { +for (auto &IndividualVI : VI) { + Io.mapRequired(validationEventToString(IndividualVI.first), + IndividualVI.second); +} + } +}; + // exegesis::Measure is rendererd as a flow instead of a list. // e.g. { "key": "the key", "value": 0123 } template <> struct MappingTraits { @@ -203,6 +254,7 @@ template <> struct MappingTraits { } Io.mapRequired("value", Obj.PerInstructionValue); Io.mapOptional("per_snippet_value", Obj.PerSnippetValue); +Io.mapOptional("validation_counters", Obj.ValidationCounters); } static const bool flow = true; }; diff --git a/llvm/tools/llvm-exege
[llvm-branch-commits] [llvm] [llvm-exegesis] Add support for validation counters (PR #76653)
llvmbot wrote: @llvm/pr-subscribers-tools-llvm-exegesis Author: Aiden Grossman (boomanaiden154) Changes This patch adds support for validation counters. Validation counters can be used to measure events that occur during snippet execution like cache misses to ensure that certain assumed invariants about the benchmark actually hold. Validation counters are setup within a perf event group, so are turned on and off at exactly the same time as the "group leader" counter that measures the desired value. --- Patch is 40.60 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/76653.diff 18 Files Affected: - (modified) llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp (+52) - (modified) llvm/tools/llvm-exegesis/lib/BenchmarkResult.h (+13-2) - (modified) llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp (+37-15) - (modified) llvm/tools/llvm-exegesis/lib/BenchmarkRunner.h (+6-2) - (modified) llvm/tools/llvm-exegesis/lib/LatencyBenchmarkRunner.cpp (+35-11) - (modified) llvm/tools/llvm-exegesis/lib/LatencyBenchmarkRunner.h (+3) - (modified) llvm/tools/llvm-exegesis/lib/PerfHelper.cpp (+34-3) - (modified) llvm/tools/llvm-exegesis/lib/PerfHelper.h (+8-2) - (modified) llvm/tools/llvm-exegesis/lib/Target.cpp (+25-10) - (modified) llvm/tools/llvm-exegesis/lib/Target.h (+5-8) - (modified) llvm/tools/llvm-exegesis/lib/UopsBenchmarkRunner.cpp (+31-6) - (modified) llvm/tools/llvm-exegesis/lib/UopsBenchmarkRunner.h (+7-2) - (modified) llvm/tools/llvm-exegesis/lib/X86/Target.cpp (+10-1) - (modified) llvm/tools/llvm-exegesis/lib/X86/X86Counter.cpp (+1-1) - (modified) llvm/tools/llvm-exegesis/llvm-exegesis.cpp (+17-1) - (modified) llvm/unittests/tools/llvm-exegesis/ClusteringTest.cpp (+15-21) - (modified) llvm/unittests/tools/llvm-exegesis/Mips/BenchmarkResultTest.cpp (+6-6) - (modified) llvm/unittests/tools/llvm-exegesis/X86/BenchmarkResultTest.cpp (+6-6) ``diff diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp b/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp index 02c4da11e032d6..1079df24b457b8 100644 --- a/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp +++ b/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp @@ -14,6 +14,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/bit.h" #include "llvm/ObjectYAML/YAML.h" +#include "llvm/Support/Errc.h" #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" @@ -192,6 +193,56 @@ template <> struct SequenceElementTraits { static const bool flow = false; }; +const char *validationEventToString(exegesis::ValidationEvent VE) { + switch (VE) { + case exegesis::ValidationEvent::L1DCacheLoadMiss: +return "l1d-load-miss"; + case exegesis::ValidationEvent::InstructionRetired: +return "instructions-retired"; + case exegesis::ValidationEvent::DataTLBLoadMiss: +return "data-tlb-load-misses"; + case exegesis::ValidationEvent::DataTLBStoreMiss: +return "data-tlb-store-misses"; + } +} + +Expected stringToValidationEvent(StringRef Input) { + if (Input == "l1d-load-miss") +return exegesis::ValidationEvent::L1DCacheLoadMiss; + else if (Input == "instructions-retired") +return exegesis::ValidationEvent::InstructionRetired; + else if (Input == "data-tlb-load-misses") +return exegesis::ValidationEvent::DataTLBLoadMiss; + else if (Input == "data-tlb-store-misses") +return exegesis::ValidationEvent::DataTLBStoreMiss; + else +return make_error("Invalid validation event string", + errc::invalid_argument); +} + +template <> +struct CustomMappingTraits< +std::unordered_map> { + static void + inputOne(IO &Io, StringRef KeyStr, + std::unordered_map &VI) { +Expected Key = stringToValidationEvent(KeyStr); +if (!Key) { + Io.setError("Key is not a valid validation event"); + return; +} +Io.mapRequired(KeyStr.str().c_str(), VI[*Key]); + } + + static void + output(IO &Io, std::unordered_map &VI) { +for (auto &IndividualVI : VI) { + Io.mapRequired(validationEventToString(IndividualVI.first), + IndividualVI.second); +} + } +}; + // exegesis::Measure is rendererd as a flow instead of a list. // e.g. { "key": "the key", "value": 0123 } template <> struct MappingTraits { @@ -203,6 +254,7 @@ template <> struct MappingTraits { } Io.mapRequired("value", Obj.PerInstructionValue); Io.mapOptional("per_snippet_value", Obj.PerSnippetValue); +Io.mapOptional("validation_counters", Obj.ValidationCounters); } static const bool flow = true; }; diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkResult.h b/llvm/tools/llvm-exegesis/lib/BenchmarkResult.h index 0d08febae20cb3..f142da07e0a47d 100644 --- a/llvm/tools/llvm-exegesis/lib/BenchmarkResult.h +++ b/llvm/tools/llvm-exegesis/lib/BenchmarkResult.h @@ -32,6 +32,13 @@ class Error; namespace exegesis { +enum ValidationEvent { +
[llvm-branch-commits] [llvm] [llvm-exegesis] Add support for validation counters (PR #76653)
https://github.com/boomanaiden154 updated https://github.com/llvm/llvm-project/pull/76653 >From 76f199f4fc7244c3d972736595c685d7316c5203 Mon Sep 17 00:00:00 2001 From: Aiden Grossman Date: Sat, 30 Dec 2023 18:18:12 -0800 Subject: [PATCH 1/2] [llvm-exegesis] Add support for validation counters This patch adds support for validation counters. Validation counters can be used to measure events that occur during snippet execution like cache misses to ensure that certain assumed invariants about the benchmark actually hold. Validation counters are setup within a perf event group, so are turned on and off at exactly the same time as the "group leader" counter that measures the desired value. --- .../llvm-exegesis/lib/BenchmarkResult.cpp | 52 +++ .../tools/llvm-exegesis/lib/BenchmarkResult.h | 15 +- .../llvm-exegesis/lib/BenchmarkRunner.cpp | 52 +-- .../tools/llvm-exegesis/lib/BenchmarkRunner.h | 8 ++- .../lib/LatencyBenchmarkRunner.cpp| 46 .../lib/LatencyBenchmarkRunner.h | 3 ++ llvm/tools/llvm-exegesis/lib/PerfHelper.cpp | 37 +++-- llvm/tools/llvm-exegesis/lib/PerfHelper.h | 10 +++- llvm/tools/llvm-exegesis/lib/Target.cpp | 35 + llvm/tools/llvm-exegesis/lib/Target.h | 13 ++--- .../llvm-exegesis/lib/UopsBenchmarkRunner.cpp | 37 ++--- .../llvm-exegesis/lib/UopsBenchmarkRunner.h | 9 +++- llvm/tools/llvm-exegesis/lib/X86/Target.cpp | 11 +++- .../llvm-exegesis/lib/X86/X86Counter.cpp | 2 +- llvm/tools/llvm-exegesis/llvm-exegesis.cpp| 18 ++- .../tools/llvm-exegesis/ClusteringTest.cpp| 36 ++--- .../Mips/BenchmarkResultTest.cpp | 12 ++--- .../llvm-exegesis/X86/BenchmarkResultTest.cpp | 12 ++--- 18 files changed, 311 insertions(+), 97 deletions(-) diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp b/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp index 02c4da11e032d6..1079df24b457b8 100644 --- a/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp +++ b/llvm/tools/llvm-exegesis/lib/BenchmarkResult.cpp @@ -14,6 +14,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/bit.h" #include "llvm/ObjectYAML/YAML.h" +#include "llvm/Support/Errc.h" #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" @@ -192,6 +193,56 @@ template <> struct SequenceElementTraits { static const bool flow = false; }; +const char *validationEventToString(exegesis::ValidationEvent VE) { + switch (VE) { + case exegesis::ValidationEvent::L1DCacheLoadMiss: +return "l1d-load-miss"; + case exegesis::ValidationEvent::InstructionRetired: +return "instructions-retired"; + case exegesis::ValidationEvent::DataTLBLoadMiss: +return "data-tlb-load-misses"; + case exegesis::ValidationEvent::DataTLBStoreMiss: +return "data-tlb-store-misses"; + } +} + +Expected stringToValidationEvent(StringRef Input) { + if (Input == "l1d-load-miss") +return exegesis::ValidationEvent::L1DCacheLoadMiss; + else if (Input == "instructions-retired") +return exegesis::ValidationEvent::InstructionRetired; + else if (Input == "data-tlb-load-misses") +return exegesis::ValidationEvent::DataTLBLoadMiss; + else if (Input == "data-tlb-store-misses") +return exegesis::ValidationEvent::DataTLBStoreMiss; + else +return make_error("Invalid validation event string", + errc::invalid_argument); +} + +template <> +struct CustomMappingTraits< +std::unordered_map> { + static void + inputOne(IO &Io, StringRef KeyStr, + std::unordered_map &VI) { +Expected Key = stringToValidationEvent(KeyStr); +if (!Key) { + Io.setError("Key is not a valid validation event"); + return; +} +Io.mapRequired(KeyStr.str().c_str(), VI[*Key]); + } + + static void + output(IO &Io, std::unordered_map &VI) { +for (auto &IndividualVI : VI) { + Io.mapRequired(validationEventToString(IndividualVI.first), + IndividualVI.second); +} + } +}; + // exegesis::Measure is rendererd as a flow instead of a list. // e.g. { "key": "the key", "value": 0123 } template <> struct MappingTraits { @@ -203,6 +254,7 @@ template <> struct MappingTraits { } Io.mapRequired("value", Obj.PerInstructionValue); Io.mapOptional("per_snippet_value", Obj.PerSnippetValue); +Io.mapOptional("validation_counters", Obj.ValidationCounters); } static const bool flow = true; }; diff --git a/llvm/tools/llvm-exegesis/lib/BenchmarkResult.h b/llvm/tools/llvm-exegesis/lib/BenchmarkResult.h index 0d08febae20cb3..f142da07e0a47d 100644 --- a/llvm/tools/llvm-exegesis/lib/BenchmarkResult.h +++ b/llvm/tools/llvm-exegesis/lib/BenchmarkResult.h @@ -32,6 +32,13 @@ class Error; namespace exegesis { +enum ValidationEvent { + L1DCacheLoadMiss, + InstructionRetired, + DataTLBLoadMiss, + DataTLBStoreMiss +}; + enu