- 适用于 JDK 23 的 GraalVM(最新版)
- 适用于 JDK 24 的 GraalVM(抢先体验版)
- 适用于 JDK 21 的 GraalVM
- 适用于 JDK 17 的 GraalVM
- 存档
- 开发版本
- Truffle 语言实现框架
- Truffle 分支检测
- 动态对象模型
- 静态对象模型
- 针对解释器代码的主机优化
- Truffle 对函数内联的处理方法
- 对 Truffle 解释器的分析
- Truffle 互操作性 2.0
- 语言实现
- 使用 Truffle 实现新的语言
- Truffle 语言和工具迁移到 Java 模块
- Truffle 原生函数接口
- 优化 Truffle 解释器
- 选项
- 栈上替换
- Truffle 字符串指南
- 专业化直方图
- 测试 DSL 专业化
- 基于 Polyglot API 的 TCK
- Truffle 对编译队列的处理方法
- Truffle 库指南
- Truffle AOT 概述
- Truffle AOT 编译
- 辅助引擎缓存
- Truffle 语言安全点教程
- 单态化
- 拆分算法
- 单态化用例
- 向运行时报告多态专业化
专业化直方图
本指南介绍如何使用 --engine.SpecializationStatistics
选项。
专业化直方图需要以特殊方式生成 Truffle DSL 节点。因此,如果您使用的是普通的专业化直方图选项,它只会打印以下内容
js --engine.SpecializationStatistics test.js
[engine] Specialization histogram:
No specialization statistics data was collected. Either no node with @Specialization annotations was executed or the interpreter was not compiled with -Atruffle.dsl.GenerateSpecializationStatistics=true e.g as parameter to the javac tool.
按照错误提示重新编译我们的解释器。对于 mx
用户,这很简单
mx build -c -A-Atruffle.dsl.GenerateSpecializationStatistics=true
重建后,专业化统计数据就可以使用了。请确保您的 IDE 在此期间不会自动重新编译源代码。在本教程中,将使用一个简单的 test.js
脚本来演示。
function test() {
var array = [42, "", {}, []]
var globalVar = true;
for (element of array) {
globalVar = element;
}
}
test();
现在,需要启用专业化统计数据,本示例使用 GraalVM 的 JavaScript 启动器
js --experimental-options --engine.SpecializationStatistics test.js
脚本执行完毕后,将为每个类打印一个直方图。这些直方图将按每个节点的执行次数总和进行排序,最常用的节点类将最后打印。
以下是一些执行 test.js
时打印的直方图:(注意:输出可能已经过时。)
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Name Instances Executions Executions per instance
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
| JSWriteCurrentFrameSlotNodeGen 8 (17%) 18 (12%) Min= 1 Avg= 2.25 Max= 5 MaxNode= test.js~5-7:76-128
| doBoolean <boolean> 1 (13%) 1 (6%) Min= 1 Avg= 1.00 Max= 1 MaxNode= test.js~4:52-71
| doInt <int> 1 (13%) 1 (6%) Min= 1 Avg= 1.00 Max= 1 MaxNode= test.js~5-7:76-128
| doSafeIntegerInt 0 (0%) 0 (0%) Min= 0 Avg= 0.00 Max= 0 MaxNode= -
| doSafeInteger 0 (0%) 0 (0%) Min= 0 Avg= 0.00 Max= 0 MaxNode= -
| doLong 0 (0%) 0 (0%) Min= 0 Avg= 0.00 Max= 0 MaxNode= -
| doDouble 0 (0%) 0 (0%) Min= 0 Avg= 0.00 Max= 0 MaxNode= -
| doObject 7 (88%) 16 (89%) Min= 1 Avg= 2.29 Max= 5 MaxNode= test.js~5-7:76-128
| <DynamicObjectBasic> 6 (86%) 12 (75%) Min= 1 Avg= 2.00 Max= 5 MaxNode= test.js~5-7:76-128
| <IteratorRecord> 1 (14%) 1 (6%) Min= 1 Avg= 1.00 Max= 1 MaxNode= test.js~1-8:16-130
| <String> 2 (29%) 2 (13%) Min= 1 Avg= 1.00 Max= 1 MaxNode= test.js~5-7:76-128
| <Integer> 1 (14%) 1 (6%) Min= 1 Avg= 1.00 Max= 1 MaxNode= test.js~6:105-123
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------
| [doBoolean] 1 (13%) 1 (6%) Min= 1 Avg= 1.00 Max= 1 MaxNode= test.js~4:52-71
| [doInt, doObject] 1 (13%) 4 (22%) Min= 4 Avg= 4.00 Max= 4 MaxNode= test.js~5-7:76-128
| doInt 1 (100%) 1 (25%) Min= 1 Avg= 1.00 Max= 1 MaxNode= test.js~5-7:76-128
| doObject 1 (100%) 3 (75%) Min= 3 Avg= 3.00 Max= 3 MaxNode= test.js~5-7:76-128
| [doObject] 6 (75%) 13 (72%) Min= 1 Avg= 2.17 Max= 5 MaxNode= test.js~5-7:76-128
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Name Instances Executions Executions per instance
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
| JSReadCurrentFrameSlotNodeGen 8 (17%) 25 (17%) Min= 1 Avg= 3.13 Max= 5 MaxNode= test.js~5-7:76-128
| doBoolean 0 (0%) 0 (0%) Min= 0 Avg= 0.00 Max= 0 MaxNode= -
| doInt <no-args> 1 (13%) 1 (4%) Min= 1 Avg= 1.00 Max= 1 MaxNode= test.js~5:81-87
| doDouble 0 (0%) 0 (0%) Min= 0 Avg= 0.00 Max= 0 MaxNode= -
| doObject <no-args> 8 (100%) 24 (96%) Min= 1 Avg= 3.00 Max= 5 MaxNode= test.js~5-7:76-128
| doSafeInteger 0 (0%) 0 (0%) Min= 0 Avg= 0.00 Max= 0 MaxNode= -
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------
| [doInt, doObject] 1 (13%) 4 (16%) Min= 4 Avg= 4.00 Max= 4 MaxNode= test.js~5:81-87
| doInt 1 (100%) 1 (25%) Min= 1 Avg= 1.00 Max= 1 MaxNode= test.js~5:81-87
| doObject 1 (100%) 3 (75%) Min= 3 Avg= 3.00 Max= 3 MaxNode= test.js~5:81-87
| [doObject] 7 (88%) 21 (84%) Min= 1 Avg= 3.00 Max= 5 MaxNode= test.js~5-7:76-128
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
直方图为每个节点类打印两个内部表格。
第一个表格将专业化和动态类型组合分组在一起。例如,在本直方图中,节点类 JSWriteCurrentFrameSlotNodeGen
被实例化了 8
次,执行了 18
次。这占总实例的 20%
,占本次运行所有节点执行的 11%
。
在本脚本中实例化了三个专业化,分别是 doBoolean
、doObject
和 doInt
。doBoolean
专业化只被实例化和执行了一次,占所有实例的 13%
,占该节点类所有执行的 6%
。doObject
专业化使用三个不同的输入值组合进行调用:DynamicObjectBasic
、IteratorRecord
和 String
。与专业化类似,我们可以看到它们使用的次数以及执行的次数。对于每一行,您可以看到每个实例的最小、平均和最大执行次数。最后一列打印实例的最大执行次数的源代码部分。
第二个表格将节点类使用的每个专业化组合分组在一起。
以下是一些您可能想从这些专业化统计数据中获取的答案
- 某个专业化组合是否很少使用,可以将其删除/合并成一个专业化吗?
- 是否存在一个具有非常常见类型组合的专业化,可以从中受益进一步的专业化吗?
- 哪些专业化组合是常见的,值得拥有自己的专业化?这可能表明代码中存在常见的多态性,可以进行研究。
- 常见的专业化有哪些,它们的数量是否与执行次数匹配?最常用的专业化应该在节点类中排在首位。这可能会提高解释器的性能。
- 是否存在意外实例化的专业化?如果有,请使用打印的源代码部分进一步调查。
- 哪些专业化经常被实例化,因此应该优化内存占用?
- 配置文件中是否存在名为
Uncached
的节点?未缓存节点的使用应该是很少见的。如果它们被频繁使用,那么值得深入研究一下原因。