VS “15”中更快的C++解决方案加载

[原文发表地址] VS “15”中更快的C++解决方案加载

[原文发表时间] 2016/10/05

自从Visual C++ 诞生以来它已经有了产品项目。直到Visual Studio 6, Visual C++ 才有了它自己的IDE。从Visual Studio.NET开始,C++移到了一个Visual Basic, C#,C++和其他工具共享的新的IDE上。这个新的IDE到处使用了COM和基于IVsHierarchy的Solution Explorer中的项。许多现有的项目系统是保持完整的,但它是通过使用一系列新的COM对象表现出来,这些COM对象是由IVsHierarchy 和其他接口实现的。

在Visual Studio 2010中,一些隐含的项目系统被从VCBuild改变到MSBuild。同时把文件的扩展名从.vcproj改到了.vcxproj。在这个阶段,已经存在的系列(和新的有关联的)COM对象被保存下来,但是后来的进入到“shim”对象中的项目被召入到一个新的项目系统中。这个新的项目系统最终将作为Visual Studio Project System (VSPS) 被熟知。

随着时间的流逝,开发人员也在创建越来越大的解决方案和项目。随之产生的问题是VS也需要越来越长的时间来加载这些不断增加的解决方案。每个项目要得到解析并且一个大型对象的图也要在内存中创建和保存,至少一个对象的每个节点都会在层次体系中被创建。这种方法需要花费大量的时间并占用很多的内存。Visual Studio也坚持去试着各种方法来支持大型项目。例如,你可以直接卸载项目来防止正在加载的项目以及ASL异步解决方案加载也被引入到Visual Studio 2013中。ASL是在后台的线程中来加载大部分的项目来确保UI 界面可以对其他的任务做出快速地反映。

因为ASL有很大的限制,我们会听到许多开发人员说他们宁愿等着整个解决方案完成加载和其他后台的工作完成之前去试着使用IDE。正如你所知道的开着解决方案去喝杯咖啡。

甚至当所有的项目完成加载后,仍然有其他的工作需要使用CPU和磁盘。在状态栏上,你可能已经习惯看到如下内容: 1

这个消息意味着我们正在做我们所说的“design-time build”。VSPS可以评估项目并指出什么将被构建和如何去构建。我们这样做是为了给每个项目中的每个文件生成命令行。然后和我们已经存储在浏览数据库中的信息做比较。如果数据已经改变了我们将会将新数据写入到数据库中。这个命令行被使用在智能感知中以及来解决被索引在浏览数据库中的头文件。

在“初始化”阶段之后你将会看到我们会检查一些陈旧的文件(如果有需要的话将会更新这些文件)。最后,状态栏上会显示准备完毕,然而如果这时你查看下任务管理器中,你将会发现CPU仍在被很大程度使用。在后台我们仍在做一些工作。第一个任务是加载每一个项目的“外部依赖”节点。每一个这个节点包含一些在项目中不十分明显的一些文件,这些文件被直接或间接地包含在项目里的其他文件中。完成这一步骤之后将会有一些隐形的步骤来检查数据库中的独立记录,例如一些我们索引的文件却没有被任何项目直接或间接的使用。当你每一次打开一个解决方案这些步骤都会一次产生即使自从你上次使用之后没有发生任何改变。

下面我们来看看Chromium解决方案的加载过程的每一步在Visual Studio 15 update 3中和VS 15 preview 5中所花费时间的比较。如果你看过Chromium网站操作指南你会知道这个解决方案是通过使用命令” gn gen –ide=vs out\Default”产生的。这个结果中的~4600项目,其中~1000是“解决方案文件夹”,其他的是.Vcxproj项目。 2

下面的结果是从我自己的Win 10机器上得到的, 配置是Intel Core i7-4790 @ 3.6GHz和两个SSDs:一个用作系统驱动器,另一个用来进行源代码工作(Samsung 850 Pro)。第一组结果是在Visual Studio 2015 Update 3上得出的,第二组结果是在Visual Studio 15 Preview 5上得出的。

我们注意到 ”parsing/resolving includes”在VS 15 Preview 5上比在VS 2015 Update 3大概慢了25%。我们正在努力改善这一点并期望可以得到解决。

为什么在Visual Studio “15”中解决方案的加载变得如此快?

因为我们现有的分层的结构使插入一个缓存层变得相当容易,这个缓存层可以解决许多项目和配置的问题而不用必须使项目下载到VSPS中。这个新的层使用了一个SQLite的数据库可以快速的取出你所需要的信息。

当一个解决方案被加载的时候我们也需要去加载一个C/C++项目,我们得到了所有的.vcxproj的文件列表的这个解决方案也将被加载。我们可以检查数据库看看我们是否已经有了这些项目以及是不是有文件被改变了。如果我们想要更新这些项目的信息可以将这些项目放入一个队列中。这个队列被多个外部进程所操纵,这些外部进程使用MSBuid来加载这些项目并收集项目相关的信息然后将这些信息写入到数据库中。

因为我们总是被请求加载每一个项目,所以可以创建一个小的对象垫来对大多数的请求做出回应而不用完全的加载项目。我们可以从数据库中提供智能感应引擎所需要的所有信息也可以提供解决方案管理器需要的信息。如果一个API被告知需要一个真实的项目(例如需要修改项目的设置),那个潜在的对象垫将会下载项目。

因为这个改变,单个项目的加载时间缩短了,但却还没有和我们想要的一样短。分析揭示了在不同地方一些带有N^2比较糟糕的算法的时间复杂度。在这一改变后我们的内存使用率也大大下降了,但我们也发现一些坏的内存使用对象在我们自己的项目中。我们应该削减一下在解决方案中的每个文件里对象的大小(包括外部依赖),例如从120 bytes减到44 bytes。这个看起来没有减少多少,但一个大的解决方案中却有百万计的这些小对象。我们现在依旧在提高项目加载的性能,我们也希望在发布最后一个版本之前可以看到其它方面的提高。

现在这个功能仍然在实验中,还有以下一些关于项目快速加载的问题需要您注意下。

  1. 需要升级的项目应该在使用快速项目加载之前进行升级,因为项目的升级在FPL期间不能实现。

  2. 对于这个预览版本,我们今天说的这些还没有完全建好。只有一个项目的简单解决方案能被建立,但是已经差不多了。

  3. 当在明确地编辑一个项目时(例如添加文件或改变属性),项目将会按需求通过VSPS进行加载。一个大的项目加载可能只花费几秒。我们想要把这个信号传递给用户但还没有在所有情况下实现。

  4. 第三方插件可以选择遍历整个解决方案的层次结构要求可以导致所有项目被完全加载在VSPS的属性。有效地击败FPL的任何好处。

无论什么时候当一个项目被完全加载到VSPS时,IDE的输出窗口将会显示一条消息。如果您看到这些消息不是期待的时候请让我们知道。

Lightweight Solution Load

在VS中有另一个在试验中的来提高解决方案加载的努力成果被称为“lightweight solution load”。你可以通过下面的选项来激活这个功能。 3

这是一个完全不同的方法,你可以在VS 博客上查看相关内容。一般情况下,这种方法会回避正在加载的所有项目而是只加载用户在解决方案管理器里展开的项目。因为C++组正在集中做”Fast Project Load”所以我们在“lightweight solution load”上投入的比较少。在Visual Studio 15 RC的版本中,我们希望可以结合lightweight solution load来支持FPL。这种结合应该提供了一个伟大的经验。

结尾

一如既往,我们欢迎您的反馈和我们很乐于从您对这些功能的体验中得到启发。如果您在试用快速加载解决方案时遇到了问题请通过填写问题记录工具让我们知道。

如果您想和我们直接联系可以给我们写邮件反映您的问题!对于新功能的建议通过填写User Voice让我们知道。