YAMLBench.cpp 6.9 KB

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