|
21 | 21 | #include "llvm/ADT/StringMap.h"
|
22 | 22 | #include "llvm/ADT/StringSwitch.h"
|
23 | 23 | #include "llvm/Support/FileOutputBuffer.h"
|
| 24 | +#include "llvm/Support/FileSystem.h" |
24 | 25 | #include "llvm/Support/raw_ostream.h"
|
25 | 26 | #include <climits>
|
| 27 | +#include <thread> |
26 | 28 |
|
27 | 29 | using namespace llvm;
|
28 | 30 | using namespace llvm::ELF;
|
@@ -1504,10 +1506,46 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
|
1504 | 1506 | Sec->writeHeaderTo<ELFT>(++SHdrs);
|
1505 | 1507 | }
|
1506 | 1508 |
|
| 1509 | +// Removes a given file asynchronously. This is a performance hack, |
| 1510 | +// so remove this when operating systems are improved. |
| 1511 | +// |
| 1512 | +// On Linux (and probably on other Unix-like systems), unlink(2) is a |
| 1513 | +// noticeably slow system call. As of 2016, unlink takes 250 |
| 1514 | +// milliseconds to remove a 1 GB file on ext4 filesystem on my machine. |
| 1515 | +// |
| 1516 | +// To create a new result file, we first remove existing file. So, if |
| 1517 | +// you repeatedly link a 1 GB program in a regular compile-link-debug |
| 1518 | +// cycle, every cycle wastes 250 milliseconds only to remove a file. |
| 1519 | +// Since LLD can link a 1 GB binary in about 5 seconds, that waste |
| 1520 | +// actually counts. |
| 1521 | +// |
| 1522 | +// This function spawns a background thread to call unlink. |
| 1523 | +// The calling thread returns almost immediately. |
| 1524 | +static void unlinkAsync(StringRef Path) { |
| 1525 | + if (!Config->Threads || !sys::fs::exists(Config->OutputFile)) |
| 1526 | + return; |
| 1527 | + |
| 1528 | + // First, rename Path to avoid race condition. We cannot remomve |
| 1529 | + // Path from a different thread because we are now going to create |
| 1530 | + // Path as a new file. If we do that in a different thread, the new |
| 1531 | + // thread can remove the new file. |
| 1532 | + SmallString<128> TempPath; |
| 1533 | + if (auto EC = sys::fs::createUniqueFile(Path + "tmp%%%%%%%%", TempPath)) |
| 1534 | + fatal(EC, "createUniqueFile failed"); |
| 1535 | + if (auto EC = sys::fs::rename(Path, TempPath)) |
| 1536 | + fatal(EC, "rename failed"); |
| 1537 | + |
| 1538 | + // Remove TempPath in background. |
| 1539 | + std::thread([=] { ::remove(TempPath.str().str().c_str()); }).detach(); |
| 1540 | +} |
| 1541 | + |
| 1542 | +// Open a result file. |
1507 | 1543 | template <class ELFT> void Writer<ELFT>::openFile() {
|
| 1544 | + unlinkAsync(Config->OutputFile); |
1508 | 1545 | ErrorOr<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
|
1509 | 1546 | FileOutputBuffer::create(Config->OutputFile, FileSize,
|
1510 | 1547 | FileOutputBuffer::F_executable);
|
| 1548 | + |
1511 | 1549 | if (auto EC = BufferOrErr.getError())
|
1512 | 1550 | error(EC, "failed to open " + Config->OutputFile);
|
1513 | 1551 | else
|
|
0 commit comments