我可以从哪里开始这个优化问题?

时间:2010-08-01 20:24:12

标签: language-agnostic optimization compiler-construction query-optimization

我有一个简单的程序,它从文件系统中读取大量内容,过滤结果并打印它们。这个简单的程序实现了特定于域的语言,使选择更容易。这个DSL“编译”成一个看起来像这样的执行计划(输入是C:\Windows\System32\* OR -md5"ABCDEFG" OR -tf):

Index  Success  Failure  Description
    0        S        1  File Matches C:\Windows\System32\*
    1        S        2  File MD5 Matches ABCDEFG
    2        S        F  File is file. (Not directory)

过滤器应用于给定文件,如果成功,则索引指针跳转到成功字段中指示的索引,如果失败,则索引指针跳转到失败字段中指示的数字。 “S”表示文件通过过滤器,F表示该文件应该被拒绝。

当然,基于简单文件属性(!FILE_ATTRIBUTE_DIRECTORY)检查的过滤器比基于文件MD5的检查快得多,这需要打开并执行文件的实际散列。每个过滤器“操作码”都有一个与之关联的时间类; MD5获得一个高时序数,ISFILE获得一个低时序数。

我想重新排序此执行计划,以便尽可能少地执行需要很长时间的操作码。对于上述计划,这意味着它必须是:

Index  Success  Failure  Description
    0        S        1  File is file. (Not directory)
    1        S        2  File Matches C:\Windows\System32\*
    2        S        F  File MD5 Matches ABCDEFG

根据“龙书”,选择三个地址代码的最佳执行顺序是NP-Complete问题(至少根据该文本第二版的第511页),但在这种情况下,他们正在谈论关于寄存器分配和机器的其他问题。就我而言,实际的“中间代码”要简单得多。我想知道一个允许我将源IL重新排序为最佳执行计划的方案。

这是另一个例子:
{C:\ Windows \ Inf * AND -tp}或{-tf AND NOT C:\ Windows \ System32 \ Drivers *}

解析:

Index  Success  Failure  Description
    0        1        2  File Matches C:\Windows\Inf\*
    1        S        2  File is a Portable Executable
    2        3        F  File is file. (Not directory)
    3        F        S  File Matches C:\Windows\System32\Drivers\*

最佳:

Index  Success  Failure  Description
    0        1        2  File is file. (Not directory)
    1        2        S  File Matches C:\Windows\System32\Drivers\*
    2        3        F  File Matches C:\Windows\Inf\*
    3        S        F  File is a Portable Executable

2 个答案:

答案 0 :(得分:3)

听起来在编译到您的操作码之前选择最佳订单可能更容易。如果您有一个解析树,并且它尽可能“平坦”,那么您可以为每个节点分配一个分数,然后按照最低总分数对每个节点的子项进行排序。

例如:

{ C:\Windows\Inf* AND -tp } OR { -tf AND NOT C:\Windows\System32\Drivers* }
         1             2          3                 4

      OR
     /  \
  AND    AND
 /  \   /   \
1    2 3     4

您可以按最低分数对AND节点(1,2)和(3,4)进行排序,然后将该分数分配给每个节点。然后按他们的子项的最低分数对OR节点的子项进行排序。

由于AND和OR是可交换的,因此这种排序操作不会改变整体表达的含义。

答案 1 :(得分:1)

@Greg Hewgill是对的,这在AST上比在中级代码上更容易执行。当您想要处理中间代码时,第一个目标是将其转换为依赖树(看起来像AST /耸肩)。

从叶子开始 - 如果你对NOT使用否定谓词,这可能是最简单的。

Index  Success  Failure  Description
0        1        2  File Matches C:\Windows\Inf\*
1        S        2  File is a Portable Executable
2        3        F  File is file. (Not directory)
3        F        S  File Matches C:\Windows\System32\Drivers\*

Extract Leaf(将子节点作为S,F或提取的节点的任何内容;在需要时插入NOT;将所有对Leaf的引用替换为对叶子节点的引用)

Index  Success  Failure  Description
0        1        2  File Matches C:\Windows\Inf\*
1        S        2  File is a Portable Executable
2        L1        F  File is file. (Not directory)

L1=NOT(cost(child))
    |
Pred(cost(PATH))

提取节点(如果成功指向提取的节点使用连接加入;失败使用析取;替换所有对节点的引用,并引用包含节点的树的结果根。)

Index  Success  Failure  Description
0        1        L3  File Matches C:\Windows\Inf\*
1        S        L3  File is a Portable Executable


L3=AND L1 L2 (cost(Min(L1,L2) + Selectivity(Min(L1,L2)) * Max(L1,L2)))
               /           \
L1=NOT(cost(child))     L2=IS(cost(child))
    |                       |
3=Pred(cost(PATH))      2=Pred(cost(ISFILE))

提取节点

Index  Success  Failure  Description
0        L5       L3  File Matches C:\Windows\Inf\*

L5=OR L3 L4 (cost(Min(L3,L4) + (1.0 - Selectivity(Min(L3,L4))) * Max(L3,L4)))
                    /                          \
                    |                       L4=IS(cost(child))
                    |                           | 
                    |                       1=Pred(cost(PORT_EXE))
                    |
L3=AND L1 L2 (cost(Min(L1,L2) + Selectivity(Min(L1,L2)) * Max(L1,L2)))
               /           \
L1=NOT(cost(child))     L2=IS(cost(child))
    |                       |
3=Pred(cost(PATH))      2=Pred(cost(ISFILE))

提取节点(在成功和失败都引用节点的情况下,您必须通过节点定义的子树的根上的模式匹配将节点注入树中)

  1. 如果root为OR,则在必要时反转谓词以确保引用为Success,并将其作为与未被Failure引用的子项的连接注入。

  2. 如果root是AND,则在必要时反转谓词以确保引用为Failure并注入与Success引用的子根分离。

  3. 导致:

    L5=OR L3 L4 (cost(Min(L3,L4) + (1.0 - Selectivity(Min(L3,L4))) * Max(L3,L4)))
                        /                          \
                        |                       L4=AND(cost(as for L3))
                        |                             /               \
                        |                       L6=IS(cost(child))   L7=IS(cost(child))
                        |                           |                       |
                        |                       1=Pred(cost(PORT_EXE))   0=Pred(cost(PATH))
                        |
    L3=AND L1 L2 (cost(Min(L1,L2) + Selectivity(Min(L1,L2)) * Max(L1,L2)))
                   /           \
    L1=NOT(cost(child))     L2=IS(cost(child))
        |                       |
    3=Pred(cost(PATH))      2=Pred(cost(ISFILE))