虽然这听起来可能是理论上的问题,但假设我决定投资并构建用Haskell编写的关键任务应用程序。一年后,我发现我绝对需要提高一些非常薄的瓶颈的性能,这将需要优化接近原始计算机功能的内存访问。
一些假设:
GHC提供什么机制来执行这种优化?可靠地说,我的意思是,如果源更改导致代码不再执行,则它在源代码中是正确的,而无需在程序集中重写。
答案 0 :(得分:2)
听起来您正在寻找未装箱的阵列。 haskell-land中的“ unboxed”表示“没有运行时堆表示形式”。通常,您可以通过查看 core 表示形式(这是一种非常类似于haskell的语言,可以了解是否将代码的某些部分编译为未装箱的循环(不执行分配的循环))那是编译的第一阶段)。所以例如您可能会在核心输出中看到Int#
,这意味着它没有堆表示形式(将在寄存器中)。
在优化haskell代码时,我们会定期查看核心,并期望能够通过更改源代码(例如添加严格性注释或摆弄可以内联的函数)来操纵或纠正性能下降。这并不总是很有趣,但是会相当稳定,尤其是当您固定编译器版本时。
返回未装箱的数组:GHC在GHC.Prim中公开了许多低级primop,尤其是听起来像您想要可变的未装箱的数组(MutableByteArray
)。 primitive
软件包将这些primops公开在稍微更安全,更友好的API之后,这是您应使用的(并取决于是否编写自己的库)。
还有许多其他实现未装箱数组的库,例如vector
,它们建立在MutableByteArray
上,但要点是,对该结构的操作不会产生垃圾,并且可能会编译成漂亮的可预测的机器指令。
如果您正在执行数字运算,并且想要使用特定指令或直接在汇编中实现某些循环,您可能还想签出this technique。
GHC还具有非常强大的FFI,您可以研究如何使用C和互操作来编写程序的某些部分。 haskell为此目的还支持其他结构中的固定数组。
如果您需要的控制权超出了您的控制能力,那么haskell可能是错误的语言。从您的描述中无法判断出是否是您遇到的问题(您的要求似乎矛盾:您需要能够编写经过仔细的缓存调整的算法,但是任意GC暂停也可以吗?)。
最后一点:您不能依靠GHC的本机代码生成器来执行任何低级的强度降低优化,例如GCC会执行(GHC的NCG可能永远不会知道比特混乱,自动矢量化等)。相反,您可以尝试LLVM后端,但绝对不能保证程序中是否看到加速。