Swift的整个模块优化能够提高编译效率,但会导致lldb/Xcode崩溃。

29

TL;DR

Enabling SWIFT_WHOLE_MODULE_OPTIMIZATION significantly improved compile times in a large Swift project, but now using po in LLDB causes Xcode to crash. The issue is likely due to a bug in Xcode.

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

0x8f附近的虚拟内存区域: --> __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。任何帮助都将不胜感激!


1
启用整模块优化会减少编译时间,这很奇怪。苹果表示启用整模块优化后的编译时间应该更长,因为这样不能同时编译多个文件,必须查看模块中的所有文件。 - Juri Noga
是的,这对我来说真的很奇怪。我们的项目中有大约500个文件,关闭整体模块优化后,每个文件编译需要几秒钟的时间。 - LunaCodeGirl
1
如果每次构建时它实际上重新编译了每个文件,那么它不应该这样做。 - rcw3
@rcw3 当 SWIFT_WHOLE_MODULE_OPTIMIZATION = YES 时,它会发生这种情况,并且即使关闭了此选项,它也经常会发生,但这绝对取决于您要处理的文件。某些模型文件似乎会导致整个项目在每次更改它们时重新编译。其他文件相当隔离,只要您不改变太多内容,部分重新编译就能正常工作。 - LunaCodeGirl
1
这似乎是SWMO=Yes所期望的。顺便说一下,我猜这可能是一次徒劳的追寻,但这些机器有多少内存? - rcw3
16GB!和3ghz i7处理器。请自行查看:https://www.evernote.com/l/AAXzDN0bN5lEJ5W5yNcl_1910NRVokUoFssB/image.png - LunaCodeGirl
2个回答

11

我曾经从事并且正在进行的项目可能比你的项目规模更大(50多个库,数百个自定义类别和成千上万行的代码)。即使是完整的Swift项目,在Late 2013 MBP上编译只需几秒钟,发布构建最多需要2分钟。

我强烈建议寻找其他原因,因为该选项告诉你的是你的问题出现在其他地方,因为它会影响应用程序性能,而不是编译速度。也许你的.pch文件里充满了不属于那里的东西或者其他一些问题,这可能会导致这种情况发生变慢。

另一个有趣的事情是推断的使用。我个人为每个变量声明类型,仅仅因为这样更容易让他人阅读,但是这并不尽如人意。由于推断可能会变得复杂,会导致编译器花费很长时间来确定您的代码实际执行了什么。读一下这篇示例文章,尽管它更像是alpha问题。但是也许,只是也许,你的代码中也有这样的问题。值得尝试的是,尝试删除所有的Swift代码,如果库能够很好地编译,那么你就知道问题出在你的Swift代码上,这可能与此有关。

此外,如果您提供导致构建时间变慢的具体原因(因为您可以看到带有时间戳的整个构建过程,并且有很高的可能性其中一个步骤将需要很长时间),则可以更准确地确定问题所在。

希望对你有所帮助!

编辑: 另一篇关于这个有趣话题的文章


因为你可以看到带有时间戳的整个构建过程。你是指在Xcode中吗?如果是这样,那么编译步骤需要很长时间。当WHOLE_MODULE_OPTIMIZATION关闭时,我可以看到每个swift文件的编译情况,每个文件大约需要2-4秒钟。我还使用xctool进行构建,它给出了每个文件的编译时间(以毫秒为单位),几乎所有文件的时间都在2000毫秒左右,只有少数几个异常值,但最长的时间也只有6000毫秒,所以没有什么特别明显的问题。是否有其他方法可以查看更详细的步骤和时间? - LunaCodeGirl
1
请尝试使用此帖子,因为我现在正在使用移动设备,更详细的答案可以在那里找到。尝试使用xctool -jobs 1查找最昂贵的文件,并查看是否有一些极端情况。 - Jiri Trecak
编译时间中没有任何异常值……有一些需要大约6秒钟左右,但几乎每个文件都需要2秒钟或更长的时间。 - LunaCodeGirl
1
到目前为止,这是最好的答案,但我希望能有更明确的原因解释为什么我们可能会遇到这个问题。 - LunaCodeGirl
1
虽然建议编写所有类型有助于最小化编译时间,但对于代码的可读性来说实际上是灾难性的。在声明类属性时声明类型是有意义的(例如 var x: Bool = false 而不是 var x = false),但绝对没有必要为每个闭包或本地变量声明类型。另请注意,编译时间的主要问题是编译器无法看到文件之间的依赖关系并且会多次编译每个文件。这可以通过整个模块优化技巧来解决。 - Sulthan

9

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

关键是要按照你在“用户定义”设置中所说的那样将SWIFT_WHOLE_MODULE_OPTIMIZATION = YES设置。

但你需要再做一次修改。在调试时,你需要将优化级别设置为None,否则你将无法调试应用程序。

我在这里写了一篇博客文章:

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接