软件风向标,重度软件行业发展门户!

文章更新 | 热门文章
您的位置: 首页  →  攻略 → 《dwarf complete攻略 undeadhorde攻略

dwarf complete攻略 undeadhorde攻略

2023-05-29 06:45:45      小编:      我要评论

作者:段继统 & 夏磊

“ 调试断点是与开发经验最密切的关系之一iOS在外部调查中,团队发现大量国内研究iOS APP研发团队也遇到了类似的问题。考虑到中国Swift现状如火如荼,我们尽快整理通过本文分享,希望对这个问题有所帮助。

前言

众所周知,Swift苹果2014年苹果开发者年会(WWDC2014年发布的编译新开发语言支持多编程范式,可以用来写作macOS、iOS、iPadOS、watchOS和tvOS上的APP。对于广大iOS对于开发学生来说,这也是未来的研发iOS APP开发必须掌握的语言技能。Swift语言在发布后的几年里发展迅速,苹果于2019年发布Swift5.0版本并宣告Swift ABI稳定。

在Swift5.0版本的ABI稳定后,Swift优酷正式拥有完善的生产研发基础iOS研发团队也开始优酷iOS、iPadOS版本的Swift迁移。被阿里巴巴收购后,优酷获得了大量集团移动基础设施和中间件的支持,因此优酷iOS App经过几年的不断演变,几十个垂直团队负责各自的业务并行开发,基本成为标准化的大型组件工程。其中,优酷播放详情页面场景是最重要的视频内容消费场景,也是2020年初第一个开始业务页面框架、播放器框架和业务模块的场景Swift迁移。

2020年底,优酷iOS消费团队完成了业务页面框架和播放器框架Swift这两个框架代码数量少,内部代码结果合理清晰,对外部依赖性少。因此在完全Swift化学后性能有所提高,得益于Swift优秀的语法,团队开发业务需求代码行数下降,团队效率也有所提高。工程开发或质量问题并不明显。

进入2021年后,业务页面框架和播放器框架Swift基于版本,优酷iOS团队全面启动业务层代码Swift在这个阶段,Swift调试断点慢的问题越来越严重。在视频内容场景中,核心主业务模块代码超过7万行,外部依赖各种模块超过200个。在该业务模块中,第一个断点可达到180秒以上,团队研发效率受到严重限制。

2022年初优酷iOS团队完成了80%以上的业务代码Swift调试首次断点慢的问题已成为业务场效率瓶颈。97%的发幸福问卷调查中,97%iOS开发学生认为,第一次调试的慢断点是当前研发过程中最大的痛点,这个问题给出了iOS研发学生带来的挫败感足以消除Swift其它优点。因此,解决这个问题已经成为优酷iOS年度团队主要目标。

首次调试断点慢现象及初步分析

Swift调试断点慢的主要现象是,当Xcode项目运行后,我们将长时间等待第一个断点。在大多数情况下,项目第一次断点生效后,第二次和后续断点的等待时间非常短,基本上可以认为没有等待时间。但是,从团队内部收集的情况来看,是不同的Mac计算机开发设备和不同的设备iOS设备性能不完全一致,部分学生第一次断点后等待断点的时间极其缓慢。

在团队内部频繁出现这种现象或问题后,我们首先与外部资深人士合作iOS开发团队进行了沟通,并附上了详细的工程文件。另一方还根据反馈进行了内部调查和验证,并最终回答说,没有发现类似的问题。在沟通过程中,我们发现其内部很大APP工程模式是传统的单一工程模式,与国内多个工程模式完全不同。基于各方面的信息汇总,我们开始初步分析和解决这个问题。

从下表可以分析,根据播放器框架模块和播放主业务模块的断点时间,断点时间似乎与外部依赖的数量相等,因此可以初步确定断点时间与外部依赖的数量有很强的相关性。

如果子工程和壳工程依赖,还有另一种现象SDK的module没有对齐,lldb断点很快就会生效,但打印错误的信息是不可能的po任何值。在断点时也可以初步分析这一现象lldb依赖子工程module扫描。

然而,仅仅依观分析是不够的,所以我们从两个方向开始,一是从主业务模块的解耦测试,快速解耦主业务模块的外部依赖,测试减少耦合数量是否有助于断点时间;二是从lldb分析自己的断点原理,看第一个断点这么长时间lldb该怎么办?

从业务模块解耦开始

我们通过删除和整理工程依赖引用代码,快速清理外部模块依赖,最终将主业务模块的外部依赖减少到90左右。整理后,主营业务首次调试的断点时间也从200秒降至120秒左右,缓解了团队发展的困难。但经过实际验证和应用,我们也发现这种依赖业务层解耦的方式对团队来说是不可行的,有两个根本原因:

改造成本高

主要业务模块的依赖从200多个模块减少到90多个模块。一方面,它积极帮助防止项目腐化。另一方面,在业务需求的压力下,研发人员需要投入大量精力进行代码重构和解耦。从长远来看,不同的垂直业务团队面临着不同的情况,未来业务技术需求的复杂性也不同。该方案不能快速重用。就劳动力成本而言,该方案只能在短期内进行工程治理,不能长期坚持。

2.实际收入低

从收入的角度来看,在主营业务模块外部依赖减少到90多个后,我们最初的预期是,调试的第一个断点时间可以减少50%甚至更低,但结果是,当外部依赖无法解除时,第一个断点的等待时间仍然超过120秒,这是我们无法接受的。因此,在优酷也得出结论iOS在这种大型组件化多工程模式下,我们无法用业务模块解耦来解决这个问题。

通过LLDB分析入手

经过工程治理,我们认为应该从积极的方面克服这个问题LLDB分析查看根本原因并解决。如果要分析LLDB对于工程师来说,最好的方法是检查Swift跑起来看看内部原型机制。我们首先根据苹果的文档下载源代码,然后进行配置。具体文档可参考 How to Set Up an Edit-Build-Test-Debug Loop,可以一步一步跟着做。

由于Swift是依赖于LLVM,并且在自己定制开发的基础上,所以切换分支不能只切换Swift需要将源码LLVM一起切到相应的分支, 确保代码同步。正好Swift它提供了帮助我们切换相应分支的工具,只需运行即可Swift文件下的utils/update-checkout相关命令即可。优酷iOS目前团队使用的是Swift5.4版本,对应Xcode版本为13.2.1。

1、使用LLVM自带耗时工具

要看断点命中后哪一块最耗时,需要用工具来计算耗时,而这一块LLVM有自己的工具TimeProfiler,计时方法包装在内部,输出相关方法json然后可以使用文件chrome自带的tracing工具分析后现实相关图表

//TimeProfiler.h void timeTraceProfilerBegin(StringRef Name, StringRef Detail); void timeTraceProfilerBegin(StringRef Name, llvm::function_ref<std::string()> Detail); void timeTraceProfilerEnd();

2.两个耗时最多的地方

通过TimeProfiler对关键函数进行耗时埋点,发现有两个函数耗时较多,如下代码:

// SwiftASTContext.cppbool SwiftASTContext::GetCompileUnitImportsImpl( SymbolContext &sc, lldb::StackFrameWP &stack_frame_wp, llvm::SmallVectorImpl<swift::AttributedImport<swift::ImportedModule>> *modules, Status &error)

// SymbolFileDWARF.cppvoid SymbolFileDWARF::FindTypes( ConstString name, const CompilerDeclContext &parent_decl_ctx, uint32_t max_matches, llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files, TypeMap &types)

一个是SwiftASTContext类的GetCompileUnitImportsImpl该方法主要分析当前的编译单元和Module相关操作,另一个是在某个变量Any对于类型,需要对其进行分析,找出与其类型相关的操作,最终这两个函数的操作都与当前工程二进制依赖分析有关,因此,如果断点命中后能减少对依赖性的分析,断点时间就会越快。

无效的解决方案

根据以上对源码的分析,我们首先考虑是否可以跳过编译器的一些选项module为了提高第一次断点的速度,以相对较小的成本尽快解决。

1 无效方案1 - 修改编译选项

通过对编译日志的分析,在构建时找到参数-serialize-debugging-options,用于名称判断debug调试时,顺序生成调试相关产品,然后我们通过swiftc -frontend --help命令发现了以下选项:

我们正在尝试这个参数Xcode在施工设置中Other Swift Flags添加此参数,但从结果中发现并不生效。所以我们再次检查内部和外部信息,并在官方Swift论坛发帖咨询,包括外国人iOS开发人员回答说,需要添加自定义flag SWIFT_SERIALIZE_DEBUGGING_OPTIONS=NO。然后我们马上就来了Xcode在项目中加入选项并进行验证后,从实际结果来看,首次断点速度有了显著提高,但也发现了严重的缺陷。当团队学生想要的时候po打印相关变量时,什么都打不出来,lldd从实际开发的角度来看,该方案不能直接分析。

2 无效方案2 - 修改依赖库

我们自己建造的lldb在调试项目时,由于编译lldb是debug当命中断点时,包,lldb会打印一些debug的log其中有一堆信息log它非常引人注目,会持续几十秒,所以我们会立即对这部分进行评论log两者分析,以下是部分截取log:

warning: (arm64) /Users/ray/workspace/YouKuUniversal/Pods/SOME/SOME.framework/SOME(SOME9999999.o) 0x00004c50: unable to locate module needed for external types: /Users/remoteserver/build/14695183/workspace/iphone-out/ModuleCache.noindex/2YQ3UYLF0BE3R/UIKit-1XGSPECLTDLOB.pcmerror: '/Users/remoteserver/build/14695183/workspace/iphone-out/ModuleCache.noindex/2YQ3UYLF0BE3R/UIKit-1XGSPECLTDLOB.pcm' does not existDebugging will be degraded due to missing types. Rebuilding the project will regenerate the needed module files.

这块log其中一个依赖库报错,大概问题是在找这个库modulecache找不到路径。因为优酷iOS二进制依赖库是通过阿里远程编译集群生成的,所以在生成这个库时debug在调试信息时,其路径指向远程机器的路径。所以,在我们本地机器上搜索这个远程服务器的地址肯定是找不到的,然后报错了。

通过这种现象,我们猜测是因为我们找不到正确的东西modulecache,导致我们当前项目的整个项目Swift依赖库的cache不能正确构建,所以每个断点都要重新搜索依赖库,然后构建cache。

那么,这条路径是从哪里进来的呢?研究发现,这条路径是卸载的Mach-O文件DWARF的debug信息里的:

核心在于如何处理这个信息。修改相对来说有点麻烦弄个Mach-O修改工具最快的方法就是去掉这个section。这个选项可以在编译设置中直接删除,称为`Generate Debug Symbol`。

因为这个报错了log涉及数百个库,即使改变这个选项有用,改变一个肯定看不到效果,所以我们直接修改了100个库,把这些库放在里面release在编译环境下,将此选项改为NO,试试是否有效。

结果令人失望。通过我们的测试,即使改变了这么多库,第一次断点的速度也没有提高,问题依然存在。

既然这两条路都走不通,那么lldb你有相关的设置吗?如果是这样的话,是吗?lldb设置能生效吗?

有效的解决方案 - LLDB配置优化

从上我们是对的lldb从分析可以看出,从执行到断点正式生效的调试首次断点主要包括两部分,其中大部分依赖于模块module另一部分是自身的分析结构Any类型分析。由于业务解耦的工程化和编译选项的配置修改显然是不可行的,因此我们考虑从lldb自己开始,通过setting list命令找到一切Swift调试相关设置项目,发现最关键的项目有两个:

1 memory-module-load-level

调试时从内存加载module默认信息水平complete,另外还有partial和minimal两种,其中minimal最快。

memory-module-load-level -- Loading modules from memory can be slow as reading the symbol tables and other data can take a long time depending on your connection to the debug target. This setting helps users control how much information gets loaded when loading modules from memory.'complete' is the default value for this setting which will load all sections and symbols by reading them from memory (slowest, most accurate). 'partial' will load sections and attempt to find function bounds without downloading the symbol table (faster, still accurate, missing symbol names). 'minimal' is the fastest setting and will load section data with no symbols, but should rarely be used as stack frames in these memory regions will be inaccurate and not provide any context (fastest).

2 use-swift-clangimporter

Swift调试时是否重建所依赖的调试?module,默认值为true。

use-swift-clangimporter -- Reconstruct Clang module dependencies from headers when debugging Swift code

因此,我们从以上两个配置项开始,在命中任何断点时执行以下两个命令:

settings set target.memory-module-load-level minimalsettings set symbols.use-swift-clangimporter false

实施后发现断点速度明显提高,首次断点从180秒缩短到40秒,两个命令单独测试,memory-module-load-level设置优化约6秒,其他时间优化来自use-swift-clangimporter设置。在论证这种方式后,我们在此配置的基础上,收集优酷和集团内部iOS同学试用。在验证了不同的开发环境后,我们惊讶地发现,第一个断点时间大大提高,基本上达到了可用性。

阿里巴巴集团内部验证结果如图所示:

配置优化后存在的问题及解决方案

当然,在上述优化设置之后,我们也发现了一些问题OC属性无法po例如Swift继承OC基类:

//oc@interface OPVideo : NSObject@property (nonatomic, strong) NSString *sid;@end//swift@objc public class DetailVideoSwift: OPVideo { @objc public var desc: String?}

此时“po video.sid不能输出,但po video.desc正常情况下,调试有很大的局限性。通过查阅lldb文档发现,lldb指定代码可以绑定到自定义命令中,因此我们可以使用这种机制来解决部分属性po的问题。

首先新建Swift代码库,外部学生可以参考自己项目的相关基础库,在库中实现方法:

public func aliprint(_ target:Any?,selector:String?){ if let target = target as AnyObject?{ if let selector = selector { let returnValue = target.perform(NSSelectorFromString(selector)) print("\(String(describing: returnValue?.takeUnretainedValue()))") }else{ print("\(String(describing: target))") } }}

包装该代码的模块打包后SDK加入主工程依赖,然后通过命令

command regex px 's/(. ) (. )/expr -l Swift -O -- import AliOneUtils; aliprint(%1,selector:%2);/'

将px命令绑定到aliprint方法,注意这里px为定义命令解决了一些属性po 经测试完全可用的问题:

总结

优酷iOS作为阿里内部的团队Swift迁移的先驱,在Swift在迁移过程中遇到了许多问题,并总结了大量的经验。调试断点是与开发经验最密切的关系之一。在外部研究中,我们发现大量的国内研究iOS APP研发团队也遇到了类似的问题。

考虑到国内Swift现状如火如荼,我们尽快整理了计划,分享了外部,希望对大家有所帮助。同时,如果有,iOS团队和大神有更好的解决方案,希望分享,共同帮助国内iOS Swift蓬勃发展的发展生态。

目前,优酷iOS团队在这个方向上的投资和研究只是一个开始。未来将积极探索性能体验、编译速度、包大小优化等方向,希望通过开发效率和技术创新,为用户带来更好的优质服务体验。

关注阿里巴巴移动技术&实践给你思考!

攻略[共106828款]

dwarf[共1款]

complete[共1款]

undeadhorde[共1款]

  • 发表评论
资讯排行 资讯中心 热门专区 软件评测
软件排行榜 软件攻略 软件下载 软件开测表
软件排行榜 软件礼包 软件下载 新软件测表
安卓排行榜 软件视频 软件下载
苹果排行榜