Zac*_*rns 5 c# performance cil ryujit
有时我想在原始双打周围增加更多类型的安全性.出现的一个想法是添加类型的单位信息.例如,
struct AngleRadians {
public readonly double Value;
/* Constructor, casting operator to AngleDegrees, etc omitted for brevity... */
}
Run Code Online (Sandbox Code Playgroud)
在如上所述的情况下,只有一个字段,JIT是否能够在所有情况下优化这种抽象?与使用未包装的双倍的类似代码相比,什么情况(如果有的话)将导致额外生成的机器指令?
任何提及过早优化的内容都将被低估.我很想知道真相.
编辑:为了缩小问题的范围,这里有几个特别感兴趣的场景......
// 1. Is the value-copy constructor zero cost?
// Is...
var angleRadians = new AngleRadians(myDouble);
// The same as...
var myDouble2 = myDouble;
// 2. Is field access zero cost?
// Is...
var myDouble2 = angleRadians.Value;
// The same as...
var myDouble2 = myDouble;
// 3. Is function passing zero cost?
// Is calling...
static void DoNaught(AngleRadians angle){}
// The same as...
static void DoNaught(double angle){}
// (disregarding inlining reducing this to a noop
Run Code Online (Sandbox Code Playgroud)
这些是我能想到的一些问题.当然,像@EricLippert这样出色的语言设计师可能会想到更多场景.因此,即使这些典型的用例是零成本,我仍然认为最好知道是否存在JIT不处理持有一个值的结构,并且将未包装的值视为等效的情况,而不列出每个可能的代码片段,因为它是自己的问题
由于 ABI 要求,可能存在一些细微且可观察到的差异。例如,对于 Windows x64,结构包装的浮点数或双精度数将通过整数寄存器传递给被调用方,而浮点数和双精度数通过 XMM 寄存器传递(类似于返回值)。最多可以通过寄存器传递 4 个整数和 4 个浮点数。
这的实际影响非常依赖于上下文。
如果扩展示例以传递至少 5 个整数和 struct-or-double args 的混合,则在 struct 包裹的 double 情况下,整数 arg 寄存器将更快用完,并且调用和访问尾随(非寄存器传递) ) 被调用方中的 args 会稍微慢一些。但是效果可能很微妙,因为第一个被调用者访问通常会将结果缓存回寄存器中。
同样,如果您传递至少 5 个双打和结构包裹双打的混合,则与将所有 args 作为双精度传递或所有 args 作为结构包裹双精度传递相比,您可以在一次调用中在寄存器中放入更多的东西。因此,使用一些结构包裹的双打和一些非结构包裹的双打可能会有一些小优势。
因此,孤立地看,如果寄存器中有更多的 args,则纯调用开销和对 args 的原始访问会降低,这意味着如果有许多其他双打,结构包装一些双打会有所帮助,而如果有许多其他双打,则结构包装不会有帮助其他整数。
但是,如果调用者和被调用者都使用这些值进行计算并接收或传递它们,则会出现复杂情况——通常在这些情况下,结构包装最终会慢一点,因为这些值必须从 int 寄存器移动到堆栈或(可能)一个浮点寄存器。
这是否会抵消调用中的小潜在收益取决于计算与调用的相对平衡以及传递的参数数量以及参数的类型、寄存器压力等。
具有 HFA 结构传递规则的 ABI 往往与这种事情更好地隔离,因为它们可以在浮点寄存器中传递结构包裹的浮点数。
| 归档时间: |
|
| 查看次数: |
261 次 |
| 最近记录: |