• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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