summaryrefslogtreecommitdiffstats
path: root/contrib/compiler-rt/lib/xray/xray_inmemory_log.cc
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/compiler-rt/lib/xray/xray_inmemory_log.cc')
-rw-r--r--contrib/compiler-rt/lib/xray/xray_inmemory_log.cc194
1 files changed, 194 insertions, 0 deletions
diff --git a/contrib/compiler-rt/lib/xray/xray_inmemory_log.cc b/contrib/compiler-rt/lib/xray/xray_inmemory_log.cc
new file mode 100644
index 0000000..adcb216
--- /dev/null
+++ b/contrib/compiler-rt/lib/xray/xray_inmemory_log.cc
@@ -0,0 +1,194 @@
+//===-- xray_inmemory_log.cc ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of XRay, a dynamic runtime instrumentation system.
+//
+// Implementation of a simple in-memory log of XRay events. This defines a
+// logging function that's compatible with the XRay handler interface, and
+// routines for exporting data to files.
+//
+//===----------------------------------------------------------------------===//
+
+#include <cassert>
+#include <cstdint>
+#include <cstdio>
+#include <fcntl.h>
+#include <mutex>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <thread>
+#include <unistd.h>
+
+#if defined(__x86_64__)
+#include "xray_x86_64.h"
+#elif defined(__arm__) || defined(__aarch64__)
+#include "xray_emulate_tsc.h"
+#else
+#error "Unsupported CPU Architecture"
+#endif /* Architecture-specific inline intrinsics */
+
+#include "sanitizer_common/sanitizer_libc.h"
+#include "xray/xray_records.h"
+#include "xray_defs.h"
+#include "xray_flags.h"
+#include "xray_interface_internal.h"
+
+// __xray_InMemoryRawLog will use a thread-local aligned buffer capped to a
+// certain size (32kb by default) and use it as if it were a circular buffer for
+// events. We store simple fixed-sized entries in the log for external analysis.
+
+extern "C" {
+void __xray_InMemoryRawLog(int32_t FuncId,
+ XRayEntryType Type) XRAY_NEVER_INSTRUMENT;
+}
+
+namespace __xray {
+
+std::mutex LogMutex;
+
+static void retryingWriteAll(int Fd, char *Begin,
+ char *End) XRAY_NEVER_INSTRUMENT {
+ if (Begin == End)
+ return;
+ auto TotalBytes = std::distance(Begin, End);
+ while (auto Written = write(Fd, Begin, TotalBytes)) {
+ if (Written < 0) {
+ if (errno == EINTR)
+ continue; // Try again.
+ Report("Failed to write; errno = %d\n", errno);
+ return;
+ }
+ TotalBytes -= Written;
+ if (TotalBytes == 0)
+ break;
+ Begin += Written;
+ }
+}
+
+class ThreadExitFlusher {
+ int Fd;
+ XRayRecord *Start;
+ size_t &Offset;
+
+public:
+ explicit ThreadExitFlusher(int Fd, XRayRecord *Start,
+ size_t &Offset) XRAY_NEVER_INSTRUMENT
+ : Fd(Fd),
+ Start(Start),
+ Offset(Offset) {}
+
+ ~ThreadExitFlusher() XRAY_NEVER_INSTRUMENT {
+ std::lock_guard<std::mutex> L(LogMutex);
+ if (Fd > 0 && Start != nullptr) {
+ retryingWriteAll(Fd, reinterpret_cast<char *>(Start),
+ reinterpret_cast<char *>(Start + Offset));
+ // Because this thread's exit could be the last one trying to write to the
+ // file and that we're not able to close out the file properly, we sync
+ // instead and hope that the pending writes are flushed as the thread
+ // exits.
+ fsync(Fd);
+ }
+ }
+};
+
+} // namespace __xray
+
+using namespace __xray;
+
+void PrintToStdErr(const char *Buffer) XRAY_NEVER_INSTRUMENT {
+ fprintf(stderr, "%s", Buffer);
+}
+
+static int __xray_OpenLogFile() XRAY_NEVER_INSTRUMENT {
+ // FIXME: Figure out how to make this less stderr-dependent.
+ SetPrintfAndReportCallback(PrintToStdErr);
+ // Open a temporary file once for the log.
+ static char TmpFilename[256] = {};
+ static char TmpWildcardPattern[] = "XXXXXX";
+ auto Argv = GetArgv();
+ const char *Progname = Argv[0] == nullptr ? "(unknown)" : Argv[0];
+ const char *LastSlash = internal_strrchr(Progname, '/');
+
+ if (LastSlash != nullptr)
+ Progname = LastSlash + 1;
+
+ const int HalfLength = sizeof(TmpFilename) / 2 - sizeof(TmpWildcardPattern);
+ int NeededLength = internal_snprintf(TmpFilename, sizeof(TmpFilename),
+ "%.*s%.*s.%s",
+ HalfLength, flags()->xray_logfile_base,
+ HalfLength, Progname,
+ TmpWildcardPattern);
+ if (NeededLength > int(sizeof(TmpFilename))) {
+ Report("XRay log file name too long (%d): %s\n", NeededLength, TmpFilename);
+ return -1;
+ }
+ int Fd = mkstemp(TmpFilename);
+ if (Fd == -1) {
+ Report("XRay: Failed opening temporary file '%s'; not logging events.\n",
+ TmpFilename);
+ return -1;
+ }
+ if (Verbosity())
+ fprintf(stderr, "XRay: Log file in '%s'\n", TmpFilename);
+
+ // Since we're here, we get to write the header. We set it up so that the
+ // header will only be written once, at the start, and let the threads
+ // logging do writes which just append.
+ XRayFileHeader Header;
+ Header.Version = 1;
+ Header.Type = FileTypes::NAIVE_LOG;
+ Header.CycleFrequency = __xray::cycleFrequency();
+
+ // FIXME: Actually check whether we have 'constant_tsc' and 'nonstop_tsc'
+ // before setting the values in the header.
+ Header.ConstantTSC = 1;
+ Header.NonstopTSC = 1;
+ retryingWriteAll(Fd, reinterpret_cast<char *>(&Header),
+ reinterpret_cast<char *>(&Header) + sizeof(Header));
+ return Fd;
+}
+
+void __xray_InMemoryRawLog(int32_t FuncId,
+ XRayEntryType Type) XRAY_NEVER_INSTRUMENT {
+ using Buffer =
+ std::aligned_storage<sizeof(XRayRecord), alignof(XRayRecord)>::type;
+ static constexpr size_t BuffLen = 1024;
+ thread_local static Buffer InMemoryBuffer[BuffLen] = {};
+ thread_local static size_t Offset = 0;
+ static int Fd = __xray_OpenLogFile();
+ if (Fd == -1)
+ return;
+ thread_local __xray::ThreadExitFlusher Flusher(
+ Fd, reinterpret_cast<__xray::XRayRecord *>(InMemoryBuffer), Offset);
+ thread_local pid_t TId = syscall(SYS_gettid);
+
+ // First we get the useful data, and stuff it into the already aligned buffer
+ // through a pointer offset.
+ auto &R = reinterpret_cast<__xray::XRayRecord *>(InMemoryBuffer)[Offset];
+ R.RecordType = RecordTypes::NORMAL;
+ R.TSC = __xray::readTSC(R.CPU);
+ R.TId = TId;
+ R.Type = Type;
+ R.FuncId = FuncId;
+ ++Offset;
+ if (Offset == BuffLen) {
+ std::lock_guard<std::mutex> L(LogMutex);
+ auto RecordBuffer = reinterpret_cast<__xray::XRayRecord *>(InMemoryBuffer);
+ retryingWriteAll(Fd, reinterpret_cast<char *>(RecordBuffer),
+ reinterpret_cast<char *>(RecordBuffer + Offset));
+ Offset = 0;
+ }
+}
+
+static auto Unused = [] {
+ if (flags()->xray_naive_log)
+ __xray_set_handler(__xray_InMemoryRawLog);
+ return true;
+}();
OpenPOWER on IntegriCloud