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
setup()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
buildSLR(benchmark::State & State)68 static void buildSLR(benchmark::State &State) {
69 for (auto _ : State)
70 LRTable::buildSLR(Lang->G);
71 }
72 BENCHMARK(buildSLR);
73
lexAndPreprocess()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
lex(benchmark::State & State)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
pairBrackets(benchmark::State & State)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
preprocess(benchmark::State & State)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
glrParse(benchmark::State & State)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
full(benchmark::State & State)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
main(int argc,char * argv[])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