Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
report percentiles along with the median
  • Loading branch information
jamis committed Aug 14, 2023
commit 897fc1c58c1188da0d19746767b28f7381a7406b
10 changes: 4 additions & 6 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -137,22 +137,20 @@ require_relative "profile/benchmarking"
namespace :benchmark do
desc "Run the driver benchmark tests."

namespace :micro do
desc "Run the common driver micro benchmarking tests"
namespace :bson do
desc "Run the bson benchmarking tests"

namespace :flat do
desc "Benchmarking for flat bson documents."

# Requirement: A file in Mongo::Benchmarking::DATA_PATH, called flat_bson.json.
task :encode do
puts "MICRO BENCHMARK:: FLAT:: ENCODE"
Mongo::Benchmarking::Micro.run(:flat, :encode)
Mongo::Benchmarking.report({ bson: { flat: { encode: Mongo::Benchmarking::Micro.run(:flat, :encode) } } })
end

# Requirement: A file in Mongo::Benchmarking::DATA_PATH, called flat_bson.json.
task :decode do
puts "MICRO BENCHMARK:: FLAT:: DECODE"
Mongo::Benchmarking::Micro.run(:flat, :decode)
Mongo::Benchmarking.report({ bson: { flat: { decode: Mongo::Benchmarking::Micro.run(:flat, :encode) } } })
end
end

Expand Down
60 changes: 57 additions & 3 deletions profile/benchmarking/helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,19 +81,73 @@ def benchmark(max_iterations: Benchmarking::TEST_REPETITIONS, min_time: 60, max_
end
end

# Formats and displays a report of the given results.
#
# @param [ Hash ] results the results of a benchmarking run.
# @param [ Integer ] indent how much the report should be indented.
# @param [ Array<Number> ] percentiles the percentile values to report
def report(results, indent: 0, percentiles: [ 10, 25, 50, 75, 90, 95, 98, 99 ])
indentation = ' ' * indent
results.each do |key, value|
puts "#{indentation}#{key}:"
if value.is_a?(Hash)
report(value, indent: indent + 2, percentiles: percentiles)
else
ps = Percentiles.new(value)
puts "#{indentation} median: %g" % [ ps[50] ]
puts "#{indentation} percentiles:"
percentiles.each do |pct|
puts "#{indentation} %g: %g" % [ pct, ps[pct] ]
end
end
end
end

# A utility class for returning the list item at a given percentile
# value.
class Percentiles
# @return [ Array<Number> ] the sorted list of numbers to consider
attr_reader :list

# Create a new Percentiles object that encapsulates the given list of
# numbers.
#
# @param [ Array<Number> ] list the list of numbers to considier
def initialize(list)
@list = list.sort
end

# Finds and returns the element in the list that represents the given
# percentile value.
#
# @param [ Number ] percentile a number in the range [1,100]
#
# @return [ Number ] the element of the list for the given percentile.
def [](percentile)
i = (list.size * percentile / 100.0).ceil - 1
list[i]
end
end

# Get the median of values in a list.
#
# @example Get the median.
# Benchmarking.median(values)
#
# @param [ Array ] The values to get the median of.
# @param [ Array ] values The values to get the median of.
#
# @return [ Numeric ] The median of the list.
#
# @since 2.2.3
def median(values)
i = (values.size / 2) - 1
values.sort[i]
end

# Runs a given block with GC disabled.
def without_gc
GC.disable
yield
ensure
GC.enable
end
end
end
58 changes: 33 additions & 25 deletions profile/benchmarking/micro.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,43 @@ module Mongo
module Benchmarking
# These tests focus on BSON encoding and decoding; they are client-side only and
# do not involve any transmission of data to or from the server.
#
# @since 2.2.3
module Micro
extend self

# Runs all of the benchmarks specified by the given mapping.
#
# @example Run a collection of benchmarks.
# Benchmarking::Micro.run_all(
# flat: %i[ encode decode ],
# deep: %i[ encode decode ],
# full: %i[ encode decode ]
# )
#
# @return [ Hash ] a hash of the results for each benchmark
def run_all(map)
{}.tap do |results|
map.each do |type, actions|
results[type] = {}

actions.each do |action|
results[type][action] = run(type, action)
end
end
end
end

# Run a micro benchmark test.
#
# @example Run a test.
# Benchmarking::Micro.run(:flat)
#
# @param [ Symbol ] type The type of test to run.
# @param [ Integer ] repetitions The number of test repetitions.
#
# @return [ Numeric ] The test results.
# @param [ :encode | :decode ] action The action to perform.
#
# @since 2.2.3
def run(type, action, repetitions = Benchmarking::TEST_REPETITIONS)
file_name = type.to_s << '_bson.json'
GC.disable
file_path = [ Benchmarking::DATA_PATH, file_name ].join('/')
puts "#{action} : #{send(action, file_path, repetitions)}"
GC.enable
# @return [ Array<Number> ] The test results for each iteration
def run(type, action)
file_path = File.join(Benchmarking::DATA_PATH, "#{type}_bson.json")
Benchmarking.without_gc { send(action, file_path) }
end

# Run an encoding micro benchmark test.
Expand All @@ -50,17 +65,14 @@ def run(type, action, repetitions = Benchmarking::TEST_REPETITIONS)
# @param [ String ] file_name The name of the file with data for the test.
# @param [ Integer ] repetitions The number of test repetitions.
#
# @return [ Numeric ] The median of the results.
#
# @since 2.2.3
def encode(file_name, repetitions)
# @return [ Array<Numeric> ] The list of the results for each iteration
def encode(file_name)
data = Benchmarking.load_file(file_name)
document = BSON::Document.new(data.first)

results = Benchmarking.benchmark(max_iterations: repetitions) do
Benchmarking.benchmark do
10_000.times { document.to_bson }
end
Benchmarking.median(results)
end

# Run a decoding micro benchmark test.
Expand All @@ -71,21 +83,17 @@ def encode(file_name, repetitions)
# @param [ String ] file_name The name of the file with data for the test.
# @param [ Integer ] repetitions The number of test repetitions.
#
# @return [ Numeric ] The median of the results.
#
# @since 2.2.3
def decode(file_name, repetitions)
# @return [ Array<Numeric> ] The list of the results for each iteration
def decode(file_name)
data = Benchmarking.load_file(file_name)
buffer = BSON::Document.new(data.first).to_bson

results = Benchmarking.benchmark(max_iterations: repetitions) do
Benchmarking.benchmark do
10_000.times do
BSON::Document.from_bson(buffer)
buffer.rewind!
end
end

Benchmarking.median(results)
end
end
end
Expand Down