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/FileSystem.h" 17 #include "llvm/Support/MemoryBuffer.h" 18 #include "llvm/Support/Path.h" 19 #include "llvm/Support/raw_ostream.h" 20 21 using namespace llvm; 22 using namespace llvm::lto; 23 24 static 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. 29 // FIXME: Avoid needing to do this by creating the temporary file in the 30 // cache directory. 31 { 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 49 NativeObjectCache 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 } 59 60 // 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; 67 68 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. 94 return llvm::make_unique<CacheStream>( 95 llvm::make_unique<raw_fd_ostream>(TempFD, /* ShouldClose */ true), 96 AddFile, TempFilename.str(), EntryPath.str(), Task); 97 }; 98 }; 99 } 100