//===--- Benchmark.cpp - clang pseudoparser benchmarks ---------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // Benchmark for the overall pseudoparser performance, it also includes other // important pieces of the pseudoparser (grammar compliation, LR table build // etc). // // Note: make sure we build it in Relase mode. // // Usage: // tools/clang/tools/extra/pseudo/benchmarks/ClangPseudoBenchmark \ // --grammar=/path/to/cxx.bnf --source=/patch/to/source-to-parse.cpp \ // --benchmark_filter=runParseOverall // //===----------------------------------------------------------------------===// #include "benchmark/benchmark.h" #include "clang-pseudo/DirectiveTree.h" #include "clang-pseudo/Forest.h" #include "clang-pseudo/GLR.h" #include "clang-pseudo/Grammar.h" #include "clang-pseudo/LRTable.h" #include "clang-pseudo/Token.h" #include "clang/Basic/LangOptions.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include using llvm::cl::desc; using llvm::cl::init; using llvm::cl::opt; static opt GrammarFile("grammar", desc("Parse and check a BNF grammar file."), init("")); static opt Source("source", desc("Source file")); namespace clang { namespace pseudo { namespace { const std::string *GrammarText = nullptr; const std::string *SourceText = nullptr; const Grammar *G = nullptr; void setupGrammarAndSource() { auto ReadFile = [](llvm::StringRef FilePath) -> std::string { llvm::ErrorOr> GrammarText = llvm::MemoryBuffer::getFile(FilePath); if (std::error_code EC = GrammarText.getError()) { llvm::errs() << "Error: can't read file '" << FilePath << "': " << EC.message() << "\n"; std::exit(1); } return GrammarText.get()->getBuffer().str(); }; GrammarText = new std::string(ReadFile(GrammarFile)); SourceText = new std::string(ReadFile(Source)); std::vector Diags; G = Grammar::parseBNF(*GrammarText, Diags).release(); } static void runParseBNFGrammar(benchmark::State &State) { std::vector Diags; for (auto _ : State) Grammar::parseBNF(*GrammarText, Diags); } BENCHMARK(runParseBNFGrammar); static void runBuildLR(benchmark::State &State) { for (auto _ : State) clang::pseudo::LRTable::buildSLR(*G); } BENCHMARK(runBuildLR); TokenStream parseableTokenStream() { clang::LangOptions LangOpts = genericLangOpts(); TokenStream RawStream = clang::pseudo::lex(*SourceText, LangOpts); auto DirectiveStructure = DirectiveTree::parse(RawStream); clang::pseudo::chooseConditionalBranches(DirectiveStructure, RawStream); TokenStream Cook = cook(DirectiveStructure.stripDirectives(RawStream), LangOpts); return clang::pseudo::stripComments(Cook); } static void runPreprocessTokens(benchmark::State &State) { for (auto _ : State) parseableTokenStream(); State.SetBytesProcessed(static_cast(State.iterations()) * SourceText->size()); } BENCHMARK(runPreprocessTokens); static void runGLRParse(benchmark::State &State) { clang::LangOptions LangOpts = genericLangOpts(); LRTable Table = clang::pseudo::LRTable::buildSLR(*G); TokenStream ParseableStream = parseableTokenStream(); SymbolID StartSymbol = *G->findNonterminal("translation-unit"); for (auto _ : State) { pseudo::ForestArena Forest; pseudo::GSS GSS; glrParse(ParseableStream, ParseParams{*G, Table, Forest, GSS}, StartSymbol); } State.SetBytesProcessed(static_cast(State.iterations()) * SourceText->size()); } BENCHMARK(runGLRParse); static void runParseOverall(benchmark::State &State) { clang::LangOptions LangOpts = genericLangOpts(); LRTable Table = clang::pseudo::LRTable::buildSLR(*G); SymbolID StartSymbol = *G->findNonterminal("translation-unit"); for (auto _ : State) { pseudo::ForestArena Forest; pseudo::GSS GSS; glrParse(parseableTokenStream(), ParseParams{*G, Table, Forest, GSS}, StartSymbol); } State.SetBytesProcessed(static_cast(State.iterations()) * SourceText->size()); } BENCHMARK(runParseOverall); } // namespace } // namespace pseudo } // namespace clang int main(int argc, char *argv[]) { benchmark::Initialize(&argc, argv); llvm::cl::ParseCommandLineOptions(argc, argv); clang::pseudo::setupGrammarAndSource(); benchmark::RunSpecifiedBenchmarks(); return 0; }