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 } 232