This patch adds in validation at two different levels that address
annotations are page aligned. This is necessary as otherwise the mmap
calls will fail as MAP_FIXED/MAP_FIXED_NOREPLACE require page aligned
addresses. This happens silently in the subprocess. This patch adds
validation at snippet parsing time to give feedback to the user and also
adds asserts at code generation/address usage time to ensure that other
users of the Exegesis APIs conform to the same requirements.
This patch refactors the MMAP platform-specific preprocessor directives
in llvm-exegesis to a single file instead of having duplicate code split
across multiple files. These originally got introduced to get buildbots
green again due to platform specific failures.
This patch switches to using explicit snippet crashes that contain more
information about the specific type of error (like the address for a
segmentation fault) that occurred. All these new error classes inherit
from SnippetExecutionFailure to allow for easily grabbing all of them in
addition to filtering for specific types using the standard LLVM error
primitives.
…ndling.
Returns an error *and* a benchmark rather than an error *or* a
benchmark. This allows users to have custom error handling while still
being able to inspect the benchmark.
Apart from this small API change, this is an NFC.
This is an alternative to #74211.
This reverts commit 30d700117b772d94d8474ec56bd6f9cc423fc613.
This relands commit 3ab41f912a6c219a93b87c257139822ea07c8863.
When I was updating the patch to use llvm::to_integer, I only ran the
lit tests and didn't run the unit tests, one of which started to fail.
This patch fixes the broken unit test.
Core dumps are currently enabled within the llvm-exegesis subprocess
executor. This can create a lot of core dumps when going through
different snippets that might segfault when experimenting with memory
annotations. These core dumps are not really needed as the information
about the segfault is reported directly to the user.
This patch refactors ExecutableFunction to use a named constructor
pattern, namely adding the create function, so that errors occurring
during the creation of an ExecutableFunction can be propogated back up
rather than having to deal with them in report_fatal_error.
If there were some scheduler effects where something like the parent
process got interrupted while the child process continued to run, there
would be nothing blocking it from exiting before the parent process
issued a PTRACE_ATTACH call. This would cause transient failures as this
occurred pretty rarely. This patch removes the possibility of a
transient failure by ensuring that the parent process attaches to the
child process before sending the counter file descriptor through the
socket, ensuring that the child process has at most progressed to being
blocked in the read call for the counter file descriptor.
There are still some transient failures on the clang-avx512 builder on
the new subprocess memory tests. Some of them seem to be related to an
inability to fork, but it's hard to debug currently as there is no
explicit error handling for a failed fork call, and nice error reporting
for a failed fork is something that we should have regardless.
Some error logging in llvm-exegesis under the subprocess executor just
prints a generic failure information rather than any details about the
error as we omit printing the string version of errno. This patch adds
in printing errno at all relevant points in the subprocess executor that
were previously missed.
Reviewed By: courbet
Differential Revision: https://reviews.llvm.org/D157682
Currently BenchmarkRunner.cpp stores the return code of recvmsg as
size_t. Not only is this incorrect (as recvmsg returns ssize_t), but it
also makes the error code check after the statement completely irrelvant
as it checks if the number of bytes read is greater than zero (which
will always be true for an unsigned type).
When compiling against recent glibc (>= 2.35) but old kernel headers (< 4.18), `SYS_rseq` is not defined and thus llvm-exegesis fails to build. So also check that `SYS_rseq` is defined before trying to use it.
Fixes https://github.com/llvm/llvm-project/issues/64456
Reviewed By: MaskRay, gchatelet
Differential Revision: https://reviews.llvm.org/D157189
Due to arguably a bug in GCC[0], using `__has_builtin` is not sufficient to check whether `__builtin_thread_pointer` can actually be compiled by GCC. This makes it impossible to compile LLVM with `llvm-exegesis` enabled with e.g. GCC 10 as it does have the builtin, but no implementation for architectures such as x86.
This patch works around this issue by making it a cmake configure check whether the builtin can be compiled and used, rather than relying on the broken preprocessor macro.
[0] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96952, demonstration: https://godbolt.org/z/9z5nWM6Ef
Differential Revision: https://reviews.llvm.org/D155828
This patch switches from moving the performance counter file descriptor
to the child process to socket calls rather than using the pidfd_getfd
system call which was introduced in kernel 5.6. This significantly
expands the range of kernel versions that are supported.
Reviewed By: courbet
Differential Revision: https://reviews.llvm.org/D154275
While Clang targets have supported __builtin_thread_pointer for a very
long time (e.g., 2007 for AArch32, 2015 for AArch64), for some GCC
ports, the support is very new (11.0 for x86[1], while we need to
support GCC 7), and many ports haven't implemented
__builtin_thread_pointer yet (m68k, powerpc, etc).
[1]: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96955
This patch switches from using PTRACE_SEIZE within the subprocess
benchmark runner for llvm-exegesis as PTRACE_SEIZE was introduced in
Linux kernel 3.4. Some LLVM users were reporting build failures as they
are using Kernel versions older than 3.4 (such as on CentOS/RHEL 6),
hence the patch.
Commit 9f80831f3627e800709e2434bbbd5bb179b1576e introduced `#include <sys/rseq.h>`,
but RSEQ_SIG is only defined by some glibc ports (aarch64,arm,mips,powerpc,s390,x86),
causing other hosts (e.g., riscv64, loongarch64) to fail to build.
Reviewed By: aidengrossman, xen0n
Differential Revision: https://reviews.llvm.org/D153938
My last patch broke most of the builders that aren't currently running
at least Kernel 5.6 as there was a variable used later on inside a
region that required that kernel version. Also fixes a minor warning
left over from a bad merge.
This patch introduces the subprocess executor mode. Currently, this new
mode doesn't do anything fancy, just executing the same code that the
inprocess executor would do, but within a subprocess. This sets up the
ability to add in many more memory-related features in the future.
Reviewed By: courbet
Differential Revision: https://reviews.llvm.org/D151021
Revert "[llvm-exegesis] Introduce Subprocess Executor Mode"
This reverts commit 5e9173c43a9b97c8614e36d6f754317f731e71e9.
This reverts commit 4d618b52f6e05e41d35f56653cb36bf7d4dc794e.
Reverting the PID commit as it is currently breaking MinGW builds and
the way I'm checking for the presence of pid_t needs to be fixed and I
need to do some testing. The subprocess executor mode patch is a
dependent patch so also needs to be reverted and also needs some work as
it is currently failing tests where libpfm is installed and the kernel
version is less than 5.6.
This patch introduces the subprocess executor mode. Currently, this new
mode doesn't do anything fancy, just executing the same code that the
inprocess executor would do, but within a subprocess. This sets up the
ability to add in many more memory-related features in the future.
This reverts commit 0d4ef4ff01addbb40b9122a00d6b2f23104cbb3b.
This was causing build failures on certain platforms when built with
-Werror due to unused variable warnings in addition to causing build
failures on Linux systems with older kernel versions as kernels prior to
v5.15 don't support sys_pidfd_getpid. Reverting as I need to setup a
system to properly test the rest of the patches in this series.
Also reverts 8c6668fa42dba59ddc286ba256d71c1b9c5228b8 which fixed the
first issue so that the patch can actually be reverted.
This patch introduces the subprocess executor mode. Currently, this new
mode doesn't do anything fancy, just executing the same code that the
inprocess executor would do, but within a subprocess. This sets up the
ability to add in many more memory-related features in the future.
Reviewed By: courbet
Differential Revision: https://reviews.llvm.org/D151021
In order to better support adding in new implementations of
FunctionExecutor, this patch makes some small changes so that it is
easier to add new ones in. FunctionExecutorImpl is renamed to
InProcessFunctionExecutorImpl to better reflect how it will be placed
relative to the soon-to-be introduced subprocess executor and a new
function is created to create executors so selection can be done more
easily. In addition, a new CLI flag, -execution-mode, which can be used
to select between the different executors.
Reviewed By: courbet
Differential Revision: https://reviews.llvm.org/D151019
Initially, llvm-exegesis was generating the benchmark code for the
host CPU to execute it inside its own process. Thus, MCJIT was reused
for fetching function's bytes to fill the assembled_snippet field in
the benchmark report.
Later, the --mtriple and --benchmark-phase command line options were
introduced that are handy for testing snippet generation even if
snippet execution is not possible. In that setup, MCJIT is asked to
parse an object file for a foreign CPU or operating system that is
probably not guaranteed to succeed and was actually observed to fail
in https://reviews.llvm.org/D145763.
This commit implements a much simplified function's code fetching,
assuming the benchmark function is the only function in the object file
and it spans across the entire text section (note that MCJIT-based code
has more or less the same assumption - see TrackingSectionMemoryManager
class).
~~~
Huawei RRI, OS Lab
Reviewed By: courbet
Differential Revision: https://reviews.llvm.org/D148921
/data/llvm-project/llvm/tools/llvm-exegesis/lib/BenchmarkRunner.cpp:66:2: error: extra ';' outside of a function is incompatible with C++98 [-Werror,-W
c++98-compat-extra-semi]
};
^
1 error generated.
This patch refactors some code out of FunctionExecutorImpl into the base
class that should be common across all implementations of
FunctionExecutor. Particularly, this patch factors out
accumulateCounterValues, and also factors out runAndSample, moving
implementation specific code into a new runWithCounter function. This
makes adding new implementations of FunctinExecutor easier.
Reviewed By: gchatelet
Differential Revision: https://reviews.llvm.org/D148079
This completes the FIXME listed in FunctionExecutor in regards to
deprecating this function. It simply makes the appropriate call into
runAndSample and grabs the first counter value. This patch completely
removes the function, moving that logic into the callers (currently only
uopsBenchmarkRunner). This makes creating new FunctionExecutors easier
as an implementation no longer needs to worry about this detail.
Reviewed By: gchatelet
Differential Revision: https://reviews.llvm.org/D147878
When llvm-exegesis was first introduced, it only supported benchmarking
individual instructions, hence the name for the data structure storing
the data corresponding to a benchmark being called InstructionBenchmark
made sense. However, now that benchmarking arbitrary snippets is
supported, InstructionBenchmark doesn't correspond to a single
instruction. This patch refactors InstructionBenchmark to be called
Benchmark to clean up this little bit of technical debt.
Reviewed By: courbet
Differential Revision: https://reviews.llvm.org/D146884
While "skip measurements mode" is super useful for test coverage,
i've come to discover it's trade-offs. It still calls back-end
to actually codegen the target assembly, and that is what is taking
80%+ of the time regardless of whether or not we skip the measurements.
On the other hand, just being able to see that exegesis can come up
with a snippet to measure something, is already very useful,
and takes maybe a second for a all-opcode sweep.
Reviewed By: gchatelet
Differential Revision: https://reviews.llvm.org/D140702
We can run as many `getRunnableConfiguration()` in parallel as we want,
but `runConfiguration()` must be run *completely* standalone from everything.
This is a step towards enabling threading.
If `BenchmarkRunner::runConfiguration()` deals with more than a single
repetitor, tasking will be less straight-forward to implement.
But i think dealing with that in it's callee is even more readable.
Sometimes we only want to ensure that we can produce snippets (all the way
through `SnippetRepetitor`!), but don't care for the execution.
E.g. all of our tests are this way.
I've built LLVM without PFM and removed my CPU from `X86PfmCounters.td`,
and this produces the expected results in that configuration.
Reviewed By: courbet
Differential Revision: https://reviews.llvm.org/D139448
I really needed this, like, factually, yesterday,
when verifying dependency breaking idioms for AMD Zen 3 scheduler model.
Consider the following example:
```
$ ./bin/llvm-exegesis --mode=inverse_throughput --snippets-file=/tmp/snippet.s --num-repetitions=1000000 --repetition-mode=duplicate
Check generated assembly with: /usr/bin/objdump -d /tmp/snippet-4a7e50.o
---
mode: inverse_throughput
key:
instructions:
- 'VPXORYrr YMM0 YMM0 YMM0'
config: ''
register_initial_values: []
cpu_name: znver3
llvm_triple: x86_64-unknown-linux-gnu
num_repetitions: 1000000
measurements:
- { key: inverse_throughput, value: 0.31025, per_snippet_value: 0.31025 }
error: ''
info: ''
assembled_snippet: C5FDEFC0C5FDEFC0C5FDEFC0C5FDEFC0C5FDEFC0C5FDEFC0C5FDEFC0C5FDEFC0C5FDEFC0C5FDEFC0C5FDEFC0C5FDEFC0C5FDEFC0C5FDEFC0C5FDEFC0C5FDEFC0C3
...
```
What does it tell us?
So wait, it can only execute ~3 x86 AVX YMM PXOR zero-idioms per cycle?
That doesn't seem right. That's even less than there are pipes supporting this type of op.
Now, second example:
```
$ ./bin/llvm-exegesis --mode=inverse_throughput --snippets-file=/tmp/snippet.s --num-repetitions=1000000 --repetition-mode=loop
Check generated assembly with: /usr/bin/objdump -d /tmp/snippet-2418b5.o
---
mode: inverse_throughput
key:
instructions:
- 'VPXORYrr YMM0 YMM0 YMM0'
config: ''
register_initial_values: []
cpu_name: znver3
llvm_triple: x86_64-unknown-linux-gnu
num_repetitions: 1000000
measurements:
- { key: inverse_throughput, value: 1.00011, per_snippet_value: 1.00011 }
error: ''
info: ''
assembled_snippet: 49B80800000000000000C5FDEFC0C5FDEFC04983C0FF75F2C3
...
```
Now that's just worse. Due to the looping, the throughput completely plummeted,
and now we can only do a single instruction/cycle!?
That's not great.
And final example:
```
$ ./bin/llvm-exegesis --mode=inverse_throughput --snippets-file=/tmp/snippet.s --num-repetitions=1000000 --repetition-mode=loop --loop-body-size=1000
Check generated assembly with: /usr/bin/objdump -d /tmp/snippet-c402e2.o
---
mode: inverse_throughput
key:
instructions:
- 'VPXORYrr YMM0 YMM0 YMM0'
config: ''
register_initial_values: []
cpu_name: znver3
llvm_triple: x86_64-unknown-linux-gnu
num_repetitions: 1000000
measurements:
- { key: inverse_throughput, value: 0.167087, per_snippet_value: 0.167087 }
error: ''
info: ''
assembled_snippet: 49B80800000000000000C5FDEFC0C5FDEFC04983C0FF75F2C3
...
```
So if we merge the previous two approaches, do duplicate this single-instruction snippet 1000x
(loop-body-size/instruction count in snippet), and run a loop with 1000 iterations
over that duplicated/unrolled snippet, the measured throughput goes through the roof,
up to 5.9 instructions/cycle, which finally tells us that this idiom is zero-cycle!
Reviewed By: courbet
Differential Revision: https://reviews.llvm.org/D102522