1 //===-- fdr_logging_test.cc -----------------------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file is a part of XRay, a function call tracing system.
12 //===----------------------------------------------------------------------===//
13 #include "sanitizer_common/sanitizer_common.h"
14 #include "xray_fdr_logging.h"
15 #include "gtest/gtest.h"
22 #include <sys/syscall.h>
23 #include <sys/types.h>
24 #include <system_error>
28 #include "xray/xray_records.h"
33 constexpr auto kBufferSize = 16384;
34 constexpr auto kBufferMax = 10;
36 struct ScopedFileCloserAndDeleter {
37 explicit ScopedFileCloserAndDeleter(int Fd, const char *Filename)
38 : Fd(Fd), Filename(Filename) {}
40 ~ScopedFileCloserAndDeleter() {
49 void registerMap(void *M, size_t S) {
60 TEST(FDRLoggingTest, Simple) {
61 FDRLoggingOptions Options;
62 Options.ReportErrors = true;
63 char TmpFilename[] = "fdr-logging-test.XXXXXX";
64 Options.Fd = mkstemp(TmpFilename);
65 ASSERT_NE(Options.Fd, -1);
66 ASSERT_EQ(fdrLoggingInit(kBufferSize, kBufferMax, &Options,
67 sizeof(FDRLoggingOptions)),
68 XRayLogInitStatus::XRAY_LOG_INITIALIZED);
69 fdrLoggingHandleArg0(1, XRayEntryType::ENTRY);
70 fdrLoggingHandleArg0(1, XRayEntryType::EXIT);
71 ASSERT_EQ(fdrLoggingFinalize(), XRayLogInitStatus::XRAY_LOG_FINALIZED);
72 ASSERT_EQ(fdrLoggingFlush(), XRayLogFlushStatus::XRAY_LOG_FLUSHED);
74 // To do this properly, we have to close the file descriptor then re-open the
75 // file for reading this time.
76 ASSERT_EQ(close(Options.Fd), 0);
77 int Fd = open(TmpFilename, O_RDONLY);
79 ScopedFileCloserAndDeleter Guard(Fd, TmpFilename);
80 auto Size = lseek(Fd, 0, SEEK_END);
82 // Map the file contents.
83 void *Map = mmap(NULL, Size, PROT_READ, MAP_PRIVATE, Fd, 0);
84 const char *Contents = static_cast<const char *>(Map);
85 Guard.registerMap(Map, Size);
86 ASSERT_NE(Contents, nullptr);
89 memcpy(&H, Contents, sizeof(XRayFileHeader));
90 ASSERT_EQ(H.Version, 3);
91 ASSERT_EQ(H.Type, FileTypes::FDR_LOG);
93 // We require one buffer at least to have the "extents" metadata record,
94 // followed by the NewBuffer record.
95 MetadataRecord MDR0, MDR1;
96 memcpy(&MDR0, Contents + sizeof(XRayFileHeader), sizeof(MetadataRecord));
97 memcpy(&MDR1, Contents + sizeof(XRayFileHeader) + sizeof(MetadataRecord),
98 sizeof(MetadataRecord));
99 ASSERT_EQ(MDR0.RecordKind,
100 uint8_t(MetadataRecord::RecordKinds::BufferExtents));
101 ASSERT_EQ(MDR1.RecordKind, uint8_t(MetadataRecord::RecordKinds::NewBuffer));
104 TEST(FDRLoggingTest, Multiple) {
105 FDRLoggingOptions Options;
106 char TmpFilename[] = "fdr-logging-test.XXXXXX";
107 Options.Fd = mkstemp(TmpFilename);
108 ASSERT_NE(Options.Fd, -1);
109 ASSERT_EQ(fdrLoggingInit(kBufferSize, kBufferMax, &Options,
110 sizeof(FDRLoggingOptions)),
111 XRayLogInitStatus::XRAY_LOG_INITIALIZED);
112 for (uint64_t I = 0; I < 100; ++I) {
113 fdrLoggingHandleArg0(1, XRayEntryType::ENTRY);
114 fdrLoggingHandleArg0(1, XRayEntryType::EXIT);
116 ASSERT_EQ(fdrLoggingFinalize(), XRayLogInitStatus::XRAY_LOG_FINALIZED);
117 ASSERT_EQ(fdrLoggingFlush(), XRayLogFlushStatus::XRAY_LOG_FLUSHED);
119 // To do this properly, we have to close the file descriptor then re-open the
120 // file for reading this time.
121 ASSERT_EQ(close(Options.Fd), 0);
122 int Fd = open(TmpFilename, O_RDONLY);
124 ScopedFileCloserAndDeleter Guard(Fd, TmpFilename);
125 auto Size = lseek(Fd, 0, SEEK_END);
127 // Map the file contents.
128 void *Map = mmap(NULL, Size, PROT_READ, MAP_PRIVATE, Fd, 0);
129 const char *Contents = static_cast<const char *>(Map);
130 Guard.registerMap(Map, Size);
131 ASSERT_NE(Contents, nullptr);
134 memcpy(&H, Contents, sizeof(XRayFileHeader));
135 ASSERT_EQ(H.Version, 3);
136 ASSERT_EQ(H.Type, FileTypes::FDR_LOG);
138 MetadataRecord MDR0, MDR1;
139 memcpy(&MDR0, Contents + sizeof(XRayFileHeader), sizeof(MetadataRecord));
140 memcpy(&MDR1, Contents + sizeof(XRayFileHeader) + sizeof(MetadataRecord),
141 sizeof(MetadataRecord));
142 ASSERT_EQ(MDR0.RecordKind,
143 uint8_t(MetadataRecord::RecordKinds::BufferExtents));
144 ASSERT_EQ(MDR1.RecordKind, uint8_t(MetadataRecord::RecordKinds::NewBuffer));
147 TEST(FDRLoggingTest, MultiThreadedCycling) {
148 FDRLoggingOptions Options;
149 char TmpFilename[] = "fdr-logging-test.XXXXXX";
150 Options.Fd = mkstemp(TmpFilename);
151 ASSERT_NE(Options.Fd, -1);
152 ASSERT_EQ(fdrLoggingInit(kBufferSize, 1, &Options, sizeof(FDRLoggingOptions)),
153 XRayLogInitStatus::XRAY_LOG_INITIALIZED);
155 // Now we want to create one thread, do some logging, then create another one,
156 // in succession and making sure that we're able to get thread records from
157 // the latest thread (effectively being able to recycle buffers).
158 std::array<tid_t, 2> Threads;
159 for (uint64_t I = 0; I < 2; ++I) {
160 std::thread t{[I, &Threads] {
161 fdrLoggingHandleArg0(I + 1, XRayEntryType::ENTRY);
162 fdrLoggingHandleArg0(I + 1, XRayEntryType::EXIT);
163 Threads[I] = GetTid();
167 ASSERT_EQ(fdrLoggingFinalize(), XRayLogInitStatus::XRAY_LOG_FINALIZED);
168 ASSERT_EQ(fdrLoggingFlush(), XRayLogFlushStatus::XRAY_LOG_FLUSHED);
170 // To do this properly, we have to close the file descriptor then re-open the
171 // file for reading this time.
172 ASSERT_EQ(close(Options.Fd), 0);
173 int Fd = open(TmpFilename, O_RDONLY);
175 ScopedFileCloserAndDeleter Guard(Fd, TmpFilename);
176 auto Size = lseek(Fd, 0, SEEK_END);
178 // Map the file contents.
179 void *Map = mmap(NULL, Size, PROT_READ, MAP_PRIVATE, Fd, 0);
180 const char *Contents = static_cast<const char *>(Map);
181 Guard.registerMap(Map, Size);
182 ASSERT_NE(Contents, nullptr);
185 memcpy(&H, Contents, sizeof(XRayFileHeader));
186 ASSERT_EQ(H.Version, 3);
187 ASSERT_EQ(H.Type, FileTypes::FDR_LOG);
189 MetadataRecord MDR0, MDR1;
190 memcpy(&MDR0, Contents + sizeof(XRayFileHeader), sizeof(MetadataRecord));
191 memcpy(&MDR1, Contents + sizeof(XRayFileHeader) + sizeof(MetadataRecord),
192 sizeof(MetadataRecord));
193 ASSERT_EQ(MDR0.RecordKind,
194 uint8_t(MetadataRecord::RecordKinds::BufferExtents));
195 ASSERT_EQ(MDR1.RecordKind, uint8_t(MetadataRecord::RecordKinds::NewBuffer));
197 memcpy(&Latest, MDR1.Data, sizeof(int32_t));
198 ASSERT_EQ(Latest, static_cast<int32_t>(Threads[1]));
202 } // namespace __xray