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/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::opt; 39 using llvm::cl::Required; 40 41 static opt<std::string> GrammarFile("grammar", 42 desc("Parse and check a BNF grammar file."), 43 Required); 44 static opt<std::string> Source("source", desc("Source file"), Required); 45 46 namespace clang { 47 namespace pseudo { 48 namespace bench { 49 namespace { 50 51 const std::string *GrammarText = nullptr; 52 const std::string *SourceText = nullptr; 53 const Grammar *G = nullptr; 54 55 void setupGrammarAndSource() { 56 auto ReadFile = [](llvm::StringRef FilePath) -> std::string { 57 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> GrammarText = 58 llvm::MemoryBuffer::getFile(FilePath); 59 if (std::error_code EC = GrammarText.getError()) { 60 llvm::errs() << "Error: can't read file '" << FilePath 61 << "': " << EC.message() << "\n"; 62 std::exit(1); 63 } 64 return GrammarText.get()->getBuffer().str(); 65 }; 66 GrammarText = new std::string(ReadFile(GrammarFile)); 67 SourceText = new std::string(ReadFile(Source)); 68 std::vector<std::string> Diags; 69 G = Grammar::parseBNF(*GrammarText, Diags).release(); 70 } 71 72 static void parseBNF(benchmark::State &State) { 73 std::vector<std::string> Diags; 74 for (auto _ : State) 75 Grammar::parseBNF(*GrammarText, Diags); 76 } 77 BENCHMARK(parseBNF); 78 79 static void buildSLR(benchmark::State &State) { 80 for (auto _ : State) 81 LRTable::buildSLR(*G); 82 } 83 BENCHMARK(buildSLR); 84 85 TokenStream lexAndPreprocess() { 86 clang::LangOptions LangOpts = genericLangOpts(); 87 TokenStream RawStream = pseudo::lex(*SourceText, LangOpts); 88 auto DirectiveStructure = DirectiveTree::parse(RawStream); 89 chooseConditionalBranches(DirectiveStructure, RawStream); 90 TokenStream Cook = 91 cook(DirectiveStructure.stripDirectives(RawStream), LangOpts); 92 return stripComments(Cook); 93 } 94 95 static void lex(benchmark::State &State) { 96 clang::LangOptions LangOpts = genericLangOpts(); 97 for (auto _ : State) 98 clang::pseudo::lex(*SourceText, LangOpts); 99 State.SetBytesProcessed(static_cast<uint64_t>(State.iterations()) * 100 SourceText->size()); 101 } 102 BENCHMARK(lex); 103 104 static void preprocess(benchmark::State &State) { 105 clang::LangOptions LangOpts = genericLangOpts(); 106 TokenStream RawStream = clang::pseudo::lex(*SourceText, LangOpts); 107 for (auto _ : State) { 108 auto DirectiveStructure = DirectiveTree::parse(RawStream); 109 chooseConditionalBranches(DirectiveStructure, RawStream); 110 stripComments( 111 cook(DirectiveStructure.stripDirectives(RawStream), LangOpts)); 112 } 113 State.SetBytesProcessed(static_cast<uint64_t>(State.iterations()) * 114 SourceText->size()); 115 } 116 BENCHMARK(preprocess); 117 118 static void glrParse(benchmark::State &State) { 119 LRTable Table = clang::pseudo::LRTable::buildSLR(*G); 120 SymbolID StartSymbol = *G->findNonterminal("translation-unit"); 121 TokenStream Stream = lexAndPreprocess(); 122 for (auto _ : State) { 123 pseudo::ForestArena Forest; 124 pseudo::GSS GSS; 125 pseudo::glrParse(Stream, ParseParams{*G, Table, Forest, GSS}, StartSymbol); 126 } 127 State.SetBytesProcessed(static_cast<uint64_t>(State.iterations()) * 128 SourceText->size()); 129 } 130 BENCHMARK(glrParse); 131 132 static void full(benchmark::State &State) { 133 LRTable Table = clang::pseudo::LRTable::buildSLR(*G); 134 SymbolID StartSymbol = *G->findNonterminal("translation-unit"); 135 for (auto _ : State) { 136 TokenStream Stream = lexAndPreprocess(); 137 pseudo::ForestArena Forest; 138 pseudo::GSS GSS; 139 pseudo::glrParse(lexAndPreprocess(), ParseParams{*G, Table, Forest, GSS}, 140 StartSymbol); 141 } 142 State.SetBytesProcessed(static_cast<uint64_t>(State.iterations()) * 143 SourceText->size()); 144 } 145 BENCHMARK(full); 146 147 } // namespace 148 } // namespace bench 149 } // namespace pseudo 150 } // namespace clang 151 152 int main(int argc, char *argv[]) { 153 benchmark::Initialize(&argc, argv); 154 llvm::cl::ParseCommandLineOptions(argc, argv); 155 clang::pseudo::bench::setupGrammarAndSource(); 156 benchmark::RunSpecifiedBenchmarks(); 157 return 0; 158 } 159