blob: fc898c49998cd3b3775e22897872482905d471ab [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 Collingbourneab76a192017-03-02 02:02:38 +000049Expected<NativeObjectCache> lto::localCache(StringRef CacheDirectoryPath,
50 AddFileFn AddFile) {
51 if (std::error_code EC = sys::fs::create_directories(CacheDirectoryPath))
52 return errorCodeToError(EC);
53
Peter Collingbourne80186a52016-09-23 21:33:43 +000054 return [=](unsigned Task, StringRef Key) -> AddStreamFn {
55 // First, see if we have a cache hit.
56 SmallString<64> EntryPath;
57 sys::path::append(EntryPath, CacheDirectoryPath, Key);
58 if (sys::fs::exists(EntryPath)) {
59 AddFile(Task, EntryPath);
60 return AddStreamFn();
61 }
Mehdi Aminiadc0e262016-08-23 21:30:12 +000062
Peter Collingbourne80186a52016-09-23 21:33:43 +000063 // This native object stream is responsible for commiting the resulting
64 // file to the cache and calling AddFile to add it to the link.
65 struct CacheStream : NativeObjectStream {
66 AddFileFn AddFile;
67 std::string TempFilename;
68 std::string EntryPath;
69 unsigned Task;
Mehdi Aminiadc0e262016-08-23 21:30:12 +000070
Peter Collingbourne80186a52016-09-23 21:33:43 +000071 CacheStream(std::unique_ptr<raw_pwrite_stream> OS, AddFileFn AddFile,
72 std::string TempFilename, std::string EntryPath,
73 unsigned Task)
Benjamin Kramer061f4a52017-01-13 14:39:03 +000074 : NativeObjectStream(std::move(OS)), AddFile(std::move(AddFile)),
75 TempFilename(std::move(TempFilename)),
76 EntryPath(std::move(EntryPath)), Task(Task) {}
Peter Collingbourne80186a52016-09-23 21:33:43 +000077
78 ~CacheStream() {
79 // Make sure the file is closed before committing it.
80 OS.reset();
81 commitEntry(TempFilename, EntryPath);
82 AddFile(Task, EntryPath);
83 }
84 };
85
86 return [=](size_t Task) -> std::unique_ptr<NativeObjectStream> {
87 // Write to a temporary to avoid race condition
88 int TempFD;
89 SmallString<64> TempFilename;
90 std::error_code EC =
91 sys::fs::createTemporaryFile("Thin", "tmp.o", TempFD, TempFilename);
92 if (EC) {
93 errs() << "Error: " << EC.message() << "\n";
94 report_fatal_error("ThinLTO: Can't get a temporary file");
95 }
96
97 // This CacheStream will move the temporary file into the cache when done.
Peter Collingbournea638fe02016-09-23 23:23:23 +000098 return llvm::make_unique<CacheStream>(
Peter Collingbourne80186a52016-09-23 21:33:43 +000099 llvm::make_unique<raw_fd_ostream>(TempFD, /* ShouldClose */ true),
100 AddFile, TempFilename.str(), EntryPath.str(), Task);
101 };
102 };
Mehdi Aminiadc0e262016-08-23 21:30:12 +0000103}