blob: fd5bdb0bc01a12129535a174278ea1c32bb8fdaa [file] [log] [blame]
Mehdi Aminiadc0e262016-08-23 21:30:12 +00001//===-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"
Mehdi Aminiadc0e262016-08-23 21:30:12 +000015#include "llvm/ADT/StringExtras.h"
16#include "llvm/Support/FileSystem.h"
Peter Collingbourne80186a52016-09-23 21:33:43 +000017#include "llvm/Support/MemoryBuffer.h"
Mehdi Aminiadc0e262016-08-23 21:30:12 +000018#include "llvm/Support/Path.h"
19#include "llvm/Support/raw_ostream.h"
20
21using namespace llvm;
22using namespace llvm::lto;
23
24static void commitEntry(StringRef TempFilename, StringRef EntryPath) {
25 // Rename to final destination (hopefully race condition won't matter here)
26 auto EC = sys::fs::rename(TempFilename, EntryPath);
27 if (EC) {
28 // Renaming failed, probably not the same filesystem, copy and delete.
Peter Collingbourne80186a52016-09-23 21:33:43 +000029 // FIXME: Avoid needing to do this by creating the temporary file in the
30 // cache directory.
Mehdi Aminiadc0e262016-08-23 21:30:12 +000031 {
32 auto ReloadedBufferOrErr = MemoryBuffer::getFile(TempFilename);
33 if (auto EC = ReloadedBufferOrErr.getError())
34 report_fatal_error(Twine("Failed to open temp file '") + TempFilename +
35 "': " + EC.message() + "\n");
36
37 raw_fd_ostream OS(EntryPath, EC, sys::fs::F_None);
38 if (EC)
39 report_fatal_error(Twine("Failed to open ") + EntryPath +
40 " to save cached entry\n");
41 // I'm not sure what are the guarantee if two processes are doing this
42 // at the same time.
43 OS << (*ReloadedBufferOrErr)->getBuffer();
44 }
45 sys::fs::remove(TempFilename);
46 }
47}
48
Peter Collingbourne80186a52016-09-23 21:33:43 +000049NativeObjectCache lto::localCache(std::string CacheDirectoryPath,
50 AddFileFn AddFile) {
51 return [=](unsigned Task, StringRef Key) -> AddStreamFn {
52 // First, see if we have a cache hit.
53 SmallString<64> EntryPath;
54 sys::path::append(EntryPath, CacheDirectoryPath, Key);
55 if (sys::fs::exists(EntryPath)) {
56 AddFile(Task, EntryPath);
57 return AddStreamFn();
58 }
Mehdi Aminiadc0e262016-08-23 21:30:12 +000059
Peter Collingbourne80186a52016-09-23 21:33:43 +000060 // This native object stream is responsible for commiting the resulting
61 // file to the cache and calling AddFile to add it to the link.
62 struct CacheStream : NativeObjectStream {
63 AddFileFn AddFile;
64 std::string TempFilename;
65 std::string EntryPath;
66 unsigned Task;
Mehdi Aminiadc0e262016-08-23 21:30:12 +000067
Peter Collingbourne80186a52016-09-23 21:33:43 +000068 CacheStream(std::unique_ptr<raw_pwrite_stream> OS, AddFileFn AddFile,
69 std::string TempFilename, std::string EntryPath,
70 unsigned Task)
71 : NativeObjectStream(std::move(OS)), AddFile(AddFile),
72 TempFilename(TempFilename), EntryPath(EntryPath), Task(Task) {}
73
74 ~CacheStream() {
75 // Make sure the file is closed before committing it.
76 OS.reset();
77 commitEntry(TempFilename, EntryPath);
78 AddFile(Task, EntryPath);
79 }
80 };
81
82 return [=](size_t Task) -> std::unique_ptr<NativeObjectStream> {
83 // Write to a temporary to avoid race condition
84 int TempFD;
85 SmallString<64> TempFilename;
86 std::error_code EC =
87 sys::fs::createTemporaryFile("Thin", "tmp.o", TempFD, TempFilename);
88 if (EC) {
89 errs() << "Error: " << EC.message() << "\n";
90 report_fatal_error("ThinLTO: Can't get a temporary file");
91 }
92
93 // This CacheStream will move the temporary file into the cache when done.
Peter Collingbournea638fe02016-09-23 23:23:23 +000094 return llvm::make_unique<CacheStream>(
Peter Collingbourne80186a52016-09-23 21:33:43 +000095 llvm::make_unique<raw_fd_ostream>(TempFD, /* ShouldClose */ true),
96 AddFile, TempFilename.str(), EntryPath.str(), Task);
97 };
98 };
Mehdi Aminiadc0e262016-08-23 21:30:12 +000099}