LLVM  7.0.0svn
Caching.cpp
Go to the documentation of this file.
1 //===-Caching.cpp - LLVM Link Time Optimizer Cache Handling ---------------===//
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 implements the Caching for ThinLTO.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "llvm/LTO/Caching.h"
15 #include "llvm/ADT/StringExtras.h"
16 #include "llvm/Support/Errc.h"
18 #include "llvm/Support/Path.h"
19 #include "llvm/Support/Process.h"
21 
22 #if !defined(_MSC_VER) && !defined(__MINGW32__)
23 #include <unistd.h>
24 #else
25 #include <io.h>
26 #endif
27 
28 using namespace llvm;
29 using namespace llvm::lto;
30 
32  AddBufferFn AddBuffer) {
33  if (std::error_code EC = sys::fs::create_directories(CacheDirectoryPath))
34  return errorCodeToError(EC);
35 
36  return [=](unsigned Task, StringRef Key) -> AddStreamFn {
37  // This choice of file name allows the cache to be pruned (see pruneCache()
38  // in include/llvm/Support/CachePruning.h).
39  SmallString<64> EntryPath;
40  sys::path::append(EntryPath, CacheDirectoryPath, "llvmcache-" + Key);
41  // First, see if we have a cache hit.
42  int FD;
43  SmallString<64> ResultPath;
44  std::error_code EC = sys::fs::openFileForRead(
45  Twine(EntryPath), FD, sys::fs::OF_UpdateAtime, &ResultPath);
46  if (!EC) {
48  MemoryBuffer::getOpenFile(FD, EntryPath,
49  /*FileSize*/ -1,
50  /*RequiresNullTerminator*/ false);
51  close(FD);
52  if (MBOrErr) {
53  AddBuffer(Task, std::move(*MBOrErr));
54  return AddStreamFn();
55  }
56  EC = MBOrErr.getError();
57  }
58 
59  // On Windows we can fail to open a cache file with a permission denied
60  // error. This generally means that another process has requested to delete
61  // the file while it is still open, but it could also mean that another
62  // process has opened the file without the sharing permissions we need.
63  // Since the file is probably being deleted we handle it in the same way as
64  // if the file did not exist at all.
66  report_fatal_error(Twine("Failed to open cache file ") + EntryPath +
67  ": " + EC.message() + "\n");
68 
69  // This native object stream is responsible for commiting the resulting
70  // file to the cache and calling AddBuffer to add it to the link.
71  struct CacheStream : NativeObjectStream {
72  AddBufferFn AddBuffer;
73  sys::fs::TempFile TempFile;
74  std::string EntryPath;
75  unsigned Task;
76 
77  CacheStream(std::unique_ptr<raw_pwrite_stream> OS, AddBufferFn AddBuffer,
78  sys::fs::TempFile TempFile, std::string EntryPath,
79  unsigned Task)
80  : NativeObjectStream(std::move(OS)), AddBuffer(std::move(AddBuffer)),
81  TempFile(std::move(TempFile)), EntryPath(std::move(EntryPath)),
82  Task(Task) {}
83 
84  ~CacheStream() {
85  // Make sure the stream is closed before committing it.
86  OS.reset();
87 
88  // Open the file first to avoid racing with a cache pruner.
90  MemoryBuffer::getOpenFile(TempFile.FD, TempFile.TmpName,
91  /*FileSize*/ -1,
92  /*RequiresNullTerminator*/ false);
93  if (!MBOrErr)
94  report_fatal_error(Twine("Failed to open new cache file ") +
95  TempFile.TmpName + ": " +
96  MBOrErr.getError().message() + "\n");
97 
98  // On POSIX systems, this will atomically replace the destination if
99  // it already exists. We try to emulate this on Windows, but this may
100  // fail with a permission denied error (for example, if the destination
101  // is currently opened by another process that does not give us the
102  // sharing permissions we need). Since the existing file should be
103  // semantically equivalent to the one we are trying to write, we give
104  // AddBuffer a copy of the bytes we wrote in that case. We do this
105  // instead of just using the existing file, because the pruner might
106  // delete the file before we get a chance to use it.
107  Error E = TempFile.keep(EntryPath);
108  E = handleErrors(std::move(E), [&](const ECError &E) -> Error {
109  std::error_code EC = E.convertToErrorCode();
110  if (EC != errc::permission_denied)
111  return errorCodeToError(EC);
112 
113  auto MBCopy = MemoryBuffer::getMemBufferCopy((*MBOrErr)->getBuffer(),
114  EntryPath);
115  MBOrErr = std::move(MBCopy);
116 
117  // FIXME: should we consume the discard error?
118  consumeError(TempFile.discard());
119 
120  return Error::success();
121  });
122 
123  if (E)
124  report_fatal_error(Twine("Failed to rename temporary file ") +
125  TempFile.TmpName + " to " + EntryPath + ": " +
126  toString(std::move(E)) + "\n");
127 
128  AddBuffer(Task, std::move(*MBOrErr));
129  }
130  };
131 
132  return [=](size_t Task) -> std::unique_ptr<NativeObjectStream> {
133  // Write to a temporary to avoid race condition
134  SmallString<64> TempFilenameModel;
135  sys::path::append(TempFilenameModel, CacheDirectoryPath, "Thin-%%%%%%.tmp.o");
137  TempFilenameModel, sys::fs::owner_read | sys::fs::owner_write);
138  if (!Temp) {
139  errs() << "Error: " << toString(Temp.takeError()) << "\n";
140  report_fatal_error("ThinLTO: Can't get a temporary file");
141  }
142 
143  // This CacheStream will move the temporary file into the cache when done.
144  return llvm::make_unique<CacheStream>(
145  llvm::make_unique<raw_fd_ostream>(Temp->FD, /* ShouldClose */ false),
146  AddBuffer, std::move(*Temp), EntryPath.str(), Task);
147  };
148  };
149 }
std::error_code create_directories(const Twine &path, bool IgnoreExisting=true, perms Perms=owner_all|group_all)
Create all the non-existent directories in path.
Definition: Path.cpp:906
Represents either an error or a value T.
Definition: ErrorOr.h:69
raw_ostream & errs()
This returns a reference to a raw_ostream for standard error.
LLVM_ATTRIBUTE_NORETURN void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:115
Compute iterated dominance frontiers using a linear time algorithm.
Definition: AllocatorList.h:24
std::error_code openFileForRead(const Twine &Name, int &ResultFD, OpenFlags Flags=OF_None, SmallVectorImpl< char > *RealPath=nullptr)
Opens the file with the given name in a read-only mode, returning its open file descriptor.
std::function< void(unsigned Task, std::unique_ptr< MemoryBuffer > MB)> AddBufferFn
This type defines the callback to add a pre-existing native object file (e.g.
Definition: Caching.h:29
Error takeError()
Take ownership of the stored error.
Definition: Error.h:545
static Expected< TempFile > create(const Twine &Model, unsigned Mode=all_read|all_write)
This creates a temporary file with createUniqueFile and schedules it for deletion with sys::RemoveFil...
Definition: Path.cpp:1201
Error keep(const Twine &Name)
Definition: Path.cpp:1145
std::error_code convertToErrorCode() const override
Convert this error to a std::error_code.
Definition: Error.h:1059
std::function< std::unique_ptr< NativeObjectStream >unsigned Task)> AddStreamFn
This type defines the callback to add a native object that is generated on the fly.
Definition: LTO.h:174
void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
Definition: Path.cpp:471
std::string toString(Error E)
Write all error messages (if any) in E to a string.
Definition: Error.h:955
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
Represents a temporary file.
Definition: FileSystem.h:774
Tagged union holding either a T or a Error.
Definition: CachePruning.h:23
StringRef str() const
Explicit conversion to StringRef.
Definition: SmallString.h:267
Key
PAL metadata keys.
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Definition: Error.cpp:78
This class wraps an output stream for a native object.
Definition: LTO.h:162
Expected< NativeObjectCache > localCache(StringRef CacheDirectoryPath, AddBufferFn AddBuffer)
Create a local file system cache which uses the given cache directory and file callback.
Definition: Caching.cpp:31
std::error_code getError() const
Definition: ErrorOr.h:172
void consumeError(Error Err)
Consume a Error without doing anything.
Definition: Error.h:970
Force files Atime to be updated on access. Only makes a difference on windows.
Definition: FileSystem.h:733
static ErrorSuccess success()
Create a success value.
Definition: Error.h:321
static std::unique_ptr< MemoryBuffer > getMemBufferCopy(StringRef InputData, const Twine &BufferName="")
Open the specified memory range as a MemoryBuffer, copying the contents and taking ownership of it...
Provides a library for accessing information about this process and other processes on the operating ...
Lightweight error class with error context and mandatory checking.
Definition: Error.h:156
Error handleErrors(Error E, HandlerTs &&... Hs)
Pass the ErrorInfo(s) contained in E to their respective handlers.
Definition: Error.h:874
This class wraps a std::error_code in a Error.
Definition: Error.h:1054
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:49
static ErrorOr< std::unique_ptr< MemoryBuffer > > getOpenFile(int FD, const Twine &Filename, uint64_t FileSize, bool RequiresNullTerminator=true, bool IsVolatile=false)
Given an already-open file descriptor, read the file and return a MemoryBuffer.