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