производительность antlr4 на многоядерном процессоре - PullRequest
0 голосов
/ 26 декабря 2018

Недавно я столкнулся с проблемой производительности моей программы.Наконец, расследование указывает на проблему глубоко в antlr4, которую я использую для разбора SQL.Как показано в коде, на dfa.states есть синхронизированный блок.Этот блок буквально ограничивает производительность анализа на компьютере с 8 или более ядрами.Мне интересно, сталкивался ли кто-нибудь с этим и нашел решение?

protected DFAState addDFAState(ATNConfigSet configs) {
    /* the lexer evaluates predicates on-the-fly; by this point configs
     * should not contain any configurations with unevaluated predicates.
     */
    assert !configs.hasSemanticContext;

    DFAState proposed = new DFAState(configs);
    ATNConfig firstConfigWithRuleStopState = null;
    for (ATNConfig c : configs) {
        if ( c.state instanceof RuleStopState ) {
            firstConfigWithRuleStopState = c;
            break;
        }
    }

    if ( firstConfigWithRuleStopState!=null ) {
        proposed.isAcceptState = true;
        proposed.lexerActionExecutor = ((LexerATNConfig)firstConfigWithRuleStopState).getLexerActionExecutor();
        proposed.prediction = atn.ruleToTokenType[firstConfigWithRuleStopState.state.ruleIndex];
    }

    DFA dfa = decisionToDFA[mode];
    synchronized (dfa.states) {
        DFAState existing = dfa.states.get(proposed);
        if ( existing!=null ) return existing;

        DFAState newState = proposed;

        newState.stateNumber = dfa.states.size();
        configs.setReadonly(true);
        newState.configs = configs;
        dfa.states.put(newState, newState);
        return newState;
    }
}

Ответы [ 2 ]

0 голосов
/ 28 декабря 2018

После нескольких дней борьбы я могу найти решение.Как сказал Майк Лиш, синхронизированный блок пытается уменьшить объем памяти.Но это оказывает значительное влияние на производительность на многоядерном компьютере с большой рабочей нагрузкой синтаксического анализа SQL.Я пытался проанализировать файл 100gb + SQL, созданный mysqldump.

Мое решение заключается в создании пользовательского интерпретатора с клонированным DFA вместо статического.Результат почти в 10 раз лучше на моем 16-ядерном потоке AMD AMD с загрузкой процессора выше 95%.

setInterpreter(new LexerATNSimulator(this, _ATN, getDFA(), new PredictionContextCache()));

private DFA[] getDFA() {
    DFA[] result = new DFA[_ATN.getNumberOfDecisions()];
    for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) {
        result[i] = new DFA(_ATN.getDecisionState(i), i);
    }
    return result;
}
0 голосов
/ 27 декабря 2018

Все экземпляры синтаксического анализатора для данного языка совместно используют один и тот же DFA (это статическая структура) по соображениям эффективности памяти.Однако для этого требуется сделать эту структуру безопасной для потока (парсеры могут использоваться в фоновых потоках).Обойти это невозможно.

...