]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/xray/tests/unit/fdr_logging_test.cc
Vendor import of compiler-rt trunk r338536:
[FreeBSD/FreeBSD.git] / lib / xray / tests / unit / fdr_logging_test.cc
1 //===-- fdr_logging_test.cc -----------------------------------------------===//
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 function call tracing system.
11 //
12 //===----------------------------------------------------------------------===//
13 #include "sanitizer_common/sanitizer_common.h"
14 #include "xray_fdr_logging.h"
15 #include "gtest/gtest.h"
16
17 #include <array>
18 #include <fcntl.h>
19 #include <iostream>
20 #include <sys/mman.h>
21 #include <sys/stat.h>
22 #include <sys/syscall.h>
23 #include <sys/types.h>
24 #include <system_error>
25 #include <thread>
26 #include <unistd.h>
27
28 #include "xray/xray_records.h"
29
30 namespace __xray {
31 namespace {
32
33 constexpr auto kBufferSize = 16384;
34 constexpr auto kBufferMax = 10;
35
36 struct ScopedFileCloserAndDeleter {
37   explicit ScopedFileCloserAndDeleter(int Fd, const char *Filename)
38       : Fd(Fd), Filename(Filename) {}
39
40   ~ScopedFileCloserAndDeleter() {
41     if (Map)
42       munmap(Map, Size);
43     if (Fd) {
44       close(Fd);
45       unlink(Filename);
46     }
47   }
48
49   void registerMap(void *M, size_t S) {
50     Map = M;
51     Size = S;
52   }
53
54   int Fd;
55   const char *Filename;
56   void *Map = nullptr;
57   size_t Size = 0;
58 };
59
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);
73
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);
78   ASSERT_NE(-1, Fd);
79   ScopedFileCloserAndDeleter Guard(Fd, TmpFilename);
80   auto Size = lseek(Fd, 0, SEEK_END);
81   ASSERT_NE(Size, 0);
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);
87
88   XRayFileHeader H;
89   memcpy(&H, Contents, sizeof(XRayFileHeader));
90   ASSERT_EQ(H.Version, 3);
91   ASSERT_EQ(H.Type, FileTypes::FDR_LOG);
92
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));
102 }
103
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);
115   }
116   ASSERT_EQ(fdrLoggingFinalize(), XRayLogInitStatus::XRAY_LOG_FINALIZED);
117   ASSERT_EQ(fdrLoggingFlush(), XRayLogFlushStatus::XRAY_LOG_FLUSHED);
118
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);
123   ASSERT_NE(-1, Fd);
124   ScopedFileCloserAndDeleter Guard(Fd, TmpFilename);
125   auto Size = lseek(Fd, 0, SEEK_END);
126   ASSERT_NE(Size, 0);
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);
132
133   XRayFileHeader H;
134   memcpy(&H, Contents, sizeof(XRayFileHeader));
135   ASSERT_EQ(H.Version, 3);
136   ASSERT_EQ(H.Type, FileTypes::FDR_LOG);
137
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));
145 }
146
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);
154
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();
164     }};
165     t.join();
166   }
167   ASSERT_EQ(fdrLoggingFinalize(), XRayLogInitStatus::XRAY_LOG_FINALIZED);
168   ASSERT_EQ(fdrLoggingFlush(), XRayLogFlushStatus::XRAY_LOG_FLUSHED);
169
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);
174   ASSERT_NE(-1, Fd);
175   ScopedFileCloserAndDeleter Guard(Fd, TmpFilename);
176   auto Size = lseek(Fd, 0, SEEK_END);
177   ASSERT_NE(Size, 0);
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);
183
184   XRayFileHeader H;
185   memcpy(&H, Contents, sizeof(XRayFileHeader));
186   ASSERT_EQ(H.Version, 3);
187   ASSERT_EQ(H.Type, FileTypes::FDR_LOG);
188
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));
196   int32_t Latest = 0;
197   memcpy(&Latest, MDR1.Data, sizeof(int32_t));
198   ASSERT_EQ(Latest, static_cast<int32_t>(Threads[1]));
199 }
200
201 } // namespace
202 } // namespace __xray