aboutsummaryrefslogtreecommitdiff
path: root/test/xray/TestCases/Posix
diff options
context:
space:
mode:
Diffstat (limited to 'test/xray/TestCases/Posix')
-rw-r--r--test/xray/TestCases/Posix/always-never-instrument.cc23
-rw-r--r--test/xray/TestCases/Posix/arg1-arg0-logging.cc39
-rw-r--r--test/xray/TestCases/Posix/arg1-logger.cc45
-rw-r--r--test/xray/TestCases/Posix/arg1-logging-implicit-this.cc31
-rw-r--r--test/xray/TestCases/Posix/argv0-log-file-name.cc16
-rw-r--r--test/xray/TestCases/Posix/basic-filtering.cc61
-rw-r--r--test/xray/TestCases/Posix/c-test.cc15
-rw-r--r--test/xray/TestCases/Posix/common-trampoline-alignment.cc57
-rw-r--r--test/xray/TestCases/Posix/coverage-sample.cc91
-rw-r--r--test/xray/TestCases/Posix/custom-event-handler-alignment.cc42
-rw-r--r--test/xray/TestCases/Posix/custom-event-logging.cc42
-rw-r--r--test/xray/TestCases/Posix/fdr-mode-inmemory.cc50
-rw-r--r--test/xray/TestCases/Posix/fdr-mode-multiple.cc76
-rw-r--r--test/xray/TestCases/Posix/fdr-mode.cc112
-rw-r--r--test/xray/TestCases/Posix/fdr-single-thread.cc38
-rw-r--r--test/xray/TestCases/Posix/fdr-thread-order.cc67
-rw-r--r--test/xray/TestCases/Posix/fixedsize-logging.cc22
-rw-r--r--test/xray/TestCases/Posix/fork_basic_logging.cc100
-rw-r--r--test/xray/TestCases/Posix/func-id-utils.cc44
-rw-r--r--test/xray/TestCases/Posix/logging-modes.cc95
-rw-r--r--test/xray/TestCases/Posix/optional-inmemory-log.cc23
-rw-r--r--test/xray/TestCases/Posix/patching-unpatching.cc49
-rw-r--r--test/xray/TestCases/Posix/pic_test.cc38
-rw-r--r--test/xray/TestCases/Posix/profiling-multi-threaded.cc57
-rw-r--r--test/xray/TestCases/Posix/profiling-single-threaded.cc65
-rw-r--r--test/xray/TestCases/Posix/quiet-start.cc26
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!
+}