blob: a9851c0f63e66a96c57efe43b585a370364bd269 [file] [log] [blame]
Michael J. Spencer22120c42012-04-03 23:09:22 +00001//===- YAMLBench - Benchmark the YAMLParser implementation ----------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Michael J. Spencer22120c42012-04-03 23:09:22 +00006//
7//===----------------------------------------------------------------------===//
8//
David Blaikie2a528822014-04-05 20:28:13 +00009// This program executes the YAMLParser on differently sized YAML texts and
Michael J. Spencer22120c42012-04-03 23:09:22 +000010// outputs the run time.
11//
12//===----------------------------------------------------------------------===//
13
14
15#include "llvm/ADT/SmallString.h"
16#include "llvm/Support/Casting.h"
17#include "llvm/Support/CommandLine.h"
18#include "llvm/Support/MemoryBuffer.h"
Michael J. Spencer22120c42012-04-03 23:09:22 +000019#include "llvm/Support/SourceMgr.h"
Michael J. Spencer22120c42012-04-03 23:09:22 +000020#include "llvm/Support/Timer.h"
Alex Lorenze4bcfbf2015-05-07 18:08:46 +000021#include "llvm/Support/Process.h"
Michael J. Spencer22120c42012-04-03 23:09:22 +000022#include "llvm/Support/YAMLParser.h"
Chandler Carruth91d19d82012-12-04 10:37:14 +000023#include "llvm/Support/raw_ostream.h"
Rafael Espindolaa6e9c3e2014-06-12 17:38:55 +000024#include <system_error>
Michael J. Spencer22120c42012-04-03 23:09:22 +000025
26using namespace llvm;
27
28static cl::opt<bool>
29 DumpTokens( "tokens"
30 , cl::desc("Print the tokenization of the file.")
31 , cl::init(false)
32 );
33
34static cl::opt<bool>
35 DumpCanonical( "canonical"
36 , cl::desc("Print the canonical YAML for this file.")
37 , cl::init(false)
38 );
39
40static cl::opt<std::string>
41 Input(cl::Positional, cl::desc("<input>"));
42
43static cl::opt<bool>
44 Verify( "verify"
45 , cl::desc(
46 "Run a quick verification useful for regression testing")
47 , cl::init(false)
48 );
49
50static cl::opt<unsigned>
51 MemoryLimitMB("memory-limit", cl::desc(
52 "Do not use more megabytes of memory"),
53 cl::init(1000));
54
Alex Lorenze4bcfbf2015-05-07 18:08:46 +000055cl::opt<cl::boolOrDefault>
56 UseColor("use-color", cl::desc("Emit colored output (default=autodetect)"),
57 cl::init(cl::BOU_UNSET));
58
Michael J. Spencer22120c42012-04-03 23:09:22 +000059struct indent {
60 unsigned distance;
61 indent(unsigned d) : distance(d) {}
62};
63
64static raw_ostream &operator <<(raw_ostream &os, const indent &in) {
65 for (unsigned i = 0; i < in.distance; ++i)
66 os << " ";
67 return os;
68}
69
Adrian Prantl5f8f34e42018-05-01 15:54:18 +000070/// Pretty print a tag by replacing tag:yaml.org,2002: with !!.
Michael J. Spencerc064a9a2013-10-18 22:38:04 +000071static std::string prettyTag(yaml::Node *N) {
72 std::string Tag = N->getVerbatimTag();
73 if (StringRef(Tag).startswith("tag:yaml.org,2002:")) {
74 std::string Ret = "!!";
75 Ret += StringRef(Tag).substr(18);
Benjamin Kramer548e8a42015-05-01 15:16:11 +000076 return Ret;
Michael J. Spencerc064a9a2013-10-18 22:38:04 +000077 }
78 std::string Ret = "!<";
79 Ret += Tag;
80 Ret += ">";
81 return Ret;
82}
83
Michael J. Spencer22120c42012-04-03 23:09:22 +000084static void dumpNode( yaml::Node *n
85 , unsigned Indent = 0
86 , bool SuppressFirstIndent = false) {
87 if (!n)
88 return;
89 if (!SuppressFirstIndent)
90 outs() << indent(Indent);
91 StringRef Anchor = n->getAnchor();
92 if (!Anchor.empty())
93 outs() << "&" << Anchor << " ";
94 if (yaml::ScalarNode *sn = dyn_cast<yaml::ScalarNode>(n)) {
95 SmallString<32> Storage;
96 StringRef Val = sn->getValue(Storage);
Michael J. Spencerc064a9a2013-10-18 22:38:04 +000097 outs() << prettyTag(n) << " \"" << yaml::escape(Val) << "\"";
Alex Lorenza22b250c2015-05-13 23:10:51 +000098 } else if (yaml::BlockScalarNode *BN = dyn_cast<yaml::BlockScalarNode>(n)) {
99 outs() << prettyTag(n) << " \"" << yaml::escape(BN->getValue()) << "\"";
Michael J. Spencer22120c42012-04-03 23:09:22 +0000100 } else if (yaml::SequenceNode *sn = dyn_cast<yaml::SequenceNode>(n)) {
Michael J. Spencerc064a9a2013-10-18 22:38:04 +0000101 outs() << prettyTag(n) << " [\n";
Michael J. Spencer22120c42012-04-03 23:09:22 +0000102 ++Indent;
103 for (yaml::SequenceNode::iterator i = sn->begin(), e = sn->end();
104 i != e; ++i) {
105 dumpNode(i, Indent);
106 outs() << ",\n";
107 }
108 --Indent;
109 outs() << indent(Indent) << "]";
110 } else if (yaml::MappingNode *mn = dyn_cast<yaml::MappingNode>(n)) {
Michael J. Spencerc064a9a2013-10-18 22:38:04 +0000111 outs() << prettyTag(n) << " {\n";
Michael J. Spencer22120c42012-04-03 23:09:22 +0000112 ++Indent;
113 for (yaml::MappingNode::iterator i = mn->begin(), e = mn->end();
114 i != e; ++i) {
115 outs() << indent(Indent) << "? ";
116 dumpNode(i->getKey(), Indent, true);
117 outs() << "\n";
118 outs() << indent(Indent) << ": ";
119 dumpNode(i->getValue(), Indent, true);
120 outs() << ",\n";
121 }
122 --Indent;
123 outs() << indent(Indent) << "}";
124 } else if (yaml::AliasNode *an = dyn_cast<yaml::AliasNode>(n)){
125 outs() << "*" << an->getName();
Benjamin Kramer619c4e52015-04-10 11:24:51 +0000126 } else if (isa<yaml::NullNode>(n)) {
Michael J. Spencerc064a9a2013-10-18 22:38:04 +0000127 outs() << prettyTag(n) << " null";
Michael J. Spencer22120c42012-04-03 23:09:22 +0000128 }
129}
130
131static void dumpStream(yaml::Stream &stream) {
132 for (yaml::document_iterator di = stream.begin(), de = stream.end(); di != de;
133 ++di) {
134 outs() << "%YAML 1.2\n"
135 << "---\n";
136 yaml::Node *n = di->getRoot();
137 if (n)
138 dumpNode(n);
139 else
140 break;
141 outs() << "\n...\n";
142 }
143}
144
Matthias Braun9f15a792016-11-18 19:43:18 +0000145static void benchmark(llvm::TimerGroup &Group, llvm::StringRef Name,
146 llvm::StringRef Description, llvm::StringRef JSONText) {
147 llvm::Timer BaseLine((Name + ".loop").str(), (Description + ": Loop").str(),
148 Group);
Michael J. Spencer22120c42012-04-03 23:09:22 +0000149 BaseLine.startTimer();
150 char C = 0;
151 for (llvm::StringRef::iterator I = JSONText.begin(),
152 E = JSONText.end();
153 I != E; ++I) { C += *I; }
154 BaseLine.stopTimer();
155 volatile char DontOptimizeOut = C; (void)DontOptimizeOut;
156
Matthias Braun9f15a792016-11-18 19:43:18 +0000157 llvm::Timer Tokenizing((Name + ".tokenizing").str(),
158 (Description + ": Tokenizing").str(), Group);
Michael J. Spencer22120c42012-04-03 23:09:22 +0000159 Tokenizing.startTimer();
160 {
161 yaml::scanTokens(JSONText);
162 }
163 Tokenizing.stopTimer();
164
Matthias Braun9f15a792016-11-18 19:43:18 +0000165 llvm::Timer Parsing((Name + ".parsing").str(),
166 (Description + ": Parsing").str(), Group);
Michael J. Spencer22120c42012-04-03 23:09:22 +0000167 Parsing.startTimer();
168 {
169 llvm::SourceMgr SM;
170 llvm::yaml::Stream stream(JSONText, SM);
171 stream.skip();
172 }
173 Parsing.stopTimer();
174}
175
176static std::string createJSONText(size_t MemoryMB, unsigned ValueSize) {
Alp Tokere69170a2014-06-26 22:52:05 +0000177 std::string JSONText;
178 llvm::raw_string_ostream Stream(JSONText);
179 Stream << "[\n";
Michael J. Spencer22120c42012-04-03 23:09:22 +0000180 size_t MemoryBytes = MemoryMB * 1024 * 1024;
Alp Tokere69170a2014-06-26 22:52:05 +0000181 while (JSONText.size() < MemoryBytes) {
182 Stream << " {\n"
183 << " \"key1\": \"" << std::string(ValueSize, '*') << "\",\n"
184 << " \"key2\": \"" << std::string(ValueSize, '*') << "\",\n"
185 << " \"key3\": \"" << std::string(ValueSize, '*') << "\"\n"
186 << " }";
187 Stream.flush();
188 if (JSONText.size() < MemoryBytes) Stream << ",";
189 Stream << "\n";
Michael J. Spencer22120c42012-04-03 23:09:22 +0000190 }
Alp Tokere69170a2014-06-26 22:52:05 +0000191 Stream << "]\n";
192 Stream.flush();
193 return JSONText;
Michael J. Spencer22120c42012-04-03 23:09:22 +0000194}
195
196int main(int argc, char **argv) {
197 llvm::cl::ParseCommandLineOptions(argc, argv);
Alex Lorenze4bcfbf2015-05-07 18:08:46 +0000198 bool ShowColors = UseColor == cl::BOU_UNSET
199 ? sys::Process::StandardOutHasColors()
200 : UseColor == cl::BOU_TRUE;
Michael J. Spencer22120c42012-04-03 23:09:22 +0000201 if (Input.getNumOccurrences()) {
Rafael Espindolaadf21f22014-07-06 17:43:13 +0000202 ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
203 MemoryBuffer::getFileOrSTDIN(Input);
204 if (!BufOrErr)
Michael J. Spencer22120c42012-04-03 23:09:22 +0000205 return 1;
Rafael Espindola3f6481d2014-08-01 14:31:55 +0000206 MemoryBuffer &Buf = *BufOrErr.get();
Michael J. Spencer22120c42012-04-03 23:09:22 +0000207
208 llvm::SourceMgr sm;
209 if (DumpTokens) {
Rafael Espindola3f6481d2014-08-01 14:31:55 +0000210 yaml::dumpTokens(Buf.getBuffer(), outs());
Michael J. Spencer22120c42012-04-03 23:09:22 +0000211 }
212
213 if (DumpCanonical) {
Alex Lorenze4bcfbf2015-05-07 18:08:46 +0000214 yaml::Stream stream(Buf.getBuffer(), sm, ShowColors);
Michael J. Spencer22120c42012-04-03 23:09:22 +0000215 dumpStream(stream);
Alex Lorenze4bcfbf2015-05-07 18:08:46 +0000216 if (stream.failed())
217 return 1;
Michael J. Spencer22120c42012-04-03 23:09:22 +0000218 }
219 }
220
221 if (Verify) {
Matthias Braun9f15a792016-11-18 19:43:18 +0000222 llvm::TimerGroup Group("yaml", "YAML parser benchmark");
223 benchmark(Group, "Fast", "Fast", createJSONText(10, 500));
Michael J. Spencer22120c42012-04-03 23:09:22 +0000224 } else if (!DumpCanonical && !DumpTokens) {
Matthias Braun9f15a792016-11-18 19:43:18 +0000225 llvm::TimerGroup Group("yaml", "YAML parser benchmark");
226 benchmark(Group, "Small", "Small Values", createJSONText(MemoryLimitMB, 5));
227 benchmark(Group, "Medium", "Medium Values",
228 createJSONText(MemoryLimitMB, 500));
229 benchmark(Group, "Large", "Large Values",
230 createJSONText(MemoryLimitMB, 50000));
Michael J. Spencer22120c42012-04-03 23:09:22 +0000231 }
232
233 return 0;
234}