Swift WHOLE_MODULE_OPTIMIZATION 提高了编译时间,但会导致 lldb/Xcode 崩溃

Posted

技术标签:

【中文标题】Swift WHOLE_MODULE_OPTIMIZATION 提高了编译时间,但会导致 lldb/Xcode 崩溃【英文标题】:Swift WHOLE_MODULE_OPTIMIZATION improves compile time, but causes lldb/Xcode crash 【发布时间】:2015-10-30 07:16:32 【问题描述】:

TL;DR

之前

SWIFT_WHOLE_MODULE_OPTIMIZATION = NO

调试编译需要 10-15 分钟 发布编译需要 25 多分钟 po 在 LLDB 中运行良好

之后

SWIFT_WHOLE_MODULE_OPTIMIZATION = YES

调试编译需要 1-2 分钟 发布编译大约需要 8 分钟 po 总是导致 Xcode 崩溃

知道为什么基于此信息的可怕编译时间,和/或为什么 Xcode 可能会崩溃吗?


迪茨

我正在开发一个 100% 的大型 Swift 项目(Objective-C 中有 3rd 方库,但我们所有的代码都是 Swift)。我们的编译时间很长,通常大约需要 10-15 分钟来编译调试配置和 30 多分钟来编译发布配置。

由于可怕的编译时间,这个项目一直很难使用。我一直在寻找改善这一点的方法,特别是通过构建设置,但几个月来都没有运气。我忽略的一件事是SWIFT_WHOLE_MODULE_OPTIMIZATION,特别是因为任何提及它都声称它会增加项目的编译时间。

所以前几天我们启用了SWIFT_WHOLE_MODULE_OPTIMIZATION,你瞧,我们的编译时间提高了 10 倍。

问题是,现在每当我们调试项目并尝试在 lldb 中使用po myObject 打印对象时,Xcode 都会立即崩溃。以下是崩溃日志中的一些信息:

进程:Xcode [5860] 路径:/Applications/Xcode.app/Contents/MacOS/Xcode 标识符:com.apple.dt.Xcode 版本:6.4 (7720) 构建信息:IDEFrameworks-7720000000000000~8 应用项目 ID:497799835 应用外部 ID:812725084 代码类型:X86-64(本机) 父进程:??? [1] 负责人:Xcode [5860]

日期/时间:2015-08-05 15:53:08.265 -0600 操作系统版本:Mac OS X 10.11 (15A235d) 报告版本:11

自启动后的唤醒时间:13000 秒

崩溃的线程:20

异常类型:EXC_BAD_ACCESS (SIGSEGV) 异常代码:0x000000000000008f 处的 KERN_INVALID_ADDRESS 异常说明:EXC_CORPSE_NOTIFY

0x8f 附近的 VM 区域: --> __TEXT 000000010ef62000-000000010ef63000 [4K] r-x/rwx SM=COW /Applications/Xcode.app/Contents/MacOS/Xcode

应用特定信息: ProductBuildVersion:6E35b

这是崩溃线程的堆栈跟踪:

Thread 20 Crashed:: <DBGLLDBSessionThread (pid=6402)>
0   com.apple.LLDB.framework        0x0000000116b09ab4 swift::ArchetypeBuilder::resolveArchetype(swift::Type) + 68
1   com.apple.LLDB.framework        0x0000000116b0f808 std::__1::__function::__func<substConcreteTypesForDependentTypes(swift::ArchetypeBuilder&, swift::Type)::$_6, std::__1::allocator<substConcreteTypesForDependentTypes(swift::ArchetypeBuilder&, swift::Type)::$_6>, swift::Type (swift::Type)>::operator()(swift::Type&&) + 152
2   com.apple.LLDB.framework        0x0000000116bc0986 swift::Type::transform(std::__1::function<swift::Type (swift::Type)> const&) const + 54
3   com.apple.LLDB.framework        0x0000000116bc0f2b swift::Type::transform(std::__1::function<swift::Type (swift::Type)> const&) const + 1499
4   com.apple.LLDB.framework        0x0000000116bc0bbb swift::Type::transform(std::__1::function<swift::Type (swift::Type)> const&) const + 619
5   com.apple.LLDB.framework        0x0000000116bc0c0a swift::Type::transform(std::__1::function<swift::Type (swift::Type)> const&) const + 698
6   com.apple.LLDB.framework        0x0000000116b0c8f2 swift::ArchetypeBuilder::substDependentType(swift::Type) + 50
7   com.apple.LLDB.framework        0x0000000116e9554e (anonymous namespace)::LowerType::visitAnyStructType(swift::CanType, swift::StructDecl*) + 270
8   com.apple.LLDB.framework        0x0000000116e92e66 swift::Lowering::TypeConverter::getTypeLoweringForUncachedLoweredType(swift::Lowering::TypeConverter::TypeKey) + 150
9   com.apple.LLDB.framework        0x0000000116e92b39 swift::Lowering::TypeConverter::getTypeLowering(swift::Lowering::AbstractionPattern, swift::Type, unsigned int) + 2361
10  com.apple.LLDB.framework        0x0000000116f8f711 lldb_private::SwiftSILManipulator::emitLValueForVariable(swift::VarDecl*, lldb_private::SwiftExpressionParser::SILVariableInfo&) + 1521
11  com.apple.LLDB.framework        0x00000001172ac7ee (anonymous namespace)::LLDBNameLookup::emitLValueForVariable(swift::VarDecl*, swift::SILBuilder&) + 102
12  com.apple.LLDB.framework        0x0000000116ebb162 swift::Lowering::SILGenFunction::emitInitializationForVarDecl(swift::VarDecl*, swift::Type) + 98
13  com.apple.LLDB.framework        0x0000000116ebbc74 swift::ASTVisitor<(anonymous namespace)::InitializationForPattern, void, void, void, std::__1::unique_ptr<swift::Lowering::Initialization, std::__1::default_delete<swift::Lowering::Initialization> >, void, void>::visit(swift::Pattern*) + 404
14  com.apple.LLDB.framework        0x0000000116ebbc57 swift::ASTVisitor<(anonymous namespace)::InitializationForPattern, void, void, void, std::__1::unique_ptr<swift::Lowering::Initialization, std::__1::default_delete<swift::Lowering::Initialization> >, void, void>::visit(swift::Pattern*) + 375
15  com.apple.LLDB.framework        0x0000000116ebba0d swift::Lowering::SILGenFunction::visitPatternBindingDecl(swift::PatternBindingDecl*) + 45
16  com.apple.LLDB.framework        0x0000000116f0617c swift::Lowering::SILGenFunction::visitBraceStmt(swift::BraceStmt*) + 284
17  com.apple.LLDB.framework        0x0000000116ecd1c0 swift::Lowering::SILGenFunction::emitFunction(swift::FuncDecl*) + 320
18  com.apple.LLDB.framework        0x0000000116ea3966 swift::Lowering::SILGenModule::emitFunction(swift::FuncDecl*) + 246
19  com.apple.LLDB.framework        0x0000000116ea3828 swift::Lowering::SILGenModule::visitFuncDecl(swift::FuncDecl*) + 168
20  com.apple.LLDB.framework        0x0000000116ea579b swift::Lowering::SILGenModule::emitSourceFile(swift::SourceFile*, unsigned int) + 427
21  com.apple.LLDB.framework        0x0000000116ea5c22 swift::SILModule::constructSIL(swift::Module*, swift::SILOptions&, swift::SourceFile*, llvm::Optional<unsigned int>, bool, bool) + 386
22  com.apple.LLDB.framework        0x0000000116ea5d42 swift::performSILGeneration(swift::SourceFile&, swift::SILOptions&, llvm::Optional<unsigned int>, bool) + 98
23  com.apple.LLDB.framework        0x00000001172aa617 lldb_private::SwiftExpressionParser::Parse(lldb_private::Stream&, unsigned int, unsigned int, unsigned int) + 10715
24  com.apple.LLDB.framework        0x000000011706b3e8 lldb_private::ClangUserExpression::Parse(lldb_private::Stream&, lldb_private::ExecutionContext&, lldb_private::ExecutionPolicy, bool, unsigned int) + 1064
25  com.apple.LLDB.framework        0x000000011706cdb4 lldb_private::ClangUserExpression::Evaluate(lldb_private::ExecutionContext&, lldb_private::EvaluateExpressionOptions const&, char const*, char const*, lldb_private::SharingPtr<lldb_private::ValueObject>&, lldb_private::Error&, unsigned int, std::__1::shared_ptr<lldb_private::Module>*) + 628
26  com.apple.LLDB.framework        0x00000001171d1696 lldb_private::Target::EvaluateExpression(char const*, lldb_private::StackFrame*, lldb_private::SharingPtr<lldb_private::ValueObject>&, lldb_private::EvaluateExpressionOptions const&) + 376
27  com.apple.LLDB.framework        0x000000011716d75c lldb_private::SwiftLanguageRuntime::GetObjectDescription(lldb_private::Stream&, lldb_private::ValueObject&) + 668
28  com.apple.LLDB.framework        0x00000001170464e6 lldb_private::ValueObject::GetObjectDescription() + 370
29  com.apple.LLDB.framework        0x000000011548e228 lldb::SBValue::GetObjectDescription() + 76
30  com.apple.dt.dbg.DebuggerLLDB   0x00000001153f3c9e -[DBGLLDBDataValue _lldbValueObjectDescription] + 24
31  com.apple.dt.dbg.DebuggerLLDB   0x00000001153f3b7f -[DBGLLDBDataValue lldbDescription] + 29
32  com.apple.dt.dbg.DebuggerLLDB   0x00000001154023dc __87-[DBGLLDBSession printDescriptionOfDataValueToConsole:runAllThreads:completionHandler:]_block_invoke + 182
33  com.apple.dt.dbg.DebuggerLLDB   0x0000000115402e6d -[DBGLLDBSession handleNextActionWithState:withRunPending:] + 424
34  com.apple.dt.dbg.DebuggerLLDB   0x00000001153fdf44 DBGLLDBSessionThread(void*) + 980
35  libsystem_pthread.dylib         0x00007fff8ec12cb3 _pthread_body + 131
36  libsystem_pthread.dylib         0x00007fff8ec12c30 _pthread_start + 168
37  libsystem_pthread.dylib         0x00007fff8ec10419 thread_start + 13

似乎我们可能处于新技术的最前沿,因为我还没有在这个问题上找到太多帮助。我想知道我们是否有某种不寻常的配置导致编译时问题,或者是否存在 lldb 可能崩溃的已知原因。它在多台不同的机器上是相同的,包括 El Capitan、Yosemite、Xcode 6.3、Xcode 6.4。任何帮助表示赞赏!

【问题讨论】:

启用整体模块优化会减少编译时间,这很奇怪。 Apple 表示启用全模块优化的编译需要更长的时间。因为这样它不能一次编译多个文件,因为它应该查看模块中的所有文件。 是的,这对我来说真的很奇怪。我们在项目中有大约 500 个文件,在关闭整个模块优化的情况下,每个文件都需要几秒钟的时间进行编译。 每次构建时实际上都在重新编译每个文件?如果是,它不应该这样做。 @rcw3 它与 SWIFT_WHOLE_MODULE_OPTIMIZATION = YES 一起使用,并且它经常关闭它,但这绝对取决于您正在使用的文件。某些模型文件似乎会导致整个项目重新编译每次他们被改变。其他文件是相当孤立的,只要您不进行太多更改,部分重新编译就可以工作。 这似乎与 SWMO=Yes.... 【参考方案1】:

我设法在我们的项目中解决了这个问题。 (总编译时间 12 分钟)

关键是按照你在user defined设置里说的设置SWIFT_WHOLE_MODULE_OPTIMIZATION = YES

但是您需要再做一项更改。您需要在调试时将优化级别设置为None,否则您将无法调试您的应用。

我在这里写了一篇关于它的博客文章:

https://tech.zalando.com/blog/improving-swift-compilation-times-from-12-to-2-minutes/

【讨论】:

【参考方案2】:

我工作过,并且正在积极从事可能比您的项目更大的项目(50 多个库、数百个自定义类和数千个 LoC)。编译需要几秒钟,发布版本(2013 年末 MBP)最多需要 2 分钟,即使对于完整的 Swift 项目也是如此。

我强烈建议寻找其他原因,因为此选项告诉您问题出在其他地方,因为它会影响应用程序性能,而不是构建速度。也许您的 .pch 文件中充满了不属于那里的东西或其他东西,这可能会导致这种速度变慢。

其他有趣的事情是使用推理。我个人为每个变量声明类型只是因为它更容易被其他人阅读,但它还有更多。由于推理可能会变得复杂,因此可能会导致编译器花费大量时间来弄清楚您的代码实际上做了什么。 Read this example article,虽然它更像是 alpha 问题。但也许,只是也许,你的代码中也有类似的东西。值得做的是尝试删除所有 swift 代码,如果运行良好则编译库,然后您就知道问题出在您的 swift 代码中,并且很可能与此有关。

此外,如果您提供 WHAT 实际上会减慢您的构建时间(因为您可以看到带有时间戳的整个构建过程,并且很可能一步将永远持续下去),它可以帮助更准确地查明问题。

希望对你有帮助!

编辑:Another article 关于这个感兴趣的话题

【讨论】:

> 因为你可以看到带有时间戳的整个构建过程你的意思是在 Xcode 中吗?如果是这样,那么它的编译步骤将永远存在。当 WHOLE_MODULE_OPTIMIZATION 关闭时,我可以看到每个 swift 文件正在编译,每个文件大约需要 2-4 秒。我还使用 xctool 构建,它为我提供了每个文件的编译时间(以毫秒为单位),除了一些异常值外,它们几乎都是 2000 毫秒左右,但最长的是 6000 毫秒,所以没什么大不了的。还有其他方法可以让我查看更精细的步骤和时间吗? 请尝试这篇文章,因为我现在在移动设备上,可以在那里找到更详细的答案。尝试使用 xctool -jobs 1 找到最昂贵的文件,看看某处是否有一些极端 编译时间没有任何异常值......少数需要 6 秒左右,但几乎每个文件都需要 2 秒或更长时间。 目前为止的最佳答案,但希望有一些更明确的原因导致我们可能会看到这个问题。 虽然编写所有类型的建议可以最大限度地减少编译时间,但它实际上是代码可读性的灾难。在声明类属性时声明类型是有意义的(例如 var x: Bool = false 而不是 var x = false),但绝对没有意义为每个闭包或局部变量声明类型。另请注意,编译时间的主要问题是编译器无法看到文件之间的依赖关系并且多次编译每个文件。目前可以通过整个模块优化技巧来解决。

以上是关于Swift WHOLE_MODULE_OPTIMIZATION 提高了编译时间,但会导致 lldb/Xcode 崩溃的主要内容,如果未能解决你的问题,请参考以下文章

Swift入门系列--Swift官方文档(2.2)--中文翻译--About Swift 关于Swift

swift 示例BS swift.swift

swift swift_bug.swift

ios 整理(一)swift和oc的区别

swift swift_extension5.swift

swift swift_optional4.swift