1 //===- YAMLBench - Benchmark the YAMLParser implementation ----------------===//
3 // 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
7 //===----------------------------------------------------------------------===//
9 // This program executes the YAMLParser on differently sized YAML texts and
10 // outputs the run time.
12 //===----------------------------------------------------------------------===//
15 #include "llvm/ADT/SmallString.h"
16 #include "llvm/Support/Casting.h"
17 #include "llvm/Support/CommandLine.h"
18 #include "llvm/Support/MemoryBuffer.h"
19 #include "llvm/Support/SourceMgr.h"
20 #include "llvm/Support/Timer.h"
21 #include "llvm/Support/Process.h"
22 #include "llvm/Support/YAMLParser.h"
23 #include "llvm/Support/raw_ostream.h"
24 #include <system_error>
30 , cl::desc("Print the tokenization of the file.")
35 DumpCanonical( "canonical"
36 , cl::desc("Print the canonical YAML for this file.")
40 static cl::opt
<std::string
>
41 Input(cl::Positional
, cl::desc("<input>"));
46 "Run a quick verification useful for regression testing")
50 static cl::opt
<unsigned>
51 MemoryLimitMB("memory-limit", cl::desc(
52 "Do not use more megabytes of memory"),
55 cl::opt
<cl::boolOrDefault
>
56 UseColor("use-color", cl::desc("Emit colored output (default=autodetect)"),
57 cl::init(cl::BOU_UNSET
));
61 indent(unsigned d
) : distance(d
) {}
64 static raw_ostream
&operator <<(raw_ostream
&os
, const indent
&in
) {
65 for (unsigned i
= 0; i
< in
.distance
; ++i
)
70 /// Pretty print a tag by replacing tag:yaml.org,2002: with !!.
71 static 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);
78 std::string Ret
= "!<";
84 static void dumpNode( yaml::Node
*n
86 , bool SuppressFirstIndent
= false) {
89 if (!SuppressFirstIndent
)
90 outs() << indent(Indent
);
91 StringRef Anchor
= n
->getAnchor();
93 outs() << "&" << Anchor
<< " ";
94 if (yaml::ScalarNode
*sn
= dyn_cast
<yaml::ScalarNode
>(n
)) {
95 SmallString
<32> Storage
;
96 StringRef Val
= sn
->getValue(Storage
);
97 outs() << prettyTag(n
) << " \"" << yaml::escape(Val
) << "\"";
98 } else if (yaml::BlockScalarNode
*BN
= dyn_cast
<yaml::BlockScalarNode
>(n
)) {
99 outs() << prettyTag(n
) << " \"" << yaml::escape(BN
->getValue()) << "\"";
100 } else if (yaml::SequenceNode
*sn
= dyn_cast
<yaml::SequenceNode
>(n
)) {
101 outs() << prettyTag(n
) << " [\n";
103 for (yaml::SequenceNode::iterator i
= sn
->begin(), e
= sn
->end();
109 outs() << indent(Indent
) << "]";
110 } else if (yaml::MappingNode
*mn
= dyn_cast
<yaml::MappingNode
>(n
)) {
111 outs() << prettyTag(n
) << " {\n";
113 for (yaml::MappingNode::iterator i
= mn
->begin(), e
= mn
->end();
115 outs() << indent(Indent
) << "? ";
116 dumpNode(i
->getKey(), Indent
, true);
118 outs() << indent(Indent
) << ": ";
119 dumpNode(i
->getValue(), Indent
, true);
123 outs() << indent(Indent
) << "}";
124 } else if (yaml::AliasNode
*an
= dyn_cast
<yaml::AliasNode
>(n
)){
125 outs() << "*" << an
->getName();
126 } else if (isa
<yaml::NullNode
>(n
)) {
127 outs() << prettyTag(n
) << " null";
131 static void dumpStream(yaml::Stream
&stream
) {
132 for (yaml::document_iterator di
= stream
.begin(), de
= stream
.end(); di
!= de
;
134 outs() << "%YAML 1.2\n"
136 yaml::Node
*n
= di
->getRoot();
145 static 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(),
149 BaseLine
.startTimer();
151 for (llvm::StringRef::iterator I
= JSONText
.begin(),
153 I
!= E
; ++I
) { C
+= *I
; }
154 BaseLine
.stopTimer();
155 volatile char DontOptimizeOut
= C
; (void)DontOptimizeOut
;
157 llvm::Timer
Tokenizing((Name
+ ".tokenizing").str(),
158 (Description
+ ": Tokenizing").str(), Group
);
159 Tokenizing
.startTimer();
161 yaml::scanTokens(JSONText
);
163 Tokenizing
.stopTimer();
165 llvm::Timer
Parsing((Name
+ ".parsing").str(),
166 (Description
+ ": Parsing").str(), Group
);
167 Parsing
.startTimer();
170 llvm::yaml::Stream
stream(JSONText
, SM
);
176 static std::string
createJSONText(size_t MemoryMB
, unsigned ValueSize
) {
177 std::string JSONText
;
178 llvm::raw_string_ostream
Stream(JSONText
);
180 size_t MemoryBytes
= MemoryMB
* 1024 * 1024;
181 while (JSONText
.size() < MemoryBytes
) {
183 << " \"key1\": \"" << std::string(ValueSize
, '*') << "\",\n"
184 << " \"key2\": \"" << std::string(ValueSize
, '*') << "\",\n"
185 << " \"key3\": \"" << std::string(ValueSize
, '*') << "\"\n"
188 if (JSONText
.size() < MemoryBytes
) Stream
<< ",";
196 int main(int argc
, char **argv
) {
197 llvm::cl::ParseCommandLineOptions(argc
, argv
);
198 bool ShowColors
= UseColor
== cl::BOU_UNSET
199 ? sys::Process::StandardOutHasColors()
200 : UseColor
== cl::BOU_TRUE
;
201 if (Input
.getNumOccurrences()) {
202 ErrorOr
<std::unique_ptr
<MemoryBuffer
>> BufOrErr
=
203 MemoryBuffer::getFileOrSTDIN(Input
);
206 MemoryBuffer
&Buf
= *BufOrErr
.get();
210 yaml::dumpTokens(Buf
.getBuffer(), outs());
214 yaml::Stream
stream(Buf
.getBuffer(), sm
, ShowColors
);
222 llvm::TimerGroup
Group("yaml", "YAML parser benchmark");
223 benchmark(Group
, "Fast", "Fast", createJSONText(10, 500));
224 } else if (!DumpCanonical
&& !DumpTokens
) {
225 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));