diff options
Diffstat (limited to 'test/xray/TestCases/Posix')
26 files changed, 1324 insertions, 0 deletions
diff --git a/test/xray/TestCases/Posix/always-never-instrument.cc b/test/xray/TestCases/Posix/always-never-instrument.cc new file mode 100644 index 000000000000..fd9299b756bb --- /dev/null +++ b/test/xray/TestCases/Posix/always-never-instrument.cc @@ -0,0 +1,23 @@ +// Test that the always/never instrument lists apply. +// RUN: echo "fun:main" > %tmp-always.txt +// RUN: echo "fun:__xray*" > %tmp-never.txt +// RUN: %clangxx_xray \ +// RUN: -fxray-never-instrument=%tmp-never.txt \ +// RUN: -fxray-always-instrument=%tmp-always.txt \ +// RUN: %s -o %t +// RUN: %llvm_xray extract -symbolize %t | \ +// RUN: FileCheck %s --check-prefix NOINSTR +// RUN: %llvm_xray extract -symbolize %t | \ +// RUN: FileCheck %s --check-prefix ALWAYSINSTR +// REQUIRES: x86_64-target-arch +// REQUIRES: built-in-llvm-tree + +// NOINSTR-NOT: {{.*__xray_NeverInstrumented.*}} +int __xray_NeverInstrumented() { + return 0; +} + +// ALWAYSINSTR: {{.*function-name:.*main.*}} +int main(int argc, char *argv[]) { + return __xray_NeverInstrumented(); +} diff --git a/test/xray/TestCases/Posix/arg1-arg0-logging.cc b/test/xray/TestCases/Posix/arg1-arg0-logging.cc new file mode 100644 index 000000000000..757f81a8babb --- /dev/null +++ b/test/xray/TestCases/Posix/arg1-arg0-logging.cc @@ -0,0 +1,39 @@ +// Allow having both the no-arg and arg1 logging implementation live together, +// and be called in the correct cases. +// +// RUN: rm -f arg0-arg1-logging-* +// RUN: %clangxx_xray -std=c++11 %s -o %t +// RUN: XRAY_OPTIONS="patch_premain=true verbosity=1 xray_logfile_base=arg0-arg1-logging-" %run %t +// +// TODO: Support these in ARM and PPC +// XFAIL: arm || aarch64 || mips +// UNSUPPORTED: powerpc64le + +#include "xray/xray_interface.h" +#include <cassert> +#include <cstdio> + +using namespace std; + +bool arg0loggercalled = false; +void arg0logger(int32_t, XRayEntryType) { arg0loggercalled = true; } + +[[clang::xray_always_instrument]] void arg0fn() { printf("hello, arg0!\n"); } + +bool arg1loggercalled = false; +void arg1logger(int32_t, XRayEntryType, uint64_t) { arg1loggercalled = true; } + +[[ clang::xray_always_instrument, clang::xray_log_args(1) ]] void +arg1fn(uint64_t arg1) { + printf("hello, arg1!\n"); +} + +int main(int argc, char *argv[]) { + __xray_set_handler(arg0logger); + __xray_set_handler_arg1(arg1logger); + arg0fn(); + arg1fn(0xcafef00d); + __xray_remove_handler_arg1(); + __xray_remove_handler(); + assert(arg0loggercalled && arg1loggercalled); +} diff --git a/test/xray/TestCases/Posix/arg1-logger.cc b/test/xray/TestCases/Posix/arg1-logger.cc new file mode 100644 index 000000000000..a6ca0a495250 --- /dev/null +++ b/test/xray/TestCases/Posix/arg1-logger.cc @@ -0,0 +1,45 @@ +// Check that we can get the first function argument logged +// using a custom logging function. +// +// RUN: %clangxx_xray -std=c++11 %s -o %t +// RUN: rm -f arg1-logger-* +// RUN: XRAY_OPTIONS="patch_premain=true verbosity=1 xray_naive_log=true \ +// RUN: xray_logfile_base=arg1-logger-" %run %t 2>&1 | FileCheck %s +// +// After all that, clean up the XRay log file. +// +// RUN: rm -f arg1-logger-* +// +// At the time of writing, the ARM trampolines weren't written yet. +// XFAIL: arm || aarch64 || mips +// See the mailing list discussion of r296998. +// UNSUPPORTED: powerpc64le + +#include "xray/xray_interface.h" + +#include <cinttypes> +#include <cstdio> + +void arg1logger(int32_t fn, XRayEntryType t, uint64_t a1) { + printf("Arg1: %" PRIx64 ", XRayEntryType %u\n", a1, t); +} + +[[clang::xray_always_instrument, clang::xray_log_args(1)]] void foo(void *) {} + +int main() { + // CHECK: XRay: Log file in 'arg1-logger-{{.*}}' + + __xray_set_handler_arg1(arg1logger); + foo(nullptr); + // CHECK: Arg1: 0, XRayEntryType 3 + + __xray_remove_handler_arg1(); + foo((void *) 0xBADC0DE); + // nothing expected to see here + + __xray_set_handler_arg1(arg1logger); + foo((void *) 0xDEADBEEFCAFE); + // CHECK-NEXT: Arg1: deadbeefcafe, XRayEntryType 3 + foo((void *) -1); + // CHECK-NEXT: Arg1: ffffffffffffffff, XRayEntryType 3 +} diff --git a/test/xray/TestCases/Posix/arg1-logging-implicit-this.cc b/test/xray/TestCases/Posix/arg1-logging-implicit-this.cc new file mode 100644 index 000000000000..d8dd62247bff --- /dev/null +++ b/test/xray/TestCases/Posix/arg1-logging-implicit-this.cc @@ -0,0 +1,31 @@ +// Intercept the implicit 'this' argument of class member functions. +// +// RUN: %clangxx_xray -g -std=c++11 %s -o %t +// RUN: rm -f log-args-this-* +// RUN: XRAY_OPTIONS="patch_premain=true verbosity=1 xray_logfile_base=log-args-this-" %run %t +// +// XFAIL: FreeBSD || arm || aarch64 || mips +// UNSUPPORTED: powerpc64le +#include "xray/xray_interface.h" +#include <cassert> + +class A { + public: + [[clang::xray_always_instrument, clang::xray_log_args(1)]] void f() { + // does nothing. + } +}; + +volatile uint64_t captured = 0; + +void handler(int32_t, XRayEntryType, uint64_t arg1) { + captured = arg1; +} + +int main() { + __xray_set_handler_arg1(handler); + A instance; + instance.f(); + __xray_remove_handler_arg1(); + assert(captured == (uint64_t)&instance); +} diff --git a/test/xray/TestCases/Posix/argv0-log-file-name.cc b/test/xray/TestCases/Posix/argv0-log-file-name.cc new file mode 100644 index 000000000000..2f9a234f8064 --- /dev/null +++ b/test/xray/TestCases/Posix/argv0-log-file-name.cc @@ -0,0 +1,16 @@ +// Check to make sure argv[0] is contained within the (randomised) XRay log file +// name. + +// RUN: %clangxx_xray -std=c++11 %s -o %t +// RUN: XRAY_OPTIONS="patch_premain=true xray_naive_log=true" %run %t > xray.log.file.name 2>&1 +// RUN: ls | FileCheck xray.log.file.name +// RUN: rm xray-log.* xray.log.file.name + +// UNSUPPORTED: target-is-mips64,target-is-mips64el + +#include <cstdio> +#include <libgen.h> + +[[clang::xray_always_instrument]] int main(int argc, char *argv[]) { + printf("// CHECK: xray-log.%s.{{.*}}\n", basename(argv[0])); +} diff --git a/test/xray/TestCases/Posix/basic-filtering.cc b/test/xray/TestCases/Posix/basic-filtering.cc new file mode 100644 index 000000000000..db07ef510c5c --- /dev/null +++ b/test/xray/TestCases/Posix/basic-filtering.cc @@ -0,0 +1,61 @@ +// Check to make sure that we are actually filtering records from the basic mode +// logging implementation. + +// RUN: %clangxx_xray -std=c++11 %s -o %t -g +// RUN: rm -f basic-filtering-* +// RUN: XRAY_OPTIONS="patch_premain=true xray_mode=xray-basic verbosity=1 \ +// RUN: xray_logfile_base=basic-filtering- \ +// RUN: xray_naive_log_func_duration_threshold_us=1000 \ +// RUN: xray_naive_log_max_stack_depth=2" %run %t 2>&1 | \ +// RUN: FileCheck %s +// RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t \ +// RUN: "`ls basic-filtering-* | head -1`" | \ +// RUN: FileCheck %s --check-prefix TRACE +// RUN: rm -f basic-filtering-* +// +// Now check support for the XRAY_BASIC_OPTIONS environment variable. +// RUN: XRAY_OPTIONS="patch_premain=true xray_mode=xray-basic verbosity=1 \ +// RUN: xray_logfile_base=basic-filtering-" \ +// RUN: XRAY_BASIC_OPTIONS="func_duration_threshold_us=1000 max_stack_depth=2" \ +// RUN: %run %t 2>&1 | FileCheck %s +// RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t \ +// RUN: "`ls basic-filtering-* | head -1`" | \ +// RUN: FileCheck %s --check-prefix TRACE +// RUN: rm -f basic-filtering-* +// +// REQUIRES: x86_64-target-arch +// REQUIRES: built-in-llvm-tree + +#include <cstdio> +#include <time.h> + +[[clang::xray_always_instrument]] void __attribute__((noinline)) filtered() { + printf("filtered was called.\n"); +} + +[[clang::xray_always_instrument]] void __attribute__((noinline)) beyond_stack() { + printf("beyond stack was called.\n"); +} + +[[clang::xray_always_instrument]] void __attribute__((noinline)) +always_shows() { + struct timespec sleep; + sleep.tv_nsec = 2000000; + sleep.tv_sec = 0; + struct timespec rem; + while (nanosleep(&sleep, &rem) == -1) + sleep = rem; + printf("always_shows was called.\n"); + beyond_stack(); +} + +[[clang::xray_always_instrument]] int main(int argc, char *argv[]) { + filtered(); // CHECK: filtered was called. + always_shows(); // CHECK: always_shows was called. + // CHECK: beyond stack was called. +} + +// TRACE-NOT: - { type: 0, func-id: {{.*}}, function: {{.*filtered.*}}, {{.*}} } +// TRACE-NOT: - { type: 0, func-id: {{.*}}, function: {{.*beyond_stack.*}}, {{.*}} } +// TRACE-DAG: - { type: 0, func-id: [[FID:[0-9]+]], function: {{.*always_shows.*}}, cpu: {{.*}}, thread: {{.*}}, kind: function-enter, tsc: {{[0-9]+}} } +// TRACE-DAG: - { type: 0, func-id: [[FID]], function: {{.*always_shows.*}}, cpu: {{.*}}, thread: {{.*}}, kind: function-{{exit|tail-exit}}, tsc: {{[0-9]+}} } diff --git a/test/xray/TestCases/Posix/c-test.cc b/test/xray/TestCases/Posix/c-test.cc new file mode 100644 index 000000000000..28a7870d0f74 --- /dev/null +++ b/test/xray/TestCases/Posix/c-test.cc @@ -0,0 +1,15 @@ +// RUN: %clang_xray -g -fxray-modes=xray-basic,xray-fdr,xray-profiling -o %t %s +// RUN: rm -f xray-log.c-test.* +// RUN: XRAY_OPTIONS=patch_premain=true:verbosity=1:xray_mode=xray-basic %t \ +// RUN: 2>&1 | FileCheck %s +// RUN: rm -f xray-log.c-test.* +// +// REQUIRES: x86_64-target-arch +// REQUIRES: built-in-llvm-tree +__attribute__((xray_always_instrument)) void always() {} + +int main() { + always(); +} + +// CHECK: =={{[0-9].*}}==XRay: Log file in '{{.*}}' diff --git a/test/xray/TestCases/Posix/common-trampoline-alignment.cc b/test/xray/TestCases/Posix/common-trampoline-alignment.cc new file mode 100644 index 000000000000..dac0789abdec --- /dev/null +++ b/test/xray/TestCases/Posix/common-trampoline-alignment.cc @@ -0,0 +1,57 @@ +// Make sure that we're aligning the stack properly to support handlers that +// expect 16-byte alignment of the stack. +// +// RUN: %clangxx_xray -std=c++11 %s -o %t +// RUN: XRAY_OPTIONS="patch_premain=false verbosity=1 xray_naive_log=false" \ +// RUN: %run %t 2>&1 +// REQUIRES: x86_64-target-arch +// REQUIRES: built-in-llvm-tree +#include "xray/xray_interface.h" +#include <stdio.h> +#include <xmmintrin.h> + +[[clang::xray_never_instrument]] __attribute__((weak)) __m128 f(__m128 *i) { + return *i; +} + +[[clang::xray_always_instrument]] __attribute__((noinline)) void noarg() { + __m128 v = {}; + f(&v); +} + +[[ clang::xray_always_instrument, clang::xray_log_args(1) ]] +__attribute__((noinline)) void arg1(int) { + __m128 v = {}; + f(&v); +} + +[[clang::xray_always_instrument]] __attribute__((noinline)) +void no_alignment() {} + +[[clang::xray_never_instrument]] void noarg_handler(int32_t, + XRayEntryType) { + printf("noarg handler called\n"); + __m128 v = {}; + f(&v); +} + +[[clang::xray_never_instrument]] void arg1_handler(int32_t, XRayEntryType, + uint64_t) { + printf("arg1 handler called\n"); + __m128 v = {}; + f(&v); +} + +int main(int argc, char *argv[]) { + __xray_set_handler(noarg_handler); + __xray_set_handler_arg1(arg1_handler); + __xray_patch(); + noarg(); // CHECK: noarg handler called + arg1(argc); // CHECK: arg1 handler called + no_alignment(); + __xray_unpatch(); + __xray_remove_handler(); + __xray_remove_handler_arg1(); + noarg(); + arg1(argc); +} diff --git a/test/xray/TestCases/Posix/coverage-sample.cc b/test/xray/TestCases/Posix/coverage-sample.cc new file mode 100644 index 000000000000..62c13ba3d42a --- /dev/null +++ b/test/xray/TestCases/Posix/coverage-sample.cc @@ -0,0 +1,91 @@ +// Check that we can patch and unpatch specific function ids. +// +// RUN: %clangxx_xray -std=c++11 %s -o %t +// RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false" %run %t | FileCheck %s + +// UNSUPPORTED: target-is-mips64,target-is-mips64el + +#include "xray/xray_interface.h" + +#include <set> +#include <cstdio> +#include <cassert> + +std::set<int32_t> function_ids; + +[[clang::xray_never_instrument]] void coverage_handler(int32_t fid, + XRayEntryType) { + thread_local bool patching = false; + if (patching) return; + patching = true; + function_ids.insert(fid); + __xray_unpatch_function(fid); + patching = false; +} + +[[clang::xray_always_instrument]] void baz() { + // do nothing! +} + +[[clang::xray_always_instrument]] void bar() { + baz(); +} + +[[clang::xray_always_instrument]] void foo() { + bar(); +} + +[[clang::xray_always_instrument]] int main(int argc, char *argv[]) { + __xray_set_handler(coverage_handler); + assert(__xray_patch() == XRayPatchingStatus::SUCCESS); + foo(); + assert(__xray_unpatch() == XRayPatchingStatus::SUCCESS); + + // print out the function_ids. + printf("first pass.\n"); + for (const auto id : function_ids) + printf("patched: %d\n", id); + + // CHECK-LABEL: first pass. + // CHECK-DAG: patched: [[F1:.*]] + // CHECK-DAG: patched: [[F2:.*]] + // CHECK-DAG: patched: [[F3:.*]] + + // make a copy of the function_ids, then patch them later. + auto called_fns = function_ids; + + // clear the function_ids. + function_ids.clear(); + + // patch the functions we've called before. + for (const auto id : called_fns) + assert(__xray_patch_function(id) == XRayPatchingStatus::SUCCESS); + + // then call them again. + foo(); + assert(__xray_unpatch() == XRayPatchingStatus::SUCCESS); + + // confirm that we've seen the same functions again. + printf("second pass.\n"); + for (const auto id : function_ids) + printf("patched: %d\n", id); + // CHECK-LABEL: second pass. + // CHECK-DAG: patched: [[F1]] + // CHECK-DAG: patched: [[F2]] + // CHECK-DAG: patched: [[F3]] + + // Now we want to make sure that if we unpatch one, that we're only going to + // see two calls of the coverage_handler. + function_ids.clear(); + assert(__xray_patch() == XRayPatchingStatus::SUCCESS); + assert(__xray_unpatch_function(1) == XRayPatchingStatus::SUCCESS); + foo(); + assert(__xray_unpatch() == XRayPatchingStatus::SUCCESS); + + // confirm that we don't see function id one called anymore. + printf("missing 1.\n"); + for (const auto id : function_ids) + printf("patched: %d\n", id); + // CHECK-LABEL: missing 1. + // CHECK-NOT: patched: 1 +} diff --git a/test/xray/TestCases/Posix/custom-event-handler-alignment.cc b/test/xray/TestCases/Posix/custom-event-handler-alignment.cc new file mode 100644 index 000000000000..c8de18b0e2b6 --- /dev/null +++ b/test/xray/TestCases/Posix/custom-event-handler-alignment.cc @@ -0,0 +1,42 @@ +// Make sure we're aligning the stack properly when lowering the custom event +// calls. +// +// RUN: %clangxx_xray -std=c++11 %s -o %t +// RUN: XRAY_OPTIONS="patch_premain=false verbosity=1 xray_naive_log=false" \ +// RUN: %run %t 2>&1 +// REQUIRES: x86_64-target-arch +// REQUIRES: built-in-llvm-tree +#include <xmmintrin.h> +#include <stdio.h> +#include "xray/xray_interface.h" + +[[clang::xray_never_instrument]] __attribute__((weak)) __m128 f(__m128 *i) { + return *i; +} + +[[clang::xray_always_instrument]] void foo() { + __xray_customevent(0, 0); + __m128 v = {}; + f(&v); +} + +[[clang::xray_always_instrument]] void bar() { + __xray_customevent(0, 0); +} + +void printer(void* ptr, size_t size) { + printf("handler called\n"); + __m128 v = {}; + f(&v); +} + +int main(int argc, char* argv[]) { + __xray_set_customevent_handler(printer); + __xray_patch(); + foo(); // CHECK: handler called + bar(); // CHECK: handler called + __xray_unpatch(); + __xray_remove_customevent_handler(); + foo(); + bar(); +} diff --git a/test/xray/TestCases/Posix/custom-event-logging.cc b/test/xray/TestCases/Posix/custom-event-logging.cc new file mode 100644 index 000000000000..48fd62034194 --- /dev/null +++ b/test/xray/TestCases/Posix/custom-event-logging.cc @@ -0,0 +1,42 @@ +// Use the clang feature for custom xray event logging. +// +// RUN: %clangxx_xray -std=c++11 %s -o %t +// RUN: XRAY_OPTIONS="patch_premain=false verbosity=1 xray_naive_log=false xray_logfile_base=custom-event-logging.xray-" %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_xray -std=c++11 -fpic -fpie %s -o %t +// RUN: XRAY_OPTIONS="patch_premain=false verbosity=1 xray_naive_log=false xray_logfile_base=custom-event-logging.xray-" %run %t 2>&1 | FileCheck %s +// FIXME: Support this in non-x86_64 as well +// REQUIRES: x86_64-linux +// REQUIRES: built-in-llvm-tree +#include <cstdio> +#include "xray/xray_interface.h" + +[[clang::xray_always_instrument]] void foo() { + static constexpr char CustomLogged[] = "hello custom logging!"; + printf("before calling the custom logging...\n"); + __xray_customevent(CustomLogged, sizeof(CustomLogged)); + printf("after calling the custom logging...\n"); +} + +void myprinter(void* ptr, size_t size) { + printf("%.*s\n", static_cast<int>(size), static_cast<const char*>(ptr)); +} + +int main() { + foo(); + // CHECK: before calling the custom logging... + // CHECK-NEXT: after calling the custom logging... + printf("setting up custom event handler...\n"); + // CHECK-NEXT: setting up custom event handler... + __xray_set_customevent_handler(myprinter); + __xray_patch(); + // CHECK-NEXT: before calling the custom logging... + foo(); + // CHECK-NEXT: hello custom logging! + // CHECK-NEXT: after calling the custom logging... + printf("removing custom event handler...\n"); + // CHECK-NEXT: removing custom event handler... + __xray_remove_customevent_handler(); + foo(); + // CHECK-NEXT: before calling the custom logging... + // CHECK-NEXT: after calling the custom logging... +} diff --git a/test/xray/TestCases/Posix/fdr-mode-inmemory.cc b/test/xray/TestCases/Posix/fdr-mode-inmemory.cc new file mode 100644 index 000000000000..ff31626d7779 --- /dev/null +++ b/test/xray/TestCases/Posix/fdr-mode-inmemory.cc @@ -0,0 +1,50 @@ +// RUN: %clangxx_xray -g -std=c++11 %s -o %t -fxray-modes=xray-fdr +// RUN: rm -f fdr-inmemory-test-* +// RUN: XRAY_OPTIONS="patch_premain=false xray_logfile_base=fdr-inmemory-test- \ +// RUN: verbosity=1" \ +// RUN: XRAY_FDR_OPTIONS="no_file_flush=true func_duration_threshold_us=0" \ +// RUN: %run %t 2>&1 | FileCheck %s +// RUN: FILES=`find %T -name 'fdr-inmemory-test-*' | wc -l` +// RUN: [ $FILES -eq 0 ] +// RUN: rm -f fdr-inmemory-test-* +// +// REQUIRES: x86_64-target-arch +// REQUIRES: built-in-llvm-tree + +#include "xray/xray_log_interface.h" +#include <cassert> +#include <iostream> + +uint64_t var = 0; +uint64_t buffers = 0; +[[clang::xray_always_instrument]] void __attribute__((noinline)) f() { ++var; } + +int main(int argc, char *argv[]) { + assert(__xray_log_select_mode("xray-fdr") == + XRayLogRegisterStatus::XRAY_REGISTRATION_OK); + auto status = __xray_log_init_mode( + "xray-fdr", + "buffer_size=4096:buffer_max=10:func_duration_threshold_us=0"); + assert(status == XRayLogInitStatus::XRAY_LOG_INITIALIZED); + __xray_patch(); + + // Create enough entries. + for (int i = 0; i != 1 << 20; ++i) { + f(); + } + + // Then we want to verify that we're getting 10 buffers outside of the initial + // header. + auto finalize_status = __xray_log_finalize(); + assert(finalize_status == XRayLogInitStatus::XRAY_LOG_FINALIZED); + auto process_status = + __xray_log_process_buffers([](const char *, XRayBuffer) { ++buffers; }); + std::cout << "buffers = " << buffers << std::endl; + assert(process_status == XRayLogFlushStatus::XRAY_LOG_FLUSHED); + auto flush_status = __xray_log_flushLog(); + assert(flush_status == XRayLogFlushStatus::XRAY_LOG_FLUSHED); + // We expect 11 buffers because 1 header buffer + 10 actual FDR buffers. + // CHECK: Buffers = 11 + std::cout << "Buffers = " << buffers << std::endl; + return 0; +} diff --git a/test/xray/TestCases/Posix/fdr-mode-multiple.cc b/test/xray/TestCases/Posix/fdr-mode-multiple.cc new file mode 100644 index 000000000000..487e3031325e --- /dev/null +++ b/test/xray/TestCases/Posix/fdr-mode-multiple.cc @@ -0,0 +1,76 @@ +// RUN: %clangxx_xray -g -std=c++11 %s -o %t -fxray-modes=xray-fdr +// RUN: rm -f fdr-inmemory-test-* +// RUN: XRAY_OPTIONS="patch_premain=false xray_logfile_base=fdr-inmemory-test- \ +// RUN: verbosity=1" \ +// RUN: XRAY_FDR_OPTIONS="no_file_flush=true func_duration_threshold_us=0" \ +// RUN: %run %t 2>&1 | FileCheck %s +// RUN: FILES=`find %T -name 'fdr-inmemory-test-*' | wc -l` +// RUN: [ $FILES -eq 0 ] +// RUN: rm -f fdr-inmemory-test-* +// +// REQUIRES: x86_64-target-arch +// REQUIRES: built-in-llvm-tree + +#include "xray/xray_log_interface.h" +#include <cassert> +#include <iostream> + +uint64_t var = 0; +uint64_t buffers = 0; +[[clang::xray_always_instrument]] void __attribute__((noinline)) f() { ++var; } + +int main(int argc, char *argv[]) { + assert(__xray_log_select_mode("xray-fdr") == + XRayLogRegisterStatus::XRAY_REGISTRATION_OK); + auto status = __xray_log_init_mode( + "xray-fdr", + "buffer_size=4096:buffer_max=10:func_duration_threshold_us=0"); + assert(status == XRayLogInitStatus::XRAY_LOG_INITIALIZED); + __xray_patch(); + + // Create enough entries. + for (int i = 0; i != 1 << 20; ++i) { + f(); + } + + // Then we want to verify that we're getting 10 buffers outside of the initial + // header. + auto finalize_status = __xray_log_finalize(); + assert(finalize_status == XRayLogInitStatus::XRAY_LOG_FINALIZED); + auto process_status = + __xray_log_process_buffers([](const char *, XRayBuffer) { ++buffers; }); + std::cout << "buffers = " << buffers << std::endl; + assert(process_status == XRayLogFlushStatus::XRAY_LOG_FLUSHED); + auto flush_status = __xray_log_flushLog(); + assert(flush_status == XRayLogFlushStatus::XRAY_LOG_FLUSHED); + // We expect 11 buffers because 1 header buffer + 10 actual FDR buffers. + // CHECK: Buffers = 11 + std::cout << "Buffers = " << buffers << std::endl; + + // In this test we ensure that we can restart the cycle after the flush. + status = __xray_log_init_mode( + "xray-fdr", + "buffer_size=4096:buffer_max=10:func_duration_threshold_us=0"); + assert(status == XRayLogInitStatus::XRAY_LOG_INITIALIZED); + __xray_patch(); + + // Create enough entries. + for (int i = 0; i != 1 << 20; ++i) { + f(); + } + + // Then we want to verify that we're getting 10 buffers outside of the initial + // header. + finalize_status = __xray_log_finalize(); + assert(finalize_status == XRayLogInitStatus::XRAY_LOG_FINALIZED); + process_status = + __xray_log_process_buffers([](const char *, XRayBuffer) { ++buffers; }); + std::cout << "buffers = " << buffers << std::endl; + assert(process_status == XRayLogFlushStatus::XRAY_LOG_FLUSHED); + flush_status = __xray_log_flushLog(); + assert(flush_status == XRayLogFlushStatus::XRAY_LOG_FLUSHED); + // We expect 22 buffers because 1 header buffer + 10 actual FDR buffers, plus + // the number of buffers we got from the previous run (also 11). + // CHECK: Buffers = 22 + std::cout << "Buffers = " << buffers << std::endl; +} diff --git a/test/xray/TestCases/Posix/fdr-mode.cc b/test/xray/TestCases/Posix/fdr-mode.cc new file mode 100644 index 000000000000..b12d97c0005a --- /dev/null +++ b/test/xray/TestCases/Posix/fdr-mode.cc @@ -0,0 +1,112 @@ +// RUN: %clangxx_xray -g -std=c++11 %s -o %t +// RUN: rm -f fdr-logging-test-* +// RUN: rm -f fdr-unwrite-test-* +// RUN: XRAY_OPTIONS="patch_premain=false xray_logfile_base=fdr-logging-test- \ +// RUN: xray_mode=xray-fdr verbosity=1" \ +// RUN: XRAY_FDR_OPTIONS="func_duration_threshold_us=0" \ +// RUN: %run %t 2>&1 | FileCheck %s +// RUN: XRAY_OPTIONS="patch_premain=false \ +// RUN: xray_logfile_base=fdr-unwrite-test- xray_mode=xray-fdr \ +// RUN: verbosity=1" \ +// RUN: XRAY_FDR_OPTIONS="func_duration_threshold_us=5000" \ +// RUN: %run %t 2>&1 | FileCheck %s +// RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t \ +// RUN: "`ls fdr-logging-test-* | head -1`" \ +// RUN: | FileCheck %s --check-prefix=TRACE +// RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t \ +// RUN: "`ls fdr-unwrite-test-* | head -1`" \ +// RUN: | FileCheck %s --check-prefix=UNWRITE +// RUN: rm fdr-logging-test-* +// RUN: rm fdr-unwrite-test-* +// FIXME: Make llvm-xray work on non-x86_64 as well. +// REQUIRES: x86_64-target-arch +// REQUIRES: built-in-llvm-tree + +#include "xray/xray_log_interface.h" +#include <cassert> +#include <chrono> +#include <cstdio> +#include <iostream> +#include <stdlib.h> +#include <thread> +#include <time.h> + +thread_local uint64_t var = 0; +[[clang::xray_always_instrument]] void __attribute__((noinline)) fC() { ++var; } + +[[clang::xray_always_instrument]] void __attribute__((noinline)) fB() { fC(); } + +[[clang::xray_always_instrument]] void __attribute__((noinline)) fA() { fB(); } + +[[clang::xray_always_instrument, clang::xray_log_args(1)]] +void __attribute__((noinline)) fArg(int) { } + +int main(int argc, char *argv[]) { + using namespace __xray; + std::cout << "Logging before init." << std::endl; + // CHECK: Logging before init. + assert(__xray_log_select_mode("xray-fdr") == + XRayLogRegisterStatus::XRAY_REGISTRATION_OK); + auto status = + __xray_log_init_mode("xray-fdr", "buffer_size=16384:buffer_max=10"); + assert(status == XRayLogInitStatus::XRAY_LOG_INITIALIZED); + std::cout << "Init status " << status << std::endl; + // CHECK: Init status {{.*}} + std::cout << "Patching..." << std::endl; + // CHECK: Patching... + __xray_patch(); + fA(); + fC(); + fB(); + fA(); + fC(); + std::thread other_thread([]() { + fC(); + fB(); + fA(); + fArg(1); + }); + other_thread.join(); + std::cout << "Joined" << std::endl; + // CHECK: Joined + std::cout << "Finalize status " << __xray_log_finalize() << std::endl; + // CHECK: Finalize status {{.*}} + fC(); + std::cout << "Main execution var = " << var << std::endl; + // CHECK: Main execution var = 6 + std::cout << "Flush status " << __xray_log_flushLog() << std::endl; + // CHECK: Flush status {{.*}} + __xray_unpatch(); + return 0; +} + +// Check that we're able to see two threads, each entering and exiting fA(). +// TRACE-DAG: - { type: 0, func-id: [[FIDA:[0-9]+]], function: {{.*fA.*}}, cpu: {{.*}}, thread: [[THREAD1:[0-9]+]], process: [[PROCESS:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } +// TRACE: - { type: 0, func-id: [[FIDA]], function: {{.*fA.*}}, cpu: {{.*}}, thread: [[THREAD1]], process: [[PROCESS]], kind: function-{{exit|tail-exit}}, tsc: {{[0-9]+}} } +// TRACE-DAG: - { type: 0, func-id: [[FIDA]], function: {{.*fA.*}}, cpu: {{.*}}, thread: [[THREAD2:[0-9]+]], process: [[PROCESS]], kind: function-enter, tsc: {{[0-9]+}} } +// TRACE: - { type: 0, func-id: [[FIDA]], function: {{.*fA.*}}, cpu: {{.*}}, thread: [[THREAD2]], process: [[PROCESS]], kind: function-{{exit|tail-exit}}, tsc: {{[0-9]+}} } +// +// Do the same as above for fC() +// TRACE-DAG: - { type: 0, func-id: [[FIDC:[0-9]+]], function: {{.*fC.*}}, cpu: {{.*}}, thread: [[THREAD1:[0-9]+]], process: [[PROCESS]], kind: function-enter, tsc: {{[0-9]+}} } +// TRACE: - { type: 0, func-id: [[FIDC]], function: {{.*fC.*}}, cpu: {{.*}}, thread: [[THREAD1]], process: [[PROCESS]], kind: function-{{exit|tail-exit}}, tsc: {{[0-9]+}} } +// TRACE-DAG: - { type: 0, func-id: [[FIDC]], function: {{.*fC.*}}, cpu: {{.*}}, thread: [[THREAD2:[0-9]+]], process: [[PROCESS]], kind: function-enter, tsc: {{[0-9]+}} } +// TRACE: - { type: 0, func-id: [[FIDC]], function: {{.*fC.*}}, cpu: {{.*}}, thread: [[THREAD2]], process: [[PROCESS]], kind: function-{{exit|tail-exit}}, tsc: {{[0-9]+}} } + +// Do the same as above for fB() +// TRACE-DAG: - { type: 0, func-id: [[FIDB:[0-9]+]], function: {{.*fB.*}}, cpu: {{.*}}, thread: [[THREAD1:[0-9]+]], process: [[PROCESS]], kind: function-enter, tsc: {{[0-9]+}} } +// TRACE: - { type: 0, func-id: [[FIDB]], function: {{.*fB.*}}, cpu: {{.*}}, thread: [[THREAD1]], process: [[PROCESS]], kind: function-{{exit|tail-exit}}, tsc: {{[0-9]+}} } +// TRACE-DAG: - { type: 0, func-id: [[FIDB]], function: {{.*fB.*}}, cpu: {{.*}}, thread: [[THREAD2:[0-9]+]], process: [[PROCESS]], kind: function-enter, tsc: {{[0-9]+}} } +// TRACE: - { type: 0, func-id: [[FIDB]], function: {{.*fB.*}}, cpu: {{.*}}, thread: [[THREAD2]], process: [[PROCESS]], kind: function-{{exit|tail-exit}}, tsc: {{[0-9]+}} } + +// TRACE-DAG: - { type: 0, func-id: [[FIDARG:[0-9]+]], function: 'fArg(int)', args: [ 1 ], cpu: {{.*}}, thread: [[THREAD2]], process: [[PROCESS]], kind: function-enter-arg, tsc: {{[0-9]+}} } +// TRACE-DAG: - { type: 0, func-id: [[FIDARG]], function: 'fArg(int)', cpu: {{.*}}, thread: [[THREAD2]], process: [[PROCESS]], kind: function-exit, tsc: {{[0-9]+}} } + +// Assert that when unwriting is enabled with a high threshold time, all the function records are erased. A CPU switch could erroneously fail this test, but +// is unlikely given the test program. +// Even with a high threshold, arg1 logging is never unwritten. +// UNWRITE: header: +// UNWRITE: records: +// UNWRITE-NEXT: - { type: 0, func-id: [[FIDARG:[0-9]+]], function: 'fArg(int)', args: [ 1 ], cpu: {{.*}}, thread: [[THREAD2:[0-9]+]], process: [[PROCESS:[0-9]+]], kind: function-enter-arg, tsc: {{[0-9]+}} } +// UNWRITE-NEXT: - { type: 0, func-id: [[FIDARG]], function: 'fArg(int)', cpu: {{.*}}, thread: [[THREAD2]], process: [[PROCESS]], kind: function-exit, tsc: {{[0-9]+}} } +// UNWRITE-NOT: function-enter +// UNWRITE-NOT: function-{{exit|tail-exit}} diff --git a/test/xray/TestCases/Posix/fdr-single-thread.cc b/test/xray/TestCases/Posix/fdr-single-thread.cc new file mode 100644 index 000000000000..480502b0a60f --- /dev/null +++ b/test/xray/TestCases/Posix/fdr-single-thread.cc @@ -0,0 +1,38 @@ +// RUN: %clangxx_xray -g -std=c++11 %s -o %t +// RUN: rm -f fdr-logging-1thr-* +// RUN: XRAY_OPTIONS=XRAY_OPTIONS="verbosity=1 patch_premain=true \ +// RUN: xray_naive_log=false xray_fdr_log=true \ +// RUN: xray_fdr_log_func_duration_threshold_us=0 \ +// RUN: xray_logfile_base=fdr-logging-1thr-" %run %t 2>&1 +// RUN: %llvm_xray convert --output-format=yaml --symbolize --instr_map=%t \ +// RUN: "`ls fdr-logging-1thr-* | head -n1`" | FileCheck %s +// RUN: rm fdr-logging-1thr-* +// +// REQUIRES: x86_64-target-arch + +#include "xray/xray_log_interface.h" +#include <cassert> + +constexpr auto kBufferSize = 16384; +constexpr auto kBufferMax = 10; + +[[clang::xray_always_instrument]] void __attribute__((noinline)) fn() { } + +int main(int argc, char *argv[]) { + using namespace __xray; + FDRLoggingOptions Opts; + + auto status = __xray_log_init(kBufferSize, kBufferMax, &Opts, sizeof(Opts)); + assert(status == XRayLogInitStatus::XRAY_LOG_INITIALIZED); + + __xray_patch(); + fn(); + __xray_unpatch(); + assert(__xray_log_finalize() == XRAY_LOG_FINALIZED); + assert(__xray_log_flushLog() == XRAY_LOG_FLUSHED); + return 0; +} + +// CHECK: records: +// CHECK-NEXT: - { type: 0, func-id: [[FID1:[0-9]+]], function: {{.*fn.*}}, cpu: {{.*}}, thread: [[THREAD1:[0-9]+]], process: [[PROCESS:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } +// CHECK-NEXT: - { type: 0, func-id: [[FID1:[0-9]+]], function: {{.*fn.*}}, cpu: {{.*}}, thread: [[THREAD1:[0-9]+]], process: [[PROCESS:[0-9]+]], kind: function-exit, tsc: {{[0-9]+}} } diff --git a/test/xray/TestCases/Posix/fdr-thread-order.cc b/test/xray/TestCases/Posix/fdr-thread-order.cc new file mode 100644 index 000000000000..1d6b01759f14 --- /dev/null +++ b/test/xray/TestCases/Posix/fdr-thread-order.cc @@ -0,0 +1,67 @@ +// RUN: %clangxx_xray -g -std=c++11 %s -o %t +// RUN: rm fdr-thread-order.* || true +// RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false \ +// RUN: xray_logfile_base=fdr-thread-order. xray_fdr_log=true verbosity=1 \ +// RUN: xray_fdr_log_func_duration_threshold_us=0" %run %t 2>&1 | \ +// RUN: FileCheck %s +// RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t \ +// RUN: "`ls fdr-thread-order.* | head -1`" +// RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t \ +// RUN: "`ls fdr-thread-order.* | head -1`" | \ +// RUN: FileCheck %s --check-prefix TRACE +// RUN: rm fdr-thread-order.* +// FIXME: Make llvm-xray work on non-x86_64 as well. +// REQUIRES: x86_64-target-arch +// REQUIRES: built-in-llvm-tree + +#include "xray/xray_log_interface.h" +#include <atomic> +#include <cassert> +#include <thread> + +constexpr auto kBufferSize = 16384; +constexpr auto kBufferMax = 10; + +std::atomic<uint64_t> var{0}; + +[[clang::xray_always_instrument]] void __attribute__((noinline)) f1() { + for (auto i = 0; i < 1 << 20; ++i) + ++var; +} + +[[clang::xray_always_instrument]] void __attribute__((noinline)) f2() { + for (auto i = 0; i < 1 << 20; ++i) + ++var; +} + +int main(int argc, char *argv[]) { + using namespace __xray; + FDRLoggingOptions Options; + __xray_patch(); + assert(__xray_log_init(kBufferSize, kBufferMax, &Options, + sizeof(FDRLoggingOptions)) == + XRayLogInitStatus::XRAY_LOG_INITIALIZED); + + std::atomic_thread_fence(std::memory_order_acq_rel); + + { + std::thread t1([] { f1(); }); + std::thread t2([] { f2(); }); + t1.join(); + t2.join(); + } + + std::atomic_thread_fence(std::memory_order_acq_rel); + __xray_log_finalize(); + __xray_log_flushLog(); + __xray_unpatch(); + return var > 0 ? 0 : 1; + // CHECK: {{.*}}XRay: Log file in '{{.*}}' + // CHECK-NOT: Failed +} + +// We want to make sure that the order of the function log doesn't matter. +// TRACE-DAG: - { type: 0, func-id: [[FID1:[0-9]+]], function: {{.*f1.*}}, cpu: {{.*}}, thread: [[THREAD1:[0-9]+]], process: [[PROCESS:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } +// TRACE-DAG: - { type: 0, func-id: [[FID2:[0-9]+]], function: {{.*f2.*}}, cpu: {{.*}}, thread: [[THREAD2:[0-9]+]], process: [[PROCESS]], kind: function-enter, tsc: {{[0-9]+}} } +// TRACE-DAG: - { type: 0, func-id: [[FID1]], function: {{.*f1.*}}, cpu: {{.*}}, thread: [[THREAD1]], process: [[PROCESS]], kind: {{function-exit|function-tail-exit}}, tsc: {{[0-9]+}} } +// TRACE-DAG: - { type: 0, func-id: [[FID2]], function: {{.*f2.*}}, cpu: {{.*}}, thread: [[THREAD2]], process: [[PROCESS]], kind: {{function-exit|function-tail-exit}}, tsc: {{[0-9]+}} } diff --git a/test/xray/TestCases/Posix/fixedsize-logging.cc b/test/xray/TestCases/Posix/fixedsize-logging.cc new file mode 100644 index 000000000000..a2a41ce60d6e --- /dev/null +++ b/test/xray/TestCases/Posix/fixedsize-logging.cc @@ -0,0 +1,22 @@ +// Check to make sure that we have a log file with a fixed-size. + +// RUN: %clangxx_xray -std=c++11 %s -o %t +// RUN: XRAY_OPTIONS="patch_premain=true xray_naive_log=true verbosity=1 xray_logfile_base=fixedsize-logging-" %run %t 2>&1 | FileCheck %s +// +// After all that, clean up the output xray log. +// +// RUN: rm fixedsize-logging-* + +// UNSUPPORTED: target-is-mips64,target-is-mips64el + +#include <cstdio> + +[[clang::xray_always_instrument]] void foo() { + printf("foo() is always instrumented!"); +} + +int main() { + // CHECK: XRay: Log file in 'fixedsize-logging-{{.*}}' + foo(); + // CHECK: foo() is always instrumented! +} diff --git a/test/xray/TestCases/Posix/fork_basic_logging.cc b/test/xray/TestCases/Posix/fork_basic_logging.cc new file mode 100644 index 000000000000..5aefdec08016 --- /dev/null +++ b/test/xray/TestCases/Posix/fork_basic_logging.cc @@ -0,0 +1,100 @@ +// Check that when forking in basic logging mode, we get the different tids for child and parent +// RUN: %clangxx_xray -g -std=c++11 %s -o %t +// RUN: rm -f fork-basic-logging-test-* +// RUN: XRAY_OPTIONS="patch_premain=true xray_logfile_base=fork-basic-logging-test- \ +// RUN: xray_mode=xray-basic verbosity=1 xray_naive_log_func_duration_threshold_us=0" \ +// RUN: %run %t 2>&1 | FileCheck %s +// RUN: %llvm_xray convert --symbolize --output-format=yaml -instr_map=%t \ +// RUN: "`ls -S fork-basic-logging-test-* | head -1`" \ +// RUN: | FileCheck %s --check-prefix=TRACE + +// REQUIRES: x86_64-target-arch +// REQUIRES: built-in-llvm-tree + +#include "xray/xray_log_interface.h" +#include <stdio.h> +#include <unistd.h> +#include <stdint.h> +#include <sys/syscall.h> + +//modified from sanitizer + +static uintptr_t syscall_gettid() { + uint64_t retval; + asm volatile("syscall" : "=a"(retval) : "a"(__NR_gettid) : "rcx", "r11", + "memory", "cc"); + return retval; +} + +///////////// + +static uint64_t parent_tid; + +[[clang::xray_always_instrument]] +uint64_t __attribute__((noinline)) log_syscall_gettid() +{ + //don't optimize this function away + uint64_t tid = syscall_gettid(); + printf("Logging tid %lu\n", tid); + return tid; +} + +[[clang::xray_always_instrument, clang::xray_log_args(1)]] +void __attribute__((noinline)) print_parent_tid(uint64_t tid) +{ + printf("Parent with tid %lu", tid); +} + +[[clang::xray_always_instrument, clang::xray_log_args(1)]] +void __attribute__((noinline)) print_child_tid(uint64_t tid) +{ + printf("Child with tid %lu", tid); +} + +[[clang::xray_always_instrument]] void __attribute__((noinline)) print_parent_or_child() +{ + uint64_t tid = syscall_gettid(); + if(tid == parent_tid) + { + print_parent_tid(tid); + } + else + { + print_child_tid(tid); + } +} + +int main() +{ + parent_tid = log_syscall_gettid(); + if(fork()) + { + print_parent_or_child(); + // CHECK-DAG: Parent with tid + } + else + { + print_parent_or_child(); + // CHECK-DAG: Child with tid + } + return 0; +} + +// Make sure we know which thread is the parent process +// TRACE-DAG: - { type: 0, func-id: [[LSGT:[0-9]+]], function: {{.*log_syscall_gettid.*}}, cpu: {{.*}}, thread: [[THREAD1:[0-9]+]], process: [[PROCESS1:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } + +// TRACE-DAG: - { type: 0, func-id: [[PPOC:[0-9]+]], function: {{.*print_parent_or_child.*}}, cpu: {{.*}}, thread: [[THREAD1]], process: [[PROCESS1]], kind: function-enter, tsc: {{[0-9]+}} } +// +// The parent will print its pid +// TRACE-DAG: - { type: 0, func-id: [[PPTARG:[0-9]+]], function: {{.*print_parent_tid.*}}, args: [ [[THREAD1]] ], cpu: {{.*}}, thread: [[THREAD1]], process: [[PROCESS1]], kind: function-enter-arg, tsc: {{[0-9]+}} } +// TRACE-DAG: - { type: 0, func-id: [[PPTARG]], function: {{.*print_parent_tid.*}}, cpu: {{.*}}, thread: [[THREAD1]], process: [[PROCESS1]], kind: function-exit, tsc: {{[0-9]+}} } +// +// TRACE-DAG - { type: 0, func-id: [[PPOC]], function: {{.*print_parent_or_child.*}}, cpu: {{.*}}, thread: [[THREAD1]], process: [[PROCESS1]], kind: function-{{exit|tail-exit}}, tsc: {{[0-9]+}} } + +// TRACE-DAG: - { type: 0, func-id: [[PPOC]], function: {{.*print_parent_or_child.*}}, cpu: {{.*}}, thread: [[THREAD2:[0-9]+]], process: [[PROCESS2:[0-9]+]], kind: function-enter, tsc: {{[0-9]+}} } +// +// The child will print its pid +// TRACE-DAG: - { type: 0, func-id: [[PCTARG:[0-9]+]], function: {{.*print_child_tid.*}}, args: [ [[THREAD2]] ], cpu: {{.*}}, thread: [[THREAD2]], process: [[PROCESS2]], kind: function-enter-arg, tsc: {{[0-9]+}} } +// TRACE-DAG: - { type: 0, func-id: [[PCTARG]], function: {{.*print_child_tid.*}}, cpu: {{.*}}, thread: [[THREAD2]], process: [[PROCESS2]], kind: function-exit, tsc: {{[0-9]+}} } +// +// TRACE-DAG: - { type: 0, func-id: [[PPOC]], function: {{.*print_parent_or_child.*}}, cpu: {{.*}}, thread: [[THREAD2]], process: [[PROCESS2]], kind: function-{{exit|tail-exit}}, tsc: {{[0-9]+}} } diff --git a/test/xray/TestCases/Posix/func-id-utils.cc b/test/xray/TestCases/Posix/func-id-utils.cc new file mode 100644 index 000000000000..412753666019 --- /dev/null +++ b/test/xray/TestCases/Posix/func-id-utils.cc @@ -0,0 +1,44 @@ +// Check that we can turn a function id to a function address, and also get the +// maximum function id for the current binary. +// +// RUN: %clangxx_xray -std=c++11 %s -o %t +// RUN: XRAY_OPTIONS="patch_premain=false xray_naive_log=false" %run %t + +// UNSUPPORTED: target-is-mips64,target-is-mips64el + +#include "xray/xray_interface.h" +#include <algorithm> +#include <cassert> +#include <cstdio> +#include <iterator> +#include <set> + +[[clang::xray_always_instrument]] void bar(){} + +[[clang::xray_always_instrument]] void foo() { + bar(); +} + +[[clang::xray_always_instrument]] int main(int argc, char *argv[]) { + assert(__xray_max_function_id() != 0 && "we need xray instrumentation!"); + std::set<void *> must_be_instrumented = {reinterpret_cast<void *>(&foo), + reinterpret_cast<void *>(&bar), + reinterpret_cast<void *>(&main)}; + std::set<void *> all_instrumented; + for (auto i = __xray_max_function_id(); i != 0; --i) { + auto addr = __xray_function_address(i); + all_instrumented.insert(reinterpret_cast<void *>(addr)); + } + assert(all_instrumented.size() == __xray_max_function_id() && + "each function id must be assigned to a unique function"); + + std::set<void *> not_instrumented; + std::set_difference( + must_be_instrumented.begin(), must_be_instrumented.end(), + all_instrumented.begin(), all_instrumented.end(), + std::inserter(not_instrumented, not_instrumented.begin())); + assert( + not_instrumented.empty() && + "we should see all explicitly instrumented functions with function ids"); + return not_instrumented.empty() ? 0 : 1; +} diff --git a/test/xray/TestCases/Posix/logging-modes.cc b/test/xray/TestCases/Posix/logging-modes.cc new file mode 100644 index 000000000000..f839ba5e5f50 --- /dev/null +++ b/test/xray/TestCases/Posix/logging-modes.cc @@ -0,0 +1,95 @@ +// Check that we can install an implementation associated with a mode. +// +// RUN: rm -f xray-log.logging-modes* +// RUN: %clangxx_xray -std=c++11 %s -o %t -fxray-modes=none +// RUN: %run %t | FileCheck %s +// +// UNSUPPORTED: target-is-mips64,target-is-mips64el + +#include "xray/xray_interface.h" +#include "xray/xray_log_interface.h" +#include <cassert> +#include <cstdio> +#include <string> + +[[clang::xray_never_instrument]] void printing_handler(int32_t fid, + XRayEntryType) { + thread_local volatile bool printing = false; + if (printing) + return; + printing = true; + std::printf("printing %d\n", fid); + printing = false; +} + +[[clang::xray_never_instrument]] XRayBuffer next_buffer(XRayBuffer buffer) { + static const char data[10] = {}; + static const XRayBuffer first_and_last{data, 10}; + if (buffer.Data == nullptr) + return first_and_last; + if (buffer.Data == first_and_last.Data) + return XRayBuffer{nullptr, 0}; + assert(false && "Invalid buffer provided."); +} + +static constexpr char Options[] = "additional_flags"; + +[[clang::xray_never_instrument]] XRayLogInitStatus +printing_init(size_t BufferSize, size_t MaxBuffers, void *Config, + size_t ArgsSize) { + // We require that the printing init is called through the + // __xray_log_init_mode(...) implementation, and that the promised contract is + // enforced. + assert(BufferSize == 0); + assert(MaxBuffers == 0); + assert(Config != nullptr); + assert(ArgsSize == 0 || ArgsSize == sizeof(Options)); + __xray_log_set_buffer_iterator(next_buffer); + return XRayLogInitStatus::XRAY_LOG_INITIALIZED; +} + +[[clang::xray_never_instrument]] XRayLogInitStatus printing_finalize() { + return XRayLogInitStatus::XRAY_LOG_FINALIZED; +} + +[[clang::xray_never_instrument]] XRayLogFlushStatus printing_flush_log() { + __xray_log_remove_buffer_iterator(); + return XRayLogFlushStatus::XRAY_LOG_FLUSHED; +} + +[[clang::xray_always_instrument]] void callme() { std::printf("called me!\n"); } + +static auto buffer_counter = 0; + +void process_buffer(const char *, XRayBuffer) { ++buffer_counter; } + +int main(int argc, char **argv) { + assert(__xray_log_register_mode("custom", + {printing_init, printing_finalize, + printing_handler, printing_flush_log}) == + XRayLogRegisterStatus::XRAY_REGISTRATION_OK); + assert(__xray_log_select_mode("custom") == + XRayLogRegisterStatus::XRAY_REGISTRATION_OK); + assert(__xray_log_get_current_mode() != nullptr); + std::string current_mode = __xray_log_get_current_mode(); + assert(current_mode == "custom"); + assert(__xray_patch() == XRayPatchingStatus::SUCCESS); + assert(__xray_log_init_mode("custom", "flags_config_here=true") == + XRayLogInitStatus::XRAY_LOG_INITIALIZED); + + // Also test that we can use the "binary" version of the + // __xray_log_niit_mode(...) API. + assert(__xray_log_init_mode_bin("custom", Options, sizeof(Options)) == + XRayLogInitStatus::XRAY_LOG_INITIALIZED); + + // CHECK: printing {{.*}} + callme(); // CHECK: called me! + // CHECK: printing {{.*}} + assert(__xray_log_finalize() == XRayLogInitStatus::XRAY_LOG_FINALIZED); + assert(__xray_log_process_buffers(process_buffer) == + XRayLogFlushStatus::XRAY_LOG_FLUSHED); + assert(buffer_counter == 1); + assert(__xray_log_flushLog() == XRayLogFlushStatus::XRAY_LOG_FLUSHED); + assert(__xray_log_select_mode("not-found") == + XRayLogRegisterStatus::XRAY_MODE_NOT_FOUND); +} diff --git a/test/xray/TestCases/Posix/optional-inmemory-log.cc b/test/xray/TestCases/Posix/optional-inmemory-log.cc new file mode 100644 index 000000000000..feaaa4124750 --- /dev/null +++ b/test/xray/TestCases/Posix/optional-inmemory-log.cc @@ -0,0 +1,23 @@ +// Make sure that we don't get the inmemory logging implementation enabled when +// we turn it off via options. + +// RUN: %clangxx_xray -std=c++11 %s -o %t +// RUN: XRAY_OPTIONS="patch_premain=true verbosity=1 xray_naive_log=false xray_logfile_base=optional-inmemory-log.xray-" %run %t 2>&1 | FileCheck %s +// +// Make sure we clean out the logs in case there was a bug. +// +// RUN: rm -f optional-inmemory-log.xray-* + +// UNSUPPORTED: target-is-mips64,target-is-mips64el + +#include <cstdio> + +[[clang::xray_always_instrument]] void foo() { + printf("foo() is always instrumented!"); +} + +int main() { + // CHECK-NOT: XRay: Log file in 'optional-inmemory-log.xray-{{.*}}' + foo(); + // CHECK: foo() is always instrumented! +} diff --git a/test/xray/TestCases/Posix/patching-unpatching.cc b/test/xray/TestCases/Posix/patching-unpatching.cc new file mode 100644 index 000000000000..a7ea58f6dc69 --- /dev/null +++ b/test/xray/TestCases/Posix/patching-unpatching.cc @@ -0,0 +1,49 @@ +// Check that we can patch and un-patch on demand, and that logging gets invoked +// appropriately. +// +// RUN: %clangxx_xray -fxray-instrument -std=c++11 %s -o %t +// RUN: XRAY_OPTIONS="patch_premain=false" %run %t 2>&1 | FileCheck %s + +// UNSUPPORTED: target-is-mips64,target-is-mips64el + +#include "xray/xray_interface.h" + +#include <cstdio> + +bool called = false; + +void test_handler(int32_t fid, XRayEntryType type) { + printf("called: %d, type=%d\n", fid, static_cast<int32_t>(type)); + called = true; +} + +[[clang::xray_always_instrument]] void always_instrument() { + printf("always instrumented called\n"); +} + +int main() { + __xray_set_handler(test_handler); + always_instrument(); + // CHECK: always instrumented called + auto status = __xray_patch(); + printf("patching status: %d\n", static_cast<int32_t>(status)); + // CHECK-NEXT: patching status: 1 + always_instrument(); + // CHECK-NEXT: called: {{.*}}, type=0 + // CHECK-NEXT: always instrumented called + // CHECK-NEXT: called: {{.*}}, type=1 + status = __xray_unpatch(); + printf("patching status: %d\n", static_cast<int32_t>(status)); + // CHECK-NEXT: patching status: 1 + always_instrument(); + // CHECK-NEXT: always instrumented called + status = __xray_patch(); + printf("patching status: %d\n", static_cast<int32_t>(status)); + // CHECK-NEXT: patching status: 1 + __xray_remove_handler(); + always_instrument(); + // CHECK-NEXT: always instrumented called + status = __xray_unpatch(); + printf("patching status: %d\n", static_cast<int32_t>(status)); + // CHECK-NEXT: patching status: 1 +} diff --git a/test/xray/TestCases/Posix/pic_test.cc b/test/xray/TestCases/Posix/pic_test.cc new file mode 100644 index 000000000000..93e1a6a47d3c --- /dev/null +++ b/test/xray/TestCases/Posix/pic_test.cc @@ -0,0 +1,38 @@ +// Test to check if we handle pic code properly. + +// RUN: %clangxx_xray -fxray-instrument -std=c++11 -ffunction-sections \ +// RUN: -fdata-sections -fpic -fpie -Wl,--gc-sections %s -o %t +// RUN: rm -f pic-test-logging-* +// RUN: XRAY_OPTIONS="patch_premain=true verbosity=1 xray_naive_log=true \ +// RUN: xray_logfile_base=pic-test-logging-" %run %t 2>&1 | FileCheck %s +// After all that, clean up the output xray log. +// +// RUN: rm -f pic-test-logging-* + +// UNSUPPORTED: target-is-mips64,target-is-mips64el + +#include <cstdio> + +[[clang::xray_always_instrument]] +unsigned short foo (unsigned b); + +[[clang::xray_always_instrument]] +unsigned short bar (unsigned short a) +{ + printf("bar() is always instrumented!\n"); + return foo(a); +} + +unsigned short foo (unsigned b) +{ + printf("foo() is always instrumented!\n"); + return b + b + 5; +} + +int main () +{ + // CHECK: XRay: Log file in 'pic-test-logging-{{.*}}' + bar(10); + // CHECK: bar() is always instrumented! + // CHECK-NEXT: foo() is always instrumented! +} diff --git a/test/xray/TestCases/Posix/profiling-multi-threaded.cc b/test/xray/TestCases/Posix/profiling-multi-threaded.cc new file mode 100644 index 000000000000..7ccad1bac1fd --- /dev/null +++ b/test/xray/TestCases/Posix/profiling-multi-threaded.cc @@ -0,0 +1,57 @@ +// Check that we can get a profile from a single-threaded application, on +// demand through the XRay logging implementation API. +// +// FIXME: Make -fxray-modes=xray-profiling part of the default? +// RUN: %clangxx_xray -std=c++11 %s -o %t -fxray-modes=xray-profiling +// RUN: rm -f xray-log.profiling-multi-* +// RUN: XRAY_OPTIONS=verbosity=1 \ +// RUN: XRAY_PROFILING_OPTIONS=no_flush=1 %run %t +// RUN: XRAY_OPTIONS=verbosity=1 %run %t +// RUN: PROFILES=`ls xray-log.profiling-multi-* | wc -l` +// RUN: [ $PROFILES -eq 1 ] +// RUN: rm -f xray-log.profiling-multi-* +// +// REQUIRES: x86_64-target-arch +// REQUIRES: built-in-llvm-tree + +#include "xray/xray_interface.h" +#include "xray/xray_log_interface.h" +#include <cassert> +#include <cstdio> +#include <string> +#include <thread> + +[[clang::xray_always_instrument]] void f2() { return; } +[[clang::xray_always_instrument]] void f1() { f2(); } +[[clang::xray_always_instrument]] void f0() { f1(); } + +using namespace std; + +volatile int buffer_counter = 0; + +[[clang::xray_never_instrument]] void process_buffer(const char *, XRayBuffer) { + // FIXME: Actually assert the contents of the buffer. + ++buffer_counter; +} + +[[clang::xray_always_instrument]] int main(int, char **) { + assert(__xray_log_select_mode("xray-profiling") == + XRayLogRegisterStatus::XRAY_REGISTRATION_OK); + assert(__xray_log_get_current_mode() != nullptr); + std::string current_mode = __xray_log_get_current_mode(); + assert(current_mode == "xray-profiling"); + assert(__xray_patch() == XRayPatchingStatus::SUCCESS); + assert(__xray_log_init(0, 0, nullptr, 0) == + XRayLogInitStatus::XRAY_LOG_INITIALIZED); + std::thread t0([] { f0(); }); + std::thread t1([] { f0(); }); + f0(); + t0.join(); + t1.join(); + assert(__xray_log_finalize() == XRayLogInitStatus::XRAY_LOG_FINALIZED); + assert(__xray_log_process_buffers(process_buffer) == + XRayLogFlushStatus::XRAY_LOG_FLUSHED); + // We're running three threds, so we expect three buffers. + assert(buffer_counter == 3); + assert(__xray_log_flushLog() == XRayLogFlushStatus::XRAY_LOG_FLUSHED); +} diff --git a/test/xray/TestCases/Posix/profiling-single-threaded.cc b/test/xray/TestCases/Posix/profiling-single-threaded.cc new file mode 100644 index 000000000000..fd508b1acd14 --- /dev/null +++ b/test/xray/TestCases/Posix/profiling-single-threaded.cc @@ -0,0 +1,65 @@ +// Check that we can get a profile from a single-threaded application, on +// demand through the XRay logging implementation API. +// +// FIXME: Make -fxray-modes=xray-profiling part of the default? +// RUN: %clangxx_xray -std=c++11 %s -o %t -fxray-modes=xray-profiling +// RUN: rm -f xray-log.profiling-single-* +// RUN: XRAY_OPTIONS=verbosity=1 \ +// RUN: XRAY_PROFILING_OPTIONS=no_flush=true %run %t +// RUN: XRAY_OPTIONS=verbosity=1 %run %t +// RUN: PROFILES=`ls xray-log.profiling-single-* | wc -l` +// RUN: [ $PROFILES -eq 2 ] +// RUN: rm -f xray-log.profiling-single-* +// +// REQUIRES: x86_64-target-arch +// REQUIRES: built-in-llvm-tree + +#include "xray/xray_interface.h" +#include "xray/xray_log_interface.h" +#include <cassert> +#include <cstdio> +#include <string> + +[[clang::xray_always_instrument]] void f2() { return; } +[[clang::xray_always_instrument]] void f1() { f2(); } +[[clang::xray_always_instrument]] void f0() { f1(); } + +using namespace std; + +volatile int buffer_counter = 0; + +[[clang::xray_never_instrument]] void process_buffer(const char *, XRayBuffer) { + // FIXME: Actually assert the contents of the buffer. + ++buffer_counter; +} + +[[clang::xray_always_instrument]] int main(int, char **) { + assert(__xray_log_select_mode("xray-profiling") == + XRayLogRegisterStatus::XRAY_REGISTRATION_OK); + assert(__xray_log_get_current_mode() != nullptr); + std::string current_mode = __xray_log_get_current_mode(); + assert(current_mode == "xray-profiling"); + assert(__xray_patch() == XRayPatchingStatus::SUCCESS); + assert(__xray_log_init_mode("xray-profiling", "") == + XRayLogInitStatus::XRAY_LOG_INITIALIZED); + f0(); + assert(__xray_log_finalize() == XRayLogInitStatus::XRAY_LOG_FINALIZED); + f0(); + assert(__xray_log_process_buffers(process_buffer) == + XRayLogFlushStatus::XRAY_LOG_FLUSHED); + assert(buffer_counter == 1); + assert(__xray_log_flushLog() == XRayLogFlushStatus::XRAY_LOG_FLUSHED); + + // Let's reset the counter. + buffer_counter = 0; + + assert(__xray_log_init_mode("xray-profiling", "") == + XRayLogInitStatus::XRAY_LOG_INITIALIZED); + f0(); + assert(__xray_log_finalize() == XRayLogInitStatus::XRAY_LOG_FINALIZED); + f0(); + assert(__xray_log_process_buffers(process_buffer) == + XRayLogFlushStatus::XRAY_LOG_FLUSHED); + assert(buffer_counter == 1); + assert(__xray_log_flushLog() == XRayLogFlushStatus::XRAY_LOG_FLUSHED); +} diff --git a/test/xray/TestCases/Posix/quiet-start.cc b/test/xray/TestCases/Posix/quiet-start.cc new file mode 100644 index 000000000000..00d5af6609dd --- /dev/null +++ b/test/xray/TestCases/Posix/quiet-start.cc @@ -0,0 +1,26 @@ +// Ensure that we have a quiet startup when we don't have the XRay +// instrumentation sleds. +// +// RUN: %clangxx -std=c++11 %s -o %t %xraylib +// RUN: XRAY_OPTIONS="patch_premain=true verbosity=1" %run %t 2>&1 | \ +// RUN: FileCheck %s --check-prefix NOISY +// RUN: XRAY_OPTIONS="patch_premain=true verbosity=0" %run %t 2>&1 | \ +// RUN: FileCheck %s --check-prefix QUIET +// RUN: XRAY_OPTIONS="" %run %t 2>&1 | FileCheck %s --check-prefix DEFAULT +// +// FIXME: Understand how to make this work on other platforms +// REQUIRES: built-in-llvm-tree +// REQUIRES: x86_64-target-arch +#include <iostream> + +using namespace std; + +int main(int, char**) { + // NOISY: {{.*}}XRay instrumentation map missing. Not initializing XRay. + // QUIET-NOT: {{.*}}XRay instrumentation map missing. Not initializing XRay. + // DEFAULT-NOT: {{.*}}XRay instrumentation map missing. Not initializing XRay. + cout << "Hello, XRay!" << endl; + // NOISY: Hello, XRay! + // QUIET: Hello, XRay! + // DEFAULT: Hello, XRay! +} |