1 //===--- Benchmark.cpp - clang pseudoparser benchmarks ---------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Benchmark for the overall pseudoparser performance, it also includes other 10 // important pieces of the pseudoparser (grammar compliation, LR table build 11 // etc). 12 // 13 // Note: make sure we build it in Relase mode. 14 // 15 // Usage: 16 // tools/clang/tools/extra/pseudo/benchmarks/ClangPseudoBenchmark \ 17 // --grammar=/path/to/cxx.bnf --source=/patch/to/source-to-parse.cpp \ 18 // --benchmark_filter=runParseOverall 19 // 20 //===----------------------------------------------------------------------===// 21 22 #include "benchmark/benchmark.h" 23 #include "clang-pseudo/DirectiveTree.h" 24 #include "clang-pseudo/Forest.h" 25 #include "clang-pseudo/GLR.h" 26 #include "clang-pseudo/Grammar.h" 27 #include "clang-pseudo/LRTable.h" 28 #include "clang-pseudo/Token.h" 29 #include "clang/Basic/LangOptions.h" 30 #include "llvm/ADT/StringRef.h" 31 #include "llvm/Support/CommandLine.h" 32 #include "llvm/Support/ErrorOr.h" 33 #include "llvm/Support/MemoryBuffer.h" 34 #include "llvm/Support/raw_ostream.h" 35 #include <string> 36 37 using llvm::cl::desc; 38 using llvm::cl::init; 39 using llvm::cl::opt; 40 41 static opt<std::string> GrammarFile("grammar", 42 desc("Parse and check a BNF grammar file."), 43 init("")); 44 static opt<std::string> Source("source", desc("Source file")); 45 46 namespace clang { 47 namespace pseudo { 48 namespace { 49 50 const std::string *GrammarText = nullptr; 51 const std::string *SourceText = nullptr; 52 const Grammar *G = nullptr; 53 54 void setupGrammarAndSource() { 55 auto ReadFile = [](llvm::StringRef FilePath) -> std::string { 56 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> GrammarText = 57 llvm::MemoryBuffer::getFile(FilePath); 58 if (std::error_code EC = GrammarText.getError()) { 59 llvm::errs() << "Error: can't read file '" << FilePath 60 << "': " << EC.message() << "\n"; 61 std::exit(1); 62 } 63 return GrammarText.get()->getBuffer().str(); 64 }; 65 GrammarText = new std::string(ReadFile(GrammarFile)); 66 SourceText = new std::string(ReadFile(Source)); 67 std::vector<std::string> Diags; 68 G = Grammar::parseBNF(*GrammarText, Diags).release(); 69 } 70 71 static void runParseBNFGrammar(benchmark::State &State) { 72 std::vector<std::string> Diags; 73 for (auto _ : State) 74 Grammar::parseBNF(*GrammarText, Diags); 75 } 76 BENCHMARK(runParseBNFGrammar); 77 78 static void runBuildLR(benchmark::State &State) { 79 for (auto _ : State) 80 clang::pseudo::LRTable::buildSLR(*G); 81 } 82 BENCHMARK(runBuildLR); 83 84 TokenStream parseableTokenStream() { 85 clang::LangOptions LangOpts = genericLangOpts(); 86 TokenStream RawStream = clang::pseudo::lex(*SourceText, LangOpts); 87 auto DirectiveStructure = DirectiveTree::parse(RawStream); 88 clang::pseudo::chooseConditionalBranches(DirectiveStructure, RawStream); 89 TokenStream Cook = 90 cook(DirectiveStructure.stripDirectives(RawStream), LangOpts); 91 return clang::pseudo::stripComments(Cook); 92 } 93 94 static void runPreprocessTokens(benchmark::State &State) { 95 for (auto _ : State) 96 parseableTokenStream(); 97 State.SetBytesProcessed(static_cast<uint64_t>(State.iterations()) * 98 SourceText->size()); 99 } 100 BENCHMARK(runPreprocessTokens); 101 102 static void runGLRParse(benchmark::State &State) { 103 clang::LangOptions LangOpts = genericLangOpts(); 104 LRTable Table = clang::pseudo::LRTable::buildSLR(*G); 105 TokenStream ParseableStream = parseableTokenStream(); 106 SymbolID StartSymbol = *G->findNonterminal("translation-unit"); 107 for (auto _ : State) { 108 pseudo::ForestArena Forest; 109 pseudo::GSS GSS; 110 glrParse(ParseableStream, ParseParams{*G, Table, Forest, GSS}, StartSymbol); 111 } 112 State.SetBytesProcessed(static_cast<uint64_t>(State.iterations()) * 113 SourceText->size()); 114 } 115 BENCHMARK(runGLRParse); 116 117 static void runParseOverall(benchmark::State &State) { 118 clang::LangOptions LangOpts = genericLangOpts(); 119 LRTable Table = clang::pseudo::LRTable::buildSLR(*G); 120 SymbolID StartSymbol = *G->findNonterminal("translation-unit"); 121 for (auto _ : State) { 122 pseudo::ForestArena Forest; 123 pseudo::GSS GSS; 124 glrParse(parseableTokenStream(), ParseParams{*G, Table, Forest, GSS}, 125 StartSymbol); 126 } 127 State.SetBytesProcessed(static_cast<uint64_t>(State.iterations()) * 128 SourceText->size()); 129 } 130 BENCHMARK(runParseOverall); 131 132 } // namespace 133 } // namespace pseudo 134 } // namespace clang 135 136 int main(int argc, char *argv[]) { 137 benchmark::Initialize(&argc, argv); 138 llvm::cl::ParseCommandLineOptions(argc, argv); 139 clang::pseudo::setupGrammarAndSource(); 140 benchmark::RunSpecifiedBenchmarks(); 141 return 0; 142 } 143