//===--- 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 to build the benchmark in Release mode. // // Usage: // tools/clang/tools/extra/pseudo/benchmarks/ClangPseudoBenchmark \ // --grammar=../clang-tools-extra/pseudo/lib/cxx.bnf \ // --source=../clang/lib/Sema/SemaDecl.cpp // //===----------------------------------------------------------------------===// #include "benchmark/benchmark.h" #include "clang-pseudo/Bracket.h" #include "clang-pseudo/DirectiveTree.h" #include "clang-pseudo/Forest.h" #include "clang-pseudo/GLR.h" #include "clang-pseudo/Token.h" #include "clang-pseudo/cli/CLI.h" #include "clang-pseudo/grammar/Grammar.h" #include "clang-pseudo/grammar/LRTable.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::opt; using llvm::cl::Required; static opt Source("source", desc("Source file"), Required); namespace clang { namespace pseudo { namespace bench { namespace { const std::string *SourceText = nullptr; const Language *Lang = nullptr; void setup() { 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(); }; SourceText = new std::string(ReadFile(Source)); Lang = &getLanguageFromFlags(); } static void buildSLR(benchmark::State &State) { for (auto _ : State) LRTable::buildSLR(Lang->G); } BENCHMARK(buildSLR); TokenStream lexAndPreprocess() { clang::LangOptions LangOpts = genericLangOpts(); TokenStream RawStream = pseudo::lex(*SourceText, LangOpts); auto DirectiveStructure = DirectiveTree::parse(RawStream); chooseConditionalBranches(DirectiveStructure, RawStream); TokenStream Cook = cook(DirectiveStructure.stripDirectives(RawStream), LangOpts); auto Stream = stripComments(Cook); pairBrackets(Stream); return Stream; } static void lex(benchmark::State &State) { clang::LangOptions LangOpts = genericLangOpts(); for (auto _ : State) clang::pseudo::lex(*SourceText, LangOpts); State.SetBytesProcessed(static_cast(State.iterations()) * SourceText->size()); } BENCHMARK(lex); static void pairBrackets(benchmark::State &State) { clang::LangOptions LangOpts = genericLangOpts(); auto Stream = clang::pseudo::lex(*SourceText, LangOpts); for (auto _ : State) pairBrackets(Stream); State.SetBytesProcessed(static_cast(State.iterations()) * SourceText->size()); } BENCHMARK(pairBrackets); static void preprocess(benchmark::State &State) { clang::LangOptions LangOpts = genericLangOpts(); TokenStream RawStream = clang::pseudo::lex(*SourceText, LangOpts); for (auto _ : State) { auto DirectiveStructure = DirectiveTree::parse(RawStream); chooseConditionalBranches(DirectiveStructure, RawStream); stripComments( cook(DirectiveStructure.stripDirectives(RawStream), LangOpts)); } State.SetBytesProcessed(static_cast(State.iterations()) * SourceText->size()); } BENCHMARK(preprocess); static void glrParse(benchmark::State &State) { SymbolID StartSymbol = *Lang->G.findNonterminal("translation-unit"); TokenStream Stream = lexAndPreprocess(); for (auto _ : State) { pseudo::ForestArena Forest; pseudo::GSS GSS; pseudo::glrParse(ParseParams{Stream, Forest, GSS}, StartSymbol, *Lang); } State.SetBytesProcessed(static_cast(State.iterations()) * SourceText->size()); } BENCHMARK(glrParse); static void full(benchmark::State &State) { SymbolID StartSymbol = *Lang->G.findNonterminal("translation-unit"); for (auto _ : State) { TokenStream Stream = lexAndPreprocess(); pseudo::ForestArena Forest; pseudo::GSS GSS; pseudo::glrParse(ParseParams{Stream, Forest, GSS}, StartSymbol, *Lang); } State.SetBytesProcessed(static_cast(State.iterations()) * SourceText->size()); } BENCHMARK(full); } // namespace } // namespace bench } // namespace pseudo } // namespace clang int main(int argc, char *argv[]) { benchmark::Initialize(&argc, argv); llvm::cl::ParseCommandLineOptions(argc, argv); clang::pseudo::bench::setup(); benchmark::RunSpecifiedBenchmarks(); return 0; }