Skip to content

Commit da62873

Browse files
[OutputBackend] Virtualize LoadedModuleTraceFile
Virtualize LoadedModuleTraceFile output using the new appending support in virtual output backend.
1 parent b5e3ab5 commit da62873

File tree

2 files changed

+22
-66
lines changed

2 files changed

+22
-66
lines changed

lib/FrontendTool/LoadedModuleTrace.cpp

Lines changed: 20 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -780,70 +780,25 @@ bool swift::emitLoadedModuleTraceIfNeeded(ModuleDecl *mainModule,
780780
}
781781
stringBuffer += "\n";
782782

783-
// If writing to stdout, just perform a normal write.
784-
// If writing to a file, ensure the write is atomic by creating a filesystem lock
785-
// on the output file path.
786-
std::error_code EC;
787-
if (loadedModuleTracePath == "-") {
788-
llvm::raw_fd_ostream out(loadedModuleTracePath, EC, llvm::sys::fs::OF_Append);
789-
if (out.has_error() || EC) {
790-
ctxt.Diags.diagnose(SourceLoc(), diag::error_opening_output,
791-
loadedModuleTracePath, EC.message());
792-
out.clear_error();
793-
return true;
794-
}
795-
out << stringBuffer;
796-
} else {
797-
while (1) {
798-
// Attempt to lock the output file.
799-
// Only one process is allowed to append to this file at a time.
800-
llvm::LockFileManager Locked(loadedModuleTracePath);
801-
switch (Locked) {
802-
case llvm::LockFileManager::LFS_Error:{
803-
// If we error acquiring a lock, we cannot ensure appends
804-
// to the trace file are atomic - cannot ensure output correctness.
805-
ctxt.Diags.diagnose(SourceLoc(), diag::error_opening_output,
806-
loadedModuleTracePath,
807-
"Failed to acquire filesystem lock");
808-
Locked.unsafeRemoveLockFile();
809-
return true;
810-
}
811-
case llvm::LockFileManager::LFS_Owned: {
812-
// Lock acquired, perform the write and release the lock.
813-
llvm::raw_fd_ostream out(loadedModuleTracePath, EC, llvm::sys::fs::OF_Append);
814-
if (out.has_error() || EC) {
815-
ctxt.Diags.diagnose(SourceLoc(), diag::error_opening_output,
816-
loadedModuleTracePath, EC.message());
817-
out.clear_error();
818-
return true;
819-
}
820-
out << stringBuffer;
821-
out.close();
822-
Locked.unsafeRemoveLockFile();
823-
return false;
824-
}
825-
case llvm::LockFileManager::LFS_Shared: {
826-
// Someone else owns the lock on this file, wait.
827-
switch (Locked.waitForUnlock(256)) {
828-
case llvm::LockFileManager::Res_Success:
829-
LLVM_FALLTHROUGH;
830-
case llvm::LockFileManager::Res_OwnerDied: {
831-
continue; // try again to get the lock.
832-
}
833-
case llvm::LockFileManager::Res_Timeout: {
834-
// We could error on timeout to avoid potentially hanging forever, but
835-
// it may be more likely that an interrupted process failed to clear the lock,
836-
// causing other waiting processes to time-out. Let's clear the lock and try
837-
// again right away. If we do start seeing compiler hangs in this location,
838-
// we will need to re-consider.
839-
Locked.unsafeRemoveLockFile();
840-
continue;
841-
}
842-
}
843-
break;
844-
}
845-
}
846-
}
783+
// Write output via atomic append.
784+
llvm::vfs::OutputConfig config;
785+
config.setAppend().setAtomicWrite();
786+
auto outputFile =
787+
ctxt.getOutputBackend().createFile(loadedModuleTracePath, config);
788+
789+
if (!outputFile) {
790+
ctxt.Diags.diagnose(SourceLoc(), diag::error_opening_output,
791+
loadedModuleTracePath,
792+
toString(outputFile.takeError()));
793+
return true;
794+
}
795+
796+
*outputFile << stringBuffer;
797+
798+
if (auto err = outputFile->keep()) {
799+
ctxt.Diags.diagnose(SourceLoc(), diag::error_opening_output,
800+
loadedModuleTracePath, toString(std::move(err)));
801+
return true;
847802
}
848-
return true;
803+
return false;
849804
}

test/Frontend/output_determinism_check.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// RUN: %empty-directory(%t)
22
// RUN: echo '[]' > %t/protocol.json
3-
// RUN: %target-swift-frontend -module-name test -emit-module -o %t/test.swiftmodule %s -emit-module-doc-path %t/test.docc -const-gather-protocols-file %t/protocol.json -emit-const-values-path %t/test.swiftconstvalues -emit-tbd-path %t/test.tbd -tbd-current-version 1 -tbd-compatibility-version 1 -tbd-install_name @rpath/test.dylib -enable-deterministic-check 2>&1 | %FileCheck %s --check-prefix=MODULE_OUTPUT --check-prefix=DOCC_OUTPUT --check-prefix=CONSTVALUE_OUTPUT --check-prefix=TBD_OUTPUT
3+
// RUN: %target-swift-frontend -module-name test -emit-module -o %t/test.swiftmodule %s -emit-module-doc-path %t/test.docc -const-gather-protocols-file %t/protocol.json -emit-const-values-path %t/test.swiftconstvalues -emit-tbd-path %t/test.tbd -tbd-current-version 1 -tbd-compatibility-version 1 -tbd-install_name @rpath/test.dylib -emit-loaded-module-trace -emit-loaded-module-trace-path %t/test.trace.json -enable-deterministic-check 2>&1 | %FileCheck %s --check-prefix=MODULE_OUTPUT --check-prefix=DOCC_OUTPUT --check-prefix=CONSTVALUE_OUTPUT --check-prefix=TBD_OUTPUT --check-prefix=TRACE_OUTPUT
44
// RUN: %target-swift-frontend -module-name test -emit-sib -o %t/test.sib -primary-file %s -enable-deterministic-check 2>&1 | %FileCheck %s --check-prefix=SIB_OUTPUT
55

66
/// object files are "not" deterministic because the second run going to match the mod hash and skip code generation.
@@ -29,6 +29,7 @@
2929
// CONSTVALUE_OUTPUT: remark: produced matching output file '{{.*}}{{/|\\}}test.swiftconstvalues'
3030
// MODULE_OUTPUT: remark: produced matching output file '{{.*}}{{/|\\}}test.swiftmodule'
3131
// TBD_OUTPUT: remark: produced matching output file '{{.*}}{{/|\\}}test.tbd'
32+
// TRACE_OUTPUT: remark: produced matching output file '{{.*}}{{/|\\}}test.trace.json'
3233
// SIB_OUTPUT: remark: produced matching output file '{{.*}}{{/|\\}}test.sib'
3334
// DEPS_OUTPUT: remark: produced matching output file '{{.*}}{{/|\\}}test.d'
3435
// OBJECT_OUTPUT: remark: produced matching output file '{{.*}}{{/|\\}}test.o'

0 commit comments

Comments
 (0)