blob: d54fd8f6b85ce58464a8d9e2a0312e9b931a7a78 [file] [log] [blame]
Dean Michael Berrisf50eb932016-08-26 06:39:33 +00001//===-- xray_inmemory_log.cc ------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file is a part of XRay, a dynamic runtime instrumentation system.
11//
12// Implementation of a simple in-memory log of XRay events. This defines a
13// logging function that's compatible with the XRay handler interface, and
14// routines for exporting data to files.
15//
16//===----------------------------------------------------------------------===//
17
18#include <cassert>
Dean Michael Berris8dcba552017-10-05 05:45:51 +000019#include <cstring>
Dean Michael Berris9952d952017-08-02 04:51:40 +000020#include <errno.h>
Dean Michael Berrisf50eb932016-08-26 06:39:33 +000021#include <fcntl.h>
Dean Michael Berris364f11c2017-11-21 07:29:21 +000022#include <pthread.h>
Dean Michael Berrisf50eb932016-08-26 06:39:33 +000023#include <sys/stat.h>
24#include <sys/syscall.h>
25#include <sys/types.h>
Dean Michael Berris9952d952017-08-02 04:51:40 +000026#include <time.h>
Dean Michael Berrisf50eb932016-08-26 06:39:33 +000027#include <unistd.h>
Dean Michael Berrisd1617cd2016-09-20 14:35:57 +000028
Dean Michael Berris364f11c2017-11-21 07:29:21 +000029#include "sanitizer_common/sanitizer_allocator_internal.h"
Dean Michael Berrisf50eb932016-08-26 06:39:33 +000030#include "sanitizer_common/sanitizer_libc.h"
31#include "xray/xray_records.h"
Dean Michael Berris4031e4b2016-11-16 01:01:13 +000032#include "xray_defs.h"
Dean Michael Berrisf50eb932016-08-26 06:39:33 +000033#include "xray_flags.h"
Dean Michael Berris364f11c2017-11-21 07:29:21 +000034#include "xray_inmemory_log.h"
Dean Michael Berrisf50eb932016-08-26 06:39:33 +000035#include "xray_interface_internal.h"
Tim Shen7d0bffb2017-02-10 20:30:43 +000036#include "xray_tsc.h"
Dean Michael Berrise7dbebf2017-01-25 03:50:46 +000037#include "xray_utils.h"
Dean Michael Berrisf50eb932016-08-26 06:39:33 +000038
Dean Michael Berrisf50eb932016-08-26 06:39:33 +000039namespace __xray {
40
Dean Michael Berris9952d952017-08-02 04:51:40 +000041__sanitizer::SpinMutex LogMutex;
Dean Michael Berrisf50eb932016-08-26 06:39:33 +000042
Dean Michael Berris364f11c2017-11-21 07:29:21 +000043// We use elements of this type to record the entry TSC of every function ID we
44// see as we're tracing a particular thread's execution.
Dean Michael Berris52517d72017-12-05 12:21:14 +000045struct alignas(16) StackEntry {
Dean Michael Berris364f11c2017-11-21 07:29:21 +000046 int32_t FuncId;
Dean Michael Berris52517d72017-12-05 12:21:14 +000047 uint16_t Type;
48 uint8_t CPU;
49 uint8_t Padding;
Dean Michael Berris364f11c2017-11-21 07:29:21 +000050 uint64_t TSC;
Dean Michael Berrisf50eb932016-08-26 06:39:33 +000051};
52
Dean Michael Berris52517d72017-12-05 12:21:14 +000053static_assert(sizeof(StackEntry) == 16, "Wrong size for StackEntry");
54
Dean Michael Berris364f11c2017-11-21 07:29:21 +000055struct alignas(64) ThreadLocalData {
Dean Michael Berris52517d72017-12-05 12:21:14 +000056 void *InMemoryBuffer = nullptr;
Dean Michael Berris364f11c2017-11-21 07:29:21 +000057 size_t BufferSize = 0;
58 size_t BufferOffset = 0;
Dean Michael Berris52517d72017-12-05 12:21:14 +000059 void *ShadowStack = nullptr;
Dean Michael Berris364f11c2017-11-21 07:29:21 +000060 size_t StackSize = 0;
61 size_t StackEntries = 0;
62 int Fd = -1;
Dean Michael Berris52517d72017-12-05 12:21:14 +000063 pid_t TID = 0;
Dean Michael Berris364f11c2017-11-21 07:29:21 +000064};
Dean Michael Berrisf50eb932016-08-26 06:39:33 +000065
Dean Michael Berris364f11c2017-11-21 07:29:21 +000066static pthread_key_t PThreadKey;
Dean Michael Berrisf50eb932016-08-26 06:39:33 +000067
Dean Michael Berris364f11c2017-11-21 07:29:21 +000068static __sanitizer::atomic_uint8_t BasicInitialized{0};
69
70BasicLoggingOptions GlobalOptions;
71
Dean Michael Berris52517d72017-12-05 12:21:14 +000072thread_local volatile bool RecursionGuard = false;
73
74static uint64_t thresholdTicks() XRAY_NEVER_INSTRUMENT {
75 static uint64_t TicksPerSec = probeRequiredCPUFeatures()
76 ? getTSCFrequency()
77 : __xray::NanosecondsPerSecond;
78 static const uint64_t ThresholdTicks =
79 TicksPerSec * GlobalOptions.DurationFilterMicros / 1000000;
80 return ThresholdTicks;
81}
Dean Michael Berris364f11c2017-11-21 07:29:21 +000082
83static int openLogFile() XRAY_NEVER_INSTRUMENT {
Dean Michael Berrise7dbebf2017-01-25 03:50:46 +000084 int F = getLogFD();
Dean Michael Berrise7dbebf2017-01-25 03:50:46 +000085 if (F == -1)
Dean Michael Berris0aba3572017-01-03 04:04:00 +000086 return -1;
Douglas Yung8439c8e2017-04-18 03:25:11 +000087
88 // Test for required CPU features and cache the cycle frequency
89 static bool TSCSupported = probeRequiredCPUFeatures();
Dean Michael Berris8dcba552017-10-05 05:45:51 +000090 static uint64_t CycleFrequency =
91 TSCSupported ? getTSCFrequency() : __xray::NanosecondsPerSecond;
Douglas Yung8439c8e2017-04-18 03:25:11 +000092
Dean Michael Berris0aba3572017-01-03 04:04:00 +000093 // Since we're here, we get to write the header. We set it up so that the
94 // header will only be written once, at the start, and let the threads
95 // logging do writes which just append.
96 XRayFileHeader Header;
Dean Michael Berris8dcba552017-10-05 05:45:51 +000097 Header.Version = 2; // Version 2 includes tail exit records.
Dean Michael Berris0aba3572017-01-03 04:04:00 +000098 Header.Type = FileTypes::NAIVE_LOG;
Douglas Yung8439c8e2017-04-18 03:25:11 +000099 Header.CycleFrequency = CycleFrequency;
Dean Michael Berris0aba3572017-01-03 04:04:00 +0000100
101 // FIXME: Actually check whether we have 'constant_tsc' and 'nonstop_tsc'
102 // before setting the values in the header.
103 Header.ConstantTSC = 1;
104 Header.NonstopTSC = 1;
Dean Michael Berrise7dbebf2017-01-25 03:50:46 +0000105 retryingWriteAll(F, reinterpret_cast<char *>(&Header),
Dean Michael Berris0aba3572017-01-03 04:04:00 +0000106 reinterpret_cast<char *>(&Header) + sizeof(Header));
Dean Michael Berrise7dbebf2017-01-25 03:50:46 +0000107 return F;
Dean Michael Berris0aba3572017-01-03 04:04:00 +0000108}
109
Dean Michael Berris8dcba552017-10-05 05:45:51 +0000110int getGlobalFd() XRAY_NEVER_INSTRUMENT {
Dean Michael Berris364f11c2017-11-21 07:29:21 +0000111 static int Fd = openLogFile();
Dean Michael Berris8dcba552017-10-05 05:45:51 +0000112 return Fd;
113}
114
Dean Michael Berris364f11c2017-11-21 07:29:21 +0000115ThreadLocalData &getThreadLocalData() XRAY_NEVER_INSTRUMENT {
116 thread_local ThreadLocalData TLD;
117 thread_local bool UNUSED TOnce = [] {
Dean Michael Berris52517d72017-12-05 12:21:14 +0000118 if (GlobalOptions.ThreadBufferSize == 0) {
119 if (__sanitizer::Verbosity())
120 Report("Not initializing TLD since ThreadBufferSize == 0.\n");
Dean Michael Berris364f11c2017-11-21 07:29:21 +0000121 return false;
Dean Michael Berris52517d72017-12-05 12:21:14 +0000122 }
123 TLD.TID = __sanitizer::GetTid();
Dean Michael Berris364f11c2017-11-21 07:29:21 +0000124 pthread_setspecific(PThreadKey, &TLD);
125 TLD.Fd = getGlobalFd();
126 TLD.InMemoryBuffer = reinterpret_cast<XRayRecord *>(
127 InternalAlloc(sizeof(XRayRecord) * GlobalOptions.ThreadBufferSize,
128 nullptr, alignof(XRayRecord)));
129 TLD.BufferSize = GlobalOptions.ThreadBufferSize;
130 TLD.BufferOffset = 0;
Dean Michael Berris52517d72017-12-05 12:21:14 +0000131 if (GlobalOptions.MaxStackDepth == 0) {
132 if (__sanitizer::Verbosity())
133 Report("Not initializing the ShadowStack since MaxStackDepth == 0.\n");
134 TLD.StackSize = 0;
135 TLD.StackEntries = 0;
136 TLD.ShadowStack = nullptr;
Dean Michael Berris364f11c2017-11-21 07:29:21 +0000137 return false;
Dean Michael Berris52517d72017-12-05 12:21:14 +0000138 }
Dean Michael Berris364f11c2017-11-21 07:29:21 +0000139 TLD.ShadowStack = reinterpret_cast<StackEntry *>(
140 InternalAlloc(sizeof(StackEntry) * GlobalOptions.MaxStackDepth, nullptr,
141 alignof(StackEntry)));
142 TLD.StackSize = GlobalOptions.MaxStackDepth;
143 TLD.StackEntries = 0;
Dean Michael Berris52517d72017-12-05 12:21:14 +0000144 if (__sanitizer::Verbosity() >= 2) {
145 static auto UNUSED Once = [] {
146 auto ticks = thresholdTicks();
147 Report("Ticks threshold: %d\n", ticks);
148 return false;
149 }();
150 }
Dean Michael Berris364f11c2017-11-21 07:29:21 +0000151 return false;
152 }();
153 return TLD;
154}
155
Dean Michael Berris66443d82017-03-15 02:28:00 +0000156template <class RDTSC>
Dean Michael Berris364f11c2017-11-21 07:29:21 +0000157void InMemoryRawLog(int32_t FuncId, XRayEntryType Type,
158 RDTSC ReadTSC) XRAY_NEVER_INSTRUMENT {
159 auto &TLD = getThreadLocalData();
Dean Michael Berris8dcba552017-10-05 05:45:51 +0000160 int Fd = getGlobalFd();
Dean Michael Berrisf50eb932016-08-26 06:39:33 +0000161 if (Fd == -1)
162 return;
Dean Michael Berrisf50eb932016-08-26 06:39:33 +0000163
Dean Michael Berris484fe0a2017-09-18 06:18:03 +0000164 // Use a simple recursion guard, to handle cases where we're already logging
165 // and for one reason or another, this function gets called again in the same
166 // thread.
Dean Michael Berris52517d72017-12-05 12:21:14 +0000167 if (RecursionGuard)
Dean Michael Berris8dcba552017-10-05 05:45:51 +0000168 return;
Dean Michael Berris52517d72017-12-05 12:21:14 +0000169 RecursionGuard = true;
170 auto ExitGuard = __sanitizer::at_scope_exit([] { RecursionGuard = false; });
Dean Michael Berris484fe0a2017-09-18 06:18:03 +0000171
Dean Michael Berris52517d72017-12-05 12:21:14 +0000172 uint8_t CPU = 0;
173 uint64_t TSC = ReadTSC(CPU);
174
175 switch (Type) {
176 case XRayEntryType::ENTRY:
177 case XRayEntryType::LOG_ARGS_ENTRY: {
178 // Short circuit if we've reached the maximum depth of the stack.
179 if (TLD.StackEntries++ >= TLD.StackSize)
180 return;
181
182 // When we encounter an entry event, we keep track of the TSC and the CPU,
183 // and put it in the stack.
184 StackEntry E;
185 E.FuncId = FuncId;
186 E.CPU = CPU;
187 E.Type = Type;
188 E.TSC = TSC;
189 auto StackEntryPtr = static_cast<char *>(TLD.ShadowStack) +
190 (sizeof(StackEntry) * (TLD.StackEntries - 1));
191 __sanitizer::internal_memcpy(StackEntryPtr, &E, sizeof(StackEntry));
192 break;
193 }
194 case XRayEntryType::EXIT:
195 case XRayEntryType::TAIL: {
196 if (TLD.StackEntries == 0)
197 break;
198
199 if (--TLD.StackEntries >= TLD.StackSize)
200 return;
201
202 // When we encounter an exit event, we check whether all the following are
203 // true:
204 //
205 // - The Function ID is the same as the most recent entry in the stack.
206 // - The CPU is the same as the most recent entry in the stack.
207 // - The Delta of the TSCs is less than the threshold amount of time we're
208 // looking to record.
209 //
210 // If all of these conditions are true, we pop the stack and don't write a
211 // record and move the record offset back.
212 StackEntry StackTop;
213 auto StackEntryPtr = static_cast<char *>(TLD.ShadowStack) +
214 (sizeof(StackEntry) * TLD.StackEntries);
215 __sanitizer::internal_memcpy(&StackTop, StackEntryPtr, sizeof(StackEntry));
216 if (StackTop.FuncId == FuncId && StackTop.CPU == CPU &&
217 StackTop.TSC < TSC) {
218 auto Delta = TSC - StackTop.TSC;
219 if (Delta < thresholdTicks()) {
220 assert(TLD.BufferOffset > 0);
221 TLD.BufferOffset -= StackTop.Type == XRayEntryType::ENTRY ? 1 : 2;
222 return;
223 }
224 }
225 break;
226 }
227 default:
228 // Should be unreachable.
229 assert(false && "Unsupported XRayEntryType encountered.");
230 break;
231 }
232
233 // First determine whether the delta between the function's enter record and
234 // the exit record is higher than the threshold.
235 __xray::XRayRecord R;
Dean Michael Berrisf50eb932016-08-26 06:39:33 +0000236 R.RecordType = RecordTypes::NORMAL;
Dean Michael Berris52517d72017-12-05 12:21:14 +0000237 R.CPU = CPU;
238 R.TSC = TSC;
239 R.TId = TLD.TID;
Dean Michael Berrisf50eb932016-08-26 06:39:33 +0000240 R.Type = Type;
241 R.FuncId = FuncId;
Martin Pelikan4834bca2018-01-19 13:18:40 +0000242 auto FirstEntry = reinterpret_cast<__xray::XRayRecord *>(TLD.InMemoryBuffer);
243 __sanitizer::internal_memcpy(FirstEntry + TLD.BufferOffset, &R, sizeof(R));
Dean Michael Berris52517d72017-12-05 12:21:14 +0000244 if (++TLD.BufferOffset == TLD.BufferSize) {
Dean Michael Berris9952d952017-08-02 04:51:40 +0000245 __sanitizer::SpinMutexLock L(&LogMutex);
Martin Pelikan4834bca2018-01-19 13:18:40 +0000246 retryingWriteAll(Fd, reinterpret_cast<char *>(FirstEntry),
247 reinterpret_cast<char *>(FirstEntry + TLD.BufferOffset));
Dean Michael Berris52517d72017-12-05 12:21:14 +0000248 TLD.BufferOffset = 0;
249 TLD.StackEntries = 0;
Dean Michael Berrisf50eb932016-08-26 06:39:33 +0000250 }
251}
252
Dean Michael Berris8dcba552017-10-05 05:45:51 +0000253template <class RDTSC>
Dean Michael Berris364f11c2017-11-21 07:29:21 +0000254void InMemoryRawLogWithArg(int32_t FuncId, XRayEntryType Type, uint64_t Arg1,
255 RDTSC ReadTSC) XRAY_NEVER_INSTRUMENT {
256 auto &TLD = getThreadLocalData();
Martin Pelikan4834bca2018-01-19 13:18:40 +0000257 auto FirstEntry =
258 reinterpret_cast<__xray::XRayArgPayload *>(TLD.InMemoryBuffer);
Dean Michael Berris364f11c2017-11-21 07:29:21 +0000259 const auto &BuffLen = TLD.BufferSize;
Dean Michael Berris8dcba552017-10-05 05:45:51 +0000260 int Fd = getGlobalFd();
261 if (Fd == -1)
262 return;
263
264 // First we check whether there's enough space to write the data consecutively
265 // in the thread-local buffer. If not, we first flush the buffer before
266 // attempting to write the two records that must be consecutive.
Martin Pelikan4834bca2018-01-19 13:18:40 +0000267 if (TLD.BufferOffset + 2 > BuffLen) {
Dean Michael Berris8dcba552017-10-05 05:45:51 +0000268 __sanitizer::SpinMutexLock L(&LogMutex);
Martin Pelikan4834bca2018-01-19 13:18:40 +0000269 retryingWriteAll(Fd, reinterpret_cast<char *>(FirstEntry),
270 reinterpret_cast<char *>(FirstEntry + TLD.BufferOffset));
271 TLD.BufferOffset = 0;
Dean Michael Berris52517d72017-12-05 12:21:14 +0000272 TLD.StackEntries = 0;
Dean Michael Berris8dcba552017-10-05 05:45:51 +0000273 }
274
275 // Then we write the "we have an argument" record.
Dean Michael Berris364f11c2017-11-21 07:29:21 +0000276 InMemoryRawLog(FuncId, Type, ReadTSC);
Dean Michael Berris8dcba552017-10-05 05:45:51 +0000277
Dean Michael Berris52517d72017-12-05 12:21:14 +0000278 if (RecursionGuard)
Dean Michael Berris8dcba552017-10-05 05:45:51 +0000279 return;
Dean Michael Berris52517d72017-12-05 12:21:14 +0000280 RecursionGuard = true;
281 auto ExitGuard = __sanitizer::at_scope_exit([] { RecursionGuard = false; });
Dean Michael Berris8dcba552017-10-05 05:45:51 +0000282
283 // And from here on write the arg payload.
284 __xray::XRayArgPayload R;
285 R.RecordType = RecordTypes::ARG_PAYLOAD;
286 R.FuncId = FuncId;
Dean Michael Berris52517d72017-12-05 12:21:14 +0000287 R.TId = TLD.TID;
Dean Michael Berris8dcba552017-10-05 05:45:51 +0000288 R.Arg = Arg1;
Martin Pelikan4834bca2018-01-19 13:18:40 +0000289 __sanitizer::internal_memcpy(FirstEntry + TLD.BufferOffset, &R, sizeof(R));
290 if (++TLD.BufferOffset == BuffLen) {
Dean Michael Berris8dcba552017-10-05 05:45:51 +0000291 __sanitizer::SpinMutexLock L(&LogMutex);
Martin Pelikan4834bca2018-01-19 13:18:40 +0000292 retryingWriteAll(Fd, reinterpret_cast<char *>(FirstEntry),
293 reinterpret_cast<char *>(FirstEntry + TLD.BufferOffset));
294 TLD.BufferOffset = 0;
Dean Michael Berris52517d72017-12-05 12:21:14 +0000295 TLD.StackEntries = 0;
Dean Michael Berris8dcba552017-10-05 05:45:51 +0000296 }
Dean Michael Berris8dcba552017-10-05 05:45:51 +0000297}
298
Dean Michael Berris364f11c2017-11-21 07:29:21 +0000299void basicLoggingHandleArg0RealTSC(int32_t FuncId,
300 XRayEntryType Type) XRAY_NEVER_INSTRUMENT {
301 InMemoryRawLog(FuncId, Type, __xray::readTSC);
Dean Michael Berris66443d82017-03-15 02:28:00 +0000302}
303
Dean Michael Berris364f11c2017-11-21 07:29:21 +0000304void basicLoggingHandleArg0EmulateTSC(int32_t FuncId, XRayEntryType Type)
305 XRAY_NEVER_INSTRUMENT {
306 InMemoryRawLog(FuncId, Type, [](uint8_t &CPU) XRAY_NEVER_INSTRUMENT {
Dean Michael Berris66443d82017-03-15 02:28:00 +0000307 timespec TS;
308 int result = clock_gettime(CLOCK_REALTIME, &TS);
309 if (result != 0) {
310 Report("clock_gettimg(2) return %d, errno=%d.", result, int(errno));
311 TS = {0, 0};
312 }
313 CPU = 0;
314 return TS.tv_sec * __xray::NanosecondsPerSecond + TS.tv_nsec;
315 });
316}
317
Dean Michael Berris364f11c2017-11-21 07:29:21 +0000318void basicLoggingHandleArg1RealTSC(int32_t FuncId, XRayEntryType Type,
319 uint64_t Arg1) XRAY_NEVER_INSTRUMENT {
320 InMemoryRawLogWithArg(FuncId, Type, Arg1, __xray::readTSC);
Dean Michael Berris8dcba552017-10-05 05:45:51 +0000321}
322
Dean Michael Berris364f11c2017-11-21 07:29:21 +0000323void basicLoggingHandleArg1EmulateTSC(int32_t FuncId, XRayEntryType Type,
324 uint64_t Arg1) XRAY_NEVER_INSTRUMENT {
325 InMemoryRawLogWithArg(
Dean Michael Berris8dcba552017-10-05 05:45:51 +0000326 FuncId, Type, Arg1, [](uint8_t &CPU) XRAY_NEVER_INSTRUMENT {
327 timespec TS;
328 int result = clock_gettime(CLOCK_REALTIME, &TS);
329 if (result != 0) {
330 Report("clock_gettimg(2) return %d, errno=%d.", result, int(errno));
331 TS = {0, 0};
332 }
333 CPU = 0;
334 return TS.tv_sec * __xray::NanosecondsPerSecond + TS.tv_nsec;
335 });
336}
337
Dean Michael Berris52517d72017-12-05 12:21:14 +0000338static void TLDDestructor(void *P) XRAY_NEVER_INSTRUMENT {
339 ThreadLocalData &TLD = *reinterpret_cast<ThreadLocalData *>(P);
340 auto ExitGuard = __sanitizer::at_scope_exit([&TLD] {
341 // Clean up dynamic resources.
342 if (TLD.InMemoryBuffer)
343 InternalFree(TLD.InMemoryBuffer);
344 if (TLD.ShadowStack)
345 InternalFree(TLD.ShadowStack);
346 if (__sanitizer::Verbosity())
347 Report("Cleaned up log for TID: %d\n", TLD.TID);
348 });
349
350 if (TLD.Fd == -1 || TLD.BufferOffset == 0) {
351 if (__sanitizer::Verbosity())
352 Report("Skipping buffer for TID: %d; Fd = %d; Offset = %llu\n", TLD.TID,
353 TLD.Fd, TLD.BufferOffset);
354 return;
355 }
356
357 {
358 __sanitizer::SpinMutexLock L(&LogMutex);
359 retryingWriteAll(TLD.Fd, reinterpret_cast<char *>(TLD.InMemoryBuffer),
360 reinterpret_cast<char *>(TLD.InMemoryBuffer) +
361 (sizeof(__xray::XRayRecord) * TLD.BufferOffset));
362 }
363
364 // Because this thread's exit could be the last one trying to write to
365 // the file and that we're not able to close out the file properly, we
366 // sync instead and hope that the pending writes are flushed as the
367 // thread exits.
368 fsync(TLD.Fd);
369}
370
Dean Michael Berris364f11c2017-11-21 07:29:21 +0000371XRayLogInitStatus basicLoggingInit(size_t BufferSize, size_t BufferMax,
372 void *Options,
373 size_t OptionsSize) XRAY_NEVER_INSTRUMENT {
374 static bool UNUSED Once = [] {
Dean Michael Berris52517d72017-12-05 12:21:14 +0000375 pthread_key_create(&PThreadKey, TLDDestructor);
Dean Michael Berris364f11c2017-11-21 07:29:21 +0000376 return false;
377 }();
378
379 uint8_t Expected = 0;
380 if (!__sanitizer::atomic_compare_exchange_strong(
381 &BasicInitialized, &Expected, 1, __sanitizer::memory_order_acq_rel)) {
382 if (__sanitizer::Verbosity())
383 Report("Basic logging already initialized.\n");
384 return XRayLogInitStatus::XRAY_LOG_INITIALIZED;
Dean Michael Berris8dcba552017-10-05 05:45:51 +0000385 }
386
Dean Michael Berris364f11c2017-11-21 07:29:21 +0000387 if (OptionsSize != sizeof(BasicLoggingOptions)) {
388 Report("Invalid options size, potential ABI mismatch; expected %d got %d",
389 sizeof(BasicLoggingOptions), OptionsSize);
390 return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED;
391 }
392
393 static auto UseRealTSC = probeRequiredCPUFeatures();
394 if (!UseRealTSC && __sanitizer::Verbosity())
395 Report("WARNING: Required CPU features missing for XRay instrumentation, "
396 "using emulation instead.\n");
397
398 GlobalOptions = *reinterpret_cast<BasicLoggingOptions *>(Options);
399 __xray_set_handler_arg1(UseRealTSC ? basicLoggingHandleArg1RealTSC
400 : basicLoggingHandleArg1EmulateTSC);
401 __xray_set_handler(UseRealTSC ? basicLoggingHandleArg0RealTSC
402 : basicLoggingHandleArg0EmulateTSC);
403 __xray_remove_customevent_handler();
Dean Michael Berris52517d72017-12-05 12:21:14 +0000404
Dean Michael Berris364f11c2017-11-21 07:29:21 +0000405 return XRayLogInitStatus::XRAY_LOG_INITIALIZED;
406}
407
408XRayLogInitStatus basicLoggingFinalize() XRAY_NEVER_INSTRUMENT {
409 uint8_t Expected = 0;
410 if (!__sanitizer::atomic_compare_exchange_strong(
411 &BasicInitialized, &Expected, 0, __sanitizer::memory_order_acq_rel) &&
412 __sanitizer::Verbosity())
413 Report("Basic logging already finalized.\n");
414
415 // Nothing really to do aside from marking state of the global to be
416 // uninitialized.
417
418 return XRayLogInitStatus::XRAY_LOG_FINALIZED;
419}
420
421XRayLogFlushStatus basicLoggingFlush() XRAY_NEVER_INSTRUMENT {
422 // This really does nothing, since flushing the logs happen at the end of a
423 // thread's lifetime, or when the buffers are full.
424 return XRayLogFlushStatus::XRAY_LOG_FLUSHED;
425}
426
427// This is a handler that, effectively, does nothing.
428void basicLoggingHandleArg0Empty(int32_t, XRayEntryType) XRAY_NEVER_INSTRUMENT {
429}
430
431bool basicLogDynamicInitializer() XRAY_NEVER_INSTRUMENT {
Dean Michael Berrisc360f412017-12-05 12:08:56 +0000432 XRayLogImpl Impl{
433 basicLoggingInit,
434 basicLoggingFinalize,
435 basicLoggingHandleArg0Empty,
436 basicLoggingFlush,
437 };
438 auto RegistrationResult = __xray_log_register_mode("xray-basic", Impl);
439 if (RegistrationResult != XRayLogRegisterStatus::XRAY_REGISTRATION_OK &&
440 __sanitizer::Verbosity())
441 Report("Cannot register XRay Basic Mode to 'xray-basic'; error = %d\n",
442 RegistrationResult);
443 if (flags()->xray_naive_log ||
444 !__sanitizer::internal_strcmp(flags()->xray_mode, "xray-basic")) {
Dean Michael Berris364f11c2017-11-21 07:29:21 +0000445 __xray_set_log_impl(Impl);
446 BasicLoggingOptions Options;
447 Options.DurationFilterMicros =
448 flags()->xray_naive_log_func_duration_threshold_us;
449 Options.MaxStackDepth = flags()->xray_naive_log_max_stack_depth;
450 Options.ThreadBufferSize = flags()->xray_naive_log_thread_buffer_size;
451 __xray_log_init(flags()->xray_naive_log_thread_buffer_size, 0, &Options,
452 sizeof(BasicLoggingOptions));
Dean Michael Berris52517d72017-12-05 12:21:14 +0000453 static auto UNUSED Once = [] {
454 static auto UNUSED &TLD = getThreadLocalData();
Dean Michael Berris21d0d532017-12-05 13:40:01 +0000455 __sanitizer::Atexit(+[] { TLDDestructor(&TLD); });
Dean Michael Berris52517d72017-12-05 12:21:14 +0000456 return false;
457 }();
Dean Michael Berris364f11c2017-11-21 07:29:21 +0000458 }
Dean Michael Berrisf50eb932016-08-26 06:39:33 +0000459 return true;
Dean Michael Berris364f11c2017-11-21 07:29:21 +0000460}
461
462} // namespace __xray
463
464static auto UNUSED Unused = __xray::basicLogDynamicInitializer();