如何对Boost Spirit Parser进行基准测试?

时间:2013-06-04 13:14:00

标签: c++ benchmarking boost-spirit boost-spirit-qi boost-spirit-lex

我正在编写一个编译器,我想提高它的性能。我发现大约50%的时间花在解析源文件上。由于源文件非常小,之后我做了很多转换,在我看来它是可以完善的。

我的解析器是一个带有词法分析器(带有lexer :: pos_iterator)的Boost Spirit解析器,我有一个中等大小的语法。我正在将源解析为AST。

我的问题是我不知道解析过程中花费的时间最多:AST节点,词法分析器,解析器规则或内存的副本。

我不认为这是I / O问题,因为我正在使用SSD并且我在开始时完全读取文件然后仅使用内存版本。

我尝试使用分析器,但是花费时间的方法是Boost的一些方法,其名称长度为数百个字符,我不确切知道它们的作用......

那么,是否有一种首选方法来对Boost Spirit Parser及其语法进行基准测试? 或者是否有一些规则可用于验证某些特定点的效率?

由于

感兴趣的人的来源:

1 个答案:

答案 0 :(得分:12)

我已经快速扫描了一些东西。

我的探查器很快告诉我,构造语法和(特别是)词法分析器对象需要相当多的资源。

实际上,只需更改SpiritParser.cpp 中的一行就可以节省40%的执行时间 1 (〜28s降至~17s):

    lexer::Lexer lexer;

进入

    static const lexer::Lexer lexer;

现在,

  • 使语法静态涉及使其无状态。

    我做到了这一点
    • position_begin移至qi::_a(使用qi::locals)和
    • 在适当的时间将其作为继承属性传递

      • EDDIGrammarValueGrammar语法,例如

        start %= qi::eps [ qi::_a = qi::_r1 ] >> program;
        
      • 以及ValueGrammar中正在使用外部的个别规则。

    这有许多次优的副作用:

    • 规则调试已注释掉,因为lexer::pos_iterator_type没有默认输出流重载
    • qi::position(position_begin)表达式已被“伪造”,并且有一个相当复杂的替代品:

      auto local_pos = qi::lazy (
              boost::phoenix::construct<qi::position>(qi::_a)
          );
      

      这似乎并不理想。 (理想情况下,有人希望用修改过的自定义解析器指令替换qi::position,该指令知道如何从qi :: locals(?)获取begin_position,这样就不需要调用了解析器表达式懒惰?)

无论如何,implementing these further changes2 削减了约15%的执行时间

static const lexer::Lexer lexer;
static const parser::EddiGrammar grammar(lexer); 

try {
    bool r = spirit::lex::tokenize_and_parse(
            position_begin, position_end,
            lexer, 
            grammar(boost::phoenix::cref(position_begin)),
            program);

缺乏想法:

  • 您是否考虑过生成静态词法分析器(Generating the Static Analyzer
  • 您是否考虑过使用期望点来减少回溯量(注意:我没有测量该区域的任何内容)
  • 您是否考虑了Position::filePosition::theLine的替代方案?复制字符串似乎比必要的重。我更愿意存储const char *。您还可以查看Boost Flyweight
  • qi::position指令中是否真的需要预先跳过?
  • (有些不严重:您是否考虑过移植到Spirit X3?它似乎以移动语义的形式承诺潜在的好处。)

希望这有帮助。


[1] test/cases/*.eddi中解析所有测试用例100次like so (github)时:

for (int i=0; i<100; i++)
    for (auto& fname : argv)
{
    eddic::ast::SourceFile program;
    std::cout << fname << ": " << std::boolalpha << parser.parse(fname, program, nullptr) << "\n";
}

用简单的

计时
time ./test ../../test/cases/*.eddi | md5sum

md5sum充当理智检查。

[2] 我在这里创建了一个带有概念验证重构的拉取请求https://github.com/wichtounet/eddic/pull/52