From: Rui Ueyama Date: Mon, 5 Dec 2016 17:40:37 +0000 (+0000) Subject: Remove existing file in a separate thread asynchronously. X-Git-Tag: llvmorg-4.0.0-rc1~2984 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=6d12eaee8b57e72c6da156f1c5667f3125771ce1;p=platform%2Fupstream%2Fllvm.git Remove existing file in a separate thread asynchronously. On Linux (and probably on other Unix-like systems), unlink(2) is noticeably slow. It takes 250 milliseconds to remove a 1 GB file on ext4 filesystem on my machine, whether the file is on SSD or on a spinning disk. To create a new result file, we remove existing file first. So, if you repeatedly link a 1 GB program in a regular compile-link-debug cycle, every cycle wastes 250 milliseconds only to remove a file. Since LLD can link a 1 GB in about 5 seconds, that waste actually matters. This patch defines `unlinkAsync` function. The function spawns a background thread to call unlink. The calling thread returns almost immediately. Differential Revision: https://reviews.llvm.org/D27295 llvm-svn: 288680 --- diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 20c9d75..28a9563 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -21,8 +21,10 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/FileOutputBuffer.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/raw_ostream.h" #include +#include using namespace llvm; using namespace llvm::ELF; @@ -1504,10 +1506,46 @@ template void Writer::writeHeader() { Sec->writeHeaderTo(++SHdrs); } +// Removes a given file asynchronously. This is a performance hack, +// so remove this when operating systems are improved. +// +// On Linux (and probably on other Unix-like systems), unlink(2) is a +// noticeably slow system call. As of 2016, unlink takes 250 +// milliseconds to remove a 1 GB file on ext4 filesystem on my machine. +// +// To create a new result file, we first remove existing file. So, if +// you repeatedly link a 1 GB program in a regular compile-link-debug +// cycle, every cycle wastes 250 milliseconds only to remove a file. +// Since LLD can link a 1 GB binary in about 5 seconds, that waste +// actually counts. +// +// This function spawns a background thread to call unlink. +// The calling thread returns almost immediately. +static void unlinkAsync(StringRef Path) { + if (!Config->Threads || !sys::fs::exists(Config->OutputFile)) + return; + + // First, rename Path to avoid race condition. We cannot remomve + // Path from a different thread because we are now going to create + // Path as a new file. If we do that in a different thread, the new + // thread can remove the new file. + SmallString<128> TempPath; + if (auto EC = sys::fs::createUniqueFile(Path + "tmp%%%%%%%%", TempPath)) + fatal(EC, "createUniqueFile failed"); + if (auto EC = sys::fs::rename(Path, TempPath)) + fatal(EC, "rename failed"); + + // Remove TempPath in background. + std::thread([=] { ::remove(TempPath.str().str().c_str()); }).detach(); +} + +// Open a result file. template void Writer::openFile() { + unlinkAsync(Config->OutputFile); ErrorOr> BufferOrErr = FileOutputBuffer::create(Config->OutputFile, FileSize, FileOutputBuffer::F_executable); + if (auto EC = BufferOrErr.getError()) error(EC, "failed to open " + Config->OutputFile); else