是否可以为ANTLR4语法强制构建完整的DFA缓存?

时间:2018-06-13 00:46:16

标签: c++ antlr4

我正在考虑移植使用从ANTLR3到ANTLR4的C ++运行时的JavaScript语法(从技术上讲,ANTLR3版本使用C运行时,但现在不相关)。

我正在努力解决的主要问题是表现。我有几个性能问题阻止我得到甚至接近0的开销,但我将专注于这个线程中最严重的一个:构建完整的缓存DFA并解析命中的文件似乎非常困难未缓存的过渡非常缓慢。

我创建了一个包含16个文件的小型测试套件,并分解了热备和测试阶段。 (Antlr3并不需要热身,但无论如何)

当预热设置===测试集(每个16个文件)

Test            ms
------------------
Antlr3Warmup   338 
Antlr4Warmup 55860  
Antlr3Test     335 
Antlr4Test     439

看起来很近吗?现在让我们看看如果集合是不相交的(每个8个文件)会发生什么

Test            ms
------------------
Antlr3Warmup    78  
Antlr4Warmup 32032  
Antlr3Test     273  
Antlr4Test   24356

显然,在32秒内它甚至没有接近构建DFA - 我们刚刚构建足以在相同文件上获得良好性能。我可以尝试在预热套件中添加更多文件,但性能似乎永远不会提高,并且需要大约15米才能通过更大的热身套件(例如jquery + angular + react)。分析执行表明确实瓶颈是ParserATNSimulator::computeTargetState

发生了什么事?有没有更智能的方法来构建完整的DFA缓存?例如。 Parser::buildCompleteDFA()

对于某些上下文,我从https://github.com/antlr/grammars-v4/blob/master/javascript/JavaScriptParser.g4开始并重构了singleExpression规则以使整个语法SLL(在此之前,性能似乎更糟)。

编辑:伊万建议左递归重构可能是罪魁祸首。所以这里是没有重构的相同基准(语法现在是LL):

当预热设置===测试集(每个16个文件)

Benchmark      ms
--------------------
Antlr3Warmup  337  
Antlr4Warmup 4224
Antlr3Test    311
Antlr4Test   1785

ANTLR4在完全缓存的文件上失去了优势,但非缓存文件的性能有所提升。在构建DFA缓存后,它会在长时间内发挥作用吗?

Benchmark      ms (same as before) ms (extra warmup)
--------------------
Antlr3Warmup                    77                77  
Antlr4Warmup                   455             47649
Antlr3Test                     275               274
Antlr4Test                    3750              3559

没那么多。我敢打赌,越来越长的热身会改善表现,但是之前测试的1785个数字是下限。

编辑2:这里有一些关于下限如此之高的分析数据:

Time spent w/ ATN transition logic: 12%
Time spent accessing the DFA:       16%
Time spent w/ shared_ptr:           27%
Time spent w/ dynamic_casts:        33%

(这已经在我已经删除了一些dynamic_casts之后。实际上这些都是向下转发,但我想LLVM无法很好地优化它)

另外,即使同一个文件被运行两次,我仍然会看到对computeReachSet的调用!在SLL语法中,解析器adaptivePredict只会调用getExistingTargetState

0 个答案:

没有答案