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 to build the benchmark in Release mode. 14 // 15 // Usage: 16 // tools/clang/tools/extra/pseudo/benchmarks/ClangPseudoBenchmark \ 17 // --grammar=../clang-tools-extra/pseudo/lib/cxx.bnf \ 18 // --source=../clang/lib/Sema/SemaDecl.cpp 19 // 20 //===----------------------------------------------------------------------===// 21 22 #include "benchmark/benchmark.h" 23 #include "clang-pseudo/Bracket.h" 24 #include "clang-pseudo/DirectiveTree.h" 25 #include "clang-pseudo/Forest.h" 26 #include "clang-pseudo/GLR.h" 27 #include "clang-pseudo/Token.h" 28 #include "clang-pseudo/grammar/Grammar.h" 29 #include "clang-pseudo/grammar/LRTable.h" 30 #include "clang/Basic/LangOptions.h" 31 #include "llvm/ADT/StringRef.h" 32 #include "llvm/Support/CommandLine.h" 33 #include "llvm/Support/ErrorOr.h" 34 #include "llvm/Support/MemoryBuffer.h" 35 #include "llvm/Support/raw_ostream.h" 36 #include <string> 37 38 using llvm::cl::desc; 39 using llvm::cl::opt; 40 using llvm::cl::Required; 41 42 static opt<std::string> GrammarFile("grammar", 43 desc("Parse and check a BNF grammar file."), 44 Required); 45 static opt<std::string> Source("source", desc("Source file"), Required); 46 47 namespace clang { 48 namespace pseudo { 49 namespace bench { 50 namespace { 51 52 const std::string *GrammarText = nullptr; 53 const std::string *SourceText = nullptr; 54 const Grammar *G = nullptr; 55 56 void setupGrammarAndSource() { 57 auto ReadFile = [](llvm::StringRef FilePath) -> std::string { 58 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> GrammarText = 59 llvm::MemoryBuffer::getFile(FilePath); 60 if (std::error_code EC = GrammarText.getError()) { 61 llvm::errs() << "Error: can't read file '" << FilePath 62 << "': " << EC.message() << "\n"; 63 std::exit(1); 64 } 65 return GrammarText.get()->getBuffer().str(); 66 }; 67 GrammarText = new std::string(ReadFile(GrammarFile)); 68 SourceText = new std::string(ReadFile(Source)); 69 std::vector<std::string> Diags; 70 G = Grammar::parseBNF(*GrammarText, Diags).release(); 71 } 72 73 static void parseBNF(benchmark::State &State) { 74 std::vector<std::string> Diags; 75 for (auto _ : State) 76 Grammar::parseBNF(*GrammarText, Diags); 77 } 78 BENCHMARK(parseBNF); 79 80 static void buildSLR(benchmark::State &State) { 81 for (auto _ : State) 82 LRTable::buildSLR(*G); 83 } 84 BENCHMARK(buildSLR); 85 86 TokenStream lexAndPreprocess() { 87 clang::LangOptions LangOpts = genericLangOpts(); 88 TokenStream RawStream = pseudo::lex(*SourceText, LangOpts); 89 auto DirectiveStructure = DirectiveTree::parse(RawStream); 90 chooseConditionalBranches(DirectiveStructure, RawStream); 91 TokenStream Cook = 92 cook(DirectiveStructure.stripDirectives(RawStream), LangOpts); 93 auto Stream = stripComments(Cook); 94 pairBrackets(Stream); 95 return Stream; 96 } 97 98 static void lex(benchmark::State &State) { 99 clang::LangOptions LangOpts = genericLangOpts(); 100 for (auto _ : State) 101 clang::pseudo::lex(*SourceText, LangOpts); 102 State.SetBytesProcessed(static_cast<uint64_t>(State.iterations()) * 103 SourceText->size()); 104 } 105 BENCHMARK(lex); 106 107 static void pairBrackets(benchmark::State &State) { 108 clang::LangOptions LangOpts = genericLangOpts(); 109 auto Stream = clang::pseudo::lex(*SourceText, LangOpts); 110 for (auto _ : State) 111 pairBrackets(Stream); 112 State.SetBytesProcessed(static_cast<uint64_t>(State.iterations()) * 113 SourceText->size()); 114 } 115 BENCHMARK(pairBrackets); 116 117 static void preprocess(benchmark::State &State) { 118 clang::LangOptions LangOpts = genericLangOpts(); 119 TokenStream RawStream = clang::pseudo::lex(*SourceText, LangOpts); 120 for (auto _ : State) { 121 auto DirectiveStructure = DirectiveTree::parse(RawStream); 122 chooseConditionalBranches(DirectiveStructure, RawStream); 123 stripComments( 124 cook(DirectiveStructure.stripDirectives(RawStream), LangOpts)); 125 } 126 State.SetBytesProcessed(static_cast<uint64_t>(State.iterations()) * 127 SourceText->size()); 128 } 129 BENCHMARK(preprocess); 130 131 static void glrParse(benchmark::State &State) { 132 LRTable Table = clang::pseudo::LRTable::buildSLR(*G); 133 SymbolID StartSymbol = *G->findNonterminal("translation-unit"); 134 TokenStream Stream = lexAndPreprocess(); 135 for (auto _ : State) { 136 pseudo::ForestArena Forest; 137 pseudo::GSS GSS; 138 pseudo::glrParse(Stream, ParseParams{*G, Table, Forest, GSS}, StartSymbol); 139 } 140 State.SetBytesProcessed(static_cast<uint64_t>(State.iterations()) * 141 SourceText->size()); 142 } 143 BENCHMARK(glrParse); 144 145 static void full(benchmark::State &State) { 146 LRTable Table = clang::pseudo::LRTable::buildSLR(*G); 147 SymbolID StartSymbol = *G->findNonterminal("translation-unit"); 148 for (auto _ : State) { 149 TokenStream Stream = lexAndPreprocess(); 150 pseudo::ForestArena Forest; 151 pseudo::GSS GSS; 152 pseudo::glrParse(lexAndPreprocess(), ParseParams{*G, Table, Forest, GSS}, 153 StartSymbol); 154 } 155 State.SetBytesProcessed(static_cast<uint64_t>(State.iterations()) * 156 SourceText->size()); 157 } 158 BENCHMARK(full); 159 160 } // namespace 161 } // namespace bench 162 } // namespace pseudo 163 } // namespace clang 164 165 int main(int argc, char *argv[]) { 166 benchmark::Initialize(&argc, argv); 167 llvm::cl::ParseCommandLineOptions(argc, argv); 168 clang::pseudo::bench::setupGrammarAndSource(); 169 benchmark::RunSpecifiedBenchmarks(); 170 return 0; 171 } 172