1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
|
#!/usr/bin/env ruby
=begin
Use this script to monitor changes in performance when making code changes to Asciidoctor.
$ ruby benchmark.rb <benchmark-name> <repeat>
The most common benchmark is the userguide-loop.
It will download the AsciiDoc User Guide automatically the first time, then convert it in memory.
Running it 10 times provides a good picture.
$ ruby benchmark.rb userguide-loop 10
Only worry about the relative change to the numbers before and after the code change.
Absolute times are highly dependent on the capabilities of the machine the the version of Ruby.
To get the best results under MRI, tune Ruby using environment variables as follows:
.Ruby < 2.1
$ RUBY_GC_MALLOC_LIMIT=90000000 RUBY_FREE_MIN=650000 ruby benchmark.rb userguide-loop 10
.Ruby >= 2.1
$ RUBY_GC_MALLOC_LIMIT=128000000 RUBY_GC_OLDMALLOC_LIMIT=128000000 RUBY_GC_HEAP_INIT_SLOTS=10000000 RUBY_GC_HEAP_FREE_SLOTS=10000000 RUBY_GC_HEAP_GROWTH_MAX_SLOTS=250000 RUBY_GC_HEAP_GROWTH_FACTOR=2 ruby benchmark.rb userguide-loop 10
$ RUBY_GC_MALLOC_LIMIT=128000000 RUBY_GC_OLDMALLOC_LIMIT=128000000 RUBY_GC_HEAP_INIT_SLOTS=20000000 RUBY_GC_HEAP_FREE_SLOTS=1000000 RUBY_GC_HEAP_GROWTH_MAX_SLOTS=250000 RUBY_GC_HEAP_GROWTH_FACTOR=2 ruby benchmark.rb userguide-loop 10
Asciidoctor starts with ~ 12,500 objects, adds ~ 300,000 each run, so tune RUBY_GC_HEAP_* accordingly
See http://globaldev.co.uk/2014/05/ruby-2-1-in-detail/#gc-tuning-environment-variables
Execute Ruby using the `--disable=gems` flag to speed up the initial load time, as shown below:
$ ruby --disable=gems ...
=end
require 'benchmark'
include Benchmark
bench = ARGV[0]
$repeat = ARGV[1].to_i || 10000
if bench.nil?
raise 'You must specify a benchmark to run.'
end
def fetch_userguide
require 'open-uri'
userguide_uri = 'https://raw.githubusercontent.com/asciidoc/asciidoc/d43faae38c4a8bf366dcba545971da99f2b2d625/doc/asciidoc.txt'
customers_uri = 'https://raw.githubusercontent.com/asciidoc/asciidoc/d43faae38c4a8bf366dcba545971da99f2b2d625/doc/customers.csv'
userguide_content = OpenURI.open_uri(userguide_uri) {|fd2| fd2.read }
customers_content = OpenURI.open_uri(customers_uri) {|fd2| fd2.read }
File.write 'sample-data/userguide.adoc', userguide_content, mode: 'w:utf-8'
File.write 'sample-data/customers.csv', customers_content, mode: 'w:utf-8'
end
case bench
=begin
# benchmark template
when 'name'
sample = 'value'
Benchmark.bmbm(12) {|bm|
bm.report('operation a') { $repeat.times { call_a_on sample } }
bm.report('operation b') { $repeat.times { call_b_on sample } }
}
=end
when 'userguide'
require '../lib/asciidoctor.rb'
Asciidoctor::Compliance.markdown_syntax = false
Asciidoctor::Compliance.shorthand_property_syntax = false if Asciidoctor::VERSION > '0.1.4'
sample_file = ENV['BENCH_TEST_FILE'] || 'sample-data/userguide.adoc'
backend = ENV['BENCH_BACKEND'] || 'html5'
fetch_userguide if sample_file == 'sample-data/userguide.adoc' && !(File.exist? sample_file)
result = Benchmark.bmbm {|bm|
bm.report(%(Convert #{sample_file} (x#{$repeat}))) {
$repeat.times {
Asciidoctor.render_file sample_file, :backend => backend, :safe => Asciidoctor::SafeMode::SAFE, :eruby => 'erubis', :header_footer => true, :to_file => false, :attributes => {'stylesheet' => nil, 'toc' => nil, 'numbered' => nil, 'icons' => nil, 'compat-mode' => ''}
}
}
}
# prints average for real run
puts %(>avg: #{result.first.real / $repeat})
when 'userguide-loop'
require '../lib/asciidoctor.rb'
GC.start
Asciidoctor::Compliance.markdown_syntax = false
Asciidoctor::Compliance.shorthand_property_syntax = false if Asciidoctor::VERSION > '0.1.4'
sample_file = ENV['BENCH_TEST_FILE'] || 'sample-data/userguide.adoc'
backend = ENV['BENCH_BACKEND'] || 'html5'
fetch_userguide if sample_file == 'sample-data/userguide.adoc' && !(File.exist? sample_file)
timings = []
2.times.each do
loop_timings = []
(1..$repeat).each do
start = Time.now
Asciidoctor.render_file sample_file, :backend => backend, :safe => Asciidoctor::SafeMode::SAFE, :eruby => 'erubis', :header_footer => true, :to_file => false, :attributes => { 'stylesheet' => nil, 'toc' => nil, 'numbered' => nil, 'icons' => nil, 'compat-mode' => '' }
loop_timings << (Time.now - start)
end
timings << loop_timings
end
best_time = nil
timings.each do |loop_timings|
puts %(#{loop_timings * "\n"}\nRun Total: #{loop_timings.reduce :+})
best_time = best_time ? [best_time, loop_timings.min].min : loop_timings.min
end
puts %(Best Time: #{best_time})
when 'mdbasics-loop'
require '../lib/asciidoctor.rb'
GC.start
sample_file = ENV['BENCH_TEST_FILE'] || 'sample-data/mdbasics.adoc'
backend = ENV['BENCH_BACKEND'] || 'html5'
timings = []
2.times do
loop_timings = []
(1..$repeat).each do
start = Time.now
Asciidoctor.render_file sample_file, :backend => backend, :safe => Asciidoctor::SafeMode::SAFE, :header_footer => false, :to_file => false, :attributes => { 'stylesheet' => nil, 'idprefix' => '', 'idseparator' => '-', 'showtitle' => '' }
loop_timings << (Time.now - start)
end
timings << loop_timings
end
best_time = nil
timings.each do |loop_timings|
puts %(#{loop_timings * "\n"}\nRun Total: #{loop_timings.reduce :+})
best_time = best_time ? [best_time, loop_timings.min].min : loop_timings.min
end
puts %(Best Time: #{best_time})
end
|