| //===--- 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 <string> |
| |
| using llvm::cl::desc; |
| using llvm::cl::opt; |
| using llvm::cl::Required; |
| |
| static opt<std::string> 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<std::unique_ptr<llvm::MemoryBuffer>> 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<uint64_t>(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<uint64_t>(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<uint64_t>(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<uint64_t>(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<uint64_t>(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; |
| } |