漫漫开发路|Build Insights对模板代码进行性能分析,使用C++( 三 )


漫漫开发路|Build Insights对模板代码进行性能分析,使用C++
文章图片
使用C++BuildInsightsSDK定位模板实例化问题
在使用模板元编程的代码库中 , 递归 , 耗时的模板实例化并不是一个普遍的问题 , 因此我们希望将来能够更快地识别这些问题 , 而不必经历启动WPA和手动检查跟踪的麻烦 。 幸运的是 , 大多数使用vcperf和WPA手动执行的分析任务也可以使用C++BuildInsightsSDK以编程方式执行 。
为了说明这一点 , 我们准备了RecursiveTemplateInspectorSDK示例 。 它打印出构建中最耗时的模板实例化层次结构 , 以及有关它们的统计信息 , 例如递归树深度 , 实例化总数和模板特化名称 。
让我们重复上一节中的Sprout案例研究 , 但是这次使用RecursiveTemplateInspector这个示例工程 。 具体操作步骤如下:
1.克隆C++BuildInsightsSDK示例工程 。
2.打开Sample.Sln并选择对应的目标平台(x86/x64)和配置(Debug/Release)进行编译 。 编译出来的二进制文件将位于:out/{architecture}/{configuration}/RecursiveTemplateInspector
3.使用上面案例研究中的步骤进行编译信息收集 。 这一次 , 使用vcperf/stopnoanalyzeSproutsprout-raw.etl命令来停止收集 , 而不是使用/stop选项 。
4.将sprout-raw.etl作为第一个参数传递给RecursiveTemplateInspector二进制文件 。
如下图所示 , RecursiveTemplateInspector正确地识别出导致我们出现问题的sprout::tpp::all_of模板实例化 , 该模板实例递归地触发其他实例化 , 总共4043个实例化 。
漫漫开发路|Build Insights对模板代码进行性能分析,使用C++
文章图片
在经过修改后的代码上重新运行RecursiveTemplateInspector会显示所有有问题的模板实例均已消失 , 剩下的持续时间很短 , 可以忽略不计 。
漫漫开发路|Build Insights对模板代码进行性能分析,使用C++
文章图片
理解示例代码
首先 , 通过要求C++BuildInsightsSDK将我们需要的内容转发给OnTemplateRecursionTreeBranch和OnSymbolName函数 , 来过滤所有停止活动和简单事件 。
函数的名称对C++BuildInsightsSDK如何过滤事件没有影响 。 只有它们的参数很重要 。 具体代码如下:
漫漫开发路|Build Insights对模板代码进行性能分析,使用C++
文章图片
我们使用OnTemplateRecursionTreeBranch函数来一一捕获模板实例化递归树的每个分支 。 因为C++BuildInsights事件以堆栈表示 , 所以捕获事件之间的递归关系是一件很容易的事情 。 TemplateInstantiationGroup捕获类自动展开事件堆栈 , 并将解析线程中发生的所有模板实例化显示为自顶向下的有序的类似矢量的C++容器 。
因为我们将OnTemplateRecursionTreeBranch函数绑定到了stop活动事件 , 所以我们将始终在解析线程从最深层返回的点处接收给定递归树中的分支 。
我们利用这一事实来计算递归树的所有分支时的最大深度 。 一旦根实例化本身达到其停止事件 , 我们就通过存储树的总实例化时间以及发生它的转换单元来包装实例化树 。
漫漫开发路|Build Insights对模板代码进行性能分析,使用C++
文章图片
模板实例化事件不包含实例化的符号的名称 。 派生名称是一项昂贵的操作 , 而在测量实例化时这样做会扭曲时间测量 。 而是发出了一个数字键 , 稍后我们可以通过侦听SymboName事件将其与适当的名称匹配 。 OnSymbolName函数就是这样做的 , 并存储每个根模板实例化的名称 。
漫漫开发路|Build Insights对模板代码进行性能分析,使用C++
文章图片
在分析的最后 , 我们遍历所有根模板实例 , 按最长持续时间对其进行排序 , 然后显示它们 。