LLVM 23.0.0git
OnDiskCASLogger.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9/// \file
10/// This file implements OnDiskCASLogger. The logger will write the timestamp
11/// and events to a log file using filestream. The logger should be thread-safe
12/// and process-safe because each write is small enough to atomically update the
13/// file.
14///
15/// The logger can be enabled via `LLVM_CAS_LOG` environmental variable.
16//
17//===----------------------------------------------------------------------===//
18
20
22#include "llvm/ADT/Twine.h"
23#include "llvm/Support/Error.h"
25#include "llvm/Support/Path.h"
29#ifdef __APPLE__
30#include <sys/time.h>
31#endif
32
33using namespace llvm;
34using namespace llvm::cas;
35using namespace llvm::cas::ondisk;
36
37// The version number in this log should be bumped if the log format is changed
38// in an incompatible way. It is currently a human-readable text file, so in
39// practice this would be if the log changed to binary or other machine-
40// readable format.
41static constexpr StringLiteral Filename = "v1.log";
42
43OnDiskCASLogger::OnDiskCASLogger(raw_fd_ostream &OS, bool LogAllocations)
44 : OS(OS), LogAllocations(LogAllocations) {}
45
47 OS.flush();
48 delete &OS;
49}
50
51static bool isDisabledEnv(StringRef V) {
52 return StringSwitch<bool>(V)
53 .Case("0", true)
54 .CaseLower("no", true)
55 .CaseLower("false", true)
56 .Default(false);
57}
58
59Expected<std::unique_ptr<OnDiskCASLogger>>
61 const char *V = getenv("LLVM_CAS_LOG");
62 if (V && !isDisabledEnv(V)) {
63 int LogLevel = -1;
64 StringRef(V).getAsInteger(10, LogLevel);
65 return OnDiskCASLogger::open(Path, /*LogAllocations=*/LogLevel > 1 ? true
66 : false);
67 }
68 return nullptr;
69}
71OnDiskCASLogger::open(const Twine &Path, bool LogAllocations) {
72 std::error_code EC;
73 SmallString<128> FullPath;
74 Path.toVector(FullPath);
75 sys::path::append(FullPath, Filename);
76
77 auto OS =
78 std::make_unique<raw_fd_ostream>(FullPath, EC, sys::fs::CD_OpenAlways,
80 if (EC)
81 return createFileError(FullPath, EC);
82
83 // Buffer is not thread-safe.
84 OS->SetUnbuffered();
85
86 return std::unique_ptr<OnDiskCASLogger>(
87 new OnDiskCASLogger{*OS.release(), LogAllocations});
88}
89
91#ifdef __APPLE__
92 // Using chrono is roughly 50% slower.
93 struct timeval T;
94 gettimeofday(&T, 0);
95 return T.tv_sec * 1000 + T.tv_usec / 1000;
96#else
97 auto Time = std::chrono::system_clock::now();
98 auto Millis = std::chrono::duration_cast<std::chrono::milliseconds>(
99 Time.time_since_epoch());
100 return Millis.count();
101#endif
102}
103
104namespace {
105/// Helper to log a single line that adds the timestamp, pid, and tid. The line
106/// is buffered and written in a single call to write() so that if the
107/// underlying OS syscall is handled atomically so is this log message.
108class TextLogLine : public raw_svector_ostream {
109public:
110 TextLogLine(raw_ostream &LogOS) : raw_svector_ostream(Buffer), LogOS(LogOS) {
111 startLogMsg(*this);
112 }
113
114 ~TextLogLine() {
115 finishLogMsg(*this);
116 LogOS.write(Buffer.data(), Buffer.size());
117 }
118
119 static void startLogMsg(raw_ostream &OS) {
120 auto Millis = getTimestampMillis();
121 OS << format("%lld.%0.3lld", Millis / 1000, Millis % 1000);
122 OS << ' ' << sys::Process::getProcessId() << ' ' << get_threadid() << ": ";
123 }
124
125 static void finishLogMsg(raw_ostream &OS) { OS << '\n'; }
126
127private:
128 raw_ostream &LogOS;
129 SmallString<128> Buffer;
130};
131} // anonymous namespace
132
133static void formatTrieOffset(raw_ostream &OS, int64_t Off) {
134 if (Off < 0) {
135 OS << '-';
136 Off = -Off;
137 }
138 OS << format_hex(Off, 0);
139}
140
142 size_t SlotI, TrieOffset Expected,
143 TrieOffset New,
144 TrieOffset Previous) {
145 TextLogLine Log(OS);
146 Log << "cmpxcgh subtrie region=" << Region << " offset=";
147 formatTrieOffset(Log, Trie);
148 Log << " slot=" << SlotI << " expected=";
150 Log << " new=";
151 formatTrieOffset(Log, New);
152 Log << " prev=";
153 formatTrieOffset(Log, Previous);
154}
155
157 uint32_t StartBit,
158 uint32_t NumBits) {
159 TextLogLine Log(OS);
160 Log << "create subtrie region=" << Region << " offset=";
161 formatTrieOffset(Log, Trie);
162 Log << " start-bit=" << StartBit << " num-bits=" << NumBits;
163}
164
166 void *Region, TrieOffset Off, ArrayRef<uint8_t> Hash) {
167 TextLogLine Log(OS);
168 Log << "create record region=" << Region << " offset=";
169 formatTrieOffset(Log, Off);
170 Log << " hash=" << format_bytes(Hash, std::nullopt, 32, 32);
171}
172
174 size_t Before,
175 size_t After) {
176 TextLogLine Log(OS);
177 Log << "resize mapped file '" << Path << "' from=" << Before
178 << " to=" << After;
179}
180
182 void *Region,
183 size_t Capacity,
184 size_t Size) {
186 std::error_code EC = status(FD, Stat);
187
188 TextLogLine Log(OS);
189 Log << "mmap '" << Path << "' " << Region;
190 Log << " size=" << Size << " capacity=" << Capacity;
191 if (EC) {
192 Log << " failed status with error: " << EC.message();
193 return;
194 }
195 Log << " dev=" << format_hex(Stat.getUniqueID().getDevice(), 4);
196 Log << " inode=" << format_hex(Stat.getUniqueID().getFile(), 4);
197}
198
200 size_t Capacity, size_t Size,
201 size_t AllocSize) {
202 TextLogLine Log(OS);
203 Log << "oom '" << Path << "' old-size=" << Size << " capacity=" << Capacity
204 << "alloc-size=" << AllocSize;
205}
207 TextLogLine Log(OS);
208 Log << "close mmap '" << Path << "'";
209}
211 TrieOffset Off,
212 size_t Size) {
213 if (!LogAllocations)
214 return;
215 TextLogLine Log(OS);
216 Log << "alloc " << Region << " offset=";
217 formatTrieOffset(Log, Off);
218 Log << " size=" << Size;
219}
220
222 TextLogLine Log(OS);
223 Log << "collect garbage '" << Path << "'";
224}
225
227 StringRef Path, uint64_t BootTime, uint64_t ValidationTime, bool CheckHash,
228 bool AllowRecovery, bool Force, std::optional<StringRef> LLVMCas,
229 StringRef ValidationError, bool Skipped, bool Recovered) {
230 TextLogLine Log(OS);
231 Log << "validate-if-needed '" << Path << "'";
232 Log << " boot=" << BootTime << " last-valid=" << ValidationTime;
233 Log << " check-hash=" << CheckHash << " allow-recovery=" << AllowRecovery;
234 Log << " force=" << Force;
235 if (LLVMCas)
236 Log << " llvm-cas=" << *LLVMCas;
237 if (Skipped)
238 Log << " skipped";
239 if (Recovered)
240 Log << " recovered";
241 if (!ValidationError.empty())
242 Log << " data was invalid " << ValidationError;
243}
244
246 TextLogLine Log(OS);
247 Log << "standalone file create '" << Name << "'";
248}
249
251 std::error_code EC) {
252 TextLogLine Log(OS);
253 Log << "standalone file rename '" << TmpName << "' to '" << Name << "'";
254 if (EC)
255 Log << " error: " << EC.message();
256}
257
258void OnDiskCASLogger::logTempFileRemove(StringRef TmpName, std::error_code EC) {
259 TextLogLine Log(OS);
260 Log << "standalone file remove '" << TmpName << "'";
261 if (EC)
262 Log << " error: " << EC.message();
263}
#define T
static void formatTrieOffset(raw_ostream &OS, int64_t Off)
static uint64_t getTimestampMillis()
static bool isDisabledEnv(StringRef V)
static constexpr StringLiteral Filename
This file declares interface for OnDiskCASLogger, an interface that can be used to log CAS events to ...
Provides a library for accessing information about this process and other processes on the operating ...
This file implements the StringSwitch template, which mimics a switch() statement whose cases are str...
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
Tagged union holding either a T or a Error.
Definition Error.h:485
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition SmallString.h:26
A wrapper around a string literal that serves as a proxy for constructing global tables of StringRefs...
Definition StringRef.h:864
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
bool getAsInteger(unsigned Radix, T &Result) const
Parse the current string as an integer of the specified radix.
Definition StringRef.h:472
constexpr bool empty() const
empty - Check if the string is empty.
Definition StringRef.h:143
A switch()-like statement whose cases are string literals.
StringSwitch & CaseLower(StringLiteral S, T Value)
StringSwitch & Case(StringLiteral S, T Value)
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
LLVM_ABI void logTempFileRemove(StringRef TmpName, std::error_code EC)
LLVM_ABI void logSubtrieHandleCreate(void *Region, TrieOffset Trie, uint32_t StartBit, uint32_t NumBits)
int64_t TrieOffset
An offset into an OnDiskTrieRawHashMap.
LLVM_ABI void logMappedFileRegionArenaAllocate(void *Region, TrieOffset Off, size_t Size)
LLVM_ABI void logMappedFileRegionArenaResizeFile(StringRef Path, size_t Before, size_t After)
LLVM_ABI void logTempFileKeep(StringRef TmpName, StringRef Name, std::error_code EC)
LLVM_ABI void logUnifiedOnDiskCacheValidateIfNeeded(StringRef Path, uint64_t BootTime, uint64_t ValidationTime, bool CheckHash, bool AllowRecovery, bool Force, std::optional< StringRef > LLVMCas, StringRef ValidationError, bool Skipped, bool Recovered)
LLVM_ABI void logMappedFileRegionArenaCreate(StringRef Path, int FD, void *Region, size_t Capacity, size_t Size)
static LLVM_ABI Expected< std::unique_ptr< OnDiskCASLogger > > open(const Twine &Path, bool LogAllocations)
Create or append to a log file inside the given CAS directory Path.
static LLVM_ABI Expected< std::unique_ptr< OnDiskCASLogger > > openIfEnabled(const Twine &Path)
Create or append to a log file inside the given CAS directory Path if logging is enabled by the envir...
LLVM_ABI void logMappedFileRegionArenaClose(StringRef Path)
LLVM_ABI void logUnifiedOnDiskCacheCollectGarbage(StringRef Path)
LLVM_ABI void logTempFileCreate(StringRef Name)
LLVM_ABI void logMappedFileRegionArenaOom(StringRef Path, size_t Capacity, size_t Size, size_t AllocSize)
LLVM_ABI void logSubtrieHandleCmpXchg(void *Region, TrieOffset Trie, size_t SlotI, TrieOffset Expected, TrieOffset New, TrieOffset Previous)
LLVM_ABI void logHashMappedTrieHandleCreateRecord(void *Region, TrieOffset TrieOffset, ArrayRef< uint8_t > Hash)
A raw_ostream that writes to a file descriptor.
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
static LLVM_ABI Pid getProcessId()
Get the process's identifier.
uint64_t getDevice() const
Definition UniqueID.h:47
uint64_t getFile() const
Definition UniqueID.h:48
Represents the result of a call to sys::fs::status().
Definition FileSystem.h:222
LLVM_ABI UniqueID getUniqueID() const
@ Recovered
The data was invalid, but was recovered.
@ Skipped
Validation was skipped, as it was not needed.
@ OF_Append
The file should be opened in append mode.
Definition FileSystem.h:767
@ CD_OpenAlways
CD_OpenAlways - When opening a file:
Definition FileSystem.h:742
LLVM_ABI void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
Definition Path.cpp:457
This is an optimization pass for GlobalISel generic memory operations.
Definition Types.h:26
Error createFileError(const Twine &F, Error E)
Concatenate a source file path and/or name with an Error.
Definition Error.h:1399
FormattedNumber format_hex(uint64_t N, unsigned Width, bool Upper=false)
format_hex - Output N as a fixed width hexadecimal.
Definition Format.h:191
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
Definition Format.h:129
LLVM_ABI uint64_t get_threadid()
Return the current thread id, as used in various OS system calls.
Definition Threading.cpp:32
FormattedBytes format_bytes(ArrayRef< uint8_t > Bytes, std::optional< uint64_t > FirstByteOffset=std::nullopt, uint32_t NumPerLine=16, uint8_t ByteGroupSize=4, uint32_t IndentLevel=0, bool Upper=false)
Definition Format.h:245