Как тестировать Boost Spirit Parser?

Я работаю над компилятором, и я хотел бы улучшить его производительность. Я обнаружил, что около 50% времени уходит на разбор исходных файлов. Поскольку исходный файл довольно мал, и после этого я довольно много преобразований, мне кажется, что он совершенен.

Мой анализатор — это анализатор Boost Spirit с лексером (с lexer :: pos_iterator), и у меня есть грамматика среднего размера. Я анализирую источник в AST.

Моя проблема в том, что я понятия не имею, что занимает больше всего времени при разборе: копии узлов AST, лексера, правил синтаксического анализатора или памяти.

Я не думаю, что это проблема ввода-вывода, так как я работаю на SSD и что я читаю файл полностью в начале, а затем использую только версию памяти.

Я пытался использовать профилировщики, но методы, которые требуют времени, — это некоторые методы Boost с именами длиной в сотни символов, и я не знаю точно, что они делают …

Итак, есть ли предпочтительный способ сравнить анализатор Boost Spirit и его грамматику?
Или есть какие-то правила, которые можно использовать для проверки эффективности в определенных точках?

Спасибо

Источники для заинтересованных:

15

Решение

Я дал вещи быстрого сканирования.

Мой профилировщик быстро сказал мне, что для создания грамматики и (особенно) объекта lexer потребовалось немало ресурсов.

Действительно, просто изменив одну строку в SpiritParser.cpp сэкономил 40% времени выполнения1 (~ 28 секунд до ~ 17 секунд):

    lexer::Lexer lexer;

в

    static const lexer::Lexer lexer;

Сейчас,

  • создание статики грамматики включает в себя ее сохранение без сохранения состояния. Я сделал это

    • перемещение position_begin в qi::_a (с помощью qi::locals) а также
    • передавая его как унаследованный атрибут в соответствующее время

      • EDDIGrammar а также ValueGrammar грамматики, например

        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 (?), поэтому нет необходимости вызывать выражение парсера лениво?)

В любом случае, реализуя эти дальнейшие изменения2 сбрил еще ~ 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);

Свободные идеи:

  • Рассматривали ли вы создание статического лексера (Генерация статического анализатора)
  • Рассматривали ли вы использование точек ожидания, чтобы потенциально уменьшить количество возвратов (примечание: я ничего не измерял в этой области)
  • Рассматривали ли вы альтернативы Position::file а также Position::theLine? Копирование строк кажется тяжелее, чем необходимо. Я бы предпочел хранить const char *, Вы также можете посмотреть на Boost Flyweight
  • Действительно ли предварительный пропуск действительно требуется внутри вашего qi::position Директива?
  • (Несколько несерьезно: рассматривали ли вы Дух X3? Похоже, обещают потенциальные выгоды в виде переместить семантику.)

Надеюсь это поможет.


[1] При разборе всех тестовых случаев в test/cases/*.eddi 100 раз вот так (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

12

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]