Merge pull request #127 from Herringway/better-benchmark
improve benchmark subpackage merged-on-behalf-of: BBasile <BBasile@users.noreply.github.com>
This commit is contained in:
commit
0b2f2396ac
|
@ -2,39 +2,21 @@
|
|||
module dyaml.yaml_bench;
|
||||
//Benchmark that loads, and optionally extracts data from and/or emits a YAML file.
|
||||
|
||||
import std.algorithm;
|
||||
import std.conv;
|
||||
import std.datetime;
|
||||
import std.datetime.systime;
|
||||
import std.datetime.stopwatch;
|
||||
import std.file;
|
||||
import std.getopt;
|
||||
import std.range;
|
||||
import std.stdio;
|
||||
import std.string;
|
||||
import dyaml;
|
||||
|
||||
///Print help information.
|
||||
void help()
|
||||
{
|
||||
string help =
|
||||
"D:YAML benchmark\n"~
|
||||
"Copyright (C) 2011-2014 Ferdinand Majerech\n"~
|
||||
"Usage: yaml_bench [OPTION ...] [YAML_FILE]\n"~
|
||||
"\n"~
|
||||
"Loads and optionally extracts data and/or dumps a YAML file.\n"~
|
||||
"\n"~
|
||||
"Available options:\n"~
|
||||
" -h --help Show this help information.\n"~
|
||||
" -g --get Extract data from the file (using Node.as()).\n"~
|
||||
" -d --dump Dump the loaded data (to YAML_FILE.dump).\n"~
|
||||
" -r --runs=NUM Repeat parsing the file NUM times.\n"~
|
||||
" --reload Reload the file from the diskl on every repeat\n"~
|
||||
" By default, the file is loaded to memory once\n"~
|
||||
" and repeatedly parsed from memory.\n"~
|
||||
" -s --scan-only Do not execute the entire parsing process, only\n"~
|
||||
" scanning. Overrides '--dump'.\n";
|
||||
writeln(help);
|
||||
}
|
||||
|
||||
///Get data out of every node.
|
||||
void extract(ref Node document)
|
||||
void extract(ref Node document) @safe
|
||||
{
|
||||
void crawl(ref Node root)
|
||||
void crawl(ref Node root) @safe
|
||||
{
|
||||
if(root.isScalar) switch(root.tag)
|
||||
{
|
||||
|
@ -61,86 +43,124 @@ void extract(ref Node document)
|
|||
crawl(document);
|
||||
}
|
||||
|
||||
void main(string[] args)
|
||||
void main(string[] args) //@safe
|
||||
{
|
||||
bool get = false;
|
||||
bool dump = false;
|
||||
bool reload = false;
|
||||
bool get = false;
|
||||
bool dump = false;
|
||||
bool reload = false;
|
||||
bool quiet = false;
|
||||
bool verbose = false;
|
||||
bool scanOnly = false;
|
||||
uint runs = 1;
|
||||
string file = null;
|
||||
|
||||
//Parse command line args
|
||||
foreach(arg; args[1 .. $])
|
||||
{
|
||||
auto parts = arg.split("=");
|
||||
if(arg[0] == '-') switch(parts[0])
|
||||
{
|
||||
case "--help", "-h": help(); return;
|
||||
case "--get", "-g": get = true; break;
|
||||
case "--dump", "-d": dump = true; break;
|
||||
case "--reload": reload = true; break;
|
||||
case "--scan-only", "-s": scanOnly = true; break;
|
||||
case "--runs", "-r": runs = parts[1].to!uint; break;
|
||||
default: writeln("\nUnknown argument: ", arg, "\n\n"); help(); return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(file !is null)
|
||||
{
|
||||
writeln("\nUnknown argument or file specified twice: ", arg, "\n\n");
|
||||
help();
|
||||
return;
|
||||
}
|
||||
auto help = getopt(
|
||||
args,
|
||||
"get|g", "Extract data from the file (using Node.as()).", &get,
|
||||
"dump|d", "Dump the loaded data (to YAML_FILE.dump).", &dump,
|
||||
"runs|r", "Repeat parsing the file NUM times.", &runs,
|
||||
"reload", "Reload the file from the diskl on every repeat By default,"~
|
||||
" the file is loaded to memory once and repeatedly parsed from memory.", &reload,
|
||||
"quiet|q", "Don't print anything.", &quiet,
|
||||
"verbose|v", "Print even more.", &verbose,
|
||||
"scan-only|s", "Do not execute the entire parsing process, only scanning. Overrides '--dump'", &scanOnly
|
||||
);
|
||||
|
||||
file = arg;
|
||||
}
|
||||
}
|
||||
if(file is null)
|
||||
if (help.helpWanted || (args.length < 2))
|
||||
{
|
||||
writeln("\nFile not specified.\n\n");
|
||||
help();
|
||||
defaultGetoptPrinter(
|
||||
"D:YAML benchmark\n"~
|
||||
"Copyright (C) 2011-2018 Ferdinand Majerech, Cameron \"Herringway\" Ross\n"~
|
||||
"Usage: yaml_bench [OPTION ...] [YAML_FILE]\n\n"~
|
||||
"Loads and optionally extracts data and/or dumps a YAML file.\n",
|
||||
help.options
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
string file = args[1];
|
||||
|
||||
auto stopWatch = StopWatch(AutoStart.yes);
|
||||
void[] fileInMemory;
|
||||
if(!reload) { fileInMemory = std.file.read(file); }
|
||||
void[] fileWorkingCopy = fileInMemory.dup;
|
||||
auto loadTime = stopWatch.peek();
|
||||
stopWatch.reset();
|
||||
try
|
||||
{
|
||||
import std.file;
|
||||
void[] fileInMemory;
|
||||
if(!reload) { fileInMemory = std.file.read(file); }
|
||||
void[] fileWorkingCopy = fileInMemory.dup;
|
||||
|
||||
// Instead of constructing a resolver/constructor with each Loader,
|
||||
// construct them once to remove noise when profiling.
|
||||
auto resolver = new Resolver();
|
||||
auto constructor = new Constructor();
|
||||
|
||||
while(runs--)
|
||||
auto constructTime = stopWatch.peek();
|
||||
|
||||
Node[] nodes;
|
||||
|
||||
void runLoaderBenchmark() //@safe
|
||||
{
|
||||
// Loading the file rewrites the loaded buffer, so if we don't reload from
|
||||
// disk, we need to use a copy of the originally loaded file.
|
||||
if(reload) { fileInMemory = std.file.read(file); }
|
||||
else { fileWorkingCopy[] = fileInMemory[]; }
|
||||
void[] fileToLoad = reload ? fileInMemory : fileWorkingCopy;
|
||||
|
||||
auto loader = Loader(fileToLoad);
|
||||
if(scanOnly)
|
||||
{
|
||||
auto loader = Loader(fileToLoad);
|
||||
loader.scanBench();
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
auto loader = Loader(fileToLoad);
|
||||
|
||||
loader.resolver = resolver;
|
||||
loader.constructor = constructor;
|
||||
auto nodes = loader.loadAll();
|
||||
nodes = loader.loadAll();
|
||||
}
|
||||
void runDumpBenchmark() @safe
|
||||
{
|
||||
if(dump)
|
||||
{
|
||||
Dumper(file ~ ".dump").dump(nodes);
|
||||
}
|
||||
}
|
||||
void runGetBenchmark() @safe
|
||||
{
|
||||
if(get) foreach(ref node; nodes)
|
||||
{
|
||||
extract(node);
|
||||
}
|
||||
}
|
||||
auto totalTime = benchmark!(runLoaderBenchmark, runDumpBenchmark, runGetBenchmark)(runs);
|
||||
if (!quiet)
|
||||
{
|
||||
auto enabledOptions =
|
||||
only(
|
||||
get ? "Get" : "",
|
||||
dump ? "Dump" : "",
|
||||
reload ? "Reload" : "",
|
||||
scanOnly ? "Scan Only": ""
|
||||
).filter!(x => x != "");
|
||||
if (!enabledOptions.empty)
|
||||
{
|
||||
writefln!"Options enabled: %-(%s, %)"(enabledOptions);
|
||||
}
|
||||
if (verbose)
|
||||
{
|
||||
if (!reload)
|
||||
{
|
||||
writeln("Time to load file: ", loadTime);
|
||||
}
|
||||
writeln("Time to set up resolver & constructor: ", constructTime);
|
||||
}
|
||||
writeln("Runs: ", runs);
|
||||
foreach(time, func, enabled; lockstep(totalTime[], only("Loader", "Dumper", "Get"), only(true, dump, get)))
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
writeln("Average time spent on ", func, ": ", time / runs);
|
||||
writeln("Total time spent on ", func, ": ", time);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(YAMLException e)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue