From fc98b543d1331631b118789fb97cab86e084f38e 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: Mon, 17 Feb 2020 00:00:00 +0000 Subject: [PATCH] profiling: start --- README.adoc | 16 +++++++++++-- userland/gcc/profile.c | 53 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 userland/gcc/profile.c diff --git a/README.adoc b/README.adoc index 968b544..3a5ed9a 100644 --- a/README.adoc +++ b/README.adoc @@ -3809,7 +3809,7 @@ Bibliography: The ID is just hardcoded on the source: -==== stack smashing detected +==== stack smashing detected when using glibc For some reason QEMU / glibc x86_64 picks up the host libc, which breaks things. @@ -3871,7 +3871,7 @@ We pass `-L` by default, so everything just works. However, in case something goes wrong, you can also try statically linked executables, since this mechanism tends to be a bit more stable, for example: -* QEMU x86_64 guest on x86_64 host was failing with <>, but we found a workaround +* QEMU x86_64 guest on x86_64 host was failing with <>, but we found a workaround * gem5 user only supported static executables in the past, as mentioned at: xref:gem5-syscall-emulation-mode[xrefstyle=full] Running statically linked executables sometimes makes things break: @@ -14449,12 +14449,24 @@ Example:: link:userland/c/smash_stack.c[] Leads to the dreadful "Stack smashing detected" message. Which is infinitely better than a silent break in any case. +We had also seen this error in our repository at: <>. + ==== Memory leaks How to debug: https://stackoverflow.com/questions/6261201/how-to-find-memory-leak-in-a-c-code-project/57877190#57877190 Example: link:userland/c/memory_leak.c[] +==== Profiling userland programs + +https://stackoverflow.com/questions/375913/how-can-i-profile-c-code-running-on-linux/60265409#60265409 + +OK, we have to learn this stuff. + +Examples: + +* link:userland/gcc/profile.c[]: simple profiling example, where certain calls of a certain function can dominate the runtime + === Interpreted languages Maybe some day someone will use this setup to study the performance of interpreters. diff --git a/userland/gcc/profile.c b/userland/gcc/profile.c new file mode 100644 index 0000000..3a05713 --- /dev/null +++ b/userland/gcc/profile.c @@ -0,0 +1,53 @@ +/* https://cirosantilli.com/linux-kernel-module-cheat#profiling-userland-programs */ + +#include +#include +#include + +uint64_t __attribute__ ((noinline)) common(uint64_t n, uint64_t seed) { + for (uint64_t i = 0; i < n; ++i) { + seed = (seed * seed) - (3 * seed) + 1; + } + return seed; +} + +uint64_t __attribute__ ((noinline)) fast(uint64_t n, uint64_t seed) { + uint64_t max = (n / 10) + 1; + for (uint64_t i = 0; i < max; ++i) { + seed = common(n, (seed * seed) - (3 * seed) + 1); + } + return seed; +} + +uint64_t __attribute__ ((noinline)) maybe_slow(uint64_t n, uint64_t seed, int is_slow) { + uint64_t max = n; + if (is_slow) { + max *= 10; + } + for (uint64_t i = 0; i < max; ++i) { + seed = common(n, (seed * seed) - (3 * seed) + 1); + } + return seed; +} + +int main(int argc, char **argv) { + uint64_t n, seed; + if (argc > 1) { + n = strtoll(argv[1], NULL, 0); + } else { + n = 1; + } + if (argc > 2) { + seed = strtoll(argv[2], NULL, 0); + } else { + seed = 0; + } + seed += maybe_slow(n, seed, 0); + seed += fast(n, seed); + seed += maybe_slow(n, seed, 1); + seed += fast(n, seed); + seed += maybe_slow(n, seed, 0); + seed += fast(n, seed); + printf("%" PRIX64 "\n", seed); + return EXIT_SUCCESS; +}