[TableGen] Remove a few spaces from AsmMatcher output. NFC
[oota-llvm.git] / utils / yaml-bench / YAMLBench.cpp
1 //===- YAMLBench - Benchmark the YAMLParser implementation ----------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This program executes the YAMLParser on differently sized YAML texts and
11 // outputs the run time.
12 //
13 //===----------------------------------------------------------------------===//
14
15
16 #include "llvm/ADT/SmallString.h"
17 #include "llvm/Support/Casting.h"
18 #include "llvm/Support/CommandLine.h"
19 #include "llvm/Support/MemoryBuffer.h"
20 #include "llvm/Support/SourceMgr.h"
21 #include "llvm/Support/Timer.h"
22 #include "llvm/Support/Process.h"
23 #include "llvm/Support/YAMLParser.h"
24 #include "llvm/Support/raw_ostream.h"
25 #include <system_error>
26
27 using namespace llvm;
28
29 static cl::opt<bool>
30   DumpTokens( "tokens"
31             , cl::desc("Print the tokenization of the file.")
32             , cl::init(false)
33             );
34
35 static cl::opt<bool>
36   DumpCanonical( "canonical"
37                , cl::desc("Print the canonical YAML for this file.")
38                , cl::init(false)
39                );
40
41 static cl::opt<std::string>
42  Input(cl::Positional, cl::desc("<input>"));
43
44 static cl::opt<bool>
45   Verify( "verify"
46         , cl::desc(
47             "Run a quick verification useful for regression testing")
48         , cl::init(false)
49         );
50
51 static cl::opt<unsigned>
52   MemoryLimitMB("memory-limit", cl::desc(
53                   "Do not use more megabytes of memory"),
54                 cl::init(1000));
55
56 cl::opt<cl::boolOrDefault>
57     UseColor("use-color", cl::desc("Emit colored output (default=autodetect)"),
58              cl::init(cl::BOU_UNSET));
59
60 struct indent {
61   unsigned distance;
62   indent(unsigned d) : distance(d) {}
63 };
64
65 static raw_ostream &operator <<(raw_ostream &os, const indent &in) {
66   for (unsigned i = 0; i < in.distance; ++i)
67     os << "  ";
68   return os;
69 }
70
71 /// \brief Pretty print a tag by replacing tag:yaml.org,2002: with !!.
72 static std::string prettyTag(yaml::Node *N) {
73   std::string Tag = N->getVerbatimTag();
74   if (StringRef(Tag).startswith("tag:yaml.org,2002:")) {
75     std::string Ret = "!!";
76     Ret += StringRef(Tag).substr(18);
77     return Ret;
78   }
79   std::string Ret = "!<";
80   Ret += Tag;
81   Ret += ">";
82   return Ret;
83 }
84
85 static void dumpNode( yaml::Node *n
86                     , unsigned Indent = 0
87                     , bool SuppressFirstIndent = false) {
88   if (!n)
89     return;
90   if (!SuppressFirstIndent)
91     outs() << indent(Indent);
92   StringRef Anchor = n->getAnchor();
93   if (!Anchor.empty())
94     outs() << "&" << Anchor << " ";
95   if (yaml::ScalarNode *sn = dyn_cast<yaml::ScalarNode>(n)) {
96     SmallString<32> Storage;
97     StringRef Val = sn->getValue(Storage);
98     outs() << prettyTag(n) << " \"" << yaml::escape(Val) << "\"";
99   } else if (yaml::BlockScalarNode *BN = dyn_cast<yaml::BlockScalarNode>(n)) {
100     outs() << prettyTag(n) << " \"" << yaml::escape(BN->getValue()) << "\"";
101   } else if (yaml::SequenceNode *sn = dyn_cast<yaml::SequenceNode>(n)) {
102     outs() << prettyTag(n) << " [\n";
103     ++Indent;
104     for (yaml::SequenceNode::iterator i = sn->begin(), e = sn->end();
105                                       i != e; ++i) {
106       dumpNode(i, Indent);
107       outs() << ",\n";
108     }
109     --Indent;
110     outs() << indent(Indent) << "]";
111   } else if (yaml::MappingNode *mn = dyn_cast<yaml::MappingNode>(n)) {
112     outs() << prettyTag(n) << " {\n";
113     ++Indent;
114     for (yaml::MappingNode::iterator i = mn->begin(), e = mn->end();
115                                      i != e; ++i) {
116       outs() << indent(Indent) << "? ";
117       dumpNode(i->getKey(), Indent, true);
118       outs() << "\n";
119       outs() << indent(Indent) << ": ";
120       dumpNode(i->getValue(), Indent, true);
121       outs() << ",\n";
122     }
123     --Indent;
124     outs() << indent(Indent) << "}";
125   } else if (yaml::AliasNode *an = dyn_cast<yaml::AliasNode>(n)){
126     outs() << "*" << an->getName();
127   } else if (isa<yaml::NullNode>(n)) {
128     outs() << prettyTag(n) << " null";
129   }
130 }
131
132 static void dumpStream(yaml::Stream &stream) {
133   for (yaml::document_iterator di = stream.begin(), de = stream.end(); di != de;
134        ++di) {
135     outs() << "%YAML 1.2\n"
136            << "---\n";
137     yaml::Node *n = di->getRoot();
138     if (n)
139       dumpNode(n);
140     else
141       break;
142     outs() << "\n...\n";
143   }
144 }
145
146 static void benchmark( llvm::TimerGroup &Group
147                      , llvm::StringRef Name
148                      , llvm::StringRef JSONText) {
149   llvm::Timer BaseLine((Name + ": Loop").str(), Group);
150   BaseLine.startTimer();
151   char C = 0;
152   for (llvm::StringRef::iterator I = JSONText.begin(),
153                                  E = JSONText.end();
154        I != E; ++I) { C += *I; }
155   BaseLine.stopTimer();
156   volatile char DontOptimizeOut = C; (void)DontOptimizeOut;
157
158   llvm::Timer Tokenizing((Name + ": Tokenizing").str(), Group);
159   Tokenizing.startTimer();
160   {
161     yaml::scanTokens(JSONText);
162   }
163   Tokenizing.stopTimer();
164
165   llvm::Timer Parsing((Name + ": Parsing").str(), Group);
166   Parsing.startTimer();
167   {
168     llvm::SourceMgr SM;
169     llvm::yaml::Stream stream(JSONText, SM);
170     stream.skip();
171   }
172   Parsing.stopTimer();
173 }
174
175 static std::string createJSONText(size_t MemoryMB, unsigned ValueSize) {
176   std::string JSONText;
177   llvm::raw_string_ostream Stream(JSONText);
178   Stream << "[\n";
179   size_t MemoryBytes = MemoryMB * 1024 * 1024;
180   while (JSONText.size() < MemoryBytes) {
181     Stream << " {\n"
182            << "  \"key1\": \"" << std::string(ValueSize, '*') << "\",\n"
183            << "  \"key2\": \"" << std::string(ValueSize, '*') << "\",\n"
184            << "  \"key3\": \"" << std::string(ValueSize, '*') << "\"\n"
185            << " }";
186     Stream.flush();
187     if (JSONText.size() < MemoryBytes) Stream << ",";
188     Stream << "\n";
189   }
190   Stream << "]\n";
191   Stream.flush();
192   return JSONText;
193 }
194
195 int main(int argc, char **argv) {
196   llvm::cl::ParseCommandLineOptions(argc, argv);
197   bool ShowColors = UseColor == cl::BOU_UNSET
198                         ? sys::Process::StandardOutHasColors()
199                         : UseColor == cl::BOU_TRUE;
200   if (Input.getNumOccurrences()) {
201     ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
202         MemoryBuffer::getFileOrSTDIN(Input);
203     if (!BufOrErr)
204       return 1;
205     MemoryBuffer &Buf = *BufOrErr.get();
206
207     llvm::SourceMgr sm;
208     if (DumpTokens) {
209       yaml::dumpTokens(Buf.getBuffer(), outs());
210     }
211
212     if (DumpCanonical) {
213       yaml::Stream stream(Buf.getBuffer(), sm, ShowColors);
214       dumpStream(stream);
215       if (stream.failed())
216         return 1;
217     }
218   }
219
220   if (Verify) {
221     llvm::TimerGroup Group("YAML parser benchmark");
222     benchmark(Group, "Fast", createJSONText(10, 500));
223   } else if (!DumpCanonical && !DumpTokens) {
224     llvm::TimerGroup Group("YAML parser benchmark");
225     benchmark(Group, "Small Values", createJSONText(MemoryLimitMB, 5));
226     benchmark(Group, "Medium Values", createJSONText(MemoryLimitMB, 500));
227     benchmark(Group, "Large Values", createJSONText(MemoryLimitMB, 50000));
228   }
229
230   return 0;
231 }