确定在什么情况下哪些变量是常数

时间:2010-05-11 06:44:38

标签: optimization runtime jit

这个想法与Apple has done in the OpenGL stack有些相似。我希望有一点更普遍。

基本上,我希望针对某些特定情况使用某些代码的专用和优化变体。

换句话说:我给了一个函数的算法/代码(让B = {0,1})

f : B^n -> B^m

现在,我特别针对一个函数的特定情况(预定义 f 的部分输入)

preset : {1..n} -> {0,1,unset}

预定义的数量(∈{0..n})由

给出
pn := |preset⁻¹({0,1})|

通常,我们现在获得一个专门的功能

f_preset : B^(n-pn) -> B^m

同样规范地说,我们得到了这个专用函数的代码/算法。当然, f_preset 的代码比 f 的代码快一些,pn> 0.然后,您还可以进一步优化此代码(现在可能存在一些死代码,现在可以解压缩一些循环,可以预先计算某些计算等)。在某些情况下,它可以有显着的改进。

Apple为他们的OpenGL堆栈(从我已阅读/知道的内容)大致做到了这一点:他们试图在运行时找到一个好的预设,然后设置变量不再变化,然后制作专业版的优化版本功能,只使用那个而不是原始功能。

最初,我想到了一种优化某些游戏的物理模拟的方法。我有很多粒子对象和一组粒子类型(在编译时是未知的)。粒子类型是一组属性。粒子类型在加载后是固定不变的。每个粒子对象都是其中一种粒子类型。粒子对象的物理模拟是一些非常重的代码,具有许多分支并且在很大程度上取决于粒子类型。我的想法是为每种粒子类型设置一个优化的物理模拟函数。

在考虑了一下之后,我想进一步了解一下:

我想在运行时自动计算一组这样的预设,并为每个预设维护优化的代码。我想在情况发生变化时自动添加或删除预设。

现在有几个问题:

  • 有没有简单的方法来计算好的预设?我怎么知道给定情况下哪些变量是常数?
  • 有没有简单的方法来检查预设有多好? “好”指的是最终优化代码的性能。
  • 如何比较两种算法/代码的性能?通过一些启发式?或者通过随机输入进行测试?
  • 一个函数应该有多少个预设(和优化的代码变体)?所有功能的固定限制?或者每种功能都有所不同吗?是否可能取决于当前的计算机状态?
  • 如何维护不同的优化代码变体?围绕 f 的包装函数自动选择最佳的优化变体似乎不是很好,因为这可能不是那么容易检查每个单独的调用。这个问题的解决方案也可能与如何找到良好预设的集合/数量的问题密切相关。 (在粒子类型的情况下,优化的代码将与粒子类型一起附加/保存。粒子类型的数量也定义预设量。)

对于我最初的案例,大多数这些问题已经过时,但我现在对如何以更一般的方式做这件事感兴趣。当然,大多数/所有这些问题都是不可估算的,但我想知道你在多大程度上仍然可以取得好成绩。

这整个主题对于JIT编译器的优化也非常重要。他们是否已经进行了这些优化?到什么程度?

最近有很好的研究工作可以回答我的一些问题吗?或者也许还有一些结果表明以这样一般的方式做这件事太难了?

1 个答案:

答案 0 :(得分:0)

在我看来,你问的是partial evaluation

我实际上对这个概念有点问题,因为它通常用过度学术和过度困难的术语表达。

通常表达的方式是你有一些通用函数F(Islow, Ifast),其参数可以在不同的时间采用不同的值。 Islow参数很少更改,每次调用时Ifast参数都可以不同。

然后问题是编写某种部分评估函数G(F, Islow) -> F1(Ifast),它接受​​函数FIslow参数,并生成一个新的(更简单的)函数{{1}只接受F1个参数。

这个问题是1)有人必须编写通用函数Ifast,2)有人必须编写一般的部分求值程序F

对我来说更有意义的是从头开始编写函数G,即专门为H(Islow) -> F1(Ifast)编写代码生成器,而不是编写两个函数F1和{ {1}},尤其是F很难写的地方。

G通常比G更容易编写,H根本不需要写!结果函数F通常较小且性能远高于G,因此这是一个双赢的局面。

当人们编写代码生成器时,这就是他们正在做的事情,而且这是一种非常有效的编程技术。