From a06672a20d160c1748223665501ca45295008423 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ciro=20Santilli=20=E5=85=AD=E5=9B=9B=E4=BA=8B=E4=BB=B6=20?= =?UTF-8?q?=E6=B3=95=E8=BD=AE=E5=8A=9F?= Date: Fri, 8 Nov 2019 00:00:00 +0000 Subject: [PATCH] gcc hacks: busy_loop and prevent_reorder --- README.adoc | 7 ++++++ userland/gcc/busy_loop.c | 29 +++++++++++++++++++++ userland/gcc/prevent_reorder.cpp | 43 ++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+) create mode 100644 userland/gcc/busy_loop.c create mode 100644 userland/gcc/prevent_reorder.cpp diff --git a/README.adoc b/README.adoc index 88c32f2..01b1981 100644 --- a/README.adoc +++ b/README.adoc @@ -18452,6 +18452,13 @@ west build -b qemu_aarch64 samples/hello_world The build system of that project is a bit excessive / wonky. You need an edge CMake not present in Ubuntu 18.04, which I don't want to install right now, and it uses the weird custom `west` build tool frontend. +== Compilers + +Argh, compilers are boring, let's learn a bit about them. + +* link:userland/gcc/busy_loop.c[]: https://stackoverflow.com/questions/7083482/how-to-prevent-gcc-from-optimizing-out-a-busy-wait-loop/58758133#58758133 +* link:userland/gcc/prevent_reorder.cpp[]: https://stackoverflow.com/questions/37786547/enforcing-statement-order-in-c/56865717#56865717 + == About this repo === Supported hosts diff --git a/userland/gcc/busy_loop.c b/userland/gcc/busy_loop.c new file mode 100644 index 0000000..18506b2 --- /dev/null +++ b/userland/gcc/busy_loop.c @@ -0,0 +1,29 @@ +/* https://cirosantilli.com/linux-kernel-module-cheat#compilers */ + +#include + +void __attribute__ ((noinline)) busy_loop( + unsigned long long max, + unsigned long long max2 +) { + for (unsigned i = 0; i < max; i++) { + for (unsigned j = 0; j < max2; j++) { + __asm__ __volatile__ ("" : "+g" (j), "+g" (j) : :); + } + } +} + +int main(int argc, char **argv) { + unsigned long long max, max2; + if (argc > 1) { + max = strtoll(argv[1], NULL, 0); + } else { + max = 1; + } + if (argc > 2) { + max2 = strtoll(argv[2], NULL, 0); + } else { + max2 = 1; + } + busy_loop(max, max2); +} diff --git a/userland/gcc/prevent_reorder.cpp b/userland/gcc/prevent_reorder.cpp new file mode 100644 index 0000000..d61d90c --- /dev/null +++ b/userland/gcc/prevent_reorder.cpp @@ -0,0 +1,43 @@ +/* https://cirosantilli.com/linux-kernel-module-cheat#compilers */ + +#include +#include +#include + +// noinline ensures that the ::now() cannot be split from the __asm__ +template +__attribute__((noinline)) auto get_clock(T& value) { + // Make the compiler think we actually use / modify the value. + // It can't "see" what is going on inside the assembly string. + __asm__ __volatile__ ("" : "+g" (value)); + return std::chrono::high_resolution_clock::now(); +} + +template +static T foo(T niters) { + T result = 42; + for (T i = 0; i < niters; ++i) { + result = (result * result) - (3 * result) + 1; + } + return result; +} + +int main(int argc, char **argv) { + unsigned long long input; + if (argc > 1) { + input = std::stoull(argv[1], NULL, 0); + } else { + input = 1; + } + + // Must come before because it could modify input + // which is passed as a reference. + auto t1 = get_clock(input); + auto output = foo(input); + // Must come after as it could use the output. + auto t2 = get_clock(output); + std::cout << "output " << output << std::endl; + std::cout << "time (ns) " + << std::chrono::duration_cast(t2 - t1).count() + << std::endl; +}