Smalltalk Cog-VM与间接变量访问

Smalltalk Cog-VM与间接变量访问,smalltalk,pharo,squeak,Smalltalk,Pharo,Squeak,有人知道Pharo和Squeak的Cog VM是否能够通过如下访问器优化简单的间接变量访问: SomeClass>>someProperty ^ someProperty SomeClass>>someSecondProperty ^ someSecondProperty SomeClass>>someMethod ^ self someProperty doWith: self someSecondProperty SomeCla

有人知道Pharo和Squeak的Cog VM是否能够通过如下访问器优化简单的间接变量访问:

SomeClass>>someProperty
    ^ someProperty
SomeClass>>someSecondProperty
    ^ someSecondProperty
SomeClass>>someMethod
    ^ self someProperty doWith: self someSecondProperty
SomeClass>>someMethod
    ^ someProperty doWith: someSecondProperty
它只返回一个实例变量,因此如下方法:

SomeClass>>someProperty
    ^ someProperty
SomeClass>>someSecondProperty
    ^ someSecondProperty
SomeClass>>someMethod
    ^ self someProperty doWith: self someSecondProperty
SomeClass>>someMethod
    ^ someProperty doWith: someSecondProperty
不会比以下方法慢:

SomeClass>>someProperty
    ^ someProperty
SomeClass>>someSecondProperty
    ^ someSecondProperty
SomeClass>>someMethod
    ^ self someProperty doWith: self someSecondProperty
SomeClass>>someMethod
    ^ someProperty doWith: someSecondProperty

我做了一些基准测试,它们的速度看起来确实大致相当,但我很好奇,熟悉Cog的人是否确实知道,因为如果有差异(无论多么微小),那么可能会出现不合适的情况,无论这种情况多么罕见。

这是一个棘手的问题。。。我不知道确切的答案。但我可以帮你学习如何通过一些线索自己检查

您需要在映像中加载VMMaker包。在Pharo中,只需从网络和github下载所有内容,就可以创建这样的映像。看

然后主要提示是,只返回实例变量的方法被编译,就像执行原语264+inst var offset。。。(例如,您可以通过检查
Interval>#first
或任何其他简单的inst var getter来了解这一点)

在经典解释器VM中,这是在
解释器>>内部ExecuteNewMethod
中处理的
您似乎支付了方法查找的费用(一些缓存使其更便宜),但没有支付真正的方法激活的费用。
我想这解释了调试器无法进入如此简单的方法。。。然而,这并不是一个真正的内联

在COG中,如果使用了解释器,则在
stackexplorer>>internalQuickPrimitiveResponse
中也会发生同样的情况

至于JIT,这是由
Cogit>>compilePrimitive
处理的,另请参见
genQuickReturnInstVar
的实现者。这也不是正确的内联,但您可以看到生成的指令很少。再一次,我敢打赌,由于所谓的多态内联缓存(PIC),您通常不会为查找付出代价

对于真正的内联,在快速浏览源代码之后,我没有找到任何线索…
我的理解是,这将通过Sista VM的回调在图像端发生,但这是正在进行的工作,只是我模糊的回忆。克莱门特·贝拉(Clement Bera)正在写一篇关于这一点的博客(sista编年史在)

如果你害怕挖掘VMMaker源代码,我邀请你在vm-dev.lists.squekfoundation.org上提问,我很确定Eliot Miranda或Clement会很乐意给你一个更准确的答案

编辑


我忘了告诉你关于以上实验的结论:我认为如果你直接使用inst.var.而不是getter,会有非常小的区别,但这不应该是非常明显的,而且在所有情况下,您的编程风格不应该受到这些不可忽视的优化的指导。

现在有一点成本,但它太小了,您不应该费心。如果您想要性能,您愿意更改代码的其他部分,而不是实例变量访问

快速工作台: 长凳 ^{[iv你自己]板凳[iv你自己]板凳] =>#('52400000每秒。'49800000每秒。')) 差别看起来不大

一旦JIT并执行一次,区别在于“self iv”除了获取实例变量值外,还执行内联缓存检查、cpu调用和cpu返回。调用和返回指令很可能是cpu预期的,而不是真正执行的。这是关于内联缓存检查的,这是一个非常便宜的操作

开发中的内联编译器将添加的是,cpu调用和返回实际上将通过内联删除,这将涵盖cpu没有预料到的情况。此外,根据具体情况,可以删除或不删除内联缓存检查

有一些细节,比如getter方法需要编译为本机代码,这会占用机器代码区域的空间,这可能会增加机器代码区域垃圾收集的数量,但这比内联缓存检查开销更有趣

简言之,目前的开销很小,但将来会减少


Clement

法罗用户组和邮件列表也可能是询问的适当位置。有很多活动。是的,这个问题应该指向pharo-dev邮件列表和cog邮件列表,cog背后的Eliot可以详细回答。我认为编译器不能真正优化=self-someProperty=因为子类可能重写此方法,编译器在编译时无法知道所有子类。还有“快速”方法的概念。Send#is quick to a Compiled Method并查看此邮件的发件人。@Daminiceassou yes,quick methods是那些标记为发送quick原语的方法,虽然源代码中没有,但我的答案都是关于虚拟机中涉及的秘密处理它们的机器。。。重写的情况也由VM中的PIC处理,这就是为什么内联如此复杂的原因。因此,使用更高级的语言处理图像中的内联,但仅在VM检测到的热点处处理内联并不是一个坏选择。感谢您给出的精彩答案!