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 differntly 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/raw_ostream.h"
21 #include "llvm/Support/SourceMgr.h"
22 #include "llvm/Support/system_error.h"
23 #include "llvm/Support/Timer.h"
24 #include "llvm/Support/YAMLParser.h"
25
26 using namespace llvm;
27
28 static cl::opt<bool>
29 DumpTokens( "tokens"
30 , cl::desc("Print the tokenization of the file.")
31 , cl::init(false)
32 );
33
34 static cl::opt<bool>
35 DumpCanonical( "canonical"
36 , cl::desc("Print the canonical YAML for this file.")
37 , cl::init(false)
38 );
39
40 static cl::opt<std::string>
41 Input(cl::Positional, cl::desc("<input>"));
42
43 static cl::opt<bool>
44 Verify( "verify"
45 , cl::desc(
46 "Run a quick verification useful for regression testing")
47 , cl::init(false)
48 );
49
50 static cl::opt<unsigned>
51 MemoryLimitMB("memory-limit", cl::desc(
52 "Do not use more megabytes of memory"),
53 cl::init(1000));
54
55 struct indent {
56 unsigned distance;
indentindent57 indent(unsigned d) : distance(d) {}
58 };
59
operator <<(raw_ostream & os,const indent & in)60 static raw_ostream &operator <<(raw_ostream &os, const indent &in) {
61 for (unsigned i = 0; i < in.distance; ++i)
62 os << " ";
63 return os;
64 }
65
dumpNode(yaml::Node * n,unsigned Indent=0,bool SuppressFirstIndent=false)66 static void dumpNode( yaml::Node *n
67 , unsigned Indent = 0
68 , bool SuppressFirstIndent = false) {
69 if (!n)
70 return;
71 if (!SuppressFirstIndent)
72 outs() << indent(Indent);
73 StringRef Anchor = n->getAnchor();
74 if (!Anchor.empty())
75 outs() << "&" << Anchor << " ";
76 if (yaml::ScalarNode *sn = dyn_cast<yaml::ScalarNode>(n)) {
77 SmallString<32> Storage;
78 StringRef Val = sn->getValue(Storage);
79 outs() << "!!str \"" << yaml::escape(Val) << "\"";
80 } else if (yaml::SequenceNode *sn = dyn_cast<yaml::SequenceNode>(n)) {
81 outs() << "!!seq [\n";
82 ++Indent;
83 for (yaml::SequenceNode::iterator i = sn->begin(), e = sn->end();
84 i != e; ++i) {
85 dumpNode(i, Indent);
86 outs() << ",\n";
87 }
88 --Indent;
89 outs() << indent(Indent) << "]";
90 } else if (yaml::MappingNode *mn = dyn_cast<yaml::MappingNode>(n)) {
91 outs() << "!!map {\n";
92 ++Indent;
93 for (yaml::MappingNode::iterator i = mn->begin(), e = mn->end();
94 i != e; ++i) {
95 outs() << indent(Indent) << "? ";
96 dumpNode(i->getKey(), Indent, true);
97 outs() << "\n";
98 outs() << indent(Indent) << ": ";
99 dumpNode(i->getValue(), Indent, true);
100 outs() << ",\n";
101 }
102 --Indent;
103 outs() << indent(Indent) << "}";
104 } else if (yaml::AliasNode *an = dyn_cast<yaml::AliasNode>(n)){
105 outs() << "*" << an->getName();
106 } else if (dyn_cast<yaml::NullNode>(n)) {
107 outs() << "!!null null";
108 }
109 }
110
dumpStream(yaml::Stream & stream)111 static void dumpStream(yaml::Stream &stream) {
112 for (yaml::document_iterator di = stream.begin(), de = stream.end(); di != de;
113 ++di) {
114 outs() << "%YAML 1.2\n"
115 << "---\n";
116 yaml::Node *n = di->getRoot();
117 if (n)
118 dumpNode(n);
119 else
120 break;
121 outs() << "\n...\n";
122 }
123 }
124
benchmark(llvm::TimerGroup & Group,llvm::StringRef Name,llvm::StringRef JSONText)125 static void benchmark( llvm::TimerGroup &Group
126 , llvm::StringRef Name
127 , llvm::StringRef JSONText) {
128 llvm::Timer BaseLine((Name + ": Loop").str(), Group);
129 BaseLine.startTimer();
130 char C = 0;
131 for (llvm::StringRef::iterator I = JSONText.begin(),
132 E = JSONText.end();
133 I != E; ++I) { C += *I; }
134 BaseLine.stopTimer();
135 volatile char DontOptimizeOut = C; (void)DontOptimizeOut;
136
137 llvm::Timer Tokenizing((Name + ": Tokenizing").str(), Group);
138 Tokenizing.startTimer();
139 {
140 yaml::scanTokens(JSONText);
141 }
142 Tokenizing.stopTimer();
143
144 llvm::Timer Parsing((Name + ": Parsing").str(), Group);
145 Parsing.startTimer();
146 {
147 llvm::SourceMgr SM;
148 llvm::yaml::Stream stream(JSONText, SM);
149 stream.skip();
150 }
151 Parsing.stopTimer();
152 }
153
createJSONText(size_t MemoryMB,unsigned ValueSize)154 static std::string createJSONText(size_t MemoryMB, unsigned ValueSize) {
155 std::string JSONText;
156 llvm::raw_string_ostream Stream(JSONText);
157 Stream << "[\n";
158 size_t MemoryBytes = MemoryMB * 1024 * 1024;
159 while (JSONText.size() < MemoryBytes) {
160 Stream << " {\n"
161 << " \"key1\": \"" << std::string(ValueSize, '*') << "\",\n"
162 << " \"key2\": \"" << std::string(ValueSize, '*') << "\",\n"
163 << " \"key3\": \"" << std::string(ValueSize, '*') << "\"\n"
164 << " }";
165 Stream.flush();
166 if (JSONText.size() < MemoryBytes) Stream << ",";
167 Stream << "\n";
168 }
169 Stream << "]\n";
170 Stream.flush();
171 return JSONText;
172 }
173
main(int argc,char ** argv)174 int main(int argc, char **argv) {
175 llvm::cl::ParseCommandLineOptions(argc, argv);
176 if (Input.getNumOccurrences()) {
177 OwningPtr<MemoryBuffer> Buf;
178 if (MemoryBuffer::getFileOrSTDIN(Input, Buf))
179 return 1;
180
181 llvm::SourceMgr sm;
182 if (DumpTokens) {
183 yaml::dumpTokens(Buf->getBuffer(), outs());
184 }
185
186 if (DumpCanonical) {
187 yaml::Stream stream(Buf->getBuffer(), sm);
188 dumpStream(stream);
189 }
190 }
191
192 if (Verify) {
193 llvm::TimerGroup Group("YAML parser benchmark");
194 benchmark(Group, "Fast", createJSONText(10, 500));
195 } else if (!DumpCanonical && !DumpTokens) {
196 llvm::TimerGroup Group("YAML parser benchmark");
197 benchmark(Group, "Small Values", createJSONText(MemoryLimitMB, 5));
198 benchmark(Group, "Medium Values", createJSONText(MemoryLimitMB, 500));
199 benchmark(Group, "Large Values", createJSONText(MemoryLimitMB, 50000));
200 }
201
202 return 0;
203 }
204